Warum ich MQTT nutze

Ich möchte Geräte und Dienste verschiedener Hersteller verbinden können. MQTT ist ein offener Standard, und mit Eclipse Mosquitto gibt es einen quelloffenen Broker. Ein Gerät veröffentlicht einen Wert auf einem Topic, zum Beispiel haus/test/temperatur. openHAB kann dieses Topic abonnieren. Andere Anwendungen können denselben Wert unabhängig davon empfangen. Für einen Verlauf speichert eine Anwendung wie openHAB die Messwerte zusätzlich ab.

  1. GerätSendet einen Messwert auf einem Topic
  2. MosquittoVerteilt die Nachricht
  3. openHABAbonniert das Topic und aktualisiert das Item
Das Gerät sendet an den Broker. openHAB empfängt die Nachricht über sein Abonnement.

Einen laufenden Broker prüfen

Auf meinem Pi 4 mit openHABian läuft Eclipse Mosquitto 2.0.21. Bevor du eine bestehende Anlage umstellst, prüfe den Dienst, die Listener und die verbundenen Clients. Ein Listener auf 0.0.0.0 oder [::] lauscht auf allen Adressen der jeweiligen IP-Version. Die Erreichbarkeit hängt zusätzlich von deinem Netzwerk und der Firewall ab.

In meinem Heimnetz verbinden sich zwei Shelly H&T Gen3, ein Shelly Plus Plug S und HeishaMon für die Wärmepumpe mit dem Broker. openHAB läuft auf demselben Pi und verbindet sich als weiterer Client. Gerade die batteriebetriebenen H&T siehst du eher im Verbindungsprotokoll als in einer Momentaufnahme.

systemctl is-active mosquitto
dpkg-query -W mosquitto
sudo ss -lntp "( sport = :1883 or sport = :8883 )"
sudo ss -Hnt state established "( sport = :1883 or sport = :8883 )"

Wenn allow_anonymous auf true steht, akzeptiert der Broker Verbindungen ohne Benutzerkonto. Erfasse zuerst auch Geräte, die nur gelegentlich online sind. Richte danach MQTT-Konten ein, trage sie in den Clients ein und teste die Verbindungen. Erst dann solltest du den anonymen Zugriff abschalten.

Mosquitto auf einem neuen System installieren

Bei mir läuft bereits ein MQTT-Broker auf dem Pi 4 mit openHABian. Prüfe auf einer bestehenden Anlage zuerst Dienst, Listener und Clients. Die folgenden Befehle zeigen eine Neueinrichtung mit den Debian-Paketen.

sudo apt update
sudo apt install mosquitto mosquitto-clients

Lege ein eigenes MQTT-Konto an. Der Befehl fragt das Kennwort ab. Die Option -c erstellt eine Passwortdatei und würde eine vorhandene Datei überschreiben. Der Test davor verhindert das. Für weitere Konten in derselben Datei verwendest du mosquitto_passwd ohne -c.

sudo test ! -e /etc/mosquitto/praxis.passwd &&
  sudo mosquitto_passwd -c /etc/mosquitto/praxis.passwd mqtt-praxis &&
  sudo chown root:mosquitto /etc/mosquitto/praxis.passwd &&
  sudo chmod 0640 /etc/mosquitto/praxis.passwd

Speichere die folgenden Zeilen in /etc/mosquitto/conf.d/praxis.conf. Die erste Zeile bindet den Broker an 127.0.0.1. Das passt, wenn du auf dem Pi testest und openHAB auf demselben Gerät läuft.

sudoedit /etc/mosquitto/conf.d/praxis.conf
listener 1883 127.0.0.1
allow_anonymous false
password_file /etc/mosquitto/praxis.passwd
sudo systemctl restart mosquitto && systemctl is-active mosquitto
sudo journalctl -u mosquitto -n 15 --no-pager

