FHEM Forum

FHEM - Hausautomations-Systeme => MQTT => Thema gestartet von: OiledAmoeba am 14 November 2022, 18:24:34

Titel: MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: OiledAmoeba am 14 November 2022, 18:24:34
Moin,

ich bastel mir gerade einen Wolf... Also, ich habe einen Temp-/Humsensor, der seinen Daten unbedingt einen Timestamp und einen Status mitgeben will.
Es kommen also z.B. solche Telegramme auf dem Topic "TEMPERATURE":
{"ts":1668443569655,"v":20.399999976158142,"s":0}
ts = unix-timestamp, v = die eigentlich wichtige Nutzlast, s = Status
Die Daten reichen mir auf ein Nachkomma gerundet.

mit
/TEMPERATURE:.* { json2nameValue($EVENT, 'TEMPERATURE_', $JSONMAP) }

lässt sich das Telegramm zerlegen in TEMPERATURE_s, TEMPERATURE_v und TEMPERATURE_ts. Mit dem json2nameValue-Filter kann ich _s und _ts ausblenden:
{ json2nameValue($EVENT, 'TEMPERATURE_', $JSONMAP,'v') }

Über jsonMap lässt sich das Ganze ja auch noch umbenennen. Weil aus TEMPERATURE_v nur temperature werden soll. Nur leider klappt das nicht, wenn man den Filter benutzt. Ich denke mal, weil der Filter erst nach der Map angewendet wird.

Das hier:
attr jsonMap TEMPERATURE:temperature
attr readingList TEMPERATURE:.* { json2nameValue($EVENT, 'TEMPERATURE_', $JSONMAP) }

klappt. Erzeugt werden dann TEMPERATURE_v, TEMPERATURE_ts und TEMPERATURE_s.
Wenn man aber den Filter einbaut:
attr jsonMap TEMPERATURE_v:temperature
attr readingList TEMPERATURE:.* { json2nameValue($EVENT, 'TEMPERATURE_', $JSONMAP,'v') }

findet er nix mehr, wonach er filtern kann und macht nix mehr.

Also habe ich mir das jetzt so gebaut:
attr readingList TEMPERATURE:.* { json2nameValue($EVENT, 'TEMPERATURE_', $JSONMAP,'v') }
attr userReadings temperature:TEMPERATURE_v.* {ReadingsNum($name,'TEMPERATURE_v',0,1)}

Blöd ist halt jetzt, dass die alten Readings und die umgenannten Readings im Device stehen. Das sieht unschön aus. Und da userReadings eine Komma-Liste ist, könnte das eventuell ein ewig langer String werden, wenn ein anderes Gerät noch mehr Topics liefert...

Geht das nur so, vor allem wegen der Rundung, oder kann ich das über die readingList direkt erreichen? Mein Ziel/Wunsch ist, dass ich nur temperature als Reading habe, welches direkt aus dem Topic abgeleitet wird und keine Dopplung der Readings, weil es nachträglich umgewandelt wird.
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: Otto123 am 14 November 2022, 18:49:55
Hallo Florian,

spartanischer Vorschlag:
readingList TEMPERATURE:.* { my $val = sprintf '%.2f', (split ':',(split ',',$EVENT)[1])[1] ;{ "temperature"=>$val } }

Gruß Otto
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: rudolfkoenig am 14 November 2022, 19:05:03
Alternativ:
readingList /TEMPERATURE:.* { {"temperature"=>sprintf("%0.2f", (%{json2nameValue($EVENT)}{v})+0)} }
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: Otto123 am 14 November 2022, 19:11:30
Rudi, Du solltest solche Beispiele irgendwo immer gleich zentral ablegen, in der commandref oder ... ;)
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: Beta-User am 14 November 2022, 19:37:24
Zitat von: Otto123 am 14 November 2022, 19:11:30
Rudi, Du solltest solche Beispiele irgendwo immer gleich zentral ablegen, in der commandref oder ... ;)
Ich liebe Rudi's commandrefs, die sind so schön kurz und knackig. Bitte nicht verwässern!

