Ratgeber · 16 Min. Lesezeit

ESP32 MQTT Anleitung: Mosquitto, Home Assistant und ESPHome

ESP32 MQTT Anleitung: Mosquitto installieren, mit PubSubClient Sensordaten senden und ein Relais schalten, Home Assistant Discovery, ESPHome-YAML und QoS.

Die Kombination ESP32 und MQTT ist der verbreitetste Weg, Sensoren und Relais im Haus miteinander und mit einem Smart-Home-System wie Home Assistant sprechen zu lassen. MQTT ist ein schlankes Nachrichtenprotokoll für kleine Geräte: Der ESP32 legt die gemessene Temperatur in einem Topic wie "ev/salon/sicaklik" ab, und jedes Programm, das dieses Topic abonniert hat, bekommt den Wert sofort. Genauso erreicht der Befehl "ON", den du in der Home-Assistant-App auf dem Handy auslöst, den ESP32 in deutlich unter einer Sekunde und schaltet das Relais. Anders als bei HTTP wird nicht für jede Anfrage eine neue Verbindung aufgebaut; MQTT arbeitet über eine einzige offene Verbindung mit Headern ab zwei Byte und ist dadurch schnell und schont WLAN und Prozessor.

In dieser Anleitung baust du von Grund auf einen funktionierenden Smart-Home-Knoten. Zuerst lernst du die MQTT-Begriffe Broker, Topic, Publish und Subscribe kennen, dann installierst du den Mosquitto-Broker in Home Assistant oder auf einem Raspberry Pi. Anschließend sendest du mit der Bibliothek PubSubClient Temperatur und Luftfeuchtigkeit eines DHT22 vom ESP32, hörst auf Relais-Befehle und ergänzt MQTT Discovery, damit das Gerät von selbst in Home Assistant erscheint. Außerdem behandeln wir QoS und Retain, die Last-Will-Nachricht (LWT), die das Gerät bei einem Verbindungsabbruch als "nicht verfügbar" markiert, die ESPHome-Alternative ganz ohne C++, die Unterschiede bei ESP8266 und Raspberry Pi Pico W sowie die häufigsten Fehler.

ESP32-Entwicklungsboard, das per MQTT mit Home Assistant verbunden ist
Dank des eingebauten WLANs verbindet sich der ESP32 direkt mit dem MQTT-Broker im Heimnetz; Sensordaten und Relais-Befehle laufen über dieselbe Verbindung.

Was ist MQTT und wie funktioniert es?

MQTT (Message Queuing Telemetry Transport) arbeitet nach dem Publish/Subscribe-Prinzip. In der Mitte sitzt ein Server, der Broker; ESP32, Home Assistant, dein Handy oder ein Programm auf dem PC verbinden sich als Clients mit ihm. Die Clients kennen sich nicht und wissen nichts von den IP-Adressen der anderen: Einer veröffentlicht eine Nachricht in einem Topic, und der Broker leitet sie an alle weiter, die dieses Topic abonniert haben. Stell es dir wie eine Post vor: Der ESP32 wirft einen Brief in das Fach "ev/salon/sicaklik", und Home Assistant, das dieses Fach beobachtet, bekommt ihn sofort. Weil immer der Client die Verbindung aufbaut, braucht der ESP32 weder eine feste IP noch eine Portfreigabe im Router; er muss nur die Adresse des Brokers kennen.

BegriffWozu dient er?Beispiel
BrokerServer, der Nachrichten empfängt und an die Abonnenten verteiltMosquitto, der Mosquitto-Broker in Home Assistant
ClientJedes Gerät oder Programm, das sich mit dem Broker verbindet; jedes hat eine eindeutige Client-IDESP32, Home Assistant, MQTT Explorer
TopicAdresse einer Nachricht aus Ebenen, die durch Schrägstriche getrennt sindev/salon/sicaklik
Publish (veröffentlichen)Eine Nachricht an ein Topic sendenDen Wert "23.4" an ev/salon/sicaklik schicken
Subscribe (abonnieren)Sich anmelden, um die Nachrichten eines Topics zu erhaltenDer ESP32 hört auf ev/salon/role/komut
Payload (Nutzdaten)Inhalt der Nachricht: Text, Zahl oder JSONON, 23.4, {"sicaklik":23.4}
RetainDer Broker speichert die letzte Nachricht eines Topics und gibt sie neuen Abonnenten sofortRelais-Zustand: ON
LWT (Last Will)Nachricht, die der Broker im Namen eines Clients veröffentlicht, wenn dieser unerwartet wegfälltev/salon/baglanti: offline
QoSZustellgarantie einer Nachricht (0, 1 oder 2)QoS 1 für Relais-Befehle

Warum MQTT? Vergleich mit Webserver, Blynk und Telegram

MethodeVorteileNachteileIdeal für
MQTT + Home AssistantLokal und schnell, in beide Richtungen; Hunderte Geräte in einem Dashboard, AutomationenEin Broker muss laufenDas ganze Haus zentral steuern
ESP32-WebserverKein zusätzlicher Server, läuft im BrowserJedes Gerät hat eine eigene Seite, keine Automationen zwischen GerätenBedienfeld für ein einzelnes Gerät
Blynk IoTFertiges Handy-Dashboard, Zugriff über das InternetCloud-abhängig, Grenzen im Gratis-TarifSchnelle mobile Prototypen
Telegram-BotKostenlose Sofortbenachrichtigungen, keine PortfreigabeKeine Diagramme und kein DashboardAlarme und einfache Befehle
ESP-NOWESP-Boards kommunizieren ohne Router und BrokerNur zwischen ESP-Boards, erreicht Home Assistant nicht direktDaten von einem Batteriesensor zu einem Gateway bringen

Kurz gesagt: MQTT spielt seine Stärke aus, je mehr Geräte du hast. Kommt ein neuer Sensor dazu, fasst du keinen bestehenden Code an, sondern veröffentlichst einfach in einem neuen Topic. Willst du ein einzelnes Gerät im Browser steuern, kommst du mit ESP32 Async Webserver und WebSocket schneller ans Ziel; für Benachrichtigungen aufs Handy gibt es ESP32 Telegram-Bot und für ein fertiges Handy-Dashboard Blynk mit dem ESP32. Für einen Gartensensor außerhalb der Router-Reichweite ist es eine gute Lösung, die Daten per ESP-NOW zu einem Gateway-ESP32 zu schicken, der mit MQTT verbunden ist.

MQTT-Topics und Platzhalter (Wildcards)

Topics sehen aus wie Ordnerpfade: "ev/salon/sicaklik" (türkisch für Haus/Wohnzimmer/Temperatur) hat drei Ebenen und unterscheidet Groß- und Kleinschreibung, "Ev/Salon" und "ev/salon" sind also zwei verschiedene Topics. Beginne nicht mit einem Schrägstrich ("/ev/salon" erzeugt eine leere erste Ebene) und verzichte auf Leerzeichen und Umlaute; einfache Buchstaben, Ziffern, Bindestrich und Unterstrich reichen. Beim Abonnieren gibt es zwei Platzhalter: + ersetzt genau eine Ebene ("ev/+/sicaklik" liefert die Temperatur aller Räume), # deckt alles danach ab und darf nur am Ende stehen ("ev/#" liefert alle Nachrichten im Haus). Platzhalter gelten nur beim Abonnieren; veröffentlicht wird immer in genau ein Topic. Topics, die mit $ beginnen (etwa $SYS), sind für die Statistiken des Brokers reserviert und werden von einem #-Abo nicht erfasst. Für das Projekt in dieser Anleitung nutzen wir diese Struktur:

TopicVeröffentlicht vonAbonniert vonRetain
ev/salon/sicaklikESP32 (alle 30 Sekunden)Home AssistantJa
ev/salon/nemESP32 (alle 30 Sekunden)Home AssistantJa
ev/salon/role/komutHome Assistant, Handy, AutomationenESP32Nein
ev/salon/role/durumESP32 (bei jeder Änderung)Home AssistantJa
ev/salon/baglantiESP32 (online), Broker (offline)Home AssistantJa
homeassistant/statusHome Assistant (online beim Start)ESP32Nein

