FHEM readings als all-in-one Nachricht publishen

Begonnen von daubsi, 21 Mai 2023, 14:57:26

Vorheriges Thema - Nächstes Thema

daubsi

Ich habe ein FHEM Device mit mehreren Readings, die ich als JSON an meinen MQTT Server schicken will. Bisher habe ich dies nur ausserhalb von FHEM gemacht, möchte jetzt aber gerne die internen Funktionen nutzen.

Ein Beispiel wie es prinzipiell aussehen soll (anderes Device):

rf/esa2000wz/state {"model": "ESA2000WZ", "battery": "ok", "sequence": 93, "total_ticks": 9892185, "actual_ticks": 22, "ticks": 500, "repeat": "+", "raw": "CNT: 93+ CUM:9892185 CUR:22 TICKS:500 LR", "total": 29518.492000002, "actual": 1.32, "diff": 0.044, "diff_sec": 120, "diff_ticks": 22, "last_sec": 1684673230, "raw_total": 19784.37, "max": 1.32, "day": 11.313999999999998, "month": 324.2460000000003, "year": 3315.07799999998, "rate": "LR", "day_hr": null, "day_lr": 11.313999999999998, "month_hr": null, "month_lr": 30.58399999999995, "year_hr": null, "year_lr": 30.58399999999995, "day_last": 16.947999999999986, "month_last": 2990.8319999999976, "year_last": 4248.71600000018, "hour": 1.5680000000000003, "hour_last": 1.056, "state": "CNT: 93+ CUM:29518.492 CUR:1.32 TICKS: 500 LR", "timestamp": "2023-05-21T12:47:10"}
Ich habe mich dazu ein bisschen eingelesen und verstanden, dass ich dafür die MQTT_GENERIC_BRIDGE nehmen könnte und dann pro FHEM Device ein bestimmtes Attribut setzen kann, so dass entsprechende Publications erfolgen.

Meinen MQTT Server aber ich wie folgt bekannt gemacht:

define mosquitto MQTT bigigloo:1883
setuuid mosquitto 5db19f35-f33f-97a9-c116-eee048480a42b458

Dann die MQTT_GENERIC_BRIDGE:

define mqttGeneric MQTT_GENERIC_BRIDGE
setuuid mqttGeneric 6469e770-f33f-97a9-cbce-80bf35716544e1de
attr mqttGeneric IODev mosquitto

Dann habe ich bei einem der Devices, dessen Readings ich übertragen möchte, folgende Attribute hinzugefügt:

attr WMBUS_DME_72564471_118_7 mqttDefaults base={"rf/mbus/hydrus"} pub:qos=0 sub:qos=2 retain=0
attr WMBUS_DME_72564471_118_7 mqttPublish 8_value!json:topic={"$base/status"} 8_value!json:expression={toJSON({volume=>$value})}
Damit bekomme ich folgende Publications im MQTT Server:

rf/mbus/hydrus/status {"volume":"0.936"}
Das sieht schon mal prima aus soweit, nur möchte ich nun unter Status mehrere Werte in das JSON schreiben. Ich habe z.B. 3_value, RSSI, batterState.
Wie referenziere ich in dem JSON Ausdruck mehrere Readings?

Das mqttGeneric Device zeigt mir beim STATE übrigens nur "???" an, das Publishen zumindest scheint aber ja zu gehen. Muss ich noch etwas hinzufügen?

Vielen Dank



[/code]

daubsi

Durch diese mqttPublish Definiton:

3_value|8_value|RSSI|batteryState:topic={"$base/status"} 3_value|8_value|RSSI|batteryState:expression={toJSON({$name=>$value})}
Schickt er schon mal die 4 Werte, und auch als JSON, nur leider alle als eigene "status" Werte und nicht in einem grossen JSON.

rf/mbus/hydrus/status {"RSSI":"-45"}
rf/mbus/hydrus/status {"3_value":"17.5"}
rf/mbus/hydrus/status {"8_value":"0.936"}
rf/mbus/hydrus/status {"batteryState":"ok"}

Natürlich würde ich dann gerne auch noch 3_value und 8_value durch "temperature" und "volume" ersetzen wollen, wenn das geht? Kann ich dem Konstrukt auch mitgeben, dass die ersten 3 Keys eigentlich Zahlen und keine Strings sind? Vermutlich muss ich dann jedes Reading manuell massieren, aber das wäre ja kein Problem?

