neues Modul MQTT - Bridge zwischen mqtt und fhem

Begonnen von ntruchsess, 01 Oktober 2014, 13:45:56

Vorheriges Thema - Nächstes Thema

ntruchsess

ich habe eine Bridge zwischen mqtt und fhem implementiert.

das sind die Module 00_MQTT.pm, 10_MQTT_BRIDGE und 10_MQTT_DEVICE.pm

mit define <mqtt-name> MQTT ip:port legt man die Verbindung zum mqtt-broker an. Als broker habe ich mosquitto verwendet. Das ist in C geschrieben und braucht nur minimal Resourcen und ist auf Debian basierten Systemen normalerweise als Packet verfügbar.

mit define <mqtt-device-name> MQTT_BRIDGE <fhem-device> legt man für ein bestehendes FHEM-device eine Verbindung zum mqtt an. Es wird die im IODev-attribute angegebne MQTT-verbindung verwendet.

Die Verbindung funktioniert bidirektioinal:

mit den Attributen 'publishState' und 'publishReading_<readingname> man kann Änderungen am State bzw. Readings nach mqtt publizieren. Der Attribut-wert ist immer das Topic an das die Message geschickt werden soll. Message-inhalt ist jeweils der neue Wert des Readings bzw. states.

mit den Attributen 'subscribeSet' bzw. 'subscribeSet_<setcommand>' kann man mqtt-topics abonnieren. Immer wenn eine Nachricht auf dem abonnierten Topic eintrifft für das betreffende Device 'set <devicename> <setcommand> <messageinhalt> ausgeführt.

Beispiel:


define mqtt MQTT 127.0.0.1:1883
define mqtt_licht_wohnzimmer MQTT_BRIDGE lichtwohnzimmer
attr mqtt_licht_wohnzimmer subscribeSet fhem/wohnzimmer/licht/set
attr mqtt_licht_wohnzimmer publishState fhem/wohnzimmer/licht


jetzt kann z.B. mit 'mosquitto_pub -t fhem/wohnzimmer/licht/set -m on' ein 'set lichtwohnzimmer on' auslösen.
oder mit einem 'mosquitto_sub -t fhem/wohnzimmer/licht' erfahren, wenn sich der state von 'lichtwohnzimmer' verändert.

für Readings werden die nahmen der betreffenden Readings als Teil des Attribute-names gesetzt:

define mqtt_heizung_wohnzimmer MQTT_BRIDGE heizungwohnzimmer
attr mqtt_heizung_wohnzimmer publishReading_mesured-temp fhem/wohnzimmer/temperature
attr mqtt_heizung_wohnzimmer subscribeReading_desired-temp fhem/wohnzimmer/temperature/set


jetzt erfährt man auf dem topic fhem/wohnzimmer/temperature, wenn sich das Reading 'mesured-temp' des fhem-devices 'heizungwohnzimmer' ändert. Die Temperatur kann man einstellen, indem man messages mit dem gewünschten Temperaturwert an das Topic 'fhem/wohnzimmer/temperature/set' schickt. MQTT_BRIDGE verwendet man, wenn man bestehende fhem-devices (Aktoren und Sensoren) über mqtt steuern bzw. sichtbar machen will.

mit define <mqtt-device-name> MQTT_DEVICE legt man ein neues auf mqtt-topics gemapptes FHEM-device an. Es wird die im IODev-attribute angegebne MQTT-verbindung verwendet. Messages von mqtt updaten die readings dieses devices direkt, es wird kein weiterer dummy benötigt. MQTT_DEVICE verwendet man zur Einbindung von über mqtt erreichbaren sensoren und aktoren.

Beispiel:

define licht_kinderzimmer MQTT_DEVICE
attr licht_kinderzimmer publishSet on off fhem/kinderzimmer/licht
attr licht_kinderzimmer subscribeReading_state fhem/kinderzimmer/licht/set


mit 'set licht_kinderzimmer on' schickt man jetzt eine message 'on' an das topic fhem/kinderzimmer/licht.
Umgekehrt kann das reading state über messages an fhem/kinderzimmer/licht/set gesetzt werden.

bzw:

define heizung_kinderzimmer MQTT_DEVICE
attr heizung_kinderzimmer publishSet_desired-temp fhem/kinderzimmer/temperatur
attr heizung_kinderzimmer subscribeReading_messured-temp fhem/kinderzimmer/temperatur/set
attr heizung_kinderzimmer stateFormat messured-temp


In den Topic-namen der vorgenannten Attribute werden aktuell noch keine Wildcards unterstützt.

um das Erstellen der Readings zu vereinfachen gibt es das Attribute autoSubscribeReadings:

'attr heizung_kinderzimmer autoSubscribeReadings fhem/kinderzimmer/+/set'