MQTT-Broker installieren: Mosquitto

Der verbreitetste kostenlose MQTT-Broker ist Eclipse Mosquitto; selbst auf einem Raspberry Pi bewältigt er mühelos Hunderte Nachrichten pro Sekunde. Es gibt drei einfache Wege: die offizielle Mosquitto-broker-App, wenn du Home Assistant OS nutzt, das apt-Paket auf einem separaten Raspberry Pi oder Linux-Rechner oder den Mosquitto-Installer unter Windows. Egal welchen Weg du wählst: Der Broker nutzt Port 1883 für unverschlüsseltes MQTT und 8883 für TLS-verschlüsseltes MQTT und muss nur im selben Heimnetz wie der ESP32 sein. In Home Assistant läuft die Einrichtung so:

  1. Öffne in Home Assistant Einstellungen > Apps (in älteren Versionen heißt der Bereich Add-ons), klicke auf App installieren und wähle Mosquitto broker aus der Liste.
  2. Klicke auf Installieren; danach auf Starten, und lass die Option zum Start beim Booten aktiviert.
  3. Lege einen eigenen Benutzer für den ESP32 an: unter Einstellungen > Personen > Benutzer einen Benutzer "esp32" mit einem starken Passwort. Siehst du diesen Reiter nicht, aktiviere in deinem Profil den erweiterten Modus. Die Namen "homeassistant" und "addons" sind für den Broker reserviert, verwende sie nicht.
  4. Auf der Seite Einstellungen > Geräte & Dienste erscheint die MQTT-Integration meist von selbst als "Entdeckt"; klicke auf Konfigurieren und bestätige. Falls nicht, suche über Integration hinzufügen nach MQTT und wähle die automatische Konfiguration von Mosquitto.
  5. Im ESP32-Code trägst du als Broker-Adresse die IP von Home Assistant ein (zum Beispiel 192.168.1.10), als Port 1883 und den eben angelegten Benutzer.

Auf einem Linux-Rechner wie einem Raspberry Pi oder Ubuntu sind es nur ein paar Befehle. Installiere Broker und Testwerkzeuge mit sudo apt install mosquitto mosquitto-clients. Lege mit sudo mosquitto_passwd -c /etc/mosquitto/passwd esp32 den Benutzer "esp32" an und gib das Passwort zweimal ein; die Option -c legt die Datei neu an, lass sie beim zweiten Benutzer also weg, sonst werden die bisherigen Benutzer gelöscht. Erstelle dann im Ordner /etc/mosquitto/conf.d/ eine Datei lokal.conf mit den drei Zeilen unten und starte den Dienst mit sudo systemctl restart mosquitto neu. Unter Windows trägst du dieselben Zeilen in die Datei mosquitto.conf im Installationsordner ein und startest den Dienst Mosquitto Broker neu.

ZeileBedeutung
listener 1883Lauscht auf Port 1883 an allen Netzwerkschnittstellen; ohne diese Zeile nimmt Mosquitto 2.x nur Verbindungen vom selben Rechner an
allow_anonymous falseLehnt Verbindungen ohne Benutzername und Passwort ab; in 2.x ohnehin Standard, aber es ausdrücklich hinzuschreiben ist eine gute Gewohnheit
password_file /etc/mosquitto/passwdVerwendet die mit mosquitto_passwd erstellte Passwortdatei; die Passwörter liegen dort als Hash
Ist in der Konfiguration kein Listener definiert, lauscht Mosquitto ab Version 2.0 nur auf 127.0.0.1 und schreibt die Warnung "Starting in local only mode. Connections will only be possible from clients running on this machine." ins Log. Dann kann sich der ESP32 nicht verbinden und du bekommst den Fehler rc=-2. Gib Port 1883 andererseits niemals im Router fürs Internet frei (keine Portweiterleitung): Unverschlüsselter MQTT-Verkehr ist unterwegs mitlesbar, und die Relais in deinem Haus könnten in fremde Hände geraten. Brauchst du Zugriff von außen, nutze ein VPN oder die Fernzugriffslösungen von Home Assistant.

Teste den Broker vom PC aus, bevor du zum ESP32 übergehst; wenn du Broker- und Codeprobleme von Anfang an trennst, sparst du viel Zeit. Starte in einem Terminal mit mosquitto_sub -h 192.168.1.10 -u esp32 -P deinpasswort -t "ev/#" -v das Mithören aller Topics im Haus. Gib in einem zweiten Terminal mosquitto_pub -h 192.168.1.10 -u esp32 -P deinpasswort -t ev/salon/test -m hallo ein. Erscheint im ersten Terminal die Zeile "ev/salon/test hallo", läuft der Broker und das Passwort stimmt. Die Option -v schreibt das Topic vor jede Nachricht, die Option -r sendet die Nachricht als Retain.

Wenn du die Kommandozeile nicht magst: Das kostenlose Programm MQTT Explorer zeigt alle Topics des Brokers als Baum mit den letzten Werten und Retain-Markierungen. Auch in Home Assistant kannst du unter Einstellungen > Geräte & Dienste > MQTT > Konfigurieren im Feld "Auf ein Topic hören" ev/# eingeben und mithören, und über "Ein Paket veröffentlichen" dem ESP32 von Hand Befehle schicken.

Bauteile und Schaltplan

Für das Projekt brauchst du ein ESP32-Entwicklungsboard, einen DHT22-Temperatur- und Feuchtigkeitssensor, ein Relaismodul, das sich mit 3,3 V ansteuern lässt, ein Breadboard und Jumper-Kabel. Der DHT22 ist genauer als der DHT11: Er misst die Temperatur auf ±0,5 °C und die Luftfeuchtigkeit auf etwa ±2–5 % und arbeitet von -40 bis 80 °C; die Sensorfamilie erklären wir ausführlich unter DHT11 Temperatur- und Feuchtigkeitssensor. Hast du einen DHT11, ändere im Code einfach DHT22 in DHT11. Für den ersten Verbindungstest reichen ein ESP32 und ein USB-Kabel; Sensor und Relais kannst du später ergänzen.

ESP32
ESP32
DHT22
DHT22
Relaismodul
Relaismodul
VerbindungESP32ESP8266 (NodeMCU)Raspberry Pi Pico W
DHT22 VCC3V33V33V3(OUT)
DHT22 DATAGPIO 4D2 (GPIO 4)GP15
DHT22 GNDGNDGNDGND
Relais VCCVIN (5V)VIN (5V)VBUS (5V)
Relais INGPIO 26D1 (GPIO 5)GP14
Relais GNDGNDGNDGND
Die Pins von ESP32, ESP8266 und Pico arbeiten mit 3,3 V und sind nicht 5-V-tolerant; deshalb versorgen wir den DHT22 über den 3V3-Pin. Dreipolige DHT22-Module haben meist schon einen Pull-up-Widerstand auf der Platine; nutzt du den nackten Sensor mit vier Beinen, setze einen Widerstand von 4,7–10 kΩ zwischen DATA und VCC. Schaltest du mit dem Relais eine 230-V-Netzlast, verdrahte nur bei gezogenem Stecker und hol dir Hilfe von einem Erwachsenen; Details findest du unter Was ist ein Relaismodul?. Alle Pins deines Boards zeigt das Werkzeug Pinout.