rudolfkoenig

Die Feinheiten von MQTT_GENERIC_BRIDGE kenne ich nicht, deswegen hier ein Alternativvorschlag mit userReadings:

attr XXX userReadings json { toJSON({\
  RSSI=>ReadingsNum($NAME, "RSSI",0)+0,\
  temperature=>ReadingsNum($NAME, "3_value",0)+0,\
  volume=>ReadingsNum($NAME, "8_value",0)+0,\
  batteryState=>ReadingsVal($NAME, "batteryState",0) }) }

Das so erstellte json Reading kann per MQTT_GENERIC_BRIDGE versendet werden.

Beta-User

Man kann diesen Code m.E. auch für Perl-Anweisungen in MQTT_GENERIC_BRIDGE direkt nutzen, das Ergebnis dann in den Rückgabewert ($val ?) schreiben. Analog zu dem, was man bei mehreren Events in userReadings zur Vermeidung von mehreren Sendungen mit (fast) unverändertem Inhalt machen sollte, sollte man sich eben das Reading als "trigger" aussuchen, das ggf. als letztes aktualisiert wird (wenn es nicht sowieso immer ein bulk-update ist).
Dabei kann es aber sein, dass MQTT_GENERIC_BRIDGE toJSON() nicht ohne weiteres direkt kennt und man mit Doppelpunkten (::toJSON()) explizit in den main-namespace verweisen muss.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

daubsi

Hm, irgendwie hatte ich gar keine Notification bekommen, dass es Antworten gab, daher sorry, dass ich erst jetzt antworte.

OK, also wenn ich das richtig verstehe würde ich mir mit dem Code von @rudolfkoenig einfach künstlich ein All-in-one reading erzeugen und das dann analog zu meinen Versuchen senden?

...
...
Gerade mal probiert - funktioniert soweit wunderbar!

Wie das mit dem direkten Perl bei MQTT_GENERIC_BRIDGE und dem Trigger gemeint ist, verstehe ich leider nicht ad-hoc... Wäre es möglich, dass Du mir das anhand dieses Beispiels eventuell zeigst?

So ist es aktuell definiert:

define WMBUS_DME_72564471_118_7 WMBUS DME 72564471 118 7
setuuid WMBUS_DME_72564471_118_7 644ac482-f33f-97a9-5466-95a3c44853fdafaf
attr WMBUS_DME_72564471_118_7 mqttDefaults base={"rf/mbus/hydrus"} pub:qos=0 sub:qos=2 retain=0
attr WMBUS_DME_72564471_118_7 mqttPublish state:topic={"$base/$name"}
attr WMBUS_DME_72564471_118_7 room Cellar
attr WMBUS_DME_72564471_118_7 userReadings state { toJSON({RSSI=>ReadingsNum($NAME, "RSSI",0)+0,temperature=>ReadingsNum($NAME, "3_value",0)+0,volume=>ReadingsNum($NAME, "1_value",0)+0,batteryState=>ReadingsVal($NAME, "batteryState",0) }) }


daubsi

Hm, es ist jetzt aktuell gerade so, dass ich immer einen Doppel-Publish des Readings alle paar Sekunden im mosquitto kriege - sogar wenn es gar keine Änderungen (an keinem der geposteten Werte) habe. Ist es das was Du meintest, @Beta-User?

Beta-User

Zitat von: daubsi am 24 Mai 2023, 15:17:23Wie das mit dem direkten Perl bei MQTT_GENERIC_BRIDGE und dem Trigger gemeint ist, verstehe ich leider nicht ad-hoc... Wäre es möglich, dass Du mir das anhand dieses Beispiels eventuell zeigst?
attr WMBUS_DME_72564471_118_7 mqttPublish state:topic={"$base/$name"} 8_value!json:topic={"$base/status"} 8_value!json:expression={toJSON({volume=>$value,RSSI=>ReadingsNum($device, "RSSI",0)+0,temperature=>ReadingsNum($device, "3_value",0)+0})}
...die Lösung stand doch schon fast in deinem Ausgangscode...

