Relay Module Control

Control high-power devices remotely using relay modules with ESP32

Relay Module

What is a Relay?

A relay is an electrically operated switch that allows low-voltage circuits (like ESP32 at 3.3V) to control high-voltage/high-current circuits (like 220V AC appliances). It provides electrical isolation between control and power circuits for safety.

Relay Module Specifications

Control Side (Low Voltage)
  • Operating Voltage: 3.3V - 5V DC
  • Trigger Current: 5-20 mA
  • Trigger Type: Active Low or High
  • Input: Digital signal from MCU
  • Response Time: 5-10 ms
Power Side (High Voltage)
  • Max AC Voltage: 250V AC
  • Max DC Voltage: 30V DC
  • Max Current: 10A (typical)
  • Max Power: 2500W (10A @ 250V)
  • Contacts: NO, NC, COM

Current Rating

Always check your specific relay module's current rating. Common ratings are 5A and 10A. Never exceed the rated current - add a safety margin (use only 80% of rated capacity for continuous operation).

Pin Configuration

Control Pins (Low Voltage Side)

PinFunctionESP32 Connection
VCCPower supply (3.3V or 5V)3.3V or 5V pin
GNDGroundGND pin
IN1Control signal for relay 1GPIO 25
IN2Control signal for relay 2GPIO 26

Power Terminals (High Voltage Side)

TerminalNameDescription
1COMCommon - always connected to power source
2NONormally Open - closed when relay activated
3NCNormally Closed - opens when relay activated

Note: For most applications, use COM and NO terminals. The load is OFF when relay is inactive, ON when relay is activated.

Active Low vs Active High

Active Low (Common)

Relay activates when signal is LOW (0V):

  • digitalWrite(pin, LOW) → Relay ON
  • digitalWrite(pin, HIGH) → Relay OFF
  • Most relay modules use this
Active High (Less Common)

Relay activates when signal is HIGH (3.3V):

  • digitalWrite(pin, HIGH) → Relay ON
  • digitalWrite(pin, LOW) → Relay OFF
  • Check your module's documentation

How to Identify

Most Chinese relay modules have LED indicators. Connect power and leave IN pin floating or connected to VCC - if LED is ON, it's Active Low. If LED is OFF, it's Active High.

Basic Control Code

relay_basic.inocpp
// Define relay pins
#define RELAY1_PIN 25
#define RELAY2_PIN 26

void setup() {
  Serial.begin(115200);
  
  // Initialize relay pins as outputs
  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  
  // Initial state - all relays OFF
  // For Active Low modules:
  digitalWrite(RELAY1_PIN, HIGH);  // OFF
  digitalWrite(RELAY2_PIN, HIGH);  // OFF
  
  Serial.println("Relay control initialized");
}

void loop() {
  // Turn relay 1 ON
  Serial.println("Relay 1 ON");
  digitalWrite(RELAY1_PIN, LOW);   // For Active Low
  delay(3000);
  
  // Turn relay 1 OFF
  Serial.println("Relay 1 OFF");
  digitalWrite(RELAY1_PIN, HIGH);  // For Active Low
  delay(3000);
  
  // Turn relay 2 ON
  Serial.println("Relay 2 ON");
  digitalWrite(RELAY2_PIN, LOW);
  delay(3000);
  
  // Turn relay 2 OFF
  Serial.println("Relay 2 OFF");
  digitalWrite(RELAY2_PIN, HIGH);
  delay(3000);
  
  // Both relays ON
  Serial.println("Both relays ON");
  digitalWrite(RELAY1_PIN, LOW);
  digitalWrite(RELAY2_PIN, LOW);
  delay(3000);
  
  // Both relays OFF
  Serial.println("Both relays OFF");
  digitalWrite(RELAY1_PIN, HIGH);
  digitalWrite(RELAY2_PIN, HIGH);
  delay(3000);
}

Control via WiFi Commands

relay_wifi_control.inocpp
#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

#define RELAY1_PIN 25
#define RELAY2_PIN 26

WebServer server(80);

// Relay states
bool relay1State = false;
bool relay2State = false;

void setup() {
  Serial.begin(115200);
  
  // Initialize relays
  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  digitalWrite(RELAY1_PIN, HIGH);  // OFF
  digitalWrite(RELAY2_PIN, HIGH);  // OFF
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("\nConnected to WiFi");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
  
  // Setup web server routes
  server.on("/", handleRoot);
  server.on("/relay1/on", []() { controlRelay(1, true); });
  server.on("/relay1/off", []() { controlRelay(1, false); });
  server.on("/relay2/on", []() { controlRelay(2, true); });
  server.on("/relay2/off", []() { controlRelay(2, false); });
  server.on("/status", handleStatus);
  
  server.begin();
  Serial.println("Web server started");
}

