MQTT mit ESP32 & Home Assistant: Sensordaten ins Smart Home bringen

Dein ESP32 misst brav die Temperatur – aber die Werte verstauben im seriellen Monitor, den nur du siehst. Der nächste Schritt macht aus dem Bastelprojekt einen echten Smart-Home-Sensor: über MQTT schickt der ESP32 seine Daten an Home Assistant, wo sie in schönen Diagrammen landen, Automationen auslösen und aufs Handy kommen. Und es geht in beide Richtungen – mit einem Klick in der App schaltest du über denselben Kanal ein Relais am ESP32. In diesem Tutorial bauen wir das komplett auf: MQTT verstehen, Broker einrichten, Sensordaten senden, per MQTT Discovery automatisch in Home Assistant auftauchen und am Ende ein Gerät fernsteuern. Alles mit fertigem, lauffähigem Code.

Was ist MQTT – und warum nicht einfach ein Webserver?

Einen Webserver auf dem ESP32 kennst du vielleicht schon: Du rufst die IP-Adresse auf und siehst die Messwerte. Das funktioniert – aber es skaliert schlecht. Hast du zehn Sensoren, mit welchen der zehn IP-Adressen redest du? Und wie soll Home Assistant von selbst wissen, dass es sie abfragen soll?

MQTT dreht das Prinzip um. Statt dass jeder jeden abfragt, gibt es einen zentralen Vermittler, den Broker. Sensoren veröffentlichen (publish) ihre Werte unter einem Themenpfad (Topic), Interessenten abonnieren (subscribe) diese Topics. Der ESP32 muss nicht wissen, wer zuhört – er wirft seine Temperatur einfach in den Kanal makeroo/wohnzimmer/temperatur, und Home Assistant fängt sie auf.

Begriff Bedeutung Beispiel
Broker zentraler Vermittler, verteilt alle Nachrichten Mosquitto in Home Assistant
Topic hierarchischer Themenpfad makeroo/wohnzimmer/temperatur
Publish Wert unter einem Topic senden ESP32 sendet "22.5"
Subscribe ein Topic abonnieren Home Assistant hört mit
Payload der eigentliche Inhalt der Nachricht "22.5" oder JSON
QoS Zustellgarantie (0/1/2) 0 = feuern und vergessen

ℹ️ Der große Vorteil: MQTT ist extrem leichtgewichtig – perfekt für batteriebetriebene ESP32-Knoten. Eine Nachricht ist nur ein paar Byte groß, der ESP32 kann nach dem Senden sofort in den Deep Sleep gehen. Genau deshalb ist MQTT der De-facto-Standard für IoT und die natürliche Brücke zwischen selbstgebauten Sensoren und fertigen Smart-Home-Zentralen wie Home Assistant, ioBroker oder Node-RED.

Das brauchst du

1x ESP32 WROOM-32 Entwicklungsboard (USB-C) – WLAN ist Pflicht, das kann der ESP32 nativ – Zum Produkt
1x BME280 Sensor (Temperatur, Luftfeuchte, Luftdruck, I2C) – Zum Produkt
Alternativ 1x DHT22 (AM2302) für Temperatur & Feuchte – Zum Produkt
1x Relais-Modul KY-019 zum Schalten von Lampen/Geräten – Zum Produkt
Optional 1x OLED 0,96 Zoll für lokale Anzeige – Zum Produkt
1x ESP32-Gehäuse aus Acryl für den Dauereinsatz – Zum Produkt

Auf der Softwareseite brauchst du eine laufende Home-Assistant-Installation (z. B. auf einem Raspberry Pi) mit dem Mosquitto-Broker-Add-on. In der Arduino IDE installierst du über den Bibliotheksverwalter die Bibliothek PubSubClient von Nick O'Leary sowie die Sensor-Bibliotheken Adafruit BME280 und Adafruit Unified Sensor.

Verkabelung

Der BME280 hängt am I2C-Bus des ESP32, das Relais an einem beliebigen GPIO. Achte darauf, dass das Relais mit 5V versorgt wird (Pin VIN am ESP32), die Signalleitung aber mit dem 3,3V-Logikpegel des ESP32 klarkommt – beim KY-019 als High-Level-Trigger funktioniert das zuverlässig.

Bauteil Pin ESP32 Anmerkung
BME280 VCC 3V3 Modul ist 3,3V/5V-tolerant
BME280 GND GND
BME280 SDA GPIO21 I2C-Daten (Standard)
BME280 SCL GPIO22 I2C-Takt (Standard)
Relais KY-019 VCC VIN (5V) Relaisspule braucht 5V
Relais KY-019 GND GND
Relais KY-019 Signal (S) GPIO26 High-Level-Trigger

