AdvancedESP32ESP32MQTTHome Assistant
ESP32 Home Automation Node with MQTT & Home Assistant
Turn an ESP32 WROOM into a smart home node that publishes sensor data and receives relay commands via MQTT. Supports Home Assistant auto-discovery, OTA firmware updates, and reconnect logic.
Circuit Hub—35 min read2 views
Overview
This project converts an ESP32 WROOM-32 into a multi-function home automation node:
- Reads temperature & humidity from a DHT22 and publishes every 30 seconds
- Controls a 5V relay (light/fan) via MQTT
commandtopic - Supports Home Assistant MQTT Discovery — the device appears automatically in HA with correct entity names, icons, and device class
- Includes Arduino OTA so you can push firmware updates over WiFi without plugging in a cable
- Robust reconnect loop with exponential back-off so it recovers from broker restarts
⚠️ Warning
Use a **mosquitto broker running on your local network** (Raspberry Pi or a Home Assistant add-on) rather than a public broker for home automation. Public brokers are unreliable and expose your home data.
Components required
C++
// ── ESP32 MQTT Home Automation Node ──────────────────────────────────────────
// Libraries: PubSubClient, DHT sensor library (Adafruit), ArduinoOTA
// ─────────────────────────────────────────────────────────────────────────────
#include <WiFi.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>
// ── Config ────────────────────────────────────────────────────────────────────
#define WIFI_SSID "YOUR_WIFI"
#define WIFI_PASS "YOUR_PASS"
#define MQTT_BROKER "192.168.1.100" // Your local broker IP
#define MQTT_PORT 1883
#define MQTT_USER "mqtt_user" // Leave "" if no auth
#define MQTT_PASS "mqtt_pass"
#define DEVICE_ID "esp32_node_01"
#define DHT_PIN 4
#define RELAY_PIN 26
#define TOPIC_TEMP "homeassistant/sensor/" DEVICE_ID "/temperature/state"
#define TOPIC_HUM "homeassistant/sensor/" DEVICE_ID "/humidity/state"
#define TOPIC_RELAY "homeassistant/switch/" DEVICE_ID "/relay/command"
#define TOPIC_RELAY_S "homeassistant/switch/" DEVICE_ID "/relay/state"
// ── Home Assistant Discovery Topics ──────────────────────────────────────────
#define DISCO_TEMP "homeassistant/sensor/" DEVICE_ID "/temperature/config"
#define DISCO_HUM "homeassistant/sensor/" DEVICE_ID "/humidity/config"
#define DISCO_RELAY "homeassistant/switch/" DEVICE_ID "/relay/config"
DHT dht(DHT_PIN, DHT22);
WiFiClient wifi;
PubSubClient mqtt(wifi);
bool relayOn = false;
unsigned long lastPublish = 0;
void publishDiscovery() {
StaticJsonDocument<512> doc;
// Temperature sensor
doc.clear();
doc["name"] = "ESP32 Temperature";
doc["unique_id"] = DEVICE_ID "_temp";
doc["state_topic"] = TOPIC_TEMP;
doc["unit_of_meas"] = "°C";
doc["device_class"] = "temperature";
doc["value_template"] = "{{ value }}";
doc["device"]["ids"] = DEVICE_ID;
doc["device"]["name"] = "ESP32 Node 01";
doc["device"]["model"]= "ESP32 WROOM-32";
char buf[512];
serializeJson(doc, buf);
mqtt.publish(DISCO_TEMP, buf, true); // retained
// Relay switch
doc.clear();
doc["name"] = "ESP32 Relay";
doc["unique_id"] = DEVICE_ID "_relay";
doc["command_topic"] = TOPIC_RELAY;
doc["state_topic"] = TOPIC_RELAY_S;
doc["payload_on"] = "ON";
doc["payload_off"] = "OFF";
doc["device"]["ids"] = DEVICE_ID;
serializeJson(doc, buf);
mqtt.publish(DISCO_RELAY, buf, true);
}
void onMessage(char* topic, byte* payload, unsigned int len) {
String msg((char*)payload, len);
if (String(topic) == TOPIC_RELAY) {
relayOn = (msg == "ON");
digitalWrite(RELAY_PIN, relayOn ? LOW : HIGH); // Relay is active-LOW
mqtt.publish(TOPIC_RELAY_S, relayOn ? "ON" : "OFF", true);
}
}
void connectMQTT() {
int delay_ms = 1000;
while (!mqtt.connected()) {
Serial.print("MQTT connecting...");
if (mqtt.connect(DEVICE_ID, MQTT_USER, MQTT_PASS)) {
Serial.println("OK");
mqtt.subscribe(TOPIC_RELAY);
publishDiscovery();
} else {
Serial.printf(" failed (%d), retry in %ds\n", mqtt.state(), delay_ms / 1000);
delay(delay_ms);
delay_ms = min(delay_ms * 2, 30000); // Exponential back-off up to 30s
}
}
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // Start relay OFF
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi: " + WiFi.localIP().toString());
ArduinoOTA.setHostname(DEVICE_ID);
ArduinoOTA.begin();
mqtt.setServer(MQTT_BROKER, MQTT_PORT);
mqtt.setCallback(onMessage);
dht.begin();
connectMQTT();
}
void loop() {
ArduinoOTA.handle();
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
if (millis() - lastPublish >= 30000) {
lastPublish = millis();
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (!isnan(temp)) mqtt.publish(TOPIC_TEMP, String(temp, 1).c_str());
if (!isnan(hum)) mqtt.publish(TOPIC_HUM, String(hum, 1).c_str());
Serial.printf("Published: %.1f°C %.1f%%\n", temp, hum);
}
}Steps
- 1Install Mosquitto on a Raspberry Pi or use the Home Assistant MQTT broker add-on
- 2Update MQTT_BROKER IP, credentials, and WiFi in the sketch
- 3Upload and open Serial Monitor — you should see 'MQTT connecting...OK'
- 4In Home Assistant → Settings → Devices, the ESP32 Node 01 device appears automatically
- 5Toggle the relay from the HA dashboard or create an automation
- 6For OTA updates: Arduino IDE → Sketch → Upload → select the ESP32's network port