void loop() {
  server.handleClient();
}

void controlRelay(int relayNum, bool state) {
  int pin = (relayNum == 1) ? RELAY1_PIN : RELAY2_PIN;
  
  // Active Low: LOW = ON, HIGH = OFF
  digitalWrite(pin, state ? LOW : HIGH);
  
  if (relayNum == 1) {
    relay1State = state;
  } else {
    relay2State = state;
  }
  
  String response = "Relay " + String(relayNum) + " turned " + (state ? "ON" : "OFF");
  server.send(200, "text/plain", response);
  
  Serial.println(response);
}

void handleRoot() {
  String html = "<html><body>";
  html += "<h1>Gridova Relay Control</h1>";
  html += "<p>Relay 1: " + String(relay1State ? "ON" : "OFF") + "</p>";
  html += "<a href='/relay1/on'><button>Turn ON</button></a> ";
  html += "<a href='/relay1/off'><button>Turn OFF</button></a><br><br>";
  html += "<p>Relay 2: " + String(relay2State ? "ON" : "OFF") + "</p>";
  html += "<a href='/relay2/on'><button>Turn ON</button></a> ";
  html += "<a href='/relay2/off'><button>Turn OFF</button></a>";
  html += "</body></html>";
  
  server.send(200, "text/html", html);
}

void handleStatus() {
  String json = "{\"relay1\":" + String(relay1State ? "true" : "false");
  json += ",\"relay2\":" + String(relay2State ? "true" : "false") + "}";
  
  server.send(200, "application/json", json);
}

Access the web interface at: http://ESP32_IP_ADDRESS/

Integration with Gridova API

gridova_relay_integration.inocpp
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* serverUrl = "https://api.gridova.com/relay/control";
const char* deviceId = "ROOM_001";
unsigned long lastCheckTime = 0;
const unsigned long checkInterval = 5000; // Check every 5 seconds

#define RELAY1_PIN 25
#define RELAY2_PIN 26

void setup() {
  Serial.begin(115200);
  
  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  digitalWrite(RELAY1_PIN, HIGH);
  digitalWrite(RELAY2_PIN, HIGH);
  
  // Connect to WiFi
  WiFi.begin("SSID", "PASSWORD");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  
  Serial.println("Connected!");
}

void loop() {
  unsigned long currentTime = millis();
  
  // Check server for relay commands
  if (currentTime - lastCheckTime >= checkInterval) {
    checkRelayCommands();
    lastCheckTime = currentTime;
  }
}

void checkRelayCommands() {
  if (WiFi.status() != WL_CONNECTED) return;
  
  HTTPClient http;
  String url = String(serverUrl) + "?device_id=" + deviceId;
  
  http.begin(url);
  int httpCode = http.GET();
  
  if (httpCode == 200) {
    String payload = http.getString();
    
    // Parse JSON response
    StaticJsonDocument<256> doc;
    DeserializationError error = deserializeJson(doc, payload);
    
    if (!error) {
      bool relay1 = doc["relay1"];
      bool relay2 = doc["relay2"];
      
      // Update relay states
      digitalWrite(RELAY1_PIN, relay1 ? LOW : HIGH);
      digitalWrite(RELAY2_PIN, relay2 ? LOW : HIGH);
      
      Serial.printf("Updated: Relay1=%s, Relay2=%s\n", 
                    relay1 ? "ON" : "OFF", 
                    relay2 ? "ON" : "OFF");
    }
  }
  
  http.end();
}

// Function to report relay state to server
void reportRelayState() {
  HTTPClient http;
  http.begin(serverUrl);
  http.addHeader("Content-Type", "application/json");
  
  StaticJsonDocument<256> doc;
  doc["device_id"] = deviceId;
  doc["relay1"] = (digitalRead(RELAY1_PIN) == LOW);
  doc["relay2"] = (digitalRead(RELAY2_PIN) == LOW);
  doc["timestamp"] = millis();
  
  String jsonString;
  serializeJson(doc, jsonString);
  
  int httpCode = http.POST(jsonString);
  Serial.printf("Report sent: %d\n", httpCode);
  
  http.end();
}

High Voltage Wiring

Electrical Safety Warning

This section involves working with mains voltage (220V AC). Only qualified personnel should perform these connections. Improper wiring can cause fire, electric shock, or death.