PubSubClient in der Arduino IDE installieren

  1. Ist das ESP32-Boardpaket in der Arduino IDE noch nicht installiert, hole das zuerst nach; die Schritte stehen unter Was ist der ESP32?.
  2. Öffne Werkzeuge > Bibliotheken verwalten, gib PubSubClient ins Suchfeld ein und installiere die Bibliothek von Nick O'Leary. Der Code in dieser Anleitung wurde mit Version 2.8 kompiliert.
  3. Suche im selben Fenster nach DHT sensor library und installiere die Bibliothek von Adafruit; bei der Frage nach Abhängigkeiten wählst du Install all, damit auch Adafruit Unified Sensor installiert wird.
  4. Gibt es Probleme beim Installieren, hilft die Anleitung Arduino-Bibliotheken hinzufügen.

Erster Test: ESP32 mit dem MQTT-Broker verbinden

Bevor die Sensoren dazukommen, prüfen wir mit dem einfachsten Code, ob WLAN-Daten, Broker-Adresse und Passwort stimmen. Der folgende Code verbindet sich mit dem Broker, veröffentlicht "merhaba" (hallo) im Topic "test/esp32/durum" und gibt jede Nachricht, die auf "test/esp32/komut" ankommt, im seriellen Monitor aus. Ersetze WLAN-Name, Passwort, Broker-IP und MQTT-Benutzer durch deine eigenen Daten, lade den Code hoch und öffne den seriellen Monitor mit 115200 Baud:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <PubSubClient.h>
3
4const char* WIFI_SSID = "AgAdi";              // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
5const char* WIFI_PASS = "Sifre123";           // Wi-Fi şifren / your Wi-Fi password
6const char* MQTT_SUNUCU = "192.168.1.10";     // broker'ın IP adresi / broker IP address
7const int   MQTT_PORT = 1883;                 // şifresiz MQTT portu / unencrypted MQTT port
8const char* MQTT_KULLANICI = "esp32";         // broker kullanıcı adı / broker username
9const char* MQTT_SIFRE = "mqttSifre";         // broker şifresi / broker password
10
11WiFiClient wifiIstemci;                       // TCP bağlantısı / TCP connection
12PubSubClient mqtt(wifiIstemci);               // MQTT istemcisi / MQTT client
13
14// Abone olunan konuya mesaj gelince çalışır / runs when a subscribed topic receives a message
15void mesajGeldi(char* topic, byte* payload, unsigned int length) {
16  Serial.print("Mesaj [");
17  Serial.print(topic);
18  Serial.print("] ");
19  for (unsigned int i = 0; i < length; i++) {
20    Serial.print((char)payload[i]);           // payload sonunda \0 yoktur / payload is not null-terminated
21  }
22  Serial.println();
23}
24
25void setup() {
26  Serial.begin(115200);
27  WiFi.mode(WIFI_STA);
28  WiFi.begin(WIFI_SSID, WIFI_PASS);
29  while (WiFi.status() != WL_CONNECTED) {
30    delay(500);
31    Serial.print(".");
32  }
33  Serial.print("\nIP: ");
34  Serial.println(WiFi.localIP());
35
36  mqtt.setServer(MQTT_SUNUCU, MQTT_PORT);     // broker adresi / broker address
37  mqtt.setCallback(mesajGeldi);               // gelen mesaj fonksiyonu / incoming message handler
38}
39
40void loop() {
41  if (!mqtt.connected()) {
42    Serial.print("MQTT baglaniyor... ");
43    if (mqtt.connect("esp32-test", MQTT_KULLANICI, MQTT_SIFRE)) {   // istemci kimliği benzersiz olmalı / client ID must be unique
44      Serial.println("baglandi");
45      mqtt.subscribe("test/esp32/komut");                  // bu konuyu dinle / listen to this topic
46      mqtt.publish("test/esp32/durum", "merhaba");         // ilk mesaj / first message
47    } else {
48      Serial.print("hata, rc=");
49      Serial.println(mqtt.state());                        // hata kodu / error code
50      delay(5000);
51      return;
52    }
53  }
54  mqtt.loop();                                             // mesajları işle, bağlantıyı canlı tut / process messages, keep the connection alive
55}

Sobald im seriellen Monitor "baglandi" (verbunden) steht, sende vom Terminal auf deinem PC mosquitto_pub -h 192.168.1.10 -u esp32 -P deinpasswort -t test/esp32/komut -m hi; nach wenigen Millisekunden erscheint im seriellen Monitor die Zeile "Mesaj [test/esp32/komut] hi". Schlägt die Verbindung fehl, gibt der Code mit mqtt.state() einen Fehlercode aus und versucht es nach 5 Sekunden erneut. Diese Codes verraten dir genau, wo das Problem liegt:

rcName in PubSubClientBedeutung und Lösung
-4MQTT_CONNECTION_TIMEOUTDer Broker hat nicht rechtzeitig geantwortet; schwaches Netz oder überlasteter Broker
-3MQTT_CONNECTION_LOSTEine bestehende Verbindung ist abgebrochen; meist weil loop() lange nicht aufgerufen wurde oder das WLAN weg war
-2MQTT_CONNECT_FAILEDDie TCP-Verbindung kam nie zustande: falsche IP oder falscher Port, Broker aus, Mosquitto im Local-only-Modus oder eine Firewall blockiert 1883
-1MQTT_DISCONNECTEDDie Verbindung wurde sauber getrennt (disconnect aufgerufen) oder bestand noch nie
2MQTT_CONNECT_BAD_CLIENT_IDDie Client-ID wurde abgelehnt; eine leere oder ungültige Client-ID wurde verwendet
4MQTT_CONNECT_BAD_CREDENTIALSBenutzername oder Passwort falsch (manche Broker liefern diesen Code)
5MQTT_CONNECT_UNAUTHORIZEDNicht autorisiert; Mosquitto liefert diesen Code sowohl bei falschem Passwort als auch beim Versuch, sich ohne Zugangsdaten zu verbinden

Mit dem ESP32 Sensordaten veröffentlichen und auf Relais-Befehle hören

Jetzt bauen wir das eigentliche Projekt. Der folgende Code liest den DHT22 alle 30 Sekunden aus und veröffentlicht Temperatur und Luftfeuchtigkeit mit Retain-Flag, schaltet das Relais mit den Befehlen ON, OFF und TOGGLE aus dem Topic "ev/salon/role/komut" und meldet den neuen Zustand an "ev/salon/role/durum". Beim Verbinden hinterlegt er beim Broker einen Last Will, stellt sich Home Assistant per MQTT Discovery vor und versucht nach einem Verbindungsabbruch alle 5 Sekunden einen Neuaufbau, ohne loop() zu blockieren. Dank des Blocks #if defined(ESP8266) am Anfang lässt sich derselbe Code ohne Änderung auch für einen NodeMCU kompilieren.