Aber Otto, du könntest sowas gerne dann direkt in "Schritt für Schritt" und/oder den Workshop übernehmen...
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: TomLee am 14 November 2022, 19:51:42
Haben die doppelten geschweiften einen Grund ? Frag nur weils auch mit einfachen geht.
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: rudolfkoenig am 14 November 2022, 20:35:24
ZitatHaben die doppelten geschweiften einen Grund ? Frag nur weils auch mit einfachen geht.
Das habe ich offensichtlich uebersehen.
Was ich noch nicht verstehe, wieso man den +0 braucht.
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: Otto123 am 14 November 2022, 20:39:35
erfolgt dadurch eine extra Datenformat Konvertierung?
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: OiledAmoeba am 14 November 2022, 23:09:58
Zitat von: rudolfkoenig am 14 November 2022, 19:05:03
Alternativ:
readingList /TEMPERATURE:.* { {"temperature"=>sprintf("%0.2f", (%{json2nameValue($EVENT)}{v})+0)} }

Das ist genau das, was ich erreichen wollte! Hat den ganzen Tag nicht funktioniert.
Warum? Ganz einfach: Ich habe den Verweis auf das Objekt {v} vergessen. Bei mir kam immer HASH... raus. Und ich hab die Ursache nicht bemerkt. Ich habe halt die ganze Zeit das komplette Array darstellen wollen, da hat FHEM mit dem HASH drauf reagiert...
Drei Zeichen im Code vergessen, den ganzen Tag verdödelt (und im Forum ein ganz kleines bissl blamiert)...
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: OiledAmoeba am 15 November 2022, 02:41:04
Zitat von: rudolfkoenig am 14 November 2022, 20:35:24
Das habe ich offensichtlich uebersehen.
Was ich noch nicht verstehe, wieso man den +0 braucht.
Das mit den doppelten Klammern hab ich auch schon mal gelesen. Ich glaub sogar irgendwo im FHEM Wiki. Ist mir nur gerade entfallen, was die Begründung war.

Immerhin das +0 kann ich erklären: Ich habe mir den Quellcode von json2nameValue nicht angesehen, aber vermutlich ist das Ergebnis ein Text-String. sprintf benötigt eine Zahl, um zu funktionieren. Durch das +0 wird an dem Ergebnis von json2nameValue eine mathematische Manipulation durchgeführt, die den Wert zwingt, zur Zahl zu werden. Durch die einfachen Klammern passiert das, bevor der Wert an sprintf übergeben wird.
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: rudolfkoenig am 15 November 2022, 09:00:43
Zitatsprintf benötigt eine Zahl, um zu funktionieren.

Das wuerde mich jetzt ueberraschen, ich war bisher der Ansicht, dass Perl automatisch zwischen Zahl und String konvertiert. Meine Theorie wird auch damit besttaetigt:
% perl -e 'printf("%0.2f\n","2.1789")'
2.18
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: OiledAmoeba am 15 November 2022, 14:20:47
Ich bin bei sprintf von sprintf(3) (Linux manpage) ausgegangen. Da steht, dass integer oder number sein muss und Fließkommazahlen nur im number-Modus verarbeitet werden können. Meine Logik war dann: Naja, durch die Addition von 0 wird der string zu einer Zahl gezwungen.

Muss wohl doch ein anderer Grund sein, denn lässt man +0 weg, schmeißt Perl diesen Fehler:
PERL WARNING: Argument "v" isn't numeric in sprintf at (eval 5004883) line 1

Also, "isn't numeric" wäre meine Erklärung zu String/Number, aber "Argument 'v'" deutet eher darauf hin, dass durch +0 der "Zeiger" auf den Inhalt des Objekts verschoben wird. Scheinbar wird ohne +0 das Objekt selbst übergeben, nicht der Inhalt.