Wiring Diagram Explanation

AC Mains (220V) → Circuit Breaker → Relay COM
Relay NO → Load (Appliance) → Neutral

Step-by-step:

  1. Disconnect all power sources
  2. Connect Live wire from breaker to relay COM terminal
  3. Connect relay NO terminal to appliance Live wire
  4. Connect appliance Neutral directly to mains Neutral
  5. Connect Ground/Earth to appliance chassis
  6. Secure all connections with proper wire nuts or terminals
  7. Install in proper electrical enclosure
  8. Test with multimeter before applying power

Safety Considerations

Current Rating & Load
  • Calculate total load current: Power (W) ÷ Voltage (V) = Current (A)
  • Use relay rated for at least 1.5x your load current
  • For inductive loads (motors, compressors), use 2x rating
  • Add heat sink for continuous high-current operation
Protection Devices
  • Always use circuit breaker or fuse (rated for load + 20%)
  • Add surge protector for sensitive electronics
  • Use GFCI/RCD for wet locations
  • Consider adding snubber circuit for inductive loads
Enclosure & Installation
  • Use IP-rated electrical box (IP54 minimum for indoor)
  • Ensure proper ventilation to prevent overheating
  • Label all wires clearly
  • Use appropriate wire gauge (14 AWG for 15A, 12 AWG for 20A)
  • Maintain proper clearance between terminals
Firmware Safety Features
  • Implement watchdog timer to reset if system hangs
  • Add maximum ON time limit (prevent stuck-on relay)
  • Use failsafe default state (OFF on boot)
  • Log all relay state changes with timestamp
  • Add manual override button for emergency shutoff

Advanced: Failsafe Code

relay_failsafe.inocpp
#include <esp_task_wdt.h>

#define RELAY1_PIN 25
#define MAX_ON_TIME 3600000  // 1 hour in milliseconds
#define WDT_TIMEOUT 10       // 10 seconds

unsigned long relay1OnTime = 0;
bool relay1Active = false;

void setup() {
  Serial.begin(115200);
  
  pinMode(RELAY1_PIN, OUTPUT);
  digitalWrite(RELAY1_PIN, HIGH);  // OFF by default (failsafe)
  
  // Setup watchdog timer
  esp_task_wdt_init(WDT_TIMEOUT, true);
  esp_task_wdt_add(NULL);
  
  Serial.println("Failsafe relay control initialized");
}

void loop() {
  // Reset watchdog
  esp_task_wdt_reset();
  
  // Check maximum ON time
  if (relay1Active) {
    if (millis() - relay1OnTime > MAX_ON_TIME) {
      Serial.println("Max ON time reached - turning OFF");
      setRelay1(false);
    }
  }
  
  // Your control logic here
  delay(100);
}

void setRelay1(bool state) {
  digitalWrite(RELAY1_PIN, state ? LOW : HIGH);
  relay1Active = state;
  
  if (state) {
    relay1OnTime = millis();
    Serial.println("Relay 1 ON");
  } else {
    Serial.println("Relay 1 OFF");
  }
  
  // Log to EEPROM or send to server
  logRelayState(1, state);
}

void logRelayState(int relay, bool state) {
  // Save to EEPROM or send to server
  Serial.printf("LOG: Relay %d = %s at %lu\n", 
                relay, state ? "ON" : "OFF", millis());
}

Troubleshooting

Relay Clicks But Load Doesn't Turn On
  • Check if using correct terminals (COM and NO, not NC)
  • Verify load is plugged in and functional
  • Test with multimeter across NO-COM when activated
  • Check wire connections are secure
Relay Doesn't Click
  • Check if relay module has power (VCC and GND)
  • Verify GPIO pin is configured as OUTPUT
  • Test if LED indicator turns on
  • Check if using correct trigger logic (Active Low/High)
  • Measure voltage on IN pin when triggered
Relay Gets Hot
  • Load current may exceed relay rating
  • Check for loose connections causing resistance
  • Ensure proper ventilation around relay
  • Consider using contactor for high-power loads
Random Triggering
  • Add pull-up/pull-down resistor on control pin
  • Ensure stable power supply
  • Check for electromagnetic interference
  • Use shielded cables for control signals
  • Add 0.1µF capacitor between VCC and GND

Next Steps

Complete Wiring Diagram
See how relay integrates with ESP32, PZEM sensor, and AC power
WebSocket Real-time Control
Implement instant relay control via WebSocket connection
Mobile App Integration
Control relays from Gridova Flutter mobile app