ESP32 Relay Interface Design Guide
1. Basic Principles of Relays
Functions and Types of Relays
A relay is an electromagnetic switch that controls a high-voltage circuit (110V/220V) through a low-voltage control signal (3.3V/5V). The common types used in the ESP32 system are:
| Type | Control Signal | Load Capacity | Isolation Method | Features |
|---|---|---|---|---|
| Mechanical Relay | Low Current | Up to 250V 10A | Electromagnetic Isolation | Has mechanical action sound, lifespan of about 100,000 cycles |
| Solid State Relay | 3-32VDC | Up to 480V 5A | Optical Isolation | No mechanical noise, long lifespan |
| Power Module | 3.3V Logic | 60V 30A | Semiconductor Isolation | Can be PWM controlled, supports high-frequency switching |
Working Principle of Relays
ESP32 GPIO → Opto-isolation → Driver Circuit → Electromagnetic Coil → Contact Switch → High Voltage Load
(Mechanical)
or
TRIAC/Transistor → High Voltage Load
(Solid State)
2. Hardware Interface Design
Typical Wiring Scheme (Mechanical Relay)
ESP32 Relay Module Load Device
-------------------------------
GND → GND
GPIO13 → IN
3.3V → VCC
NO → Load Live Wire
COM → AC Power Live Wire
NC → Not Used (Normally Closed)
Load Neutral Wire → AC Power Neutral Wire
Key Design for Anti-Interference
- Opto-IsolationChoose a relay module with opto-isolation (e.g., JQC-3FF-S-Z)
- Reverse ProtectionConnect a 1N4007 diode in parallel with the relay coil
- Buffer CircuitConnect an RC snubber circuit (100Ω + 0.1μF) in parallel with the relay output
- Independent Power SupplyPower the relay separately (do not share with ESP32)
3. Basic Control Code
Simple Switch Control
const int RELAY_PIN = 13; // Control Pin
void setup() {
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // Initial off state
Serial.begin(115200);
}
void loop() {
// Turn on the relay
digitalWrite(RELAY_PIN, HIGH);
Serial.println("Relay is ON");
delay(5000); // Maintain for 5 seconds
// Turn off the relay
digitalWrite(RELAY_PIN, LOW);
Serial.println("Relay is OFF");
delay(5000); // Off for 5 seconds
}
Improvement: Adding Protection Mechanism
unsigned long lastSwitchTime = 0;
const int MIN_SWITCH_INTERVAL = 3000; // Minimum switch interval (milliseconds)
void controlRelay(bool state) {
if (millis() - lastSwitchTime < MIN_SWITCH_INTERVAL) {
Serial.println("Switching too frequently!");
return;
}
digitalWrite(RELAY_PIN, state ? HIGH : LOW);
lastSwitchTime = millis();
// State confirmation
int actualState = digitalRead(RELAY_PIN);
if (actualState != state) {
Serial.println("Relay state abnormal!");
// Execute safety protection
emergencyShutdown();
}
}
4. Advanced Application Design
Multi-Channel Relay Control
// Relay Pin Mapping
const int RELAY_PINS[] = {13, 12, 14, 27};
const int RELAY_COUNT = sizeof(RELAY_PINS) / sizeof(int);
// Relay interlock safety mechanism
void activateRelay(int index, bool state) {
if (index < 0 || index >= RELAY_COUNT) return;
// Check conflicting relay
if (state && index == 0) {
deactivateRelay(1); // Turn off relay 1 when relay 0 is on
}
digitalWrite(RELAY_PINS[index], state ? HIGH : LOW);
}
// Emergency shutdown for all relays
void emergencyShutdown() {
for (int i = 0; i < RELAY_COUNT; i++) {
digitalWrite(RELAY_PINS[i], LOW);
}
Serial.println("All relays have been emergency shut down");
}
Timed Control Function
#include <TimeLib.h> // Time Library
struct Schedule {
int relayIndex;
int hourOn;
int minOn;
int hourOff;
int minOff;
};
Schedule schedules[] = {
{0, 7, 0, 9, 0}, // Relay 0: ON 7:00 - OFF 9:00
{1, 18, 30, 22, 0} // Relay 1: ON 18:30 - OFF 22:00
};
void checkSchedules() {
time_t now = now(); // Get current time
int currentHour = hour(now);
int currentMin = minute(now);
for (int i = 0; i < sizeof(schedules) / sizeof(Schedule); i++) {
bool shouldBeOn = (currentHour > schedules[i].hourOn ||
(currentHour == schedules[i].hourOn && currentMin >= schedules[i].minOn)) &&
(currentHour < schedules[i].hourOff ||
(currentHour == schedules[i].hourOff && currentMin < schedules[i].minOff));
digitalWrite(RELAY_PINS[schedules[i].relayIndex], shouldBeOn ? HIGH : LOW);
}
}
// Call in loop
void loop() {
checkSchedules();
delay(60000); // Check every minute
}
5. Network Control
Web Server Control
#include <WiFi.h>
#include <WebServer.h>
WebServer server(80);
void handleRoot() {
String html = "<html><body><h1>Relay Control</h1>";
for (int i = 0; i < RELAY_COUNT; i++) {
html += "<p>Relay " + String(i) + ": ";
html += "<a href=\"/relay/" + String(i) + "/on\"><button>ON</button></a> ";
html += "<a href=\"/relay/" + String(i) + "/off\"><button>OFF</button></a></p>";
}
html += "</body></html>";
server.send(200, "text/html", html);
}
void handleRelayControl() {
String relayId = server.uri().substring(7, 8);
String action = server.uri().substring(9);
int relayIndex = relayId.toInt();
if (action == "on") {
activateRelay(relayIndex, true);
server.send(200, "text/plain", "Relay " + relayId + " is ON");
} else if (action == "off") {
activateRelay(relayIndex, false);
server.send(200, "text/plain", "Relay " + relayId + " is OFF");
}
}
void setupServer() {
server.on("/", handleRoot);
server.on("/relay/*", handleRelayControl);
server.begin();
}
MQTT Remote Control
#include <PubSubClient.h>
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
void mqttCallback(char* topic, byte* payload, unsigned int length) {
String topicStr = String(topic);
String payloadStr = String((char*)payload, length);
if (topicStr.endsWith("/relay/command")) {
int separator = payloadStr.indexOf(',');
if (separator != -1) {
int relayIndex = payloadStr.substring(0, separator).toInt();
bool state = payloadStr.substring(separator + 1) == "on";
activateRelay(relayIndex, state);
}
}
}
void connectMQTT() {
mqttClient.setServer("mqtt.server.com", 1883);
mqttClient.setCallback(mqttCallback);
while (!mqttClient.connect("ESP32RelayController")) {
delay(1000);
}
mqttClient.subscribe("home/relay/command");
mqttClient.publish("home/relay/status", "Online");
}
6. Safety Protection Mechanisms
Hardware Protection Measures
- Overvoltage ProtectionConnect a TVS diode (15V) in parallel at the input
- Overcurrent ProtectionConnect a resettable fuse in series at the relay output
- Heat Dissipation DesignLeave at least 20mm spacing between each relay
- Dust ProtectionCover high voltage parts with insulating plates
Software Protection Mechanisms
// Temperature Monitoring Protection
#include <OneWire.h>
#include <DallasTemperature.h>
#define TEMP_SENSOR_PIN 25
OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature sensors(&oneWire);
void checkTemperature() {
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
if (temp > 65.0) { // Temperature threshold
emergencyShutdown();
Serial.println("Overheat protection triggered");
}
}
// Communication watchdog
unsigned long lastCommTime = 0;
const int COMM_TIMEOUT = 600000; // 10 minutes
void checkCommunication() {
if (millis() - lastCommTime > COMM_TIMEOUT) {
Serial.println("Communication timeout, entering safe mode");
activateSafeMode();
}
}
void updateCommWatchdog() {
lastCommTime = millis();
}
7. Application Scenario Examples
Smart Home Control Center
#define LIGHT_RELAY 0
#define AC_RELAY 1
#define HEATER_RELAY 2
void controlHomeAppliances(String device, bool state) {
if (device == "light") {
activateRelay(LIGHT_RELAY, state);
} else if (device == "ac") {
activateRelay(AC_RELAY, state);
} else if (device == "heater") {
if (state) {
// Check safety before turning on heater
if (!isWindowClosed()) {
Serial.println("Window is open, heater disabled");
return;
}
activateRelay(HEATER_RELAY, true);
} else {
activateRelay(HEATER_RELAY, false);
}
}
}
Industrial Automation Control
#define MOTOR_START_RELAY 0
#define MOTOR_DIRECTION_RELAY 1
#define EMERGENCY_STOP_RELAY 3
void controlMotor(bool start, bool direction) {
// Interlock logic: must select direction before starting
if (start && !digitalRead(MOTOR_DIRECTION_RELAY)) {
Serial.println("Direction not selected, cannot start");
return;
}
// Sequential operation
activateRelay(MOTOR_DIRECTION_RELAY, direction);
delay(100); // Ensure direction relay fully actuates
activateRelay(MOTOR_START_RELAY, start);
// Safety interlock: prevent direction change during operation
if (start) {
deactivateRelay(MOTOR_DIRECTION_RELAY); // Disable direction switching
}
}
// Emergency stop button handling
void handleEmergencyStop() {
activateRelay(EMERGENCY_STOP_RELAY, true); // Trigger safety relay
activateRelay(MOTOR_START_RELAY, false); // Stop operation
Serial.println("Emergency stop triggered");
}
8. Optimization and Debugging
Power Consumption Optimization
void enterLowPowerMode() {
// 1. Disable relay power supply
digitalWrite(RELAY_POWER_PIN, LOW);
// 2. ESP32 enters deep sleep
esp_sleep_enable_timer_wakeup(3600 * 1000000); // 1 hour
esp_deep_sleep_start();
}
// Wake up only when needed
void activateSystem() {
if (detectedActivity()) {
digitalWrite(RELAY_POWER_PIN, HIGH);
delay(100); // Relay stabilization time
// ...normal operation
}
}
Status Monitoring
void reportRelayStatus() {
String status = "";
for (int i = 0; i < RELAY_COUNT; i++) {
status += "Relay " + String(i) + ": " +
(digitalRead(RELAY_PINS[i]) ? "ON" : "OFF");
if (i < RELAY_COUNT - 1) status += " | ";
}
// Send to cloud
if (WiFi.status() == WL_CONNECTED) {
mqttClient.publish("home/relay/status", status.c_str());
}
Serial.println(status);
}
Fault Diagnosis
void diagnoseRelay(int index) {
Serial.println("===== Relay Diagnosis =====");
Serial.print("Status: ");
Serial.println(digitalRead(RELAY_PINS[index]) ? "ON" : "OFF");
// Load detection (simple)
float voltage = analogRead(LOAD_SENSE_PINS[index]) * (3.3 / 4095.0);
if (voltage < 0.2) {
Serial.println("No load detected");
} else if (voltage > 2.5) {
Serial.println("Abnormal load current!");
} else {
Serial.print("Load current: ");
Serial.println(map(voltage, 0, 3.3, 0, 10)); // 10A full scale
}
Serial.println("=====================");
}
9. Design Considerations
- Isolation LevelThere should be at least 2000V electrical isolation between the control circuit and the controlled load
- Heat ManagementLeave heat dissipation slots in PCB design under the relay, avoid copper covering
- Creepage DistanceHigh voltage terminal spacing should be at least 3.2mm (for 220VAC applications)
- Emergency MeasuresRetain a physical cutoff switch (forced disconnection device)
- Labeling StandardsAll high voltage terminals must be clearly marked with voltage levels and hazard signs
With proper design, the ESP32 relay control system can be applied in various fields such as smart homes, industrial automation, and agricultural irrigation. Always adhere to high voltage safety standards and incorporate multiple safety mechanisms during the design phase.
ESP32 IoT CompassThree Days to Master MicrocontrollersArduino Development Board