Readings als JSON formatierte Attributliste auf MQTT publishen / Perl-Problem

Begonnen von thorschtn, 04 September 2020, 09:22:44

Vorheriges Thema - Nächstes Thema

thorschtn

Hallo,

ich möchte alle Readings eines Gerätes als Attribute in einer JSON Nachricht auf meinem MQTT Server veröffentlichen.

Hierzu habe ich mir ein notify angelegt, welches grundsätzlich auch funktioniert (d.h. die JSON Nachricht korrekt zusammenbaut und auf dem MQTT Server veröffentlicht.


defmod not_DB23 notify FriedrStr.* set MQTT_Broker publish fhem/DB23/attributes {(\
my $d="$NAME";;;;\
my $hash = $defs{$d};;;;\
my $readings = $hash->{READINGS};;;;\
my $message="{ \"connection\": \"Friedr\",";;;;\
foreach my $a ( keys %{$readings} ) {\
if ( substr($a, -1, 1) == 3 ) {\
my $b = $a;;;;\
chop($b);;;; chop($b);;;;\
$message .= toJSON($b)." : ".toJSON(ReadingsVal($d,$a,"error"))." ," \
}\
};;;;\
chop($message);;;;



{
  "connection": "Friedr",
  "travel_note_text": "Aktuelle Informationen liegen vor",
  "travel_note_error": "none",
  "plan_arrival": "09:57",
  "plan_arrival_delay": "0",
  "travel_note": "achtung",
  "travel_destination": "Berlin Friedrichstraße (S) - Gl. 12",
  "travel_price": "VBB ab 3,60 EUR ",
  "plan_departure_delay": 1,
  "plan_connection": "RE, S",
  "plan_travel_change": "1",
  "travel_vehicle_nr": "RE 92408 | S 2",
  "travel_departure": "Rangsdorf - Gl. 2\n\nBlankenfelde(Teltow-Fläming)\n\n\n\nFußweg\n3 Min.\n\n\n\nBlankenfelde (S)\nab 09:20  Gl. 3",
  "plan_departure": "09:04",
  "plan_travel_duration": "0:52"
}

   
Allerdings erhalte ich jedesmal, wenn das Notify ausgeführt wird, pro Notify zig (~ 100) Einträge


2020.09.04 08:57:35 1: PERL WARNING: Argument "e" isn't numeric in numeric eq (==) at (eval 3752) line 7.
2020.09.04 08:57:35 1: PERL WARNING: Argument "r" isn't numeric in numeric eq (==) at (eval 3752) line 7.
2020.09.04 08:57:35 1: PERL WARNING: Argument "e" isn't numeric in numeric eq (==) at (eval 3753) line 7.
2020.09.04 08:57:35 1: PERL WARNING: Argument "r" isn't numeric in numeric eq (==) at (eval 3753) line 7.


in meinem Logfile und gefühlt deutliche Performanceeinbussen / Hänger im System.

Kann mir jemand einen Tipp geben, was an meinem Code falsch ist?

Hat ggfs jemand eine alternative Lösung, die JSON Nachricht mit den Readings zusammen zu bauen?

Danke & viele Grüße

Thorsten
NUC - FHEM & HA
MapleCUN, Homematic, 433MHz, AB440, 1-Wire Bewässerung & Pool, Jarolift (Signalduino), Signal Messenger, Denon AVR, LG WebOS, AmazonEcho, Jura S90 (ESP8266), Sonoff, Xiaomi Mii Sauger, Worx SO500i

rudolfkoenig

Der Zahlenvergleich in perl (==) beschwert sich, wenn einer der Argumente kein Zahl ist.
=> Nicht jeder Reading(name) der ausloesenden Eintraege endet in einem Ziffer.

thorschtn

Das klingt logisch. Hätte ich wahrscheinlich eher im Perl-Anfängerforum posten sollen.

Danke @rudolfkoenig für den Hinweis.
NUC - FHEM & HA
MapleCUN, Homematic, 433MHz, AB440, 1-Wire Bewässerung & Pool, Jarolift (Signalduino), Signal Messenger, Denon AVR, LG WebOS, AmazonEcho, Jura S90 (ESP8266), Sonoff, Xiaomi Mii Sauger, Worx SO500i

tbk

Hi,

sorry, dass ich jetzt diesen alten Thread wieder öffne, aber ich habe leider nichts passenderes im Forum gefunden aber das ist genau das was ich gesucht habe.

Ich nutze MAX! Heizthermostate und möchte für jeden Thermostat einen JSON formatierte Attributliste auf MQTT publishen.

Was ich bis jetzt erreicht habe:
DMHAVE
define myBroker MQTT2_CLIENT <IP>:1883                                                                                                                                                                           
setuuid myBroker 662bfcba-f33f-c92d-b418-5c9bc23c90828bcc                                                                                                                                                               
attr myBroker alias MQTT Broker                                                                                                                                                                                         
attr myBroker clientId fhem                                                                                                                                                                                             
attr myBroker devStateIcon .*active:none:disconnect .*disconnected:none:connect                                                                                                                                         
attr myBroker icon mqtt                                                                                                                                                                                                 
attr myBroker ignoreRegexp ignoreRegexp cmnd/[^:"]+:|homeassistant/[^:"]+/config:|shellies/[^:"]+/command:|zigbee2mqtt/[^/]+/set:|milight/0x[0-9a-fA-F]{1,4}/.*/[0-8]:|tasmota/discovery/|ems-esp/|fhem/                 
attr myBroker keepaliveTimeout 60                                                                                                                                                                                       
attr myBroker msgAfterConnect -r fhem/connection/status connected                                                                                                                                                       
attr myBroker msgBeforeDisconnect -r fhem/connection/status disconnected                                                                                                                                                 
attr myBroker qosMaxQueueLength 100                                                                                                                                                                                     
attr myBroker room MQTT                                                                                                                                                                                                 
attr myBroker username <USERNAME>   
                                                                                                                                                                                           
 define mqttBridge MQTT_GENERIC_BRIDGE mqtt room=MAX                                                                                                                                                                   
setuuid mqttBridge 662c08d5-f33f-c92d-bf5a-bf944ab5ecbb36a9                                                                                                                                                           
attr mqttBridge alias MQTT generic bridge                                                                                                                                                                             
attr mqttBridge globalDefaults sub:qos=2 pub:qos=0 retain=1 base={"fhem/$device"}                                                                                                                                     
attr mqttBridge globalPublish state|desiredTemperature|temperature|valveposition|battery|mode:topic={"$base"} state|desiredTemperature|temperature|valveposition|battery|mode:expression={toJSON({$name=>$value})}   
attr mqttBridge icon mqtt_bridge_2                                                                                                                                                                                   
attr mqttBridge room MQTT                                                                                                                                                                                             
attr mqttBridge stateFormat in: incoming-count out: outgoing-count devices: device-count                                                                                                                             
attr mqttBridge verbose 5                                                                                                                                                                                                                                                                                                                                                                                         

Dadurch bekomme ich sowas

{"state":"16.0"}                 
{"desiredTemperature":"16.0"}   
{"battery":"ok"}                 
{"mode":"manual"}               

aber eigentlich möchte ich sowas:

{
 "state":"16.0"
 "desiredTemperature":"16.0"
 "battery":"ok"
 "mode":"manual"
}

Das ganze sieht ja eigentlich genau nach dem aus was hier geteilt wurden,
aber ich verstehe das nicht mit dem notify.

Grüße
  Tamas

rudolfkoenig

ZitatDas ganze sieht ja eigentlich genau nach dem aus was hier geteilt wurden,
Vielleicht auf dem ersten Blick.

Das notify oben erstellt beim Eintreffen eines beliebigen Events fuer FriedrStr.* ein JSON fuer eine Reihe von Readings per Hand(*), und versendet das Ergebnis auf einmal per publish.
(*) Statt toJSON(X) haette man im Perl-Skript oben auch "X" schreiben koennen.

Im zweiten Fall versendet MQTT_GENERIC_BRIDGE (MGB) fuer jedes der aufgefuehrten Events jeweils ein JSON (nur) mit dem eingetroffenen Event.

Soweit ich weiss, laesst sich das Gewuenschte nur mit Perl-Code bewerkstelligen.
Ich wuerde in 99_myUtils.pm Folgendes einbauen:
sub
readings2json($@)
{
  my $in = $defs{shift()}{READINGS};
  my %out;
  map { $out{$_} = $in->{$_}{VAL} } @_;
  return toJSON(\%out);
}
Aufruf mit readings2json($device, "state","desiredTemperature","battery","mode")

tbk

Vielen Dank für die schnelle Hilfe, dass war genau das was ich gesucht habe.

Nach dem ich verstanden habe wie das mit dem 99_myUtils.pm so funktioniert, klappt das genau so wie ich es mir gewünscht habe.

Zur Vollständigkeit hier mein 99_myUtils.pm

##############################################                                                         
## $Id: myUtilsTemplate.pm 21509 2020-03-25 11:20:51Z rudolfkoenig $                                   
##                                                                                                     
## Save this file as 99_myUtils.pm, and create your own functions in the new                           
## file. They are then available in every Perl expression.                                             
                                                                                                       
package main;                                                                                           
                                                                                                       
use strict;                                                                                             
use warnings;                                                                                           
                                                                                                       
sub                                                                                                     
myUtils_Initialize($$)                                                                                 
{                                                                                                       
  my ($hash) = @_;                                                                                     
}                                                                                                       
                                                                                                       
sub
readings2json($@)
{                                                                                 
  my $in = $defs{shift()}{READINGS};                                                                   
  my %out;                                                                                             
  map { $out{$_} = $in->{$_}{VAL} } @_;                                                                 
  return toJSON(\%out);                                                                                 
}                                                                                                                                                                                                           
                                                                                                       
1;                                                                                                     

Beim Aufruf sieht dass dann so aus

attr mqttBridge globalPublish state|desiredTemperature|temperature|valveposition|battery|mode:topic={"$base"} state|desiredTemperature|temperature|valveposition|battery|mode:expression={main::readings2json($device, "state","desiredTemperature","temperature","valveposition","battery","mode")}                                                                                                                                                                                                                                                       

Beta-User

Zitat von: tbk am 05 Mai 2024, 21:29:59klappt das genau so wie gewünscht
Du solltest dir ggf. mal ansehen, ob die Häufigkeit des Sendens auch so klappt wie gedacht ;) .

Falls es zu viel ist: ggf. einfach nur (vermeintlich) das letzte durch das bulk-update (nehme ich zumindest an, dass die Readings per bulk befüllt werden) aktualisierte Reading "versenden" (also eigentlich: als trigger für den Code innerhalb MGB verwenden).

PS @tbk: Da dein Problem zwar ähnlich ist, aber doch anders und der eigentliche TE sein Problem gelöst hatte (aber nicht als solches markiert...), wäre es m.E. besser gewesen, einen neuen Thread aufzumachen und ggf. hierauf zu verweisen.
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