Mit Home Assistant MQTT Discovery beschreibt sich ein Gerät selbst, sodass Home Assistant seine Entitäten automatisch anlegt, ganz ohne YAML auf der Home-Assistant-Seite. In diesem Tutorial lernen Sie das Format der Discovery-Topics kennen, schreiben Config-Payloads für Sensoren und einen Schalter, fassen sie zu einem Gerät zusammen, behandeln Verfügbarkeit und Neustarts von Home Assistant und entfernen Entitäten sauber, alles mit einem Python-Gerätesimulator, der mit einem ConnectMQ-Broker verbunden ist.
So funktioniert MQTT Discovery
Beim Start abonniert die MQTT-Integration Topics unterhalb eines Discovery-Präfixes, standardmäßig homeassistant. Ein Gerät veröffentlicht pro Entität eine retained JSON-Nachricht auf einem Config-Topic:
<discovery_prefix>/<component>/[<node_id>/]<object_id>/config
homeassistant/sensor/hvac-node-1/temperature/config
homeassistant/switch/hvac-node-1/relay/config
componentist die Entitätsplattform:sensor,binary_sensor,switch,light,button,number,select,climateund weitere.node_idist optional und gruppiert lediglich Topics; es legt kein Gerät an.object_ididentifiziert die Entität innerhalb des Knotens.
Der Config-Payload teilt Home Assistant mit, wo der Zustand gelesen wird, wohin Befehle gehen, wie Werte geparst werden und zu welchem Gerät die Entität gehört. Da die Nachricht retained ist, spielt der Broker sie bei jeder erneuten Verbindung von Home Assistant wieder ab, sodass die Entitäten nach einem Neustart wieder erscheinen.
Discovery liefert nur Metadaten. Die eigentlichen Daten fließen weiterhin über Ihre eigenen Zustands- und Befehls-Topics, die Sie wie bei jeder Home Assistant MQTT-Integration selbst entwerfen.
Voraussetzungen
- Home Assistant mit konfigurierter MQTT-Integration und aktivierter Discovery (standardmäßig eingeschaltet).
- Ein privater ConnectMQ-Broker: Legen Sie ihn im Portal an und notieren Sie den generierten Benutzernamen, das Passwort und die Client-ID. Home Assistant und der Simulator benötigen jeweils eigene Zugangsdaten.
- Python 3.10+ mit
pip install "paho-mqtt>=2.0".
Sie können auch mit dem öffentlichen MQTT-Broker experimentieren, der für Tests und Prototypen gedacht ist, doch zwei Punkte machen ihn für Discovery unpraktisch. Erstens sind retained Config-Topics unter dem gemeinsam genutzten Präfix homeassistant für jede dort verbundene Home-Assistant-Instanz sichtbar; legen Sie deshalb in den Optionen der Integration ein eigenes Discovery-Präfix fest (zum Beispiel cmqx7d2). Zweitens erlaubt der öffentliche MQTT-Broker 10 Subscriptions pro Client, Home Assistant benötigt aber mehrere für Discovery plus eine pro Entität. Ein privater Broker vermeidet beide Probleme.
Ein Discovery-Payload, Feld für Feld
Hier ist die Konfiguration für einen Temperatursensor:
{
"name": "Supply Air Temperature",
"unique_id": "hvacnode1_supply_temp",
"object_id": "hvac_node_1_supply_temp",
"state_topic": "home/hvac-node-1/state",
"value_template": "{{ value_json.supply_c }}",
"unit_of_measurement": "°C",
"device_class": "temperature",
"state_class": "measurement",
"availability_topic": "home/hvac-node-1/availability",
"device": {
"identifiers": ["hvacnode1"],
"name": "HVAC Node 1",
"manufacturer": "DIY",
"model": "ESP32 duct sensor",
"sw_version": "1.3.0"
}
}
| Feld | Warum es wichtig ist |
|---|---|
unique_id |
Erforderlich für die Entitätsregistrierung: Umbenennen, Bereiche, Deaktivieren. Muss für immer stabil bleiben. |
device.identifiers |
Fasst alle Entitäten mit demselben Identifier zu einer Gerätekarte zusammen. |
state_topic + value_template |
Mehrere Entitäten können unterschiedliche Felder einer JSON-Zustandsnachricht lesen. |
availability_topic |
Entitäten werden nicht verfügbar, wenn das Gerät offline veröffentlicht (typischerweise per Last Will). |
device_class, state_class |
Korrekte Icons, Einheiten und Langzeitstatistiken. |
object_id |
Beeinflusst die generierte Entitäts-ID. |
Lange Payloads können die dokumentierten Abkürzungen verwenden, zum Beispiel stat_t für state_topic, uniq_id für unique_id und dev für device. Sie sind auf Mikrocontrollern mit kleinen Puffern nützlich; auf einem PC lassen sich die vollen Namen leichter lesen.
Ein vollständiges Python-Gerät mit Discovery
Der folgende Simulator verhält sich wie ein echtes Gerät: Er meldet drei Entitäten an, veröffentlicht alle zehn Sekunden einen JSON-Zustand, befolgt Schaltbefehle, setzt einen Last Will für die Verfügbarkeit und veröffentlicht seine Konfiguration erneut, sobald Home Assistant wieder online ist.
import json
import random
import time
import paho.mqtt.client as mqtt
BROKER, PORT = "broker.connectmq.com", 8883
USERNAME, PASSWORD = "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = "YOUR_CLIENT_ID"
DISCOVERY_PREFIX = "homeassistant"
NODE = "hvac-node-1"
BASE = f"home/{NODE}"
STATE_T = f"{BASE}/state"
AVAIL_T = f"{BASE}/availability"
RELAY_CMD_T = f"{BASE}/relay/set"
RELAY_STATE_T = f"{BASE}/relay/state"
DEVICE = {
"identifiers": ["hvacnode1"],
"name": "HVAC Node 1",
"manufacturer": "DIY",
"model": "ESP32 duct sensor",
"sw_version": "1.3.0",
}
ENTITIES = [
("sensor", "supply_temp", {
"name": "Supply Air Temperature",
"state_topic": STATE_T,
"value_template": "{{ value_json.supply_c }}",
"unit_of_measurement": "°C",
"device_class": "temperature",
"state_class": "measurement",
}),
("sensor", "filter_dp", {
"name": "Filter Pressure Drop",
"state_topic": STATE_T,
"value_template": "{{ value_json.filter_dp_pa }}",
"unit_of_measurement": "Pa",
"device_class": "pressure",
"state_class": "measurement",
}),
("switch", "relay", {
"name": "Fan Relay",
"command_topic": RELAY_CMD_T,
"state_topic": RELAY_STATE_T,
"payload_on": "ON",
"payload_off": "OFF",
}),
]
relay_on = False
def publish_discovery(client):
for component, object_id, cfg in ENTITIES:
payload = {
**cfg,
"unique_id": f"hvacnode1_{object_id}",
"availability_topic": AVAIL_T,
"device": DEVICE,
}
topic = f"{DISCOVERY_PREFIX}/{component}/{NODE}/{object_id}/config"
client.publish(topic, json.dumps(payload), qos=1, retain=True)
client.publish(AVAIL_T, "online", qos=1, retain=True)
client.publish(RELAY_STATE_T, "ON" if relay_on else "OFF", qos=1, retain=True)
def on_connect(client, userdata, flags, reason_code, properties):
print("connected:", reason_code)
client.subscribe(RELAY_CMD_T, qos=1)
client.subscribe("homeassistant/status", qos=1) # Birth Message von Home Assistant
publish_discovery(client)
def on_message(client, userdata, msg):
global relay_on
if msg.topic == "homeassistant/status" and msg.payload == b"online":
time.sleep(random.uniform(0.5, 2.0)) # Last nach HA-Neustarts verteilen
publish_discovery(client)
elif msg.topic == RELAY_CMD_T:
relay_on = msg.payload == b"ON"
client.publish(RELAY_STATE_T, "ON" if relay_on else "OFF", qos=1, retain=True)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.username_pw_set(USERNAME, PASSWORD)
client.tls_set()
client.will_set(AVAIL_T, "offline", qos=1, retain=True)
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=30)
client.loop_start()
while True:
state = {"supply_c": round(random.uniform(12.5, 14.5), 1),
"filter_dp_pa": random.randint(150, 190)}
client.publish(STATE_T, json.dumps(state), qos=0)
time.sleep(10)
Starten Sie das Skript und öffnen Sie Einstellungen > Geräte & Dienste > MQTT. Ein Gerät namens HVAC Node 1 erscheint mit zwei Sensoren und einem Schalter. Beenden Sie das Skript mit Strg+C: Innerhalb des Keep-Alive-Fensters veröffentlicht der Broker den Last Will, und die Entitäten werden als nicht verfügbar angezeigt.
Die Behandlung der Birth Message ist wichtig. Home Assistant veröffentlicht beim Start online auf homeassistant/status. Retained Configs machen ein erneutes Veröffentlichen meist überflüssig, doch ein Gerät, das bei der Birth Message neu veröffentlicht, erholt sich auch dann, wenn retained Nachrichten gelöscht wurden.
Gerätebasierte Discovery
Neuere Home-Assistant-Versionen akzeptieren außerdem eine einzige Config-Nachricht pro Gerät auf <prefix>/device/<object_id>/config, die alle Entitäten unter einem Schlüssel components (abgekürzt cmps) auflistet, jeweils mit einer platform (p). Zusätzlich ist ein origin-Block (o) nötig, der die veröffentlichende Software benennt:
{
"dev": {"ids": ["hvacnode1"], "name": "HVAC Node 1", "mf": "DIY", "mdl": "ESP32 duct sensor"},
"o": {"name": "hvac-node-firmware", "sw": "1.3.0"},
"avty_t": "home/hvac-node-1/availability",
"stat_t": "home/hvac-node-1/state",
"cmps": {
"supply_temp": {"p": "sensor", "dev_cla": "temperature", "unit_of_meas": "°C",
"val_tpl": "{{ value_json.supply_c }}", "uniq_id": "hvacnode1_supply_temp"},
"filter_dp": {"p": "sensor", "dev_cla": "pressure", "unit_of_meas": "Pa",
"val_tpl": "{{ value_json.filter_dp_pa }}", "uniq_id": "hvacnode1_filter_dp"}
}
}
Eine retained Nachricht statt vieler ist für Geräte mit Dutzenden Entitäten attraktiv. Verwenden Sie pro Gerät nur einen Stil; melden Sie dieselben Unique IDs nicht über beide Wege an.
Entitäten entfernen und ändern
Um eine Entität zu löschen, veröffentlichen Sie einen leeren retained Payload auf ihrem Config-Topic:
mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID -r -n \
-t "homeassistant/sensor/hvac-node-1/filter_dp/config"
-n sendet eine Nachricht der Länge null und -r macht sie retained, wodurch auch die gespeicherte Config auf dem Broker gelöscht wird. Um eine Entität zu ändern, veröffentlichen Sie die neue Config auf demselben Topic mit derselben unique_id. Eine geänderte unique_id erzeugt eine neue Entität und lässt die alte verwaist zurück.
Checkliste zur Fehlersuche
- Nichts erscheint. Prüfen Sie, ob das Discovery-Präfix in den Optionen der Integration mit dem Ihres Geräts übereinstimmt und ob Discovery aktiviert ist.
- Entitäten erscheinen, sind aber nicht verfügbar. Auf dem Availability-Topic liegt keine retained
online-Nachricht, oder der Payload lautet nicht exaktonline. - „Unique ID already exists“ im Log. Zwei Configs teilen sich eine
unique_id. Machen Sie sie global eindeutig, idealerweise abgeleitet von einer MAC-Adresse. - Doppelte Geräte nach einem Firmware-Update. Der Wert von
device.identifiershat sich geändert. Halten Sie ihn stabil. - Geisterentitäten. Alte retained Configs liegen noch auf dem Broker. Finden Sie sie mit dem ConnectMQ-Topic-Explorer unter dem Discovery-Präfix und löschen Sie sie mit leeren retained Nachrichten.
- Config wird stillschweigend abgelehnt. Validieren Sie Ihr JSON; ein überzähliges Komma in einem handgeschriebenen Payload ist der übliche Übeltäter, und Home Assistant protokolliert den Fehler unter der MQTT-Integration.
Discovery von einem ESP32
Auf einem Mikrocontroller ist die Logik identisch: Jeden Config-Payload aufbauen, ihn nach jeder erfolgreichen Verbindung retained veröffentlichen und das Birth-Topic abonnieren. Drei Details unterscheiden sich von Python. Erstens ist der Standard-Paketpuffer von PubSubClient klein; rufen Sie daher vor dem Verbinden mqtt.setBufferSize(1024) oder mehr auf, sonst werden lange Discovery-Payloads stillschweigend verworfen. Zweitens leiten Sie unique_id und device.identifiers von der MAC-Adresse des Chips ab, damit jede Platine ohne manuelle Konfiguration stabile, eindeutige Werte erhält. Drittens veröffentlichen Sie die Verfügbarkeit über den Last Will in connect(), damit Home Assistant von einem Stromausfall erfährt, ohne dass das Gerät etwas tun muss.
Abgekürzte Schlüssel helfen auf kleinen Geräten, und das Erzeugen der Payloads mit ArduinoJson vermeidet Fehler beim Quoting in handgeschriebenen Strings. Testen Sie die Payloads Ihrer Firmware, indem Sie mit einem beliebigen MQTT-Client homeassistant/# abonnieren und prüfen, ob jede Config gültiges JSON ist, bevor Sie die Entitäten in Home Assistant suchen.
Wo Discovery ins Bild passt
Firmware wie Tasmota, ESPHome im MQTT-Modus und Zigbee2MQTT veröffentlicht bereits Discovery-Payloads, weshalb deren Geräte sofort erscheinen. Für Ihre eigene Firmware lässt sich das Python-Beispiel oben direkt mit PubSubClient oder AsyncMqttClient nach C++ übertragen; erhöhen Sie nur die Puffergröße des Clients, denn Config-Payloads überschreiten den Standardwert leicht. Wenn sich Geräte außerhalb Ihres Heimnetzes befinden, bringen Sie sie alle auf einem Cloud-MQTT-Broker zusammen, wie unter Home Assistant mit einem externen MQTT-Broker nutzen beschrieben. Der Leitfaden zu ESPHome MQTT und unser Leitfaden zur IoT-Automatisierung zeigen weitere Geräte, die auf Discovery setzen.
Discovery-fähige Geräte mit ConnectMQ bauen
Erstellen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker, ganz ohne Kreditkarte, und vergeben Sie Zugangsdaten für Home Assistant und jedes Gerät. Mit einem verwalteten MQTT-Broker von ConnectMQ liegen retained Discovery-Configs auf einem Broker, den Sie nie patchen müssen, und der Live-Topic-Explorer zeigt genau, was jedes Gerät ankündigt.
Häufig gestellte Fragen
Müssen Discovery-Nachrichten retained sein?
Sie sollten es sein. Retained Configs ermöglichen es Home Assistant, Entitäten nach einem Neustart wiederherzustellen, ohne dass das Gerät neu veröffentlicht; das erneute Veröffentlichen bei der Birth Message ist eine nützliche Absicherung.
Was ist der Unterschied zwischen node_id und dem Gerät?
node_id ist nur eine Topic-Ebene zur Organisation. Die Gerätekarte entsteht aus dem device-Block, und Entitäten mit denselben identifiers werden gruppiert.
Wie entferne ich eine per Discovery angelegte Entität?
Veröffentlichen Sie eine retained Nachricht der Länge null auf ihrem Config-Topic. Home Assistant löscht die Entität, und der Broker vergisst die retained Config.
Kann ich das Discovery-Präfix ändern?
Ja, in den Optionen der MQTT-Integration. Jedes Gerät muss seine Configs dann unter dem neuen Präfix veröffentlichen.