Für Geräte im Heimnetz ergänze in derselben Datei einen Listener mit der festen LAN-IP deines Pi. Ersetze die Beispiel-IP durch deine eigene, starte Mosquitto neu und hinterlege diese IP, Port 1883 und das MQTT-Konto auf dem Gerät. Verwende dafür dein vertrauenswürdiges Heimnetz. Auf Port 1883 sind Nachrichten und Anmeldedaten ohne TLS unverschlüsselt. Lass den Port am Router geschlossen und nutze für Zugriffe über fremde Netze TLS oder eine verschlüsselte private Verbindung.

listener 1883 192.168.1.50

Eine Nachricht veröffentlichen und empfangen

Führe den Block im Bash-Terminal auf dem Pi aus und gib das soeben gesetzte MQTT-Kennwort ein. Er verwendet das reservierte Beispiel-Topic haus/test/praxis/temperatur. Der Broker merkt sich den Testwert kurz (Retain), damit der danach gestartete Empfänger ihn lesen kann. Erwartete Ausgabe ist haus/test/praxis/temperatur 21.5. Anschließend räumt der Block den gespeicherten Wert und die temporären Zugangsdaten auf.

(
  set -e
  umask 077
  config=$(mktemp -d)
  trap 'rm -f -- "$config/mosquitto_pub" "$config/mosquitto_sub"; rmdir -- "$config"' EXIT
  IFS= read -rs -p "MQTT password: " password
  printf '\n'
  printf '%s\n' '-h 127.0.0.1' '-p 1883' '-u mqtt-praxis' "-P $password" > "$config/mosquitto_pub"
  unset password
  cp -- "$config/mosquitto_pub" "$config/mosquitto_sub"
  export XDG_CONFIG_HOME="$config"
  topic=haus/test/praxis/temperatur
  mosquitto_pub -t "$topic" -q 1 -r -m 21.5
  status=0
  mosquitto_sub -t "$topic" -C 1 -W 5 -v || status=$?
  mosquitto_pub -t "$topic" -q 1 -r -n
  exit "$status"
)

openHAB mit dem Broker verbinden

  1. Installiere in openHAB das MQTT Binding. Lege unter Einstellungen → Things ein MQTT Broker Thing an.
  2. Trage als Broker-Adresse 127.0.0.1 ein, wenn beide Dienste auf demselben Pi laufen, dazu Port 1883 und das MQTT-Konto. Das Broker Thing sollte anschließend ONLINE sein.
  3. Lege für ein Gerät ein Generic MQTT Thing an und wähle das Broker Thing. Verknüpfe einen Kanal mit dem State Topic des Geräts und den Kanal mit einem Item. Für einen reinen Messwert genügt das State Topic. Ein Command Topic brauchst du erst für Geräte, denen openHAB Befehle senden soll.
  4. Für den Test legst du einen Kanal vom Typ Number an, trägst haus/test/praxis/temperatur als State Topic ein und verknüpfst ein Number-Item. Führe den Sende- und Empfangstest erneut aus. Du solltest die Aktualisierung auf 21.5 in openHAB sehen.

Der Broker ist online, aber der Wert fehlt

Prüfe zuerst den Topic-Namen. MQTT unterscheidet Groß- und Kleinschreibung. Bei Geräten, die nur zeitweise senden, warte bis zur nächsten Meldung. Kommt eine Nachricht an und der Number-Kanal erhält ein ganzes JSON-Objekt, kann das Item leer bleiben oder seinen bisherigen Wert behalten.

Einen Zahlenwert mit JSONPath auslesen

  1. MQTT-Nachricht{"temperature": 21.5}
  2. Transformation im KanalJSONPATH($.temperature)
  3. Number-Item21.5
Aus dem JSON-Beispiel wird der Zahlenwert 21.5.

Installiere bei Bedarf das Add-on JSONPath Transformation. Öffne den MQTT-Kanal, blende die erweiterten Einstellungen ein und trage JSONPATH($.temperature) unter Incoming Value Transformations ein. $.temperature zeigt auf das Feld temperature direkt im JSON-Objekt. Passe den Pfad an die tatsächliche Nachricht deines Geräts an.

Quellen