MQTT GENERIC BRIDGE: Unterschied zwischen den Versionen
F Klee (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
K (Text-Highlighting (kursiv) geändert auf "vermutete Absicht") |
||
Zeile 125: | Zeile 125: | ||
mosquitto_pub -h 127.0.0.1 -i fhem-test -t mqttGenericBridge/set/myRelay -m on | mosquitto_pub -h 127.0.0.1 -i fhem-test -t mqttGenericBridge/set/myRelay -m on | ||
Bei ''mosquitto_sub'' auf der Linux-Konsole sollte jetzt zunächst die Schaltanweisung (Topic mit ''set | Bei ''mosquitto_sub'' auf der Linux-Konsole sollte jetzt zunächst die Schaltanweisung (Topic mit ''set-Element'') wie auch die Readingänderung am Device vermeldet werden. | ||
====Geräte mit mehreren Settern==== | ====Geräte mit mehreren Settern==== |
Version vom 16. August 2021, 16:33 Uhr
MQTT_GENERIC_BRIDGE | |
---|---|
Zweck / Funktion | |
Stellt für beliebige Geräte eine Schnittstellt zum MQTT-Protokoll zur Verfügung | |
Allgemein | |
Typ | Gerätemodul |
Details | |
Dokumentation | EN / DE |
Support (Forum) | MQTT |
Modulname | 10_MQTT_GENERIC_BRIDGE.pm |
Ersteller | hexenmeister (Forum ) |
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref! |
An dieser Seite wird momentan noch gearbeitet. |
Einführung
Das Modul MQTT_GENERIC_BRIDGE stellt eine zentrale Schnittstelle zum MQTT-Protokoll für beliebig viele andere FHEM-Geräte bereit. Es wird für eine FHEM-Installation jeweils nur ein erreichbarer MQTT-Server sowie eine Instanz der MQTT_GENERIC_BRIDGE benötigt (es ist aber möglich, mehrere Parallen .
Dieses Modul kann seit November 2018 mit allen drei IO-Modul-Varianten zusammen eingesetzt werden, also sowohl mit MQTT2_SERVER bzw. MQTT2_CLIENT oder MQTT(00_MQTT.pm), und seit Rev. 23514 (Jan. 2021) wird für MQTT_GENERIC_BRIDGE iVm. den MQTT2-IO-Modulen keine zusätzliche Software mehr benötigt.
Dabei erfolgt an dem zentralen MQTT_GENERIC_BRIDGE-Gerät selbst nur eine Basiskonfiguration, die Standardwerte für alle anzubindenden Geräte bereitstellt, alle übrigen Einstellungen erfolgen durch Attribute an dem jeweiligs anzubindenden Gerät selbst.
Beispiel: ein Aktor des Typs CUL_HM kann über MQTT-Kommandos an den für ihn passenden Topic an- oder ausgeschaltet werden oder auch einfach nur seinen aktuellen Schaltzustand per MQTT-Protokoll publizieren.
Installation
Vorbereitung
Im folgenden wird als MQTT-Server mosquitto verwendet, der in aktuellen Linux-Distributionen über die Paketverwaltung angeboten wird. Hier die Installation für Raspberry Pi OS:
sudo apt-get update sudo apt-get upgrade sudo apt-get install mosquitto
Es kann aber auch ein bereits vorhandener MQTT2_SERVER verwendet werden.
Grundsätzliche Konfiguration
Definition der Schnittstelle zum MQTT-Server (hier: auf demselben Raspberry):
defmod mqtt_io MQTT2_CLIENT 127.0.0.1:1883 attr mqtt_io alias MQTT Broker attr mqtt_io devStateIcon .*active:none:disconnect .*disconnected:none:connect attr mqtt_io group MQTT attr mqtt_io icon mqtt attr mqtt_io room IO_Devices
Wer möchte, kann den Status des FHEM-Servers per MQTT LWT mitteilen:
Für MQTT2_CLIENT:
attr mqtt_io lwt system/<fhem-name>/connection/status connection lost attr mqtt_io lwtRetain 1 attr mqtt_io msgAfterConnect -r system/<fhem-name>/connection/status connected attr mqtt_io msgBeforeDisconnect -r system/<fhem-name>/connection/status disconnected
Alternativ: für MQTT
attr mqtt last-will retain:1 system/<fhem-name>/connection/status connection lost attr mqtt on-connect retain:1 {Log3("mqtt",3,"connected to MQTT server");;1} system/<fhem-name>/connection/status connected attr mqtt on-disconnect retain:1 {Log3("mqtt",3,"disconnected from MQTT server");;1} system/<fhem-name>/connection/status disconnected
Definition der Generic Bridge
Der Name mqttGenericBridge kann dabei frei gewählt werden:
defmod mqttGenericBridge MQTT_GENERIC_BRIDGE attr mqttGenericBridge IODev mqtt_io attr mqttGenericBridge alias MQTT generic bridge attr mqttGenericBridge group MQTT attr mqttGenericBridge room IO_Devices attr mqttGenericBridge stateFormat dev: device-count in: incoming-count out: outgoing-count
Damit sind die wesentlichen Vorarbeiten abgeschlossen, und die MQTT_GENERIC_BRIDGE kann bereits dafür genutzt werden, beliebige Reading- oder Attribut-Änderungen von FHEM-Devices über MQTT zu publishen oder entsprechende Anweisungen umzusetzen. Es wird jedoch empfohlen, zunächst noch einige grundlegende Einstellungen vorzunehmen. Hierfür - sowie dann auch für die Konfiguration der weiteren Devices, die an MQTT angebunden werden sollen, steht als Hilfsmittel attrTemplate zur Verfügung.
Basisangaben in der MQTT_GENERIC_BRIDGE selbst
Zunächst werden die Basisangaben zur Struktur der zu verwendenden MQTT-Topics sowie - bei Verwendung eines MQTT2-Interface-Moduls - die clientOrder konfiguriert:
set mqttGenericBridge attrTemplate base_settings_to_MQTT_GENERIC_BRIDGE
Dies kann direkt über die Detailansicht des Geräts mqttGenericBridge erfolgen, siehe der nebenstehende screenshot, aus dem auch zu entnehmen ist, was das attrTemplate an Änderungen der Konfiguration vornehmen wird. Dies sind zwei Aspekte: Zum einen wird eine Variable namens $base in Sende- und in Empfangsrichtung festgelegt. In Senderichtung (pub:) besteht diese nur aus dem Namen der MQTT_GENERIC_BRIDGE, in Empfangsrichtung (sub:) aus dem Namen sowie dem Topic-Anteil set. Diese Angaben können im Prinzip beliebig geändert werden, es muss lediglich darauf geachtet werden, dass die Angaben unterschiedlich sind, sonst kann es zu unbeabsichtigten Schleifen kommen!
Zum anderen wird - sofern ein MQTT2_CLIENT und MQTT2_SERVER als Interface verwendet wird - je nach Wahl des Nutzers in dem dann erscheinenden Dialogfeld - die clientOrder festgelegt. Wer hier unschlüssig ist, sollte die empfohlene Variante wählen, um Probleme im Zusammenspiel mit der autocreate-Funktion dieser Interface-Typen möglichst zu vermeiden.
Basics zur Konfiguration der anzubindenden Geräte
Um gezielt einzelne Werte zu senden und auch nur gewünschte Anweisungen zu erhalten, ist stattdessen eine auf das jeweilige Gerät angepasste Konfiguration der Schnittstelle zu empfehlen. Um die hier dargestellten Schritte und deren Wirksamkeit zu prüfen, sollte der Verkehr von und zum MQTT-Server beobachtet werden. Im Folgenden werden hierfür die Programme mosquitto_sub und mosquitto_pub aus dem Paket mosquitto-clients verwendet. Auf einem Raspberry Pi OS können diese mit sudo apt-get install mosquitto-clients
installiert werden. Beide Programme funktionieren auch mit einem MQTT2_SERVER.
Den Verkehr auf der Linux-Konsole kann man mit
mosquitto_sub -h 127.0.0.1 -i fhem-test -v -t mqttGenericBridge/# -t system/#
verfolgen, gegebenenfalls sind Username und Passwort zu ergänzen, falls die Einstellungen am Server dies erfordern (siehe manpage zu mosquitto_sub).
Readingwerte publishen
mqttPublish
Um Reading-Werte von einem Gerät zu versenden, wird das Attribut mqttPublish verwendet. Im einfachsten Fall wird festgelegt, welche Readings versendet werden sollen, und unter welchem Topic. Für einen beliebigen Temperatursensor könnte dies z.B. so aussehen:
attr mySensor mqttPublish temperature:topic={"$base/$device/$name"}
In der Linux.Konsole, in der mosquitto_sub läuft, sollte jetzt bei jeder Aktualisierung des Sensor-Werts anzeigen, dass eine entsprechende Message an den MQTT-Server gesendet wurde. Dies geschieht Event-basiert, so dass sich hier ggf. auch insbesondere Einstellungen im Attribut event-on-change-reading auf die Häufigkeit der Aktualisierung auswirken.
Es können auch mehrere Readings erfasst werden, für einen typischen kombinierten Temperatur- und Luftfeuchtigkeitssensor könnte dies z.B. so aussehen:
attr mySensor mqttPublish temperature|humidity:topic={"$base/$device/$name"}
oder auch so:
attr mySensor mqttPublish temperature|humidity|battery:topic={"$base/$device/$name"}
Falls (!) erforderlich oder gewünscht, kann auch ein * als wildcard verwendet werden. Dann werden alle Readings gepublisht:
attr mySensor mqttPublish *:topic={"$base/$device/$name"}
mqttAlias
Verfolgt man den Verkehr eine Zeitlang, wird die Bedeutung der Variablen klarer: $base entspricht der Angabe aus den globalDefaults an der MQTT_GENERIC_BRIDGE, $device wird durch den Namen des Geräts in FHEM erstetzt, und $name entspricht (noch) dem Namen des Readings. Bis hierhin könnte man also auch statt einer MQTTT_GENERIC_BRIDGE problemlos ein notify verwenden, um die Events für direkte publish-Anweisungen am jeweiligen Interface-Modul (z.B. MQTT2_CLIENT) auszuwerten.
Eine MQTT_GENERIC_BRIDGE bietet jedoch auch für das Publishen erweiterte Funktionalitäten an. Die erste: Z.B. kann der Parameter $name - etwa zur Standardisierung der Namensstruktur der Readings - mit Hilfe des Attributs mqttAlias verändert werden. Durch die folgende Einstellung würde z.B. ein battery-Wert unter dem Topic-Teil batteryPercent versendet und das Reading measured-temp unter temperature:
attr mySensor mqttAlias battery=batteryPercent measured-temp=temperature
state
Da das Reading state in FHEM in der Regel eine Art Hauptzustand eines Geräts beschreibt, wird für die weiter unten dargestellten attrTemplate dieses Reading kein $name-Anteil im Topic versendet. Ein einfaches "ein-aus"-Gerät kann man dieser Vorgabe folgend daher so konfigurieren:
attr myRelay mqttPublish state:topic={"$base/$device"}
Für ein dimmbares Licht (das als Reading pct kennt) kombiniert man beides:
attr myDimmer mqttPublish state:topic={"$base/$device"} pct:topic={"$base/$device/$name"}
Und zu guter letzt noch als farbiges (mit Reading rgb) und dimmbares Licht:
attr myRGBLight mqttPublish state:topic={"$base/$device"} pct|rgb:topic={"$base/$device/$name"}
Geräte steuern
Um Geräte über die MQTT-Schnittstelle bedienen zu können, wird zum einen eine Software benötigt, mit der man entsprechende publish-Anweisungen generieren kann. Dies kann z.B. das bereits genannte mosquitto_pub sein.
mqttSubscribe
Spiegelbildlich zum o.g. mqttPublish-Attribut wird über das jeweilige mqttSubscribe-Attribut festgelegt, welche Topics für das FHEM-Gerät ausgewertet werden sollen und welchen Readings diese zugeordnet sind. Für ein einfaches "ein-aus"-Gerät verwendet man daher denselben Attributwert wie für das mqttPublish:
attr myRelay mqttSubscribe state:stopic={"$base/$device"}
Da wir oben in globalDefaults für sub:$base=mqttGenericBridge/set festgelegt haben, muss die Schaltanweisung allerdings an einen anderen Topic erfolgen als die Statusmeldung, die wir wegen des mqttPublish-Attributs erhalten - auf diese Weise können unbeabsichtigte Schleifen unterbunden werden.
Um jetzt mit mosquitto_pub eine passende Anweisung zu erzeugen, benötigen wir eine weitere (ssh-Linux-) Konsole, über die wir dann auf dem MQTT-Weg schalten können - vorausgesetzt, das Gerät myRelay kann den Befehl set myRelay on
(bzw. off) verarbeiten. Auch hier wären ggf. die Zugangsdaten entsprechend der manpage zu ergänzen:
mosquitto_pub -h 127.0.0.1 -i fhem-test -t mqttGenericBridge/set/myRelay -m on
Bei mosquitto_sub auf der Linux-Konsole sollte jetzt zunächst die Schaltanweisung (Topic mit set-Element) wie auch die Readingänderung am Device vermeldet werden.
Geräte mit mehreren Settern
Das Prinzip dürfte jetzt klarer sein, also versuchen wir es direkt mit unserer farbigen Leuchte:
attr myRGBLight mqttSubscribe state:stopic={"$base/$device"} pct|rgb:stopic={"$base/$device/$name"}
Und schon sollte diese über msoquitto_pub bzw. MQTT schalt- und dimmbar sein und Farbänderungen entegennehmen - und natürlich den zugehörigen Status zurückmelden.
mqttAlias
Auch bei den Supscriptions besteht die Möglichkeit, mqttAlias zu verwenden und die Namen über diesen Weg zu verändern. Dies kann insbesondere sinnvoll sein, um in externen Anwendungen dann (dort) dieselben Vorlagen nutzen zu können.
topic, stopic und atopic
In obigem Beispiel haben wir in mqttSubscribe das Schlüsselwort stopic (die Kurzform von set-topic) verwendet. Dieses bewirkt bei einer entsprechenden MQTT-Nachricht dasselbe wie der FHEM-Befehl set <device> <reading> <value>
, also set myRGBLight pct 70
. Daneben gibt es die weiteren Schlüsselwörter topic und atopic.
- topic (Langform: readings-topic) entspicht einer setreading-Anweisung. Dabei wird dann lediglich der Readingwert aktualisiert, allerdings (falls Hardware gesteuert werden könnte) aber kein Schaltbefehl an die Hardware gesendet. In Installationen ohne MQTT2-Interface kann dies dazu genutzt werden, dummy-Geräte ähnlich flexibel zu verwenden wie MQTT2_DEVICE.
- atopic (Langform: attr-topic) schließlich dient dazu, Attributwerte zu ändern. atopic kann auch in mqttPublish eingesetzt werden, um Änderungen der Attribut-Werte an den MQTT-Server zu übermitteln.
Weitere Optionen
MQTT_GENERIC_BRIDGE bietet weitere Attribute, die im Zusammenspiel teils sehr umfassende weitere Möglichkeiten ergeben, Geräte an MQTT anzubinden. Einige der Möglichkeiten, insbesondere, über expression beliebigen Perl-Code zur Auswertung bzw. Strukturierung der Daten zu verwenden, sind in den Grundzügen weiter unten dargestellt.
Standardisierung via attrTemplate
Insbesondere zur Anbindung externer Lösungen ist es jedoch häufig ausreichend, die Geräte-Daten in einer etwas strukturierten Weise aufzubereiten. Dies ist das Ziel der für MQTT_GENERIC_BRIDGE entwickelten attrTemplate.
(tbc)
Konfigurationsmöglichkeiten für Fortgeschrittene
expression
attr ZWave_THERMOSTAT_20 mqttGB1Alias reportedState=actuator attr ZWave_THERMOSTAT_20 mqttGB1Publish desired-temp|temperature|reportedState:topic={"$base/$device/$name"} temperature:expression={$value=~m,(-?\d+(\.\d+)?),?::round($1,1):undef} reportedState:expression={$value=~m,dim.(\d+),?$1:undef} attr ZWave_THERMOSTAT_20 mqttGB1Subscribe desired-temp:stopic={"$base/$device/$name"}
JSON
json2nameValue() und toJSON() via expression
publishes an mehrere Topics
"das Ausrufezeichen"
(Noch nachzubearbeiten, aus dem Thread Anwendungsfälle und Beispiele für MQTT_GENERIC_BRIDGE - https://forum.fhem.de/index.php/topic,91642.msg841367.html#msg841367)
eine Reading an einem beliebigen Device per MQTT setzen (für State-Reading soll state verwendet werden) Code: [Auswählen]
attr <device-name> mqttSubscribe <reading-name>:topic=<topic>
(anstatt 'topic' kann für eine bessere Lesbarkeit 'readings-topic' verwendet werden)
ein Set-Befehl an einem beliebigen Device mit dem per MQTT gesendeten Wert ausführen (für set ohne namen (set on, set off) soll state verwendet werden) Code: [Auswählen]
attr <device-name> mqttSubscribe <set-befehl>:stopic=<topic>
(anstatt 'stopic' kann für eine bessere Lesbarkeit 'set-topic' verwendet werden)
ein Attribut an einem beliebigen Device per MQTT setzen Code: [Auswählen]
attr <device-name> mqttSubscribe <attribut-name>:atopic=<topic>
(anstatt 'atopic' kann für eine bessere Lesbarkeit 'attr-topic' verwendet werden)
eine Änderung eines Readings per MQTT senen Code: [Auswählen]
attr <device-name> mqttPublish <readings-name>:topic=<topic>
eine Änderung eines Attributes per MQTT senen
attr <device-name> mqttPublish <attribut-name>:atopic=<topic>
Verwendung von Variablen
Es können mit dem Attribute mqttDefaults Variablen definiert werden, die in mqttPublish und mqttSubscribe verwendet werden können:
Code: [Auswählen]
attr <device-name> mqttDefaults base={"allgemeinerPfad/"} ... attr <device-name> mqttPublish <reading-name>:topic={"$base/irgendEinName"}
Weiterhin können in Topics folgende vordefinierte Variablen verwendet werden: $reading - aktuell zu verarbeitende Reading $device - aktulles Gerät $name - Die Variable $name wird im Unterschied zu $reading ggf. ueber die in 'mqttAlias' definierten Aliases beeinflusst. (s. Commandref für mqttAlias) Code: [Auswählen]
attr <device-name> mqttPublish <reading-name>:topic={"$base/$device/$name"}
Mehrere Readings auf einmal
Es können für einen Topic (sinnigerweise mit Variablen) auch mehrere Readings gleichzeitig angegeben werden. Diese müssen in diesem Fall durch ein | getrennt werden:
Code: [Auswählen]
attr <device-name> mqttPublish <reading-name1>|<reading-name2>:topic={"$base/$device/$name"}
Wildcards
mit einem * kann ein Topic für alle Readings zusammen definiert werden:
Code: [Auswählen]
attr <device-name> mqttPublish *:topic={"$base/$device/$name"}
Beim Subscribe können in der Topic-Definition auch MQTT-Wildcards (+ und #) verwendet werden.
Falls der Reading-Name mit einem '*'-Zeichen am Anfang definiert wird, gilt dieser als 'Platzhalter'. Der tatsaechliche Name der Reading (und ggf. des Geraetes) wird dabei durch Variablen aus dem Topic definiert ($reading, $name). Im Topic wirken diese Variablen als Wildcards, macht natuerlich nur Sinn, wenn Reading-Name auch nicht fest definiert ist (also faengt mit '*' an).
Sensoren-Werte von einer FHEM-Instanz in eine andere übertragen
Definition für ein HomeMatic-Device (Dirk's-Sensor + Verwendung von DevPoint-Modul): (es werden gezielt bestimmte Werte übertragen) Code: [Auswählen]
defmod <sensor-device-name> CUL_HM xxxxxx attr <sensor-device-name> model HB-UW-Sen-THPL-I ... attr <sensor-device-name> mqttDefaults base=haus/wohnzimmer attr <sensor-device-name> mqttPublish humidity|luminosity|dewpoint|absoluteHumidity:topic={"$base/klima/$name"}
Definition eines Empfänger-Dummy:
(es werden alle Werte bei passenden Topics empfangen)
Code: [Auswählen]
defmod <dummy-device-name> dummy attr <dummy-device-name> readingList absoluteHumidity dewpoint humidity luminosity temperature vapourPressure attr <dummy-device-name> mqttDefaults base=haus/wohnzimmer attr <dummy-device-name> mqttSubscribe *:topic={"$base/klima/$reading"}
« Letzte Änderung: 11 Januar 2019, 21:31:38 von hexenmeister »
Aktoren, die in einer FHEM-Instanz definiert sind, aus einer anderen schalten Switch
Definition eines Schalters (EnOcean FSR14) Code: [Auswählen]
defmod <actor-device-name> EnOcean 0000000B attr <actor-device-name> IODev FGW14 attr <actor-device-name> alias Licht attr <actor-device-name> devStateIcon off:light_light_dim_00@gray on:light_light_dim_100@yellow .*:hourglass attr <actor-device-name> eep A5-38-08 attr <actor-device-name> group Beleuchtung attr <actor-device-name> gwCmd switching attr <actor-device-name> icon light_downlight attr <actor-device-name> manufID 00D attr <actor-device-name> mqttPublish state:topic=haus/wohnzimmer/licht/top/state attr <actor-device-name> mqttSubscribe state:stopic=haus/wohnzimmer/licht/top/set attr <actor-device-name> room Wohnzimmer attr <actor-device-name> subDef 0010000B attr <actor-device-name> subType gateway attr <actor-device-name> webCmd on:off
Aktoren, die in einer FHEM-Instanz definiert sind, aus einer anderen schalten Dimmer
Aktor-Definition: Code: [Auswählen]
defmod <actor-device-name> CUL_HM xxxxxx attr <actor-device-name> model HM-LC-Dim1TPBU-FM ... attr <actor-device-name> mqttPublish pct:topic=haus/wohnzimmer/licht/level state:topic=haus/wohnzimmer/licht/state attr <actor-device-name> mqttSubscribe pct:stopic=haus/wohnzimmer/licht/set
Aktoren, die in einer FHEM-Instanz definiert sind, aus einer anderen schalten Shutters / Blinds
Aktor-Definition: Code: [Auswählen]
defmod <actor-device-name> CUL_HM xxxxxx attr <actor-device-name> model HM-LC-Bl1PBU-FM ... attr <actor-device-name> mqttPublish pct:topic=haus/wohnzimmer/rollo/all/position state:topic=haus/wohnzimmer/rollo/all/state attr <actor-device-name> mqttSubscribe pct:stopic=haus/wohnzimmer/rollo/all/set
FAQ
Das ist so nicht vorgesehen, ein reading = ein Topic.
a) beim device-count werden nur Geräte gezählt, die mit eigenen mqtt*-Attributen versehen sind. Bei einer globalen Definition 'globalPublish' kann die Bridge nicht (ohne weiteres) wissen, welche Geräte angesprochen werden sollen. Daher wird auch nichts gezählt.
b) mqttSubscribe ist gedacht für diejenigen Geräte, die per MQTT 'versorgt' werden sollen. Die Bridge selbst gehört nicht dazu. Aus technischen Gründen kann es sein, dass diese Attribute trotzdem vom FHEM angeboten werden, gesetzt werden können sie jedoch nicht, die Bridge 'währt' sich dagegen. Ein 'globalSubscribe' gibt es nicht. Ich habe mich entschieden, diese Festure nicht anzubieten. Bei unbedachten Verwendung könnte ein großes Sicherheitsrisiko entstehen. Einfach diese Attribute an den gewünschgten Devices erstellen.
Die Definition lautet 'fhem room=MQTT_BRIDGE_DEVICES'. Der erste Parameter (wie im Commandref steht) ist der Prefix für die Optionsattribute. Ist für Sonderfälle gedacht, wenn mehr als eine Bridge im System vorhanen ist. Deine Parameter heißen also 'fhemSubscribe' etc.
Bin nun draufgekommen das dieses fehlerhafte Verhalten (Bridge geht nicht nach restart so lange bis man im User Interface DEF und "modify" geklickt hat) nur dann auftritt wenn device-count = 0 ist. Nun hab ich ein Device mit einem "fhemSubscribe" Attribut ausgestattet ... und nun lebt die Bridge auch nach einem Restart.
Du kannst aber mit * alle Readings greifen und dann mit Perlmitteln in der expression filtern.
irgendwie so (ungetestet): Code: [Auswählen]
desired-temp!info:expression={if($reading=~/SMAEM12345678.*/){$value}else{undef})}