A relay module lets the S3 switch a separate circuit. This guide covers the low-voltage side: coil power from 5V, trigger on GPIO21, relay held off through boot, and the DevKitC’s RGB LED as a status light.
Type 1 or 0 in the Serial Monitor on the UART port. Keep what you switch within the relay’s rating, and leave mains wiring to an electrician.
Wiring
| ESP32-S3-DevKitC-1 | 1-channel relay module (5 V coil) | Wire | Notes |
|---|---|---|---|
| 5V | DC+ | red | Coil supply from USB 5 V (~70 mA per relay). |
| GND | DC− | black | |
| 21 | IN | yellow | Use a module sold as “3.3 V trigger” (opto-isolated, active-LOW). |
5 V coil part, 3.3 V board. The coil runs on 5 V, but the IN pin only drives an optocoupler LED. Pick a module rated for a 3.3 V trigger when using ESP32 or Pico — some 5 V-only modules never fully release from a 3.3 V HIGH.
Board quirks
- GPIO21 has no boot role. Don’t put a relay on GPIO0, 3, 45 or 46 (strapping pins), or on TX/RX (GPIO43/44), which carry boot messages and would click the relay at every reset.
- The pin is set HIGH (off) before it becomes an output, so the relay stays off while the S3 starts.
- The sketch mirrors the relay on the on-board RGB LED with
rgbLedWrite(): GPIO48 on DevKitC-1 v1.0, GPIO38 on v1.1 — changeRGB_PINif yours stays dark. - COM/NO/NC are the switched side. Keep to low-voltage loads or a small lamp within the relay’s rating; a pump or motor goes through a contactor, and 230 V wiring with MCB, RCCB and earth is for an electrician.
Code
// 1-channel relay module (3.3 V-trigger, active-LOW) on an ESP32-S3-DevKitC-1.
// DC+ → 5V, DC− → GND, IN → GPIO21. Type 1 / 0 in the Serial Monitor (UART port, 115200).
// Shows the relay state on the on-board RGB LED too (GPIO48 on v1.0, GPIO38 on v1.1).
// Low-voltage or small resistive loads only; motors and pumps go through a contactor,
// and any 230 V wiring is for an electrician.
constexpr uint8_t RELAY_PIN = 21;
constexpr bool RELAY_ACTIVE_LOW = true;
constexpr uint8_t RGB_PIN = 48; // change to 38 for a v1.1 board
void setRelay(bool on) {
digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW);
rgbLedWrite(RGB_PIN, on ? 30 : 0, on ? 0 : 10, 0); // red = on, dim green = off
Serial.println(on ? "Relay ON" : "Relay OFF");
}
void setup() {
digitalWrite(RELAY_PIN, RELAY_ACTIVE_LOW ? HIGH : LOW); // off before the pin becomes an output
pinMode(RELAY_PIN, OUTPUT);
Serial.begin(115200);
setRelay(false);
Serial.println("Send 1 = on, 0 = off");
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c == '1') setRelay(true);
if (c == '0') setRelay(false);
}
}// 1-channel relay module (3.3 V-trigger, active-LOW) on an ESP32-S3-DevKitC-1.
// DC+ → 5V, DC− → GND, IN → GPIO21. Type 1 / 0 in the Serial Monitor (UART port, 115200).
// Shows the relay state on the on-board RGB LED too (GPIO48 on v1.0, GPIO38 on v1.1).
// Low-voltage or small resistive loads only; motors and pumps go through a contactor,
// and any 230 V wiring is for an electrician.
constexpr uint8_t RELAY_PIN = 21;
constexpr bool RELAY_ACTIVE_LOW = true;
constexpr uint8_t RGB_PIN = 48; // change to 38 for a v1.1 board
void setRelay(bool on) {
digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW);
rgbLedWrite(RGB_PIN, on ? 30 : 0, on ? 0 : 10, 0); // red = on, dim green = off
Serial.println(on ? "Relay ON" : "Relay OFF");
}
void setup() {
digitalWrite(RELAY_PIN, RELAY_ACTIVE_LOW ? HIGH : LOW); // off before the pin becomes an output
pinMode(RELAY_PIN, OUTPUT);
Serial.begin(115200);
setRelay(false);
Serial.println("Send 1 = on, 0 = off");
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c == '1') setRelay(true);
if (c == '0') setRelay(false);
}
}Expected serial output
Relay OFF
Send 1 = on, 0 = off
Relay ON
Relay OFFRelay OFF Send 1 = on, 0 = off Relay ON Relay OFF
Common errors
Relay clicks but the load doesn’t switch
Load on NC instead of NO. Full fix.
Relay never releases
Module needs a 5 V trigger. Use a 3.3 V-trigger module or one with a JD-VCC jumper.