The most common mistake when wiring an ESP32 relay module is powering the relay coils directly from the ESP32's onboard 5V pin, which instantly triggers a brownout reset when the coil energizes. The second most common mistake is using GPIO 12, which is a strapping pin that will prevent the ESP32 from booting if pulled high. To drive a standard 4-channel 5V relay module safely with an ESP32 DevKit v1, you must use safe GPIOs (5, 18, 19, 21), remove the JD-VCC jumper to isolate the logic from the coil power, and use a dedicated 5V power supply for the relay coils.
Project Overview & Parts List
This build targets the ESP32 DevKit v1 (specifically the ESP32-WROOM-32 variant) and a standard 4-channel optocoupler relay module. We are building a non-blocking, WiFi-ready relay controller that avoids the classic inrush-current brownouts.
| Component | Exact Variant / Model | Est. Cost (2026) | Why This Part? |
|---|---|---|---|
| Microcontroller | ESP32 DevKit v1 (ESP32-WROOM-32) | $6.00 | Dual-core, built-in WiFi, 3.3V logic. |
| Relay Module | 5V 4-Channel Optocoupler (Songle SRD-05VDC-SL-C) | $5.50 | Optocouplers provide galvanic isolation between logic and coil. |
| Relay Power Supply | 5V 2A Switching PSU (Mean Well or generic) | $4.00 | 4 coils draw ~280mA; ESP32 WiFi spikes draw ~160mA. Separate rails prevent brownouts. |
| Logic Power | ESP32 onboard 3.3V LDO (via USB) | $0.00 | Powers the optocoupler LEDs safely. |
Pin Mapping & Wiring the ESP32 Relay Module
The wiring for an ESP32 relay module hinges entirely on understanding the JD-VCC jumper. Most cheap 4-channel modules ship with a blue jumper cap connecting the VCC pin to the JD-VCC pin. You must remove this jumper.
According to the Espressif ESP32 Datasheet, several GPIOs are strapping pins that dictate boot modes. GPIO 12, for example, must be LOW at boot. If you wire a relay to GPIO 12 and the module pulls it HIGH, your ESP32 will brick itself in a boot loop. We use GPIOs 5, 18, 19, and 21, which are safe for output and do not interfere with boot strapping or SPI flash.
The JD-VCC Jumper Trick (Crucial for 3.3V Logic)
The ESP32 outputs 3.3V. The relay module requires 5V for the coils. If you leave the jumper ON and feed 5V into VCC, the optocoupler LEDs are tied to 5V. When the ESP32 tries to pull the IN pin LOW, current flows backward from the 5V rail into the 3.3V GPIO, eventually frying the ESP32 pin. By removing the jumper, we split the power domains:
| Relay Module Pin | Connect To | Purpose |
|---|---|---|
| JD-VCC | 5V PSU Positive (+) | Powers the physical relay coils (requires ~70mA per coil). |
| VCC | ESP32 3V3 Pin | Powers the optocoupler input LEDs (requires ~10mA per channel). |
| GND | 5V PSU Negative (-) AND ESP32 GND | Common ground reference for both power domains. |
| IN1 | ESP32 GPIO 5 | Relay 1 Logic Trigger (Active LOW). |
| IN2 | ESP32 GPIO 18 | Relay 2 Logic Trigger (Active LOW). |
| IN3ESP32 GPIO 19 | Relay 3 Logic Trigger (Active LOW). | |
| IN4 | ESP32 GPIO 21 | Relay 4 Logic Trigger (Active LOW). |
Complete ESP32 C++ Code with Error Handling
This code targets the ESP32 DevKit v1 board in the Arduino IDE. It uses a non-blocking millis() timer to toggle the relays. Blocking delays (delay()) are forbidden in ESP32 projects because they can starve the WiFi stack and trigger the watchdog timer.
#include <WiFi.h>
// --- PIN DEFINITIONS ---
// Using safe GPIOs (avoiding strapping pins 0, 2, 5, 12, 15)
#define RELAY_1 5
#define RELAY_2 18
#define RELAY_3 19
#define RELAY_4 21
#define STATUS_LED 2 // Built-in blue LED on most DevKit v1 boards
// --- TIMING VARIABLES ---
unsigned long previousMillis = 0;
const long interval = 5000; // Toggle every 5 seconds
bool relayState = false;
// --- WIFI CREDENTIALS ---
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
void setup() {
Serial.begin(115200);
delay(1000); // Allow serial monitor to connect
Serial.println("\n[INFO] ESP32 Relay Module Controller Booting...");
// Initialize Pins
// Relays are Active LOW, so we set them HIGH (OFF) immediately
pinMode(RELAY_1, OUTPUT);
pinMode(RELAY_2, OUTPUT);
pinMode(RELAY_3, OUTPUT);
pinMode(RELAY_4, OUTPUT);
pinMode(STATUS_LED, OUTPUT);
digitalWrite(RELAY_1, HIGH);
digitalWrite(RELAY_2, HIGH);
digitalWrite(RELAY_3, HIGH);
digitalWrite(RELAY_4, HIGH);
digitalWrite(STATUS_LED, LOW);
// Connect to WiFi
Serial.print("[INFO] Connecting to WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[SUCCESS] WiFi Connected!");
Serial.print("[INFO] IP Address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\n[ERROR] WiFi Connection Failed. Running in offline mode.");
}
}
void loop() {
unsigned long currentMillis = millis();
// Non-blocking timer to toggle relays
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
relayState = !relayState; // Invert state
if (relayState) {
Serial.println("[ACTION] Energizing Relays (Pulling GPIOs LOW)");
digitalWrite(RELAY_1, LOW);
digitalWrite(RELAY_2, LOW);
digitalWrite(RELAY_3, LOW);
digitalWrite(RELAY_4, LOW);
digitalWrite(STATUS_LED, HIGH);
} else {
Serial.println("[ACTION] De-energizing Relays (Pulling GPIOs HIGH)");
digitalWrite(RELAY_1, HIGH);
digitalWrite(RELAY_2, HIGH);
digitalWrite(RELAY_3, HIGH);
digitalWrite(RELAY_4, HIGH);
digitalWrite(STATUS_LED, LOW);
}
}
// Yield to WiFi stack to prevent Watchdog resets
yield();
}
Debugging: First Three Things to Check When It Fails
When an ESP32 relay module setup fails, it rarely fails silently. It usually resets, refuses to boot, or clicks without switching. Here is the ranked decision path for troubleshooting.
1. The ESP32 Reboots Randomly or When Relays Click
Exact Error String in Serial Monitor: Brownout detector was triggered
Cause: A relay coil draws roughly 70mA when energized. Four coils draw 280mA. When the ESP32 transmits a WiFi packet, it spikes to ~160mA. If you are powering the relay coils from the ESP32's onboard 5V pin (which is fed by your PC's USB port, often limited to 500mA total), the combined 440mA+ load causes the voltage rail to sag below the ESP32's brownout threshold (usually ~2.4V on the 3.3V rail).
Fix: Use the dedicated 5V 2A power supply wired to the JD-VCC pin as described in the wiring table. Never power inductive loads directly from the ESP32's USB-fed 5V pin.
2. The ESP32 Fails to Boot or Upload Code
Exact Error String in Serial Monitor: ets_main.c 371 or continuous boot loop garbage text.
Cause: You wired a relay to GPIO 12 or GPIO 0. GPIO 12 is a strapping pin that selects the flash voltage. If the relay module's optocoupler pulls GPIO 12 HIGH during boot, the ESP32 attempts to boot using 1.8V flash logic instead of 3.3V, causing an immediate crash.
Fix: Move the relay IN wire to a safe GPIO (5, 18, 19, 21, 22, 23). If you must use GPIO 12 for an existing PCB, you have to use the espefuse.py tool to burn the XPD_SDIO_TIEH efuse, which is risky for beginners.
3. Relay Clicks Audibly, But the Load Doesn't Turn On
Cause: You wired the load to the Normally Closed (NC) terminal instead of Normally Open (NO), or the relay contacts are welded shut from a previous over-current event.
Fix: With the power disconnected, use a multimeter in continuity mode. Probe the COM and NO terminals. It should read OL (open). Energize the relay manually by applying 5V to JD-VCC and pulling IN1 to GND. The meter should now beep (0 ohms). If COM and NC beep when de-energized, you have your load wired to the wrong terminal. For detailed contact ratings, refer to All About Circuits' guide on relay applications.
Extending and Simplifying the Build
The beauty of the ESP32 is its scalability. Depending on your end goal, you can strip this build down or scale it up to a full home automation node.
Simplifying: The Single-Channel 3.3V Relay
If you only need to switch one 120V lamp and want to eliminate the JD-VCC jumper headache entirely, buy a 3.3V 1-Channel Relay Module (Songle SRD-03VDC-SL-C). These modules have the coil matched to the ESP32's native logic level. You can wire VCC to the ESP32 3V3 pin, GND to GND, and IN to a GPIO. Because a single 3.3V coil only draws ~40mA, the ESP32's onboard LDO can usually handle it without a brownout, provided you aren't maxing out WiFi transmission power.
Extending: MQTT and Home Assistant Integration
To turn this bench test into a smart home node, replace the millis() toggle in the loop() with an MQTT client. Using the PubSubClient library, subscribe to a topic like home/livingroom/lights/set. When a payload of "ON" arrives, pull GPIO 5 LOW. This allows Home Assistant to control the relays over your local network without relying on cloud servers. Ensure you add a watchdog timer (esp_task_wdt_init) to automatically reboot the ESP32 if the WiFi stack hangs.
ESP32 Relay Module FAQ
Can I power a 5V relay module directly from the ESP32 3V3 pin?
No. The 3V3 pin on an ESP32 DevKit v1 is fed by an onboard LDO regulator (usually an AMS1117-3.3) that is rated for a maximum of 800mA, but realistically handles about 500mA safely before overheating. A 5V relay coil will not even energize on 3.3V because the coil resistance is tuned for 5V. You must use the 5V pin for the coils, and as noted, a separate 5V PSU is highly recommended to prevent brownouts.
Why does my ESP32 relay module click but the load doesn't turn on?
Aside from wiring the load to the NC (Normally Closed) terminal instead of NO (Normally Open), the most common culprit is exceeding the relay's contact rating. The Songle SRD-05VDC-SL-C is rated for 10A at 120VAC. If you connect a heavy inductive load like a large AC motor or an un-snubbered transformer, the inrush current can be 5x to 10x the running current. This causes an arc across the contacts, welding them together or pitting them until they fail to make a solid connection. Use a snubber circuit (RC network) across inductive loads.
Do I need a flyback diode for the ESP32 relay module?
If you are using a pre-assembled relay module (the blue PCB with the black relay cubes), no. These modules already include a flyback diode (usually a 1N4148) wired in reverse bias across the relay coil to absorb the inductive kickback when the coil de-energizes. However, if you are wiring a bare, standalone relay component directly to a transistor on a custom PCB, you must add a flyback diode, or the voltage spike will destroy your switching transistor or induce noise that resets the ESP32.
Is it safe to switch 240V AC with these cheap relay modules?
While the relay component itself might be rated for 240VAC, the module PCB often lacks adequate creepage and clearance distances on the underside of the board. The copper traces on the low-voltage side sometimes run too close to the high-voltage side. For 240V AC or 15A+ loads, it is vastly safer to use a DIN-rail mounted contactor or a purpose-built smart relay (like a Shelly or Sonoff) that is enclosed and certified by UL/CE standards.