C++ (Arduino IDE)
1#if defined(ESP8266)
2#include <ESP8266WiFi.h>
3#else
4#include <WiFi.h>
5#endif
6#include <PubSubClient.h>
7#include <DHT.h>
8
9// ---- Ayarlar / Settings ----
10const char* WIFI_SSID = "AgAdi";
11const char* WIFI_PASS = "Sifre123";
12const char* MQTT_SUNUCU = "192.168.1.10";        // broker IP (Home Assistant ya da Raspberry Pi) / broker IP (Home Assistant or Raspberry Pi)
13const int   MQTT_PORT = 1883;
14const char* MQTT_KULLANICI = "esp32";
15const char* MQTT_SIFRE = "mqttSifre";
16const char* ISTEMCI_ID = "esp32-salon";          // her cihazda farklı olmalı / must be different on every device
17
18#if defined(ESP8266)
19const int DHT_PIN = 4;                           // NodeMCU D2
20const int ROLE_PIN = 5;                          // NodeMCU D1
21#else
22const int DHT_PIN = 4;                           // ESP32 GPIO 4
23const int ROLE_PIN = 26;                         // ESP32 GPIO 26
24#endif
25const bool ROLE_AKTIF_LOW = true;                // çoğu röle modülü LOW ile çeker / most relay modules switch on LOW
26const unsigned long OLCUM_ARALIGI = 30000;       // 30 saniyede bir ölçüm / one reading every 30 s
27
28// ---- Konular (topic) / Topics ----
29const char* T_SICAKLIK = "ev/salon/sicaklik";
30const char* T_NEM      = "ev/salon/nem";
31const char* T_KOMUT    = "ev/salon/role/komut";  // ON, OFF ya da TOGGLE / ON, OFF or TOGGLE
32const char* T_DURUM    = "ev/salon/role/durum";
33const char* T_BAGLANTI = "ev/salon/baglanti";    // online / offline (son vasiyet / last will)
34const char* T_HA_DURUM = "homeassistant/status"; // HA açılınca "online" yayınlar / HA publishes "online" when it starts
35
36WiFiClient wifiIstemci;
37PubSubClient mqtt(wifiIstemci);
38DHT dht(DHT_PIN, DHT22);
39
40bool roleAcik = false;
41unsigned long sonOlcum = 0;
42unsigned long sonDeneme = 0;
43
44// Röleyi sür ve yeni durumu kalıcı (retain) yayınla / drive the relay and publish the new state as retained
45void roleAyarla(bool acik) {
46  roleAcik = acik;
47  bool seviye = ROLE_AKTIF_LOW ? !acik : acik;
48  digitalWrite(ROLE_PIN, seviye ? HIGH : LOW);
49  mqtt.publish(T_DURUM, acik ? "ON" : "OFF", true);
50  Serial.println(acik ? "Role: ON" : "Role: OFF");
51}
52
53// Tek bir Home Assistant keşif mesajı gönder / send one Home Assistant discovery message
54void kesifYayinla(const char* tur, const char* nesne, const char* ad, const char* ekAlanlar) {
55  char konu[96];
56  snprintf(konu, sizeof(konu), "homeassistant/%s/%s/%s/config", tur, ISTEMCI_ID, nesne);
57  char json[600];
58  snprintf(json, sizeof(json),
59           "{\"name\":\"%s\",\"unique_id\":\"%s_%s\",%s,\"availability_topic\":\"%s\","
60           "\"device\":{\"identifiers\":[\"%s\"],\"name\":\"Salon ESP32\",\"model\":\"ESP32 + DHT22\"}}",
61           ad, ISTEMCI_ID, nesne, ekAlanlar, T_BAGLANTI, ISTEMCI_ID);
62  if (!mqtt.publish(konu, json, true)) {         // false: tampon küçük ya da bağlantı yok / false: buffer too small or not connected
63    Serial.println("Kesif mesaji gonderilemedi");
64  }
65}
66
67// Sıcaklık, nem ve röleyi Home Assistant'a tanıt / announce temperature, humidity and relay to Home Assistant
68void haKesifGonder() {
69  char ek[200];
70  snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"device_class\":\"temperature\",\"unit_of_measurement\":\"°C\",\"state_class\":\"measurement\"", T_SICAKLIK);
71  kesifYayinla("sensor", "sicaklik", "Sıcaklık", ek);
72  snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"device_class\":\"humidity\",\"unit_of_measurement\":\"%%\",\"state_class\":\"measurement\"", T_NEM);
73  kesifYayinla("sensor", "nem", "Nem", ek);
74  snprintf(ek, sizeof(ek), "\"state_topic\":\"%s\",\"command_topic\":\"%s\"", T_DURUM, T_KOMUT);
75  kesifYayinla("switch", "role", "Röle", ek);
76}
77
78// DHT22'yi oku ve değerleri yayınla / read the DHT22 and publish the values
79void olcumGonder() {
80  float t = dht.readTemperature();
81  float h = dht.readHumidity();
82  if (isnan(t) || isnan(h)) {
83    Serial.println("DHT22 okunamadi");
84    return;
85  }
86  char deger[12];
87  snprintf(deger, sizeof(deger), "%.1f", t);     // 23.4 gibi / like 23.4
88  mqtt.publish(T_SICAKLIK, deger, true);
89  snprintf(deger, sizeof(deger), "%.0f", h);     // 45 gibi / like 45
90  mqtt.publish(T_NEM, deger, true);
91  Serial.printf("Sicaklik %.1f C, nem %.0f %%\n", t, h);
92}
93
94// Abone olunan konulara mesaj gelince çalışır / runs when a subscribed topic receives a message
95void mesajGeldi(char* topic, byte* payload, unsigned int length) {
96  // Önce kopyala: yayın yapınca kütüphane aynı tamponu kullanır / copy first: publishing reuses the same buffer
97  String konu = topic;
98  String mesaj;
99  for (unsigned int i = 0; i < length; i++) mesaj += (char)payload[i];
100  mesaj.trim();
101
102  if (konu == T_KOMUT) {
103    if (mesaj == "ON") roleAyarla(true);
104    else if (mesaj == "OFF") roleAyarla(false);
105    else if (mesaj == "TOGGLE") roleAyarla(!roleAcik);
106  } else if (konu == T_HA_DURUM && mesaj == "online") {
107    haKesifGonder();                             // HA yeniden başladı, tanıtımı yenile / HA restarted, announce again
108    mqtt.publish(T_DURUM, roleAcik ? "ON" : "OFF", true);
109  }
110}
111
112bool mqttBaglan() {
113  Serial.print("MQTT baglaniyor... ");
114  // Bağlantı koparsa broker T_BAGLANTI'ya "offline" yazar / if we drop, the broker publishes "offline" to T_BAGLANTI
115  if (!mqtt.connect(ISTEMCI_ID, MQTT_KULLANICI, MQTT_SIFRE, T_BAGLANTI, 1, true, "offline")) {
116    Serial.print("hata, rc=");
117    Serial.println(mqtt.state());
118    return false;
119  }
120  Serial.println("baglandi");
121  mqtt.publish(T_BAGLANTI, "online", true);
122  mqtt.subscribe(T_KOMUT, 1);                    // komutları QoS 1 ile dinle / listen to commands with QoS 1
123  mqtt.subscribe(T_HA_DURUM);
124  haKesifGonder();
125  mqtt.publish(T_DURUM, roleAcik ? "ON" : "OFF", true);
126  return true;
127}
128
129void setup() {
130  Serial.begin(115200);
131  pinMode(ROLE_PIN, OUTPUT);
132  roleAyarla(false);                             // güvenli başlangıç: röle kapalı / safe start: relay off
133  dht.begin();
134
135  WiFi.mode(WIFI_STA);
136  WiFi.begin(WIFI_SSID, WIFI_PASS);
137  Serial.print("Wi-Fi");
138  while (WiFi.status() != WL_CONNECTED) {
139    delay(500);
140    Serial.print(".");
141  }
142  Serial.print(" IP: ");
143  Serial.println(WiFi.localIP());
144
145  mqtt.setServer(MQTT_SUNUCU, MQTT_PORT);
146  mqtt.setCallback(mesajGeldi);
147  mqtt.setBufferSize(1024);                      // keşif JSON'u varsayılan 256 bayta sığmaz / discovery JSON doesn't fit the default 256 bytes
148}
149
150void loop() {
151  if (!mqtt.connected()) {
152    unsigned long simdi = millis();
153    if (sonDeneme == 0 || simdi - sonDeneme >= 5000) {   // 5 sn'de bir dene, loop'u kilitleme / retry every 5 s without blocking
154      sonDeneme = simdi;
155      if (mqttBaglan()) sonOlcum = simdi - OLCUM_ARALIGI;  // bağlanınca hemen ölç / measure right after connecting
156    }
157    return;
158  }
159  mqtt.loop();                                   // gelen komutlar ve keep-alive / incoming commands and keep-alive
160
161  if (millis() - sonOlcum >= OLCUM_ARALIGI) {
162    sonOlcum = millis();
163    olcumGonder();
164  }
165}
ZeileAufgabe
mqtt.connect(ISTEMCI_ID, ..., T_BAGLANTI, 1, true, "offline")Meldet beim Verbinden auch den Last Will an: Fällt der ESP32 unerwartet weg, schreibt der Broker dauerhaft "offline" nach ev/salon/baglanti
mqtt.publish(T_BAGLANTI, "online", true)Setzt den Status direkt nach dem Verbinden auf "online"; Home Assistant zeigt das Gerät wieder als verfügbar
mqtt.subscribe(T_KOMUT, 1)Hört mit QoS 1 auf Relais-Befehle; PubSubClient unterstützt beim Abonnieren nur QoS 0 und 1
mqtt.setBufferSize(1024)Vergrößert den Paketpuffer von standardmäßig 256 Byte; das größte Discovery-Paket hat etwa 355 Byte
mqtt.loop()Liest eingehende Nachrichten und sendet Keep-alive-Pakete (PINGREQ); muss in jedem Durchlauf von loop aufgerufen werden
ROLE_AKTIF_LOWDie meisten Relaismodule schalten bei LOW; schaltet deins bei HIGH, setze den Wert auf false
OLCUM_ARALIGIMessintervall; der DHT22 darf höchstens alle 2 Sekunden gelesen werden, für Raumtemperatur sind 30–60 Sekunden ideal