sorgt dafür, dass für alle empfangenen Messages automatisch das jeweils passende 'subscribeReading_xxx'-Attribut erstellt und das zugehörige Reading auch gleich geupdated wird. Das letzte '+' im Topic wird als Name des Readings benutzt.
Also wenn eine Message '17.5' an 'fhem/kinderzimmer/messured-temp/set' empfangen wird, wird 'attr heizung_kinderzimmer subscribeReading_messured-temp fhem/kinderzimmer/messsured-temp' gesetzt und gleichzeitig das Reading 'messured-temp' erzeugt und auf den Wert '17.5' gesetzt. Wenn alle gewünschten Readings auf diese Weise angelegt sind, kann man das Attribut 'autoSubscribeReadings' wieder entfernen.

alles im SVN zu finden.

Gruß,

Norbert
while (!asleep()) {sheep++};

hexenmeister

Sehr interessant :)
Kann man auch als mächtigeres FHEM2FHEM einsetzen.

btw. es sollte bestimmt 'define mqtt_licht_wohnzimmer MQTT_DEVICE lichtwohnzimmer' heißen.
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

ntruchsess

Zitat von: hexenmeister am 01 Oktober 2014, 14:39:37
btw. es sollte bestimmt 'define mqtt_licht_wohnzimmer MQTT_DEVICE lichtwohnzimmer' heißen.
danke ;-)
Geändert
while (!asleep()) {sheep++};

hexenmeister

Läuft bei mir nicht:
2014.10.01 21:03:45.092 1: reload: Error:Modul 00_MQTT deactivated:
Not enough arguments for main::DevIo_SimpleWrite at ./FHEM/00_MQTT.pm line 299, near "->bytes)"

2014.10.01 21:03:45.093 0: Not enough arguments for main::DevIo_SimpleWrite at ./FHEM/00_MQTT.pm line 299, near "->bytes)"


Habe mit 0 ergänzt. Das führt zum längeren 'Einfrieren' von FHEM. Im Log sieht mas folgenes

2014.10.01 21:34:02.680 5: MQTT mqtt message received: ConnAck/at-most-once Connection Accepted
2014.10.01 21:34:02.681 5: Triggering mqtt (1 changes)
2014.10.01 21:34:02.682 5: Notify loop for mqtt connection: connected
2014.10.01 21:34:02.697 5: MQTT mqtt message received: PingResp/at-most-once
2014.10.01 21:34:02.698 5: Triggering mqtt (1 changes)
2014.10.01 21:34:02.698 5: Notify loop for mqtt connection: active

Wenn ich mosquitto stoppe, 'erwacht' er weder.
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

ntruchsess

Ich habe noch ein weiteres Modul dazugebaut. Jetzt gibt es MQTT_DEVICE und MQTT_BRIDGE.
MQTT_DEVICE wird verwendet, wenn das physikalische Device (Sensor oder Aktor) über mqtt kommuniziert. (Kein dummy mehr nötig!)
MQTT_BRIDGE ist für den Fall, dass ein fhem-device existiert und dieses über mqtt sicht- bzw. steuerbar gemacht werden soll.

Hab den Startpost entsprechend angepasst.

@Alexander: Danke fürs Feedback. Auf welcher Plattform läuft das bei Dir?

Gruß,

Norbert
while (!asleep()) {sheep++};

hexenmeister

Fhem und mosquitto auf CubieTruck. Habe Dein Beispiel durchgespielt. Als wirklich etwas transportiert werden sollte, ging das Ganze scheinbar ist eine Timeout-Schleife.
Werde morgen die neue Version ausprobieren und poste ggf. Logs und Beobachtungen.
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

hexenmeister

#6
Habe die aktuellen Sources aus SVN. Es gibt noch ein Compile Error:
Can't continue after import errors at ./FHEM/10_MQTT_BRIDGE.pm line 70
BEGIN failed--compilation aborted at ./FHEM/10_MQTT_BRIDGE.pm line 79.

und
"all" is not defined in %MQTT::EXPORT_TAGS at ./FHEM/10_MQTT_BRIDGE.pm line 79



und noch etwas:
fhem> reload 00_MQTT
Undefined subroutine &MQTT::GP_Import called at ./FHEM/00_MQTT.pm line 76.
BEGIN failed--compilation aborted at ./FHEM/00_MQTT.pm line 88.


fhem> reload 10_MQTT_DEVICE
Can't continue after import errors at ./FHEM/10_MQTT_DEVICE.pm line 66
BEGIN failed--compilation aborted at ./FHEM/10_MQTT_DEVICE.pm line 72.


Mein Perl (revision 5 version 14 subversion 2) mag dieses Konstruktion anscheinend nicht ...

Grüße,

Alexander

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

rudolfkoenig

@Norbert: Net::MQTT gehoert nicht nach FHEM/lib.

Ich weiss, die Grenze ist nicht scharf (wieso ist jquery eingecheckt?), aber bei fremden Perl-Modulen bin ich sicher.
Sonst muessen wir noch den kompletten CPAN nach FHEM/lib einchecken. Eigentlich sollte Device::Firmata auch den gleichen Schicksal haben, da es vom CPAN verfuegbar ist.
Lieber sollten wir ueberlegen, wie man benoetigte Perl-Pakete automatisch von CPAN/etc installiert.

hexenmeister

