Welche Geräte sind gerade verbunden? Das ist die erste Frage, die jeder Betreiber stellt, ob in der Leitwarte eines Werks oder im Service eines Maschinenbauers, und beim MQTT Online-Status von Geräten lässt sich erstaunlich viel falsch machen. Das zuverlässige Muster kombiniert drei Bausteine: eine retained Birth Message, ein retained Last Will und eine explizite Offline-Meldung beim Herunterfahren. In diesem Leitfaden bauen Sie dieses Muster Schritt für Schritt auf, ergänzen einen Flotten-Monitor in Python und lernen, wie Sie die Sonderfälle vermeiden, durch die Dashboards falsche Zustände anzeigen.
Die Bausteine
Jeder Baustein löst einen Teil des Problems:
| Baustein | Wer veröffentlicht | Wann | Deckt ab |
|---|---|---|---|
Birth Message (online, retained) |
Gerät | Direkt nach jedem erfolgreichen Verbindungsaufbau | Gerät ist aktiv, auch nach Reconnects |
Last Will (offline, retained) |
Broker, im Namen des Geräts | Verbindungsverlust ohne DISCONNECT | Abstürze, Stromausfall, Netzwerkfehler |
Shutdown-Meldung (offline, retained) |
Gerät | Vor einem sauberen Disconnect | Geplante Neustarts und Abschaltungen |
| Retain-Flag bei allen dreien | Alle | Immer | Später geöffnete Dashboards sehen trotzdem den aktuellen Zustand |
Lassen Sie einen davon weg, entsteht ein blinder Fleck. Ohne Birth Message bleibt ein wiederhergestelltes Gerät „offline“. Ohne Will bleiben Abstürze unbemerkt. Ohne Shutdown-Meldung bleibt ein geplant abgeschaltetes Gerät für immer „online“, denn ein sauberes DISCONNECT weist den Broker an, den Will zu verwerfen. Falls der Will-Mechanismus neu für Sie ist, lesen Sie zuerst MQTT Last Will and Testament.
Das Status-Topic entwerfen
Geben Sie jedem Gerät genau ein Status-Topic an einer vorhersehbaren Stelle:
connectmq/demo/<prefix>/<site>/<device-id>/status
Eine Wildcard wie connectmq/demo/<prefix>/+/+/status liefert dann den Status der gesamten Flotte mit einem einzigen Abonnement. Da alle Statusmeldungen retained sind, erhält ein startender Monitor sofort den letzten bekannten Zustand jedes Geräts. Wie das Speichern funktioniert, erklärt der Artikel zu MQTT Retained Messages.
In einer Fabrik mit Unified Namespace (UNS) gehört das Status-Topic direkt unter den ISA-95-Pfad der Maschine, also unter Enterprise, Site, Area, Line und Cell, etwa acme/werk-stuttgart/montage/linie-1/zelle-3/status. Mit acme/werk-stuttgart/+/+/+/status sieht die Leitwarte eines Werks dann alle Maschinen dieses Standorts, mit acme/+/montage/# die Montagebereiche aller Werke. Sparkplug B setzt dasselbe Prinzip mit eigenen Birth- und Death-Nachrichten um; mehr dazu in Sparkplug B und Unified Namespace.
Als Payload genügt für viele Tools ein einfacher String online oder offline. JSON liefert zusätzlichen Kontext, der im Betrieb hilft:
{"state":"online","ts":1760600000,"fw":"2.4.1","ip":"10.0.4.17","reason":"boot"}
Beim Will kann das Gerät den Zeitstempel eines künftigen Ausfalls nicht kennen, halten Sie ihn also einfach: {"state":"offline","reason":"lwt"}. Der Monitor protokolliert, wann er ihn empfangen hat.
Schritt 1: Das Gerät
Dieses paho-mqtt-2.x-Skript verhält sich wie ein gut konzipiertes Gerät. Es setzt vor dem Verbinden einen retained Will, veröffentlicht in on_connect eine retained Birth Message, damit sie sich nach jedem Reconnect wiederholt, und sendet beim geordneten Herunterfahren eine retained Offline-Meldung. Es verbindet sich mit dem öffentlichen MQTT-Broker unter broker.connectmq.com, der für Tests und Prototypen gedacht ist:
import json
import signal
import sys
import time
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
DEVICE_ID = sys.argv[1] if len(sys.argv) > 1 else "pump-07"
STATUS = f"connectmq/demo/z8b2/plant1/{DEVICE_ID}/status"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"z8b2-{DEVICE_ID}")
client.will_set(STATUS, json.dumps({"state": "offline", "reason": "lwt"}),
qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=30)
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print("connect failed:", reason_code)
return
birth = {"state": "online", "ts": int(time.time()), "reason": "connect"}
client.publish(STATUS, json.dumps(birth), qos=1, retain=True)
print("online")
def shutdown(signum, frame):
bye = {"state": "offline", "ts": int(time.time()), "reason": "shutdown"}
client.publish(STATUS, json.dumps(bye), qos=1, retain=True).wait_for_publish(timeout=5)
client.disconnect()
client.loop_stop()
sys.exit(0)
client.on_connect = on_connect
signal.signal(signal.SIGINT, shutdown)
signal.signal(signal.SIGTERM, shutdown)
client.connect(BROKER, 1883, keepalive=20)
client.loop_start()
while True:
time.sleep(1) # hier würde echte Telemetrie veröffentlicht
Starten Sie es mit python device.py pump-07 und in einem zweiten Terminal mit python device.py fan-02.
Schritt 2: Der Flotten-Monitor
Der Monitor abonniert alle Status-Topics und führt eine Gerätetabelle. Da die Statusmeldungen retained sind, kennt er den vollständigen Flottenzustand wenige Sekunden nach dem Start:
import json
import time
import uuid
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
FILTER = "connectmq/demo/z8b2/+/+/status"
fleet = {}
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(FILTER, qos=1)
def on_message(client, userdata, msg):
device = msg.topic.split("/")[-2]
if not msg.payload: # leerer retained Payload = Gerät entfernt
fleet.pop(device, None)
return
try:
state = json.loads(msg.payload).get("state", "unknown")
except ValueError:
state = msg.payload.decode(errors="replace")
previous = fleet.get(device, {}).get("state")
fleet[device] = {"state": state, "since": time.strftime("%H:%M:%S")}
tag = "retained" if msg.retain else "live"
if previous != state:
print(f"[{tag}] {device}: {previous} -> {state}")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"monitor-{uuid.uuid4().hex[:8]}")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=30)
client.loop_forever()
Schritt 3: Jeden Fehlerfall testen
Starten Sie den Monitor und beide Geräte, arbeiten Sie dann diese Checkliste ab und prüfen Sie jedes Mal, ob der Monitor korrekt reagiert:
- Monitor-Neustart. Stoppen und starten Sie den Monitor. Beide Geräte erscheinen sofort als
online, markiert mitretained. - Geordnetes Herunterfahren. Drücken Sie Strg+C bei
fan-02. Der Monitor zeigt sofortofflinemit dem Grundshutdown. - Absturz. Beenden Sie
pump-07mitkill -9. Das Betriebssystem schließt den Socket, der Broker veröffentlicht den Will und der Monitor zeigtoffline. - Stiller Netzwerkverlust. Trennen Sie das Netzwerk des Geräts, ohne den Prozess zu beenden. Nach etwa dem 1,5-Fachen des Keepalive von 20 Sekunden greift der Will.
- Wiederherstellung. Stellen Sie das Netzwerk wieder her. paho verbindet sich neu,
on_connectläuft, und die Birth Message setzt das Gerät wieder aufonline. - Außerbetriebnahme. Veröffentlichen Sie eine leere retained Message auf dem Status-Topic. Der Monitor entfernt das Gerät.
Dieselben Topics können Sie auch live im Browser beobachten: Der browserbasierte Client und der Topic-Explorer im ConnectMQ-Portal zeigen Statuswechsel in Echtzeit, sobald Ihre Geräte mit Ihrem eigenen Broker verbunden sind.
Sonderfälle, durch die Dashboards falsche Zustände zeigen
Doppelte Client IDs. Zwei Geräte mit derselben ID werfen sich gegenseitig hinaus. Jede Übernahme kann einen Will und eine Birth Message auslösen, sodass der Status ständig flattert. Eindeutige IDs sind Pflicht; siehe den Leitfaden zur MQTT Client ID.
Birth Message nur einmal beim Booten. Wenn Sie online außerhalb des Connect-Callbacks veröffentlichen, bleibt ein Gerät, das sich nach einem kurzen Netzwerkaussetzer neu verbindet, für immer offline. Veröffentlichen Sie sie bei jedem Verbindungsaufbau.
Will nicht retained. Ein Dashboard, das nach dem Ausfall geöffnet wird, erfährt nie davon.
Flackern durch schnelle Reconnects. Ein Gerät, das sich innerhalb von Sekunden neu verbindet, erzeugt trotzdem ein Offline/Online-Paar. In MQTT 5 unterdrückt ein Will Delay Interval den Will, wenn die Session rechtzeitig wieder aufgenommen wird.
Langer Keepalive. Bei einem Keepalive von 300 Sekunden wirkt ein ausgefallenes Gerät über sieben Minuten lang online. Wählen Sie einen Keepalive, der dazu passt, wie schnell Sie Bescheid wissen müssen.
„Verbunden“ heißt nicht „gesund“. Ein Gerät kann seine MQTT-Verbindung halten, während sein Sensor ausgefallen ist. Veröffentlichen Sie ein separates Health- oder Heartbeat-Feld, wenn Sie Lebendigkeit auf Anwendungsebene brauchen.
Präsenz oder Heartbeat: Was brauchen Sie?
Verbindungsbasierte Präsenz und Anwendungs-Heartbeats beantworten unterschiedliche Fragen, und viele Flotten benötigen beides.
| Signal | Beantwortet | Erkennungszeit | Aufwand |
|---|---|---|---|
| Birth + LWT auf dem Status-Topic | Ist das Gerät mit dem Broker verbunden? | Sofort bis 1,5 x Keepalive | Nahezu keiner; nur Keepalive-Pings |
| Periodische Heartbeat-Nachricht | Läuft die Anwendungsschleife noch? | Ein bis zwei Heartbeat-Intervalle | Ein kleines Publish pro Intervall |
| Prüfung der Telemetrie-Aktualität | Liefert der Sensor noch Daten? | Abhängig von der erwarteten Publish-Rate | Keiner auf dem Gerät; Logik im Consumer |
Ein Gerät, dessen Hauptschleife hängt, kann weiterhin Keepalive-Pings beantworten, wenn der MQTT-Client in einem eigenen Thread läuft; der Verbindungsstatus bleibt dann online. Ein aus der Hauptschleife veröffentlichter Heartbeat oder ein Consumer, der Geräte mit veralteter Telemetrie markiert, erkennt diesen Fall. Senden Sie Heartbeats nicht retained und in maßvoller Frequenz; einmal pro Minute reicht für die meisten Überwachungszwecke.
Status-Topics in anderen Tools nutzen
Da das Muster nur aus retained MQTT-Nachrichten besteht, kann jedes MQTT-fähige Tool es ohne spezielle Integration verarbeiten. In Node-RED speist ein mqtt in-Node, der die Status-Wildcard abonniert, ein Dashboard oder einen Benachrichtigungs-Flow. Die MQTT-Integration von Home Assistant kann ein Status-Topic mit den Payloads online und offline einer Availability-Einstellung zuordnen. Der MQTT-Consumer-Input von Telegraf kann Zustandswechsel für Verfügbarkeitsberichte in eine Zeitreihendatenbank schreiben. Jedes dieser Tools verbindet sich als gewöhnlicher MQTT-Client mit dem Broker; Voraussetzung ist nur, dass Sie sich auf Topic-Namen und Payload-Werte einigen. Einfache Strings online und offline sind am portabelsten, wenn Sie Standard-Tools einsetzen wollen; JSON liefert reicheren Kontext für Ihren eigenen Code.
Broker-seitiger Status bei ConnectMQ
Das obige Muster funktioniert mit jedem Broker. Zusätzlich veröffentlicht ConnectMQ den Verbindungsstatus unter $SYS/broker/connection/{clientId}/state. Ein Monitor kann dies als unabhängige Quelle abonnieren, die nicht davon abhängt, dass die Geräte-Firmware ihren Will korrekt konfiguriert. Die Geräteansicht im Portal ordnet Ihre Geräte nach ISA-95-Ebenen und passt damit zu einem UNS-Topic-Baum, und Alarmregeln mit Schwellenwerten können Sie benachrichtigen, wenn Werte Grenzen überschreiten. Nutzen Sie in der Produktion TLS auf Port 8883 mit YOUR_USERNAME, YOUR_PASSWORD und YOUR_CLIENT_ID aus dem Portal. Ein verwalteter MQTT-Broker hält die Präsenz-Infrastruktur für Sie am Laufen; die Grundlagen dahinter finden Sie im MQTT-Tutorial.
Starten Sie mit ConnectMQ
Erstellen Sie unter app.connectmq.com einen kostenlosen Broker im Serverless-Plan, ganz ohne Kreditkarte. Setzen Sie die Geräte- und Monitor-Skripte mit Ihren Zugangsdaten ein, und Sie haben in wenigen Minuten eine zuverlässige Präsenzerkennung für Ihre Flotte auf einem Cloud-MQTT-Broker.
Häufig gestellte Fragen
Warum wird mein Gerät nach dem Herunterfahren noch als online angezeigt?
Ein sauberes DISCONNECT verwirft den Last Will. Veröffentlichen Sie vor dem Trennen selbst eine retained Offline-Meldung.
Warum bleibt mein Gerät nach dem Reconnect offline?
Vermutlich wird die Birth Message nur einmal beim Start veröffentlicht. Senden Sie sie im On-Connect-Callback, damit jeder Reconnect den Status aktualisiert.
Wie schnell wird ein Offline-Gerät erkannt?
Sofort, wenn die TCP-Verbindung geschlossen wird. Verschwindet das Gerät still, nach etwa dem 1,5-Fachen des Keepalive-Intervalls.
Sollten Statusmeldungen retained sein?
Ja. Wenn Birth-, Will- und Shutdown-Meldungen retained sind, erhält jeder später abonnierende Client sofort den aktuellen Zustand.



