ESP32 Relay Control
Control a relay (light, pump, fan, door lock) from your SiliconWit.IO dashboard while also reading sensor data — a complete bidirectional IoT example.
What You’ll Build
Section titled “What You’ll Build”- ESP32 reads a DHT22 temperature/humidity sensor and sends data to the cloud
- Dashboard shows live readings and an on/off toggle for a relay
- Clicking the toggle sends a command over MQTT; the ESP32 switches the relay
┌─────────────┐ MQTT (TLS) ┌──────────────────┐│ ESP32 │ ◄──────────────────────── │ SiliconWit.IO ││ + DHT22 │ commands topic │ Dashboard ││ + Relay │ ────────────────────────► │ (toggle relay) ││ │ telemetry topic │ │└─────────────┘ └──────────────────┘Requirements
Section titled “Requirements”Hardware
Section titled “Hardware”- ESP32 development board
- 1-channel relay module (5V or 3.3V, with optocoupler)
- DHT22 temperature/humidity sensor
- Jumper wires, breadboard
- USB cable for programming
Software
Section titled “Software”- Arduino IDE with ESP32 board support (setup guide)
- Libraries: PubSubClient, ArduinoJson, DHT sensor library
SiliconWit.IO Setup
Section titled “SiliconWit.IO Setup”- A registered actuator device with direction set to bidirectional
- One toggle command configured (e.g. name:
relay, label:Light Relay) - One data field configured (e.g. name:
temperature)
Wiring
Section titled “Wiring”| ESP32 Pin | Component |
|---|---|
| GPIO 4 | DHT22 data pin (with 10K pull-up to 3.3V) |
| GPIO 26 | Relay IN (signal) |
| 3.3V | DHT22 VCC |
| 5V (VIN) | Relay VCC |
| GND | DHT22 GND, Relay GND |
Full Code
Section titled “Full Code”#include <WiFi.h>#include <WiFiClientSecure.h>#include <PubSubClient.h>#include <ArduinoJson.h>#include <DHT.h>
// ─── Configuration ───────────────────────────────const char* WIFI_SSID = "YOUR_WIFI_SSID";const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* MQTT_BROKER = "mqtt.siliconwit.io";const int MQTT_PORT = 8883;const char* DEVICE_ID = "YOUR_DEVICE_ID"; // from dashboardconst char* ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"; // from dashboard
// ─── Pins ────────────────────────────────────────#define DHT_PIN 4#define RELAY_PIN 26#define DHT_TYPE DHT22
// ─── Globals ─────────────────────────────────────DHT dht(DHT_PIN, DHT_TYPE);WiFiClientSecure espClient;PubSubClient mqtt(espClient);
String telemetryTopic;String commandTopic;
unsigned long lastSend = 0;const unsigned long SEND_INTERVAL = 15000; // 15 seconds
// ─── MQTT command handler ────────────────────────void onMessage(char* topic, byte* payload, unsigned int length) { // Parse JSON command JsonDocument doc; DeserializationError err = deserializeJson(doc, payload, length); if (err) { Serial.print("JSON parse error: "); Serial.println(err.c_str()); return; }
const char* command = doc["command"]; if (!command) return;
Serial.print("Command received: "); Serial.println(command);
// Handle relay command if (strcmp(command, "relay") == 0) { bool state = doc["value"] | false; digitalWrite(RELAY_PIN, state ? LOW : HIGH); // active LOW relay Serial.print("Relay → "); Serial.println(state ? "ON" : "OFF"); }}
// ─── WiFi ────────────────────────────────────────void setupWifi() { Serial.print("Connecting to WiFi"); WiFi.begin(WIFI_SSID, WIFI_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.print("\nConnected — IP: "); Serial.println(WiFi.localIP());}
// ─── MQTT connect + subscribe ────────────────────void connectMqtt() { while (!mqtt.connected()) { Serial.print("Connecting to MQTT..."); if (mqtt.connect(DEVICE_ID, DEVICE_ID, ACCESS_TOKEN)) { Serial.println("connected"); // Subscribe to commands topic mqtt.subscribe(commandTopic.c_str(), 1); Serial.print("Subscribed to: "); Serial.println(commandTopic); } else { Serial.print("failed (rc="); Serial.print(mqtt.state()); Serial.println(") retrying in 5s"); delay(5000); } }}
// ─── Setup ───────────────────────────────────────void setup() { Serial.begin(115200);
// Build topic strings telemetryTopic = "d/" + String(DEVICE_ID) + "/t"; commandTopic = "d/" + String(DEVICE_ID) + "/c";
// Relay pin — start OFF (HIGH for active-low) pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, HIGH);
dht.begin(); setupWifi();
espClient.setInsecure(); // Use setCACert() in production mqtt.setServer(MQTT_BROKER, MQTT_PORT); mqtt.setCallback(onMessage);}
// ─── Loop ────────────────────────────────────────void loop() { if (!mqtt.connected()) { connectMqtt(); } mqtt.loop();
// Send sensor data periodically if (millis() - lastSend >= SEND_INTERVAL) { lastSend = millis();
float temp = dht.readTemperature(); float hum = dht.readHumidity();
if (!isnan(temp) && !isnan(hum)) { JsonDocument doc; doc["temperature"] = round(temp * 10) / 10.0; doc["humidity"] = round(hum * 10) / 10.0;
char buf[128]; serializeJson(doc, buf); mqtt.publish(telemetryTopic.c_str(), buf);
Serial.print("Sent: "); Serial.println(buf); } }}Step-by-Step Walkthrough
Section titled “Step-by-Step Walkthrough”1. Create the device on SiliconWit.IO
Section titled “1. Create the device on SiliconWit.IO”- Go to Dashboard > Devices > Add Device
- Set Name to something like “Living Room Controller”
- Set Type to Actuator
- Set Direction to Bidirectional
- Add a Data Field: name
temperature, labelTemperature, unit°C - Add a Command: name
relay, labelLight Relay, type Toggle - Click Create Device and copy the Device ID and Access Token
2. Upload the code
Section titled “2. Upload the code”- Replace
YOUR_WIFI_SSID,YOUR_WIFI_PASSWORD,YOUR_DEVICE_ID, andYOUR_ACCESS_TOKENin the code - Upload to your ESP32
- Open Serial Monitor at 115200 baud — you should see WiFi connect, then MQTT connect
3. Test from the dashboard
Section titled “3. Test from the dashboard”- Open your device page — you’ll see temperature readings arriving
- In the Control Panel sidebar, click ON next to “Light Relay”
- The relay should click and the connected load should turn on
- Click OFF to turn it back off
- Check the Command History section to see the sent commands
How It Works
Section titled “How It Works”- The ESP32 subscribes to
d/{id}/con connect - When you press a toggle in the dashboard, the server publishes
{"command":"relay","value":true}to that topic via the MQTT broker - The
onMessagecallback fires on the ESP32, parses the JSON, and sets the relay GPIO - Meanwhile, every 15 seconds the ESP32 publishes sensor data to
d/{id}/t
Adding More Controls
Section titled “Adding More Controls”You can add multiple commands to one device. For example, add a second relay or a PWM-controlled fan:
Second relay (toggle)
Section titled “Second relay (toggle)”Add another command in device settings: name relay2, label Fan Relay, type Toggle.
Then extend the callback:
if (strcmp(command, "relay2") == 0) { bool state = doc["value"] | false; digitalWrite(RELAY2_PIN, state ? LOW : HIGH);}Fan speed (slider)
Section titled “Fan speed (slider)”Add a command: name fan_speed, label Fan Speed, type Slider, min 0, max 255.
if (strcmp(command, "fan_speed") == 0) { int speed = doc["value"] | 0; analogWrite(FAN_PIN, constrain(speed, 0, 255));}Custom JSON command
Section titled “Custom JSON command”For advanced use cases, add a command with type JSON (Custom). This lets you send any JSON payload from the dashboard — useful for multi-field configuration, schedules, or batch operations.
Add a command in device settings: name config, label Device Config, type JSON.
From the dashboard, you can type any valid JSON in the text area, for example:
{"mode": "auto", "threshold": 30, "interval": 10}Then parse the full value object on the ESP32:
if (strcmp(command, "config") == 0) { // The "value" field contains whatever JSON you sent JsonObject cfg = doc["value"]; const char* mode = cfg["mode"] | "manual"; int threshold = cfg["threshold"] | 25; int interval = cfg["interval"] | 15;
Serial.print("Mode: "); Serial.println(mode); Serial.print("Threshold: "); Serial.println(threshold); Serial.print("Interval: "); Serial.println(interval);
// Apply settings to your device logic...}Troubleshooting
Section titled “Troubleshooting”| Problem | Solution |
|---|---|
| Relay doesn’t click | Check wiring, verify relay VCC gets 5V, try inverting HIGH/LOW |
| Commands not received | Ensure device direction is Bidirectional, check Serial Monitor for subscribe confirmation |
| Sensor reads NaN | Check DHT22 wiring, add 10K pull-up resistor on data pin |
| MQTT disconnects | Increase mqtt.setKeepAlive(60), check WiFi stability |
| Relay clicks but load doesn’t switch | Verify load wiring to relay’s NO/COM terminals |
Next Steps
Section titled “Next Steps”- ESP32 Setup — Basic sensor-only setup and TLS configuration
- Topics & Payloads — Full MQTT message format reference
- Dashboard Alerts — Trigger alerts when temperature exceeds a threshold