Mit CPAN bekommen FritzBox-Anwender Probleme, andererseits reiten sie bereits ein totes Pferd. (Schade eigentlich :( )
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

hexenmeister

Mit den neuen Versionen funktioniert es.
Eigentlich ganz cool. AbBer mit QOS scheint es noch nicht so zu funktionieren, wie man das erwartet.
Ich habe qos auf 2 gesetzt, dann mosquitto restartet => es dauert dann eine Weile, bis sich MQTT-Device wieder verbindet. In dieser Zeit habe ich mit mosquitto_pub einen neuen Wert geschickt. Dieser ist aber nie angekommen, auch dann nicht, wenn Device wieder verbunden war. Muss das mosquitton nicht zwischenspeichern und bei nächten Gelegenheit sicher übermitteln?

Zwischendurch haben sich einige Warnungen gesammelt:

Use of uninitialized value in concatenation (.) or string at FHEM/lib/Net/MQTT/Message/Subscribe.pm line 26.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Use of uninitialized value in concatenation (.) or string at FHEM/lib/Net/MQTT/Message/Subscribe.pm line 26.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Argument "" isn't numeric in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Use of uninitialized value $_ in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Argument "lichtwohnzimmer" isn't numeric in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

ntruchsess

Zitat von: rudolfkoenig am 03 Oktober 2014, 08:49:03
Lieber sollten wir ueberlegen, wie man benoetigte Perl-Pakete automatisch von CPAN/etc installiert.

Da kann ich mich vorbehaltlos anschließen. Auch wenn ich mein Device-Firmata dort erst mal sauber untergebracht habe bin ich (noch nicht) so der CPAN-spezialist. Wie man das aus Perl heraus handhaben könnte habe ich mir noch nicht angeschaut.

Gruß,

Norbert
while (!asleep()) {sheep++};

ntruchsess

Zitat von: hexenmeister am 03 Oktober 2014, 13:46:03
Muss das mosquitto nicht zwischenspeichern und bei nächten Gelegenheit sicher übermitteln?

im Prinzip ja, hängt aber wohl von der Konfiguration ab. Default ist wohl alles im Speicher zu machen und nur bei einem sauberen Shutdown zu persistieren. Ich weiß aber auch nicht, wie die Logik (mqtt-seitig) tatsächlich sein soll, wenn der Subscriber gar nicht mehr verbunden ist (also ob die subscription dann eventuell einfach automatisch gelöscht wird).

Zitat von: hexenmeister am 03 Oktober 2014, 13:46:03
Zwischendurch haben sich einige Warnungen gesammelt:

Use of uninitialized value in concatenation (.) or string at FHEM/lib/Net/MQTT/Message/Subscribe.pm line 26.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Use of uninitialized value in concatenation (.) or string at FHEM/lib/Net/MQTT/Message/Subscribe.pm line 26.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Use of uninitialized value $_[0] in pack at FHEM/lib/Net/MQTT/Constants.pm line 130.
Argument "" isn't numeric in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Use of uninitialized value $_ in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Argument "lichtwohnzimmer" isn't numeric in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.


danke fürs Testen und das Feedback, schau ich mir an. Das mit dem Reconnect habe ich selber noch nicht so ausgiebig getestet, da habe ich einfach nur meinen (dort sauber funktioneierenden) code aus FRM übernommen und kurz mal gecheckt, ob es tut. Sollte aber kein Problem sein, das zu fixen.

Gruß,

Norbert
while (!asleep()) {sheep++};

ntruchsess

Zitat von: hexenmeister am 03 Oktober 2014, 13:46:03

Argument "" isn't numeric in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Use of uninitialized value $_ in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.
Argument "lichtwohnzimmer" isn't numeric in numeric ne (!=) at ./FHEM/10_MQTT_DEVICE.pm line 112.


behoben
while (!asleep()) {sheep++};

hexenmeister

Die Warnungen sind weg.
Wieso wurde eigentlich bei  MQTT_DEVICE Attribut IODev automatisch gesetzt und bei Bridge nicht?

Die qos funktioniert irgendwie nicht korrekt. Ein Restart von mosquitto führt dazu dass danach gesendeten Werte nicht ankommen. Auch wenn Reconnect sehr schnell zu funktionieren scheint.

Viele Grüße,

Alexander

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

ntruchsess

Zitat von: hexenmeister am 07 Oktober 2014, 00:02:31
Wieso wurde eigentlich bei  MQTT_DEVICE Attribut IODev automatisch gesetzt und bei Bridge nicht?

-> behoben

beim qos ist mir auch noch nicht so recht klar, ob sich das auf die Message bezieht, die man aktuell abschickt, oder ob man beim subscribe angeben kann, mit welchem qos man messages zugestellt bekommen möchte (ich denke es ist ersteres...)

Könnte auch sein, das mosquitto bei einem restart alles subscriptions vergisst. Mal sehen, was die Doku dazu sagt. Bei einem Reconnect einfach alles neu zu subscriben wäre auch kein Ding.

Gruß,

Norbert
while (!asleep()) {sheep++};