Test:

Blob:
{"v": 19.5}






Code|Rückgabe
{ {%{json2nameValue($EVENT)}{v}} }|v
{ {(%{json2nameValue($EVENT)}{v})+0} }|19.5

Es liegt also gar nicht an sprintf(), sondern an der Rückgabe von json2nameValue, bzw. die Referenzierung. Von JSON verstehe ich (noch) zu wenig, aber ich meine gelesen zu haben, dass es im Prinzip (teils verschachtelte) Arrays sind. Dann dürfte +0 wohl bedeuten, dass auf das erste Objekt im Array zugegriffen werden soll, da die Zählung hier ja bei 0 beginnt.
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: rudolfkoenig am 15 November 2022, 15:27:36
ZitatVon JSON verstehe ich (noch) zu wenig, aber ich meine gelesen zu haben, dass es im Prinzip (teils verschachtelte) Arrays sind.
No comment :)

Meine Experimente:
fhem> { use Data::Dumper }
fhem> { Dumper(json2nameValue('{"ts":1668443569655,"v":20.399999976158142,"s":0}')) }
$VAR1 = {
          'v' => '20.399999976158142',
          's' => '0',
          'ts' => '1668443569655'
        };
fhem> { %{json2nameValue('{"v":20.399}')}{v} }
20.399
fhem> { sprintf("%0.2f", %{json2nameValue('{"v":20.399}')}{v}) }
0.00
# Inklusive Fehlermeldung in FHEM-Log: Argument "v" isn't numeric in sprintf
fhem> { sprintf("%0.2f", %{json2nameValue('{"v":20.399}')}{v}."") }
20.40
fhem> { sprintf("%0.2f", %{json2nameValue('{"v":20.399}')}{v}+0) }
20.40


Bin immer noch ratlos.
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: rudolfkoenig am 15 November 2022, 15:36:13
Die Symptome sind auch ohne json2nameValue nachzustellen:
fhem> { my $j={v=>20.3999};; sprintf("%0.2f", %{$j}{v}) }
0.00
# Inklusive Fehlermeldung in FHEM-Log: Argument "v" isn't numeric in sprintf
fhem> { my $j={v=>20.3999};; sprintf("%0.2f", %{$j}{v}+0) }
20.40
fhem> { my $j={v=>20.3999};; sprintf("%0.2f", $j->{v}) }
20.40


Leider kann ich -> nicht bei Ruckgabewert einer Funktion verwenden:
fhem> { sprintf("%0.2f", %{json2nameValue('{"v":20.399}')}->{v}) }
Can't use a hash as a reference at (eval 54) line 1.

fhem> { sprintf("%0.2f", ${json2nameValue('{"v":20.399}')}->{v}) }
Not a SCALAR reference at (eval 55) line 1.

Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: rudolfkoenig am 15 November 2022, 15:40:10
Nachtrag: sicher kann man es verwenden:
fhem> { sprintf("%0.2f", json2nameValue('{"v":20.399}')->{v}) }
20.40


Also meine Alternative von oben nochmal sauber und verstaendlich:
/TEMPERATURE:.* {"temperature"=>sprintf("%.2f", json2nameValue($EVENT)->{v})}


Schwere Geburt :)
Titel: Antw:MQTT2: JSON Blob zerlegen, nur Teile benutzen, umbenennen und runden?
Beitrag von: OiledAmoeba am 15 November 2022, 16:57:08
Zitat von: rudolfkoenig am 15 November 2022, 15:40:10
Also meine Alternative von oben nochmal sauber und verstaendlich:
/TEMPERATURE:.* {"temperature"=>sprintf("%.2f", json2nameValue($EVENT)->{v})}


Super! Gleiches Ergebnis, aber sieht besser aus ;-)
Damit mache ich weiter. Und als pflichtbewusster User stelle ich das/die Template/s dann auch öffentlich zur Verfügung, wenn ich die anderen Devices auch zusammengebastelt habe.