Mit dem "trigger" ist gemeint: Da das userReading nicht nur auf ein einziges Reading-update reagiert, kann es sein, dass jede Aktualisierung eine Sendung auslöst, selbst, wenn das alles funktional zusammengehört. Ob es so ist, oder eine einzige Event-loop mehrere Readings aktualisiert, kann ich von hier aus nicht beurteilen, weil ich weder WMBUS im Einsatz habe, noch in den Code geschaut, noch hier irgendwas gepostet zu sein scheint, anhand dessen man das ablesen könnte ;) .

OK, während ich schreibe hast du den vermuteten Effekt beobachtet => kein "bulk-update"...

Bitte beachten: Am sinnvollsten das Reading auswählen, das immer zuletzt aktualisiert wird.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

daubsi

Danke, jetzt ist das mit dem mqttPublich klar. Was die Readings betrifft: ja, alle 20-30 Sekunden werden anscheinend alle readings durch das Modul angefasst (die Timestamps in der Übersicht werden rot), egal ob sich ein Wert geändert hat oder nicht. Wie mache ich das mit dem Reading auswählen, welches als letztes aktualisiert werden soll? Das hier ist nicht gemeint, oder? https://fhem.de/commandref_DE.html#trigger

Beta-User

Schau mal in den Event-Monitor, dann sollte es vielleicht klarer sein ;) .

Ach so: ggf. solltest du dich auch mal mit "event-on-change-reading" (etc.) befassen ::), damit könntest du ggf. eingrenzen, dass nur bei einer Änderung, aber mind. alle 15 Minuten ein publish erfolgt. MQTT_GENERIC_BRIDGE ist einfach nur ein Event-Handler, was das publish angeht.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

daubsi

OK!

Ich spiele gerade noch mit dem direkten Erstellen des JSON im mqttpublish rum, aber irgendwie scheint das dort anders zu funktionieren?

Das hier geht und wird entsprechend gepublished:

status:topic={"$base/$name"} 8_value!json:topic={"$base/status"} 8_value!json:expression={toJSON({volume=>$value,product=>"Diehl HYDRUS 2.0"})}
Aber sobald ich einen dynamischen Anteil mit hinzunehme, wird ab da gar nichts mehr gepublished. Als wenn ein Syntaxfehler o.ä. vorliegen würde, es ist aber nirgends etwas von einem Fehler zu sehen?

status:topic={"$base/$name"} 8_value!json:topic={"$base/status"} 8_value!json:expression={toJSON({volume=>$value,product=>"Diehl HYDRUS 2.0",temperature=>ReadingsNum($NAME, "3_value",0)+0})}
Deinem Beispiel entnehme ich aber, dass Funktionen wie ReadingsNum() auch funktionieren sollten?

daubsi

#10
Ich hab jetzt doch was in den Logs gefunden... Offenbar mag FHEM an der Stelle das $NAME nicht, aber wenn ich es auf $device ändere, ist er auch noch nicht glücklicher?


2023.05.24 16:26:00 2: MQTT_GENERIC_BRIDGE: [mqttGeneric] error while evaluating expression ('{toJSON({volume=>$value,product=>"Diehl HYDRUS 2.0",temperature=>ReadingsNum($NAME, "3_value",0)+0})}'') eval error: Global symbol "$NAME" requires explicit package name (did you forget to declare "my $NAME"?) at (eval 189984) line 1.
$NAME in $device geändert im Attribut:

2023.05.24 16:26:29 2: MQTT_GENERIC_BRIDGE: [mqttGeneric] error while evaluating expression ('{toJSON({volume=>$value,product=>"Diehl HYDRUS 2.0",temperature=>ReadingsNum($device, "3_value",0)+0})}'') eval error: Undefined subroutine &MQTT::GENERIC_BRIDGE::ReadingsNum called at (eval 189990) line 1.
Ein ReadingsVal gibt es wohl - aber da ist der zurückgegebene Wert dann immer 0 (am Beispiel "Termperature")

daubsi

Got it!

mqttPublish status:topic={"$base/$name"} 1_value!json:topic={"$base/status"} 1_value!json:expression={toJSON({volume=>$value,product=>"Diehl HYDRUS 2.0",temperature=>ReadingsVal($device, "3_value",0)+0,RSSI=>ReadingsVal($device, "RSSI",0)+0})}
Ausgabe:

mbus/hydrus/status {"RSSI":-45.5,"product":"Diehl HYDRUS 2.0","temperature":16.2,"volume":"7.333"}