Einige Details im Code sind bewusst so gewählt. Die Funktion mesajGeldi() kopiert Topic und Payload zuerst in Strings, denn PubSubClient nutzt einen einzigen Puffer für ein- und ausgehende Nachrichten: Sobald du im Callback publish() aufrufst, werden die Daten überschrieben, auf die topic und payload zeigen. Die Payload hat außerdem kein abschließendes \0 wie ein C-String, deshalb lesen wir genau length Zeichen. Für Messwerte und Relais-Zustand nutzen wir Retain, damit Home Assistant nach einem Neustart sofort den letzten Wert sieht, statt 30 Sekunden zu warten. Auch das Timing läuft über millis(): Ein langes delay() in loop() würde die Keep-alive-Pakete verzögern, und der Broker würde die Verbindung trennen. Diese Technik erklären wir ausführlich unter Arduino millis() statt delay().

Sende an Befehls-Topics niemals Nachrichten mit Retain-Flag. Bleibt auf "ev/salon/role/komut" ein gespeichertes "ON" liegen, bekommt der ESP32 diesen alten Befehl nach jedem Stromausfall oder WLAN-Abbruch erneut und schaltet das Relais mitten in der Nacht von selbst ein. Hast du versehentlich einen Befehl mit Retain gesendet, lösche ihn mit einer leeren Retain-Nachricht: mosquitto_pub -r -n -t ev/salon/role/komut. Die MQTT-Schalter von Home Assistant senden Befehle standardmäßig ohne Retain.

So sieht es in Home Assistant aus: MQTT Discovery

Home Assistant hört ständig auf Topics mit dem Präfix homeassistant/. Veröffentlicht ein Gerät eine JSON-Konfiguration in einem Topic der Form homeassistant/[Komponente]/[Knoten]/[Objekt]/config, legt Home Assistant die Entität automatisch an; das nennt sich MQTT Discovery. Unser Code sendet drei Nachrichten: zwei für die Sensoren (Temperatur und Luftfeuchtigkeit) unter homeassistant/sensor/esp32-salon/... und eine für das Relais unter homeassistant/switch/esp32-salon/role/config. Weil sie mit Retain gesendet werden, überstehen sie auch einen Neustart von Home Assistant. Außerdem abonniert der Code homeassistant/status: Home Assistant schreibt dort beim Start "online", und der ESP32 meldet sich erneut an. Bei vielen Geräten empfiehlt die Home-Assistant-Dokumentation, diese erneute Anmeldung mit einer kleinen zufälligen Verzögerung zu senden.

JSON-FeldBedeutungUnser Wert
nameAnzeigename der Entität; der Gerätename wird davor gesetztSıcaklık (erscheint als Salon ESP32 Sıcaklık)
unique_idDauerhafte ID der Entität; ohne sie lassen sich Name und Bereich nicht in der Oberfläche ändernesp32-salon_sicaklik
state_topicTopic, aus dem der Wert gelesen wirdev/salon/sicaklik
command_topicTopic, an das Schaltbefehle (switch) gesendet werdenev/salon/role/komut
device_classLegt Symbol, Einheitenauswahl und Diagrammart festtemperature, humidity
unit_of_measurementMaßeinheit°C und %
state_classDer Wert measurement sorgt für Langzeitstatistiken und Diagrammemeasurement
availability_topicTopic für den Status online/offline; die Standard-Payloads sind online und offlineev/salon/baglanti
deviceFasst die Entitäten auf einer Gerätekarte zusammenidentifiers, name, model

Ein paar Sekunden nach dem Hochladen erscheint unter Einstellungen > Geräte & Dienste > MQTT ein Gerät namens "Salon ESP32". Auf seiner Gerätekarte findest du die Sensoren für Temperatur und Luftfeuchtigkeit sowie einen Relais-Schalter; ein Klick auf die Temperatur öffnet den Verlauf, ein Klick auf den Schalter lässt das Relais anziehen. Du kannst diese Entitäten aufs Dashboard legen, Sprachassistenten freigeben oder in Automationen nutzen: Eine Regel wie "steigt die Wohnzimmertemperatur über 27 °C, schalte das Relais mit dem Ventilator ein, unter 25 °C wieder aus" ist mit ein paar Klicks erstellt. Ziehst du den Stecker des ESP32, wechseln die Entitäten nach spätestens etwa 22 Sekunden auf "Nicht verfügbar"; daran siehst du, dass der Last Will funktioniert. Willst du kein Discovery nutzen, kannst du dieselben Entitäten auch von Hand in der configuration.yaml unter mqtt: als sensor und switch anlegen.

Hast du Name oder Topics des Geräts geändert und alte Entitäten bleiben in Home Assistant hängen, sende eine leere Retain-Nachricht an das passende config-Topic: mosquitto_pub -r -n -t homeassistant/sensor/esp32-salon/sicaklik/config. Home Assistant löscht die Entität und entfernt auch das Gerät, wenn keine weitere Entität daran hängt. Gibst du jedem ESP32 eine andere ISTEMCI_ID, unterscheiden sich auch die unique_id-Werte automatisch, und du kannst mehrere Räume ohne Durcheinander hinzufügen.

QoS und Retain: Was nimmst du wann?

QoS (Quality of Service) legt fest, wie sicher du sein willst, dass eine Nachricht ankommt. Ein wichtiges Detail: QoS gilt getrennt auf zwei Strecken. Zwischen Absender und Broker gilt die QoS des Absenders, zwischen Broker und Abonnent die QoS des Abonnements; der Abonnent bekommt die niedrigere der beiden Garantien. PubSubClient unterstützt beim Veröffentlichen nur QoS 0 und beim Abonnieren QoS 0 und 1. Im Heim-WLAN geht mit QoS 0 nur sehr selten etwas verloren, trotzdem ist QoS 1 für das Befehls-Abo eine günstige Versicherung.

QoSGarantieWie funktioniert es?Wann verwenden?
0Höchstens einmalDie Nachricht wird einmal ohne Bestätigung gesendet; bricht die Verbindung genau dann ab, kann sie verloren gehenHäufige Sensormesswerte
1Mindestens einmalDer Empfänger bestätigt mit PUBACK, ohne Bestätigung wird erneut gesendet; die Nachricht kann doppelt ankommenRelais-Befehle, Alarme
2Genau einmalVierstufiger Handshake mit PUBREC, PUBREL und PUBCOMP; die langsamste StufeZähler und Ähnliches, wo Doppelte schaden; von PubSubClient nicht unterstützt

