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 device (see Create Your Device below)
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 = "SWD-XXXXXX"; // 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”Create Your Device on SiliconWit.io
Section titled “Create Your Device on SiliconWit.io”-
Go to Dashboard > Devices > Add Device
-
Fill in the device details:
Field Value Why Name ESP32 RelayDescriptive name shown on your dashboard Type ControllerThe device sends sensor data and receives commands Data Direction BidirectionalSends telemetry and receives relay toggle commands Connectivity WiFi + MQTTUses MQTT over TLS for real-time communication Data Interval 15 secondsHow often the device sends readings -
Configure Data Fields - define the telemetry fields the device will send:
[{ "name": "temperature", "label": "Temperature", "unit": "°C" },{ "name": "humidity", "label": "Humidity", "unit": "%" }] -
Configure Commands - add a toggle command so you can control the relay from the dashboard:
[{ "name": "relay", "label": "Light 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,SWD-XXXXXX, 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