MQTT2 DEVICE - Schritt für Schritt
An dieser Seite wird momentan noch gearbeitet. |
Einführung
Das Protokoll MQTT ermöglicht einen flexiblen Datenaustausch zwischen unterschiedlichsten Geräten und FHEM und insbesondere auch bidirektionale Kommunikation von und zu FHEM. Es gibt dabei jedoch nur einen geringen Grad der Standardisierung des Datenaustauschs. In der Praxis sind daher relative viele unterschiedliche Wege aufzufinden, wie die Kommunikation via MQTT in den externen Geräten und Diensten konkret umgesetzt wurde - jeder Autor einer firmware oder Software ist in dieser Beziehung relativ frei, und nicht jeder beherzigt dabei den Grundsatz, dass die Kommunikation via MQTT "leichtgewichtig" sein sollte.
Das Modul MQTT2_DEVICE bietet eine Vielzahl von Möglichkeiten, auf die verschiedensten Anforderungen einzugehen, und die ein- und ausgehenden Daten zu einem oder mehreren FHEM-Gerät/en zusammenzufassen. Eine Übersicht häufig vorkommender MQTT-Geräte ist in MQTT2-Module - Praxisbeispiele zu finden.
Ziel dieses Artikels ist die Darstellung der Schritte, die sich als zweckmäßig erwiesen haben zur Einrichtung von "guten" FHEM-Geräten.
Dabei soll am Ende erreicht werden:
- standardisierte set- (und ggf. get-)-Kommandos, insbesondere unter Beachtung der Developer Guidelines für Readings
- Schließen des Informationskreises von eventuellen Kommandos bis zur Rückmeldung des (externen) Gerätes oder Dienstes (im Folgenden: "Gegenstelle")
- standardisierte Reading-Namen, damit möglichst Auswertungen nicht speziell an das jeweilige Gerät angepasst werden müssen
- Reduzierung und Vermeidung von unnötigen Datenpunkten und Events.
Vorbereitung
MQTT2_SERVER
Selbst, wenn grundsätzlich ein externer MQTT-Server IO-Device zum Einsatz kommt, ist sehr zu empfehlen, für die Beschäftigung mit einem neuen, unbekannten Device zunächst einen MQTT2_SERVER einzurichten. Ist der Port 1883 bereits durch einen anderen Server belegt, nimmt man einfach einen anderen Port, z.B. 1884: define m2server MQTT2_SERVER 1884 global
. Vor allem, wenn die Gegenstelle tiefer strukturierte Daten im JSON-Format über verschiedene Topics als Payload übermittelt, empfiehlt es sich, in der Einrichtungsphase auch das Attribut "autocreate" am MQTT2_SERVER auf "complex" zu stellen: attr m2server autocreate complex
. Weiter muss die allgemeine |autocreate-Instanz aktiv sein.
Begrifflichkeiten
Ein typisches, von "autocreate" erstelltes Gerät sieht dann z.b. (mit autocreate = simple) so aus:
defmod MQTT2_DVES_9B01BD MQTT2_DEVICE DVES_9B01BD
attr MQTT2_DVES_9B01BD readingList DVES_9B01BD:tele/DVES_9B01BD/STATE:.* { json2nameValue($EVENT) }\
DVES_9B01BD:tele/DVES_9B01BD/LWT:.* LWT\
DVES_9B01BD:tele/DVES_9B01BD/UPTIME:.* { json2nameValue($EVENT) }\
DVES_9B01BD:tele/DVES_9B01BD/SENSOR:.* { json2nameValue($EVENT) }\
DVES_9B01BD:tele/DVES_9B01BD/INFO1:.* { json2nameValue($EVENT) }\
DVES_9B01BD:tele/DVES_9B01BD/INFO2:.* { json2nameValue($EVENT) }\
DVES_9B01BD:tele/DVES_9B01BD/INFO3:.* { json2nameValue($EVENT) }\
DVES_9B01BD:stat/DVES_9B01BD/RESULT:.* { json2nameValue($EVENT) }\
DVES_9B01BD:stat/DVES_9B01BD/STATE:.* { json2nameValue($EVENT) }
attr MQTT2_DVES_9B01BD room MQTT2_DEVICE
Wir unterscheiden bei jeder Zeile des readingList-Attributs vier Elemente, die ersten drei werden jeweils durch einen Doppelpunkt voneinander getrennt:
CID
Dies ist die Gerätekennung (hier: DVES_9B01BD). Diese ist auch Bestandteil des define, über diese wird ermittelt, zu welchem FHEM-Gerät via MQTT eingehende Informationen zugeordnet werden sollen. Diese Angabe ist weder im define noch in der readingList zwingend, aber in der Definition für den Hauptkanal eines Gerätes empfohlen.
Topic
Datenpunkt, an den eine Information gesendet wird. Empfangsseitig sind dies hier z.B. tele/DVES_9B01BD/STATE oder tele/DVES_9B01BD/LWT
Payload
Der jeweilige Nachrichteninhalt. Da dieser nicht im Vorhinein bekannt ist, wird er in der readingList typischerweise als "beliebige Zeichenfolge" (".*") notiert.
Auswertung
Dies kann entweder direkt der Reading-Name sein, dem die Payload zugeordnet werden soll, oder ein Perl-Ausdruck. Hier wird z.B. die eingehende Information für tele/DVES_9B01BD/LWT dem Reading LWT zugeordnet, während die Informationen aus tele/DVES_9B01BD/STATE an die Funktion json2nameValue() übergeben werden. $EVENT entspricht dabei der Payload.
defaults
Für unbekannte Gegenstellen ist zunächst immer zu empfehlen, deren "Grundeinstellungen" zu verwenden, und Anpassungen erst und nur insoweit vorzunehmen, als es für ein besseres Zusammenspiel mit FHEM sinnvoll ist. Abzuraten ist insbesondere von:
- Änderungen der Topics und Topic-Sturkturen (ausgenommen den Fall, dass schon andere Gegenstellen im Einsatz sind, die identische Topics verwenden)
- Vergabe von friendly names
Bestandsaufnahme
Projektseiten finden
Viele Geräte, die das MQTT-Protokoll verwenden, haben eigene Projektseiten oder API-Beschreibungen, denen man entnehmen kann, wie mit dieser Gegenstelle Daten ausgetauscht werden können. Diese sollte man bei allen weiteren Schritten stets zur Hand haben. Dabei kann es neben der allgemeinen Beschreibung auch ein oder mehrere Detail-Seiten geben, auf denen nähere Informationen zu den spezifischen Geräte zu finden sein können.
readingList
Zunächst empfiehlt es sich, einfach die Gegenstelle neu zu starten und (ggf. über ein FileLog) auzuzuzeichnen, was über welchen Topic wie oft an Informationen gesendet wird. Dabei kann und sollte durchaus - sofern dies möglich ist - der eine oder andere Schaltvorgang (z.B. über das Web-Interface der Gegenstelle) durchgeführt werden, sofern dies möglich ist (oder allgemeiner: möglichst viele bekannte Anweisungen ausführen lassen). Am Ende sollte man eine möglichst vollständige Auflistung in der readingList erhalten haben. Falls strukturierte Daten im JSON-Format als Payload verwendet werden, kann man diese auch zusätzlich ohne die Verarbeitung durch json2nameValue() aufzeichnen, z.B. indem man die betreffende Zeile in der readingList doppelt:
defmod MQTT2_DVES_9B01BD MQTT2_DEVICE DVES_9B01BD
attr MQTT2_DVES_9B01BD readingList tele/DVES_9B01BD/STATE:.* { json2nameValue($EVENT) }\
tele/DVES_9B01BD/STATE:.* json_STATE\
tele/DVES_9B01BD/LWT:.* LWT\
[...]
So kann man mit Hilfe des betreffenden Logs ggf. auch über ein externes Tool wie mosquitto_pub MQTT-Nachrichten an FHEM generieren, ohne darauf warten zu müssen, dass diese von der Gegenstelle selbst erzeugt werden.
ignoreRegexp
Manche Gegenstellen senden beim Start Konfigurationsinformationen, die allerdings nicht durch FHEM ausgewertet werden können. Die betreffenden Topics sollte man (allgemein) so in die ignoreRegexp beim MQTT2_SERVER bzw. MQTT2_CLIENT aufnehmen, dass derartige Informationen künftig gar nicht mehr an MQTT2_DEVICE weitergereicht werden. Danach kann man die betreffenden Zeilen aus der readingList löschen! Entsprechendes gilt für die hierüber generierten Readings.
Weiter ist zu empfehlen, in diese ignoreRegexp auch die Topics aufzunehmen, über die Gegenstellen typischerweise Kommandos entgegennehmen. Dies könnte z.B. so aussehen:
attr m2server ignoreRegexp shellies/[^/]+/command|cmnd/[^/]+/|homeassistant/.*/config|tasmota/discovery
readingList optimieren
gute Reading-Namen - Klartext
Viele Gegenstellen senden z.B. einen online/offline-Status als "last will and testament" unter einem Topic, der mit "LWT" endet. Dieses hier sendet zwar passende Daten, aber an einen anderen Topic. In solchen Fällen man kann den von autocreate erzeugten Eintrag einfach anpassen:
attr DEVICE readingList /dingtian/DEVNAME/out/lwt_availability:.* LWT
Bedingte Hash-Rückgaben
Manchmal erfolgt zwar die Übergabe eines Klartextes als $EVENT - allerdings nicht in der Form, wie man das in FHEM gerne hätte. Hier als "0" oder "1". Mit etwas Perl und der Rückgabe eines Hashes kann man so etwas beliebig umformen:
attr DEVICE readingList DEVNAME/relay/0:.* { $EVENT ? {state=>'on'} : {state=>'off'} }\ DEVNAME/status:.* { $EVENT ? {LWT=>'Online'} : {LWT=>'Offline'} }
json2nameValue()
Mit Hilfe der Funktion json2nameValue() (in Verbindung mit dem attribut jsonMap) lassen sich "gute Reading-Namen" auch aus JSON-Payloads erzeugen
Auswertung unterbinden
Indem man einen Perl-Aufruf festlegt (geschweifte Klammern), aber dann nichts zurückgibt, kann man bestimmte unerwünschte Readings ausfiltern
shellies/DEVNAME/temperature_f:.* {}
Events optimieren
Leider senden relativ viele Gegenstellen in ihren Standardeinstellungen sehr viele Daten, auch ohne dass sich etwas geändert hätte. Dies erzeugt uU. in FHEM eine erhebliche Last, so dass es dringend zu empfehlen ist, alle Maßnahmen zu prüfen, durch die dieses Verhalten unterbunden oder vermindert werden kann.
firmware-Einstellungen
Bei manchen firmwares kann man einstellen, ob bzw. wie oft oder aus welchem Anlass Daten gesendet werden sollen.
Auswertung unterbinden
(s.o. für Topics/Readings, die gar nicht benötigt werden). Dies ist insbesondere auch zu empfehlen, wenn identische Daten zum gleichen Zeitpunkt sowohl als Klartext wie auch in einem JSON-Format übermittelt werden. In solchen Fällen ist es eher zu empfehlen, die JSON-Zweige zu abonnieren und den Rest (ggf. über einen ignoreRegexp-Eintrag) gar nicht auszuwerten. Doppelungen sollten in jedem Fall vermieden werden!