Beim Retain-Flag geht es nicht um Zustellung, sondern um Gedächtnis: Der Broker speichert pro Topic nur die letzte Retain-Nachricht und schickt sie jedem neuen Abonnenten sofort. Ideal ist das für Nachrichten zum "aktuellen Zustand" wie Messwerte, Relais-Zustand und Online-Status, gefährlich dagegen für Befehle und einmalige Ereignisse. Der Last Will (LWT) ergänzt das: Erhält der Broker vom Client 1,5-mal so lange wie das Keep-alive-Intervall kein Paket, hält er die Verbindung für verloren und veröffentlicht die Last-Will-Nachricht. Das Standard-Keep-alive von PubSubClient beträgt 15 Sekunden, ein ausgesteckter ESP32 erscheint also nach spätestens etwa 22 Sekunden als "offline". Mit einer Zeile wie mqtt.setKeepAlive(30) kannst du das ändern, aber je länger der Wert, desto später bemerkst du einen Abbruch.

Die Alternative ohne Code: ESPHome

ESPHome ist ein kostenloses Werkzeug, das ein in einer YAML-Datei beschriebenes Gerät in fertige ESP32-Firmware verwandelt; du schreibst keine einzige Zeile C++. Installiere in Home Assistant unter Einstellungen > Apps den ESPHome Device Builder, öffne seine Oberfläche und lege mit dem Assistenten Neues Gerät eine Konfiguration an. Der erste Upload erfolgt einmalig per USB: Chrome oder Edge können das Board direkt programmieren, und falls das nicht klappt, spielst du die vom Assistenten heruntergeladene Datei mit der Seite ESPHome Web auf. Alle späteren Updates laufen drahtlos über WLAN (OTA). Die folgende Konfiguration entspricht dem Arduino-Projekt oben: Sie liest den DHT22 an GPIO 4 alle 30 Sekunden und stellt das Low-aktive Relais an GPIO 26 als Schalter bereit. WLAN-Daten und Passwörter werden per !secret aus einer separaten secrets.yaml gelesen:

Code
1esphome:
2  name: salon-sensor               # küçük harf, rakam ve tire / lowercase, digits and hyphens
3  friendly_name: Salon Sensör
4
5esp32:
6  board: esp32dev
7
8logger:
9
10api:                               # Home Assistant ile doğrudan bağlantı / direct link to Home Assistant
11  encryption:
12    key: !secret api_anahtari
13
14ota:
15  - platform: esphome
16    password: !secret ota_sifresi
17
18wifi:
19  ssid: !secret wifi_ssid
20  password: !secret wifi_sifresi
21  ap:                              # Wi-Fi yoksa kendi ağını açar / opens its own network if Wi-Fi fails
22    ssid: "Salon-Sensor"
23    password: "yedek1234"
24
25captive_portal:
26
27sensor:
28  - platform: dht
29    pin: GPIO4
30    model: DHT22
31    update_interval: 30s
32    temperature:
33      name: "Sıcaklık"
34    humidity:
35      name: "Nem"
36
37switch:
38  - platform: gpio
39    name: "Röle"
40    pin:
41      number: GPIO26
42      inverted: true               # aktif LOW röle / active-LOW relay
43    restore_mode: ALWAYS_OFF       # açılışta kapalı / off at boot
44
45# MQTT ile kullanmak için api: bloğunu sil, bunu aç / to use MQTT, delete api: and uncomment this
46# mqtt:
47#   broker: 192.168.1.10
48#   username: esp32
49#   password: !secret mqtt_sifresi

Einen Unterschied solltest du kennen: ESPHome nutzt standardmäßig nicht MQTT, sondern seine eigene verschlüsselte Native API. Home Assistant findet das Gerät im Netz von selbst und braucht überhaupt keinen Broker. MQTT lohnt sich nur, wenn auch andere Systeme wie Node-RED dieselben Daten lesen sollen oder wenn du Home Assistant nicht nutzt. Dazu entfernst du die Kommentarzeichen vor den mqtt:-Zeilen am Dateiende und löschst den Block api:; tust du das nicht, startet das Gerät neu, sobald sich 15 Minuten lang niemand mit der Native API verbunden hat (das ist die Einstellung reboot_timeout). Im MQTT-Modus sendet ESPHome die Discovery-Nachrichten für Home Assistant und die online/offline-Meldungen in salon-sensor/status selbst, erledigt also automatisch alles, was wir im Arduino-Code von Hand gemacht haben.

MerkmalPubSubClient (Arduino-Code)ESPHome (YAML)
ProgrammierenDu schreibst alles selbst in C++Nur YAML; die Firmware wird automatisch kompiliert
Einbindung in Home AssistantDu sendest die Discovery-JSONs selbstWird automatisch gefunden
FlexibilitätUnbegrenzt; jede Bibliothek und jede Logik ist möglichAuf fertige Komponenten begrenzt, aber Hunderte Sensoren werden unterstützt; C++ per Lambda ergänzbar
Drahtlose UpdatesArduinoOTA musst du selbst einbauenIst dabei
Broker nötigJaMit der Native API nicht
LerneffektVermittelt das MQTT-Protokoll und ProgrammierenSchnelle Ergebnisse, verbirgt die Technik dahinter

MQTT mit ESP8266 und Raspberry Pi Pico W

Der vollständige Code oben läuft unverändert auf ESP8266 NodeMCU und Wemos D1 Mini: Wählst du unter Werkzeuge > Board den NodeMCU 1.0, nimmt der Block #if defined(ESP8266) automatisch ESP8266WiFi.h statt WiFi.h sowie die Pins D2 und D1. Beim Raspberry Pi Pico W nutzen wir das MicroPython-Modul umqtt.simple. Es ist in der MicroPython-Firmware des Pico W nicht enthalten; installiere es in Thonny über Extras > Pakete verwalten mit der Suche nach umqtt.simple oder tippe bei bestehender WLAN-Verbindung in der REPL import mip; mip.install("umqtt.simple"). Das dht-Modul für den DHT22 ist dagegen schon in der Firmware. Mit dem folgenden Code übernimmt ein Pico W in der Küche dieselbe Mess- und Relaisaufgabe. Damit er kurz bleibt, fehlen die Discovery-Nachrichten; damit der Pico W in Home Assistant erscheint, veröffentlichst du dieselben Discovery-JSONs wie im ESP32-Code mit den ev/mutfak-Topics oder legst die Entitäten in der configuration.yaml unter mqtt: von Hand an. Speicherst du die Datei als main.py, startet sie bei jedem Einschalten:

MicroPython
1import network, time, dht
2from machine import Pin
3from umqtt.simple import MQTTClient    # önce mip ile kur / install with mip first
4
5WIFI_SSID = "AgAdi"                    # Wi-Fi adın / your Wi-Fi name
6WIFI_PASS = "Sifre123"                 # Wi-Fi şifren / your Wi-Fi password
7MQTT_SUNUCU = "192.168.1.10"           # broker IP / broker IP
8ISTEMCI_ID = "pico-mutfak"             # benzersiz olmalı / must be unique
9
10T_SICAKLIK = b"ev/mutfak/sicaklik"
11T_NEM = b"ev/mutfak/nem"
12T_KOMUT = b"ev/mutfak/role/komut"
13T_DURUM = b"ev/mutfak/role/durum"
14T_BAGLANTI = b"ev/mutfak/baglanti"
15
16sensor = dht.DHT22(Pin(15))            # DHT22 DATA -> GP15
17role = Pin(14, Pin.OUT, value=1)       # aktif LOW röle kapalı başlar / active-LOW relay starts off
18led = Pin("LED", Pin.OUT)              # Pico W dahili LED / Pico W onboard LED
19
20wlan = network.WLAN(network.STA_IF)
21wlan.active(True)
22wlan.connect(WIFI_SSID, WIFI_PASS)
23while not wlan.isconnected():
24    time.sleep(0.5)
25print("IP:", wlan.ifconfig()[0])
26
27def mesaj_geldi(konu, mesaj):          # ikisi de bytes gelir / both arrive as bytes
28    if konu == T_KOMUT and mesaj in (b"ON", b"OFF"):
29        acik = mesaj == b"ON"
30        role.value(0 if acik else 1)
31        led.value(1 if acik else 0)
32        istemci.publish(T_DURUM, mesaj, retain=True)
33
34istemci = MQTTClient(ISTEMCI_ID, MQTT_SUNUCU, user="esp32", password="mqttSifre", keepalive=60)   # Mosquitto kullanıcısı / Mosquitto user
35istemci.set_callback(mesaj_geldi)
36istemci.set_last_will(T_BAGLANTI, b"offline", retain=True)   # son vasiyet / last will
37
38def baglan():
39    while True:
40        try:
41            if not wlan.isconnected():         # Wi-Fi koptuysa yeniden bağlan / reconnect Wi-Fi if it dropped
42                wlan.connect(WIFI_SSID, WIFI_PASS)
43                time.sleep(5)
44            istemci.connect()
45            istemci.publish(T_BAGLANTI, b"online", retain=True)
46            istemci.publish(T_DURUM, b"OFF" if role.value() else b"ON", retain=True)
47            istemci.subscribe(T_KOMUT)
48            print("MQTT baglandi")
49            return
50        except Exception as e:         # MQTTException(5): yetki yok / not authorized
51            print("MQTT hatasi:", e)
52            time.sleep(5)
53
54baglan()
55son = time.ticks_add(time.ticks_ms(), -30000)   # ilk ölçüm hemen / first reading right away
56while True:
57    try:
58        istemci.check_msg()            # bekleyen komut var mı? / any pending command?
59        if time.ticks_diff(time.ticks_ms(), son) >= 30000:
60            son = time.ticks_ms()
61            try:
62                sensor.measure()
63            except OSError:
64                print("DHT22 okunamadi")
65                istemci.ping()         # veri yoksa da bağlantıyı canlı tut / keep the link alive without data
66            else:
67                istemci.publish(T_SICAKLIK, "{:.1f}".format(sensor.temperature()).encode(), retain=True)
68                istemci.publish(T_NEM, "{:.0f}".format(sensor.humidity()).encode(), retain=True)
69    except OSError:
70        print("Baglanti koptu, yeniden baglaniliyor")
71        time.sleep(5)
72        baglan()
73    time.sleep_ms(100)

ESP32-MQTT-Projektideen

  • Temperaturkarte für jeden Raum: Stell in jeden Raum einen ESP32 mit DHT22 oder BME280 und verfolge das ganze Haus per Abo auf ev/+/sicaklik in einem Diagramm.
  • Smarte Lampe und Steckdose: Verknüpfe das Relais mit einer Home-Assistant-Automation, die bei Sonnenuntergang ein- und um Mitternacht ausschaltet.
  • Tür- und Fenstersensor: Sende mit einem Reedkontakt beim Öffnen der Tür eine MQTT-Nachricht und bekomme eine Handy-Benachrichtigung, wenn niemand zu Hause ist.
  • Flurlicht mit Bewegungsmelder: Ein PIR-Sensor meldet Bewegung, eine Home-Assistant-Automation schaltet das Licht.
  • Pflanzenbewässerung: Veröffentliche den Wert eines Bodenfeuchtesensors und starte die Pumpe per MQTT-Befehl, wenn die Erde trocken ist.
  • Energiemonitor: Miss mit einem ACS712-Stromsensor den Strom eines Geräts und stelle den Tagesverbrauch grafisch dar.
  • Batteriebetriebener Sensor: Baue einen Knoten, der misst, per MQTT sendet und wieder schlafen geht; Details unter ESP32 Deep Sleep.

Häufige ESP32-MQTT-Fehler und Lösungen

Symptom oder MeldungUrsacheLösung
Dauerhaft rc=-2Falsche Broker-IP oder falscher Port, Broker aus oder Mosquitto im Local-only-ModusIP prüfen, listener 1883 in die Konfiguration schreiben, Port 1883 in der Firewall freigeben
rc=5Benutzername oder Passwort falsch oder Verbindungsversuch ohne ZugangsdatenPasswort am PC mit mosquitto_sub testen; den Benutzer bei Bedarf neu anlegen
Verbindet sich, fällt nach wenigen Sekunden ab, EndlosschleifeZwei Geräte nutzen dieselbe Client-ID; Mosquitto schreibt "Client esp32-salon already connected, closing old connection." ins LogJedem Gerät eine eindeutige ISTEMCI_ID geben
Discovery-Nachrichten kommen nicht an, publish() liefert falseDer PubSubClient-Puffer hat standardmäßig 256 Byte, das JSON passt nicht hineinIn setup() mqtt.setBufferSize(1024) aufrufen
Häufig rc=-3Ein langes delay() in loop() verhindert Keep-alive-Pakete, oder das WLAN-Signal ist schwachTiming mit millis() lösen, Board näher an den Router bringen
Befehle kommen beim ESP32 nicht anTopic-Name weicht in Schreibweise oder Groß-/Kleinschreibung ab, oder subscribe() wird nach dem Neuverbinden nicht wiederholtTopic mit mosquitto_sub prüfen; subscribe() in die Verbindungsfunktion setzen
Relais schaltet beim Start von selbst einAuf dem Befehls-Topic liegt eine alte Retain-NachrichtMit mosquitto_pub -r -n -t ev/salon/role/komut löschen
Entitäten in Home Assistant "Nicht verfügbar"Im Availability-Topic steht offline, oder online ist anders geschriebenev/salon/baglanti mithören; sicherstellen, dass der Code nach dem Verbinden online sendet
Kryptische Zeichen statt eines WertsDie Payload endet nicht mit \0 und wurde ohne length gelesenPayload in einer Schleife bis length kopieren
ESPHome-Gerät startet alle 15 Minuten neuIm MQTT-Modus steht noch der Block api:, aber Home Assistant verbindet sich nieBlock api: löschen oder reboot_timeout: 0s setzen
Halte bei der Fehlersuche eine Reihenfolge ein: Prüfe zuerst im seriellen Monitor WLAN-Verbindung und IP-Adresse, beobachte dann am PC mit mosquitto_sub -v -t "#", was tatsächlich beim Broker ankommt, und schau erst danach in Home Assistant. Ist die Nachricht beim Broker zu sehen, aber nicht in Home Assistant, liegt der Fehler im Discovery-JSON; kommt sie gar nicht beim Broker an, liegt er beim ESP32. Hängst du schon beim WLAN fest, hilft ESP32 verbindet sich nicht mit dem WLAN; startet das Board beim Schalten des Relais neu, lies ESP32 Brownout und Guru Meditation.

Mit einem Broker, ein paar Topics und PubSubClient ist dein ESP32 zu einem Smart-Home-Gerät geworden, das dieselbe Sprache spricht wie der Rest des Hauses. Du kannst neue Sensoren, weitere Räume und andere Boards wie den Pico W hinzufügen und alles zentral in Home Assistant verwalten. In der BlueGrays-App findest du Projekte wie ESP32-WLAN-Verbindung, Temperatur- und Feuchtemessung mit dem DHT22, smarte Beleuchtung mit PIR und Relais, Echtzeitsteuerung per WebSocket und smarte Pflanzenbewässerung Schritt für Schritt mit Schaltplänen und Code.

Häufige Fragen

Was ist MQTT und wofür wird es verwendet?

MQTT ist ein schlankes Nachrichtenprotokoll, bei dem Geräte über einen Broker Nachrichten anhand von Topic-Namen senden und empfangen. Weil es wenig Bandbreite und Energie braucht, eignet es sich ideal für kleine Geräte wie den ESP32, um Sensordaten zu senden und Befehle zu empfangen. Home Assistant, Node-RED und die meisten industriellen IoT-Systeme sprechen MQTT.

Welchen Port nutzt MQTT?

Unverschlüsseltes MQTT nutzt standardmäßig Port 1883, TLS-verschlüsseltes MQTT Port 8883. Der WebSocket-Port für Verbindungen aus dem Browser hängt vom Broker ab; beim Mosquitto-Broker in Home Assistant ist es 1884. Im Heimnetz verbindet sich der ESP32 meist mit 1883.

Braucht MQTT eine Internetverbindung?

Nein. Läuft der Broker zu Hause auf einem Raspberry Pi oder in Home Assistant, bleibt der Verkehr zwischen ESP32 und Broker komplett im lokalen Netz; Sensoren und Relais funktionieren auch bei Internetausfall weiter. Internet brauchst du nur für den Zugriff von außen oder einen Cloud-Broker.

Warum erscheint mein ESP32 nicht in Home Assistant?

Die häufigsten Gründe sind eine Discovery-Nachricht, die nicht in den 256-Byte-Puffer von PubSubClient passt, ein falsch geschriebenes config-Topic oder ein Anführungszeichenfehler im JSON. Höre mit mosquitto_sub auf homeassistant/#, um zu prüfen, ob die Nachricht beim Broker ankommt, und stelle sicher, dass der Code die Zeile mqtt.setBufferSize(1024) enthält. Außerdem muss die MQTT-Integration von Home Assistant mit demselben Broker verbunden sein.

Soll ich ESPHome oder MQTT mit Arduino verwenden?

Willst du schnell ein funktionierendes Smart-Home-Gerät, macht ESPHome weniger Arbeit: Du schreibst YAML, das Gerät erscheint von selbst in Home Assistant und wird drahtlos aktualisiert. Willst du das MQTT-Protokoll lernen, eigene Logik schreiben oder mit anderen Systemen als Home Assistant arbeiten, ist Arduino mit PubSubClient flexibler. Beides lässt sich problemlos im selben Haus kombinieren.

Was ist der Unterschied zwischen MQTT QoS 0, 1 und 2?

QoS 0 sendet eine Nachricht einmal ohne Bestätigung, QoS 1 sendet erneut, bis sie bestätigt ist, wobei sie doppelt ankommen kann, und QoS 2 garantiert mit einem vierstufigen Handshake, dass sie genau einmal ankommt. Für Messwerte reicht QoS 0, für Befehle QoS 1. PubSubClient kann nur mit QoS 0 veröffentlichen und mit QoS 0 oder 1 abonnieren.

Alle Projekte ansehen
LED Blinken mit ESP32
#103Anfänger

LED Blinken mit ESP32

Lehrt die grundlegende Verwendung von GPIO-Ausgängen mit ESP32. Wir erreichen einen Blinkeffekt, indem wir eine LED über einen digitalen Pin ein- und ausschalten. ESP32-Version des klassischen Blink-Projekts auf Arduino UNO; die grundlegenden Blink-Befehle in der Arduino-Umgebung bleiben gleich, aber die Pinbelegung und die GPIO-Pegel von 3,3 V des ESP32 unterscheiden sich von denen des Arduino UNO.

4.7(37)
99
ESP32-WLAN-STA-Verbindung (mit LCD-Display)
#127Fortgeschritten

ESP32-WLAN-STA-Verbindung (mit LCD-Display)

In diesem Projekt verbinden wir den ESP32 im Station-Modus (STA) sicher und fehlertolerant mit dem heimischen WLAN. Wir lagern SSID und Passwort in eine separate secrets.h-Datei aus, um Leaks zu Git zu verhindern, richten einen Auto-Reconnect-Mechanismus ein und zeigen RSSI-Signalpegel und IP-Adresse auf einem I2C-LCD-Display an. Die interne LED dient als Statusanzeige. Ein Verbindungsmanager auf Produktionsniveau.

4.4(21)
34
ESP32 DHT22 Temperatur und Luftfeuchtigkeit (mit LCD-Display)
#117Mittel

ESP32 DHT22 Temperatur und Luftfeuchtigkeit (mit LCD-Display)

Bei diesem Projekt werden die Umgebungstemperatur und die Luftfeuchtigkeit mit einem DHT22-Sensor gemessen und in Echtzeit auf einem 16x2 I2C-LCD angezeigt. Mithilfe der Adafruit-DHT-Bibliothek werden die Daten über das One-Wire-Protokoll vom Sensor ausgelesen. Dieses Projekt bildet die Grundlage für IoT-Wetterstationen, Smart-Home-Automatisierung oder Umgebungsüberwachungssysteme in Gewächshäusern. Die Kommunikation mit dem DHT22 erfolgt über den GPIO-4-Pin des ESP32.

4.8(38)
56
ESP32 Intelligente Beleuchtung (PIR + LDR + Relais + OLED)
#141Fortgeschritten
Premium

ESP32 Intelligente Beleuchtung (PIR + LDR + Relais + OLED)

Verwandle deinen Flur, dein Badezimmer oder deine Speisekammer mit dem ESP32 in intelligente Beleuchtung! Mit einem PIR-Bewegungssensor, einem LDR-Lichtsensor und einem Relaismodul realisieren wir das klassische Szenario "Licht geht an, wenn im Dunkeln Bewegung erkannt wird" — bei Tageslicht bleibt das Licht trotz Bewegung aus, was tagsüber Energie spart. Das Licht bleibt 30 Sekunden lang an; bei anhaltender Bewegung wird der Timer zurückgesetzt und das Licht bleibt länger an. Das SSD1306 OLED-D

4.3(6)
11
ESP32-WebSocket-Zähler (2 Tasten + LCD + Web-Echtzeit)
#130Fortgeschritten
Premium

ESP32-WebSocket-Zähler (2 Tasten + LCD + Web-Echtzeit)

In diesem Projekt ändern zwei am ESP32 angeschlossene Taster (GPIO 5 zählt hoch, GPIO 4 zählt herunter) einen Zähler. Der Wert wird sofort auf einem 16x2-I2C-LCD und über die WebSocket-Unterstützung von ESPAsyncWebServer in allen verbundenen Browsern aktualisiert, ohne die Seite neu zu laden. Statt HTTP-Polling wird eine einzige dauerhafte Verbindung genutzt; der ESP32 sendet den neuen Wert mit ws.textAll() an alle.

4.5(14)
23
ESP32 mDNS: Zugriff auf das Gerät über „bluegrays-esp.local“ (mit LCD-Display)
#131Fortgeschritten
Premium

ESP32 mDNS: Zugriff auf das Gerät über „bluegrays-esp.local“ (mit LCD-Display)

In diesem Projekt fügen wir dem ESP32 einen mDNS-Dienst (Multicast DNS) hinzu, um den Zugriff nicht über eine IP-Adresse, sondern über einen lesbaren Hostnamen wie bluegrays-esp.local zu ermöglichen. Selbst wenn sich die vom DHCP zugewiesene IP-Adresse ändert, können Sie das Gerät immer unter demselben Namen erreichen. Indem wir zusätzlich einen kleinen Webserver darauf betreiben, senden wir über den Browser unter der Adresse http://bluegrays-esp.local/ Befehle zur LED-Steuerung. Auf dem I2C

4.8(14)
23
ESP32 Bewegungsalarmsystem (PIR + Buzzer + LED + Telegram)
#145Fortgeschritten
Premium

ESP32 Bewegungsalarmsystem (PIR + Buzzer + LED + Telegram)

Ein intelligentes Sicherheitsalarmsystem, das Buzzer und LED aktiviert, sobald der PIR-Sensor Bewegung erkennt, und gleichzeitig eine sofortige Benachrichtigung per Telegram an den Besitzer sendet. Ein 30-sekündiger Cooldown begrenzt die Häufigkeit wiederholter Alarme; dieser Mechanismus überprüft weder die Gültigkeit der PIR-Erkennungen noch verhindert er Fehlauslösungen. Geeignet für Heimsicherheit, Garagenüberwachung, Lagerräume oder Arbeitszimmer. Mit ESP32-CAM sind Foto-Benachrichtigungen m

0.0(0)
9