⚠️ Netzspannung ist lebensgefährlich: Wenn du mit dem Relais 230-V-Geräte schalten willst, gehört das in erfahrene Hände und ein isoliertes Gehäuse. Zum Lernen und Testen schaltest du besser eine LED oder ein 5-V-Lüfterchen. Details zum sicheren Umgang mit dem Relais stehen im Artikel Relais-Modul KY-019 schalten.

1Mit WLAN und MQTT-Broker verbinden

Das Grundgerüst jedes MQTT-Projekts: WLAN aufbauen, mit dem Broker verbinden und die Verbindung im loop() am Leben halten. Fällt die Verbindung ab, baut der Code sie automatisch wieder auf.

#include <WiFi.h>
#include <PubSubClient.h>

const char* WIFI_SSID = "DEIN_WLAN";
const char* WIFI_PASS = "DEIN_PASSWORT";

// IP deines Home-Assistant-/Mosquitto-Rechners
const char* MQTT_HOST = "192.168.1.50";
const int   MQTT_PORT = 1883;
const char* MQTT_USER = "esp32";        // im Mosquitto-Add-on angelegt
const char* MQTT_PASS = "geheim";

WiFiClient   netClient;
PubSubClient mqtt(netClient);

void wifiVerbinden() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("WLAN");
  while (WiFi.status() != WL_CONNECTED) {
    delay(400); Serial.print(".");
  }
  Serial.print(" verbunden, IP: ");
  Serial.println(WiFi.localIP());
}

void mqttVerbinden() {
  while (!mqtt.connected()) {
    Serial.print("MQTT-Verbindung... ");
    String clientId = "esp32-wohnzimmer";
    if (mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS)) {
      Serial.println("ok");
    } else {
      Serial.print("Fehler rc=");
      Serial.print(mqtt.state());
      Serial.println(" – neuer Versuch in 3s");
      delay(3000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  wifiVerbinden();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) wifiVerbinden();
  if (!mqtt.connected())             mqttVerbinden();
  mqtt.loop();   // haelt die Verbindung am Leben
}

ℹ️ Der Broker gehoert zu Home Assistant: Am einfachsten installierst du in Home Assistant unter Einstellungen → Add-ons das offizielle Mosquitto broker-Add-on. Leg dort einen Benutzer an (z. B. esp32 mit Passwort), genau diese Zugangsdaten trägst du oben ein. Danach fügst du in Home Assistant die MQTT-Integration hinzu – sie findet den lokalen Broker meist automatisch.

2Sensordaten messen und senden

Jetzt lesen wir den BME280 aus und veröffentlichen die drei Messwerte alle 30 Sekunden. Wir senden sie als ein einziges JSON-Paket auf ein Topic – das ist sauberer, als drei Einzeltopics zu pflegen, und Home Assistant kann die Felder daraus per Template ziehen.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Adafruit_BME280 bme;

const char* TOPIC_STATE = "makeroo/wohnzimmer/state";
unsigned long letzteMessung = 0;

void sensorSetup() {
  if (!bme.begin(0x76)) {          // manche Module auf 0x77
    Serial.println("BME280 nicht gefunden – Adresse/Wiring pruefen!");
  }
}

void messenUndSenden() {
  float temp     = bme.readTemperature();
  float feuchte  = bme.readHumidity();
  float druck    = bme.readPressure() / 100.0F;   // Pa -> hPa

  // JSON von Hand bauen – spart eine extra Bibliothek
  char payload[128];
  snprintf(payload, sizeof(payload),
    "{\"temperatur\":%.1f,\"feuchte\":%.1f,\"druck\":%.1f}",
    temp, feuchte, druck);

  // retained = true: der letzte Wert bleibt am Broker gespeichert
  mqtt.publish(TOPIC_STATE, payload, true);

  Serial.print("gesendet: ");
  Serial.println(payload);
}

// im loop() ergaenzen:
// if (millis() - letzteMessung > 30000) {
//   letzteMessung = millis();
//   messenUndSenden();
// }

💡 Retained Messages nutzen: Das dritte Argument true bei publish() markiert die Nachricht als retained. Der Broker merkt sich den letzten Wert und liefert ihn sofort, wenn Home Assistant neu startet – so steht nach einem Neustart nicht "unbekannt" da, bis der ESP32 das nächste Mal sendet. Für Sensorzustände ist das genau richtig. Kein BME280 zur Hand? Der DHT22 liefert Temperatur und Feuchte ebenso – nur den Luftdruck lässt du dann weg.

3Automatisch in Home Assistant auftauchen (MQTT Discovery)

Jetzt kommt der Teil, der MQTT mit Home Assistant so komfortabel macht. Statt in der configuration.yaml jeden Sensor von Hand einzutragen, sendet der ESP32 einmalig eine Konfigurationsnachricht auf ein spezielles Discovery-Topic. Home Assistant liest sie und legt die Entität automatisch an – mit Namen, Einheit und Gerätezuordnung.

Diese Discovery-Nachrichten schickst du einmal direkt nach dem Verbindungsaufbau:

void discoveryPublish() {
  // Ein Config-Topic pro Messgroesse.
  // Der value_template zieht das Feld aus unserem JSON-state.

  // --- Temperatur ---
  mqtt.publish(
    "homeassistant/sensor/wohnzimmer_temp/config",
    "{\"name\":\"Wohnzimmer Temperatur\","
    "\"uniq_id\":\"wz_temp\","
    "\"stat_t\":\"makeroo/wohnzimmer/state\","
    "\"unit_of_meas\":\"°C\","
    "\"dev_cla\":\"temperature\","
    "\"val_tpl\":\"{{ value_json.temperatur }}\","
    "\"dev\":{\"ids\":\"esp32_wohnzimmer\",\"name\":\"ESP32 Wohnzimmer\"}}",
    true);

  // --- Luftfeuchte ---
  mqtt.publish(
    "homeassistant/sensor/wohnzimmer_hum/config",
    "{\"name\":\"Wohnzimmer Feuchte\","
    "\"uniq_id\":\"wz_hum\","
    "\"stat_t\":\"makeroo/wohnzimmer/state\","
    "\"unit_of_meas\":\"%\","
    "\"dev_cla\":\"humidity\","
    "\"val_tpl\":\"{{ value_json.feuchte }}\","
    "\"dev\":{\"ids\":\"esp32_wohnzimmer\"}}",
    true);

  // --- Luftdruck ---
  mqtt.publish(
    "homeassistant/sensor/wohnzimmer_press/config",
    "{\"name\":\"Wohnzimmer Luftdruck\","
    "\"uniq_id\":\"wz_press\","
    "\"stat_t\":\"makeroo/wohnzimmer/state\","
    "\"unit_of_meas\":\"hPa\","
    "\"dev_cla\":\"pressure\","
    "\"val_tpl\":\"{{ value_json.druck }}\","
    "\"dev\":{\"ids\":\"esp32_wohnzimmer\"}}",
    true);
}

Rufst du discoveryPublish() einmal nach dem MQTT-Connect auf, erscheinen im Home-Assistant-Dashboard drei neue Sensoren, alle sauber unter dem Gerät "ESP32 Wohnzimmer" gruppiert. Kein einziger Eintrag in einer YAML-Datei nötig.

⚠️ Achte auf die Feldkürzel: Home Assistant erlaubt in Discovery-Nachrichten Abkürzungen: stat_t = state_topic, val_tpl = value_template, dev_cla = device_class, uniq_id = unique_id. Die unique_id ist wichtig – ohne sie kannst du die Entität später nicht im UI umbenennen. Und alle Sensoren mit derselben dev.ids landen unter einem gemeinsamen Gerät.

4Zurück-Kanal: ein Relais aus Home Assistant schalten

MQTT geht in beide Richtungen. Damit du aus der App ein Relais schalten kannst, abonniert der ESP32 ein Kommando-Topic. Kommt dort "ON" oder "OFF" an, feuert die Callback-Funktion und schaltet den GPIO. Zusätzlich melden wir per Discovery einen Switch an Home Assistant.

#define RELAIS_PIN 26

const char* TOPIC_CMD   = "makeroo/wohnzimmer/relais/set";
const char* TOPIC_RELST = "makeroo/wohnzimmer/relais/state";

// wird bei jeder eingehenden Nachricht aufgerufen
void mqttCallback(char* topic, byte* payload, unsigned int len) {
  String msg;
  for (unsigned int i = 0; i < len; i++) msg += (char)payload[i];

  if (String(topic) == TOPIC_CMD) {
    if (msg == "ON") {
      digitalWrite(RELAIS_PIN, HIGH);
      mqtt.publish(TOPIC_RELST, "ON", true);
    } else if (msg == "OFF") {
      digitalWrite(RELAIS_PIN, LOW);
      mqtt.publish(TOPIC_RELST, "OFF", true);
    }
  }
}

void relaisDiscovery() {
  mqtt.publish(
    "homeassistant/switch/wohnzimmer_relais/config",
    "{\"name\":\"Wohnzimmer Relais\","
    "\"uniq_id\":\"wz_relais\","
    "\"cmd_t\":\"makeroo/wohnzimmer/relais/set\","
    "\"stat_t\":\"makeroo/wohnzimmer/relais/state\","
    "\"dev\":{\"ids\":\"esp32_wohnzimmer\"}}",
    true);
}

// in setup():
//   pinMode(RELAIS_PIN, OUTPUT);
//   mqtt.setCallback(mqttCallback);
// nach dem Connect:
//   mqtt.subscribe(TOPIC_CMD);
//   relaisDiscovery();

Ab jetzt hast du in Home Assistant einen Schalter, der das Relais am ESP32 steuert – per App, per Sprachassistent oder in einer Automation ("Wenn Temperatur unter 18 °C, schalte Heizlüfter ein"). Der state-Topic sorgt dafür, dass die App auch dann den richtigen Zustand zeigt, wenn du den ESP32 anderweitig schaltest.

💡 Last Will nicht vergessen: MQTT kann ein "Testament" (Last Will and Testament) hinterlegen. Fällt der ESP32 aus, sendet der Broker automatisch eine Offline-Nachricht. Bei mqtt.connect() gibst du dafür ein Availability-Topic an und meldest dich nach dem Connect mit "online". So zeigt Home Assistant sauber "nicht verfügbar", wenn dein Sensor mal offline geht – statt ewig den letzten Wert einzufrieren.

Troubleshooting

⚠️ rc=-2 oder rc=5 beim Verbinden: -2 heißt, der Broker ist nicht erreichbar – prüfe IP und Port 1883 sowie ob Mosquitto läuft. 5 bedeutet "nicht autorisiert" – Benutzername oder Passwort stimmen nicht mit dem Mosquitto-Benutzer überein.

⚠️ Sensoren tauchen nicht in Home Assistant auf: Ist die MQTT-Integration hinzugefügt? Steht das Discovery-Präfix wirklich auf homeassistant (Standard)? Beobachte den Datenverkehr mit dem Tool MQTT Explorer – damit siehst du sofort, ob deine Config-Topics ankommen.

⚠️ Werte aktualisieren sich nicht: Meist blockiert ein delay() den mqtt.loop(). Nutze konsequent millis()-Timing statt delay(), damit die MQTT-Verbindung jederzeit bedient wird.

⚠️ Verbindung bricht ständig ab: Zwei Clients mit derselben Client-ID werfen sich gegenseitig raus. Gib jedem ESP32 eine eindeutige ID (z. B. mit der MAC-Adresse als Suffix).

Praxistipps

  • Deep Sleep für Batteriebetrieb: Messen, senden, dann per esp_deep_sleep_start() für ein paar Minuten schlafen. So läuft ein ESP32-Sensor monatelang an einem Akku.
  • Topics sauber strukturieren: Ein durchdachtes Schema wie standort/raum/messgroesse macht dein Setup auch mit 20 Sensoren übersichtlich.
  • Zugangsdaten auslagern: Leg WLAN- und MQTT-Daten in eine separate secrets.h, die du nicht mit dem Sketch teilst.
  • OLED als lokale Anzeige: Ein 0,96-Zoll-OLED am selben I2C-Bus zeigt die Werte direkt am Gerät – praktisch, wenn Home Assistant mal nicht griffbereit ist.
  • Ins Gehäuse setzen: Für den Dauerbetrieb gehört der ESP32 in ein Acryl-Gehäuse – schon damit die Elektronik nicht offen herumliegt.

🚀 Dein Smart-Home-Sensor bei MAKEROO

Alles für den ESP32-MQTT-Knoten:

Fazit

Mit MQTT wird aus einem einsamen ESP32-Sensor ein vollwertiges Mitglied deines Smart Homes. Das Prinzip ist schnell verstanden: Der Sensor veröffentlicht seine Werte auf einem Topic, Home Assistant hört zu, und dank MQTT Discovery legt sich alles von selbst an – ohne eine Zeile YAML. Über den Rückkanal schaltest du sogar Geräte fern.

Hast du diesen einen Knoten erst am Laufen, ist der Rest Copy-and-paste: Jeder weitere Raum ist ein neuer ESP32 mit angepasstem Topic und eigener Client-ID. So wächst aus einem Nachmittagsprojekt nach und nach ein komplettes, selbstgebautes Sensornetz – günstiger, flexibler und lehrreicher als jede fertige Smart-Home-Marke. Fang mit Temperatur und Feuchte an, füg das Relais dazu, und bau dein Zuhause Stück für Stück intelligenter.

Zurück zum Blog