Erklärung zu json2nameValue / MQTT readingList Json - bestimmte Elemente filtern

Begonnen von 87insane, 07 Juli 2020, 20:09:47

Vorheriges Thema - Nächstes Thema

87insane

Hallo zusammen,

ich benötige eine Erklärung zu json2nameValue.
{ json2nameValue($EVENT,'',$JSONMAP) } = Ein Wert wie HASH(0x6401360)
Leider findet man im Netz nicht wirklich was oder ich suche falsch... Habe auch separat nochmal hier im Forum gesucht aber leider kein Wiki oder erklärten Beitrag dazu gefunden.

Wenn man in einer ReadingList mit json2nameValue so wie oben gezeigt auflöst, werden darauß einzelne Readings mit den entsprechenden Werten.
Nun würde ich gerne aus einem so auflösbarem Json String aber gerne nur z.B. eine Sache heraus suchen. Dazu würde ich an sich gerne verstehen wie das hier genau funktioniert.
Bei vielen MQTT Geräten bin ich immer wieder am überlegen ob und wie ich es am besten nutze.

Ich würde mich über ein paar Worte dazu freuen....

Danke und Gruß,
87insane

Beta-User

Rudi hatte dazu mal das geschrieben:
Zitat von: rudolfkoenig am 01 Juni 2020, 10:47:26
json2nameValue liefert eine Referenz auf ein Hash zurueck
Rund um diesen Beitrag gibt es mMn. auch ein paar brauchbare Ideen, was man zur Vor- und Nachbereitung der in dem referenzierten Hash enthaltenen Daten machen kann.

Vielleicht erläuterst du deinen Usecase etwas näher, dann wird es ggf. etwas weniger abstrakt?

Wenn es "nur" darum geht, den JSON auf das Vorhandensein eines bestimmten Elements zu prüfen und dann nur diesen Auszug bzw. den zugehörigen Wert (ggf. unter anderem Readingnamen) zurückzugeben: auch dafür gibt es ein paar Beispiele in der mqtt2.template, wie man das direkter mit regex lösen kann.

Und: "Wunschliste" dürfte der falsche Forenbereich sein ;)
ZitatAnregungen, Ideen, Vorschläge für FHEM Erweiterungen.

Verschiebe das ganze nach (?) MQTT (json2nameValue() ist zwar nicht auf MQTT beschränkt, aber dort bisher am häufigsten verwendet afaik, und ins Wiki braucht das mMn. auch nicht, ist zu speziell).
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

87insane

#2
...verschoben...

Es geht mir um eine generelle Erklärung da ich dieses Stück Code und was dahinter steckt als sehr mächtig erachte. Dafür möchte ich es aber auch verstehen. (Große macht und Verantwortung usw :-P)

Ja es geht am Ende darum (auch wenn das dann wieder eine andere Funktion ist), aus einem JSON String gezielt Elemente heraus zu holen. Oft braucht man gerade bei MQTT nicht den ganzen Zweig zu abonnieren. ABER bitte nicht falsch verstehen. Auch wenn es eine andere Funktion sein sollte, möchte ich json2nameValue verstehen!

Was ich probiere ist aktuell:
Testweise (da es da ggf auch gebraucht wird) aus dem SONOS2MQTT gezielt Master und Slave-Erkennung zu bauen.
Dafür teste ich einfach damit ich es verstehe zb. aus dem folgendem was rauß zu ziehen. Ich weiß durch eine bekannte Suchmaschine, das es auch möglich sein muss ein Extrakt zu ziehen von einzelnen Elementen. Da jason2nameValue den ganzen kram wohl entpackt muss ich es ja nutzen können. FHEM macht aus dem HASH ja auch einzel Werte.
Ich dachte an sowas wie, alles in eine VAR zu packen und dann rauß reg exen... Also die gleiche Richtung wie du und auch die Templates. Um das ganze zu testen (gestern zu viele Stunden!), habe ich mir die ganze Zeit die aktuelle SVN offen gehalten mit den Template Daten. Leider war das ganze nicht von Erfolg gekrönt.

Am Ende würde ich in der ReadingList so auch gegen die CID des Gerätes vergleichen usw.... Aber ich will absichtlich zu tief ins Detail gehen, da es mir um die grundsätzliche Funktionalität geht.
Im devGuide hatte ich auch alles durch geklickt aber es ist einfach nix gutes zu finden. Spätestens hier (https://wiki.fhem.de/wiki/Kategorie:Development) hätte ich Text dazu erwartet, der mehr als ein "diese Funktion existiert" ist (hab ich mir ausgedacht den Satz.. geht um die wenigen Infos.

Anbei noch der JSON Array String (denke den wolltest du auch mal haben ;) - Ist aus dem "sonos/RINCON_([0-9A-Z]+):.*" Pfad):
{"uuid":"RINCON_7828CAF427B201400","name":"Wohnzimmer","groupName":"Wohnzimmer","coordinatorUuid":"RINCON_7828CAF427B201400",
"currentTrack":{"Album":"Hey Pablo EP","Artist":"Anti Up",
"AlbumArtUri":"http://192.168.20.70:1400/getaa?s=1&u=x-sonos-spotify:spotify:track:4gnH8nfdJfN115QAzzUc3E%3fsid%3d9%26flags%3d8224%26sn%3d3",
"Title":"Hey Pablo","UpnpClass":"object.item.audioItem.musicTrack","Duration":"0:04:09","ItemId":"-1","ParentId":"-1",
"TrackUri":"x-sonos-spotify:spotify:track:4gnH8nfdJfN115QAzzUc3E?sid=9&flags=8224&sn=3","ProtocolInfo":"sonos.com-spotify:*:audio/x-spotify:*"},
"enqueuedMetadata":{"Artist":"Spotify","AlbumArtUri":"https://i.scdn.co/image/ab67706f00000002470dd505fcf08e4693db9b24","Title":"Dance Party",
"UpnpClass":"object.container.playlistContainer#playlistItem","ItemId":"0006002cspotify%3aplaylist%3a37i9dQZF1DXaXB8fQg7xif",
"ParentId":"spotify%3aview%3aginger-genre-affinity%5b0%5d"},"nextTrack":{"Album":"Arbeit nervt","Artist":"Deichkind",
"AlbumArtUri":"http://192.168.20.70:1400/getaa?s=1&u=x-sonos-spotify:spotify:track:1PzWE6FRyQzyUIQ60DSceN%3fsid%3d9%26flags%3d8224%26sn%3d3",
"Title":"Arbeit nervt","UpnpClass":"object.item.audioItem.musicTrack","Duration":"0:03:18","ItemId":"-1","ParentId":"-1",
"TrackUri":"x-sonos-spotify:spotify:track:1PzWE6FRyQzyUIQ60DSceN?sid=9&flags=8224&sn=3","ProtocolInfo":"sonos.com-spotify:*:audio/x-spotify:*"},
"transportState":"PAUSED_PLAYBACK","playmode":"NORMAL","ts":1594128615493,"volume":{"Master":0,"LF":100,"RF":100},
"mute":{"Master":false,"LF":false,"RF":false}}


sonos/RINCON_7828CAF4289001400:..uuid...RINCON_([0-9A-Z]+) so geht es ja leider nicht^^ Das wäre zu einfach.

Beta-User

Also:

Zu json2NameValue() hatte ich die mMn. aufschlussreichste Diskussion bereits verlinkt, die mir bekannt ist. Zurück kommt also ein Hash (genauer: eine Referenz darauf!), etwas verkürzt gesagt also eine unsortierte "Liste" von "Namen-Wert"-Paaren.
Dass dabei durch json2NameValue() nicht einfach nur der JSON aufgebrochen wird (das können auch andere, allgemeine Perl-Funktionen aus diversen libs), sondern auch eine "doppelte Umbenennung" bzw. Filterung stattfindet (1. Umbenennung mit "Präfix", zweite+Filterung via jsonMap), sollte auch soweit klar sein.



Um dein Problem zu lösen, brauchst du mMn json2nameValue() nicht:
Mal unterstellt, es ist der konkrete "RINCON" Topic-Branch, über den der JSON reinkommt? Dann brauchst du auch den Rückgriff auf die CID nicht, machst eine Regex mit zwei Suchelementen auf den Inhalt von "uuid" bzw. "coordinatorUuid", vergleichst beide miteinander und gibst dann "irgendwas" zurück.
Was, kannst du selbst bestimmen, ich wäre für was "einfaches" zu haben, also z.B. einen Hash, der entweder {"isMaster"=>"true"} oder {"isMaster"=>"false"} lautet. Falls gar kein match gefunden wird, gib "undef" zurück.
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

87insane

Zu 1) Naja den Link hatte ich beim suchen auch gesehen. Aber dafür reicht mein Verständnis nicht...




Zu 2) Ne. Das geht leider so einfach nicht. Dachte ich zuerst auch und dann wäre es etwas einfacher. Aber wenn ein Player nun den Pfad aller Player abonniert, bekommt er immer auch alle Infos. Die eigene uuid ändert sich in dem Moment ja auch. Also müsste man explizit Dinge rauß filtern. Weil der String kommt so komplett rein. Ich hätte nun die uuid gegen die CID gestellt. Dann habe ich bei aktueller CID Vergabe, immer den eigentlichen Playernamen ohne große Zauberei. Denn uuid = CID.
Wenn man nun gezielt Dinge aus einem Zweig ableiten würde, hätte man zwar mehr readingList-Einträge aber es wäre dafür sauberer am Ende im devStateIcon und es würden x Prüfungen weg fallen. Dazu hätte man eine saubere Struktur....
Klar kann man eine solche Ausgabe machen wie auch loadState.... Ich wollt aber erstmal tiefer rein bevor ich etwas irgendwie aufbaue... Deswegen hier die Frage :)

Beta-User

Na ja, 1) ist eben nicht so einfach, es setzt ein "etwas vertiefteres" Verständnis von Perl data types voraus (weiß nicht, ob dir das hier weiterhilft: https://perldoc.perl.org/perldata.html).... Bin da selber immer sehr stark gefordert...

Wenn "alle" "RINCON" abboniert werden, dann macht es wohl Sinn, vorab dann noch eine Prüfung einzubauen, ob "man" überhaupt betroffen ist, also entweder $1 oder $2; dann aber eventuell als "tristate": Master ($1 eq CID, $2 ne CID), Slave ($1 ne CID, $2 eq CID) oder "Single" ($1 eq CID eq $2)?
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

87insane

#6
1) Schaue ich mir an. DANKE - Es hilft wenn einer die korrekten Worte kennt.




2)
sonos/RINCON_([0-9A-Z]+):.* { $TOPIC =~ m,(RINCON_[0-9A-Z]+),; InternalVal("$NAME","CID","") eq "$1" ? {"TEST"=>"$1"} : {"TEST" => "0"} }

Das hier ist mein Test bisher... Alle RINCONS drin und Vergleich gegen CID. Aber da muss noch ein wenig mehr rein.. Geht aber schonmal.
Woher kommt bei dir die $2? Im Topic steht ja z.B. "sonos/RINCON_7828CAF4289001400"

Beta-User

Zitat von: 87insane am 08 Juli 2020, 13:42:33
sonos/RINCON_([0-9A-Z]+):.* { $TOPIC =~ m,(RINCON_[0-9A-Z]+),; InternalVal("$NAME","CID","") eq "$1" ? {"TEST"=>"$1"} : {"TEST" => "0"} }

Das hier ist mein Test bisher... Alle RINCONS drin und Vergleich gegen CID. Aber da muss noch ein wenig mehr rein.. Geht aber schonmal.
Woher kommt bei dir die 2? Im Topic steht ja z.B. "sonos/RINCON_7828CAF4289001400"
Verstehe ich nicht. Du kannst zwar auch erst "$TOPIC" nochmal scannen, aber im JSON-payload ist es ja auch nochmal drin, und die mußt du sowieso auch regex-parsen (sonst würde es reichen, nur den "eigenen" Topic doppelt zu abbonieren, oder?), von daher kann man sich das mMn. direkt sparen. (Aber das Prinzip scheint jetzt klarer zu sein?)
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

87insane

Es ist klarer.. Auf jeden Fall...

Ich würde gerne direkt aus der Payload lesen. Hatte mir dann aber erstmal mit der Bridge Regex geholfen, da ich es nicht hinbekam. Wenn du natürlich jetzt sagst, du bekommst aus dem Zweig dies und jenes rauß indem du.... - Wäre ich glücklich :)

Was Punkt 1) angeht, werde ich mir da noch einiges durchlesen müssen. Danke für den Link! (Hab gehofft von Arrays weg bleiben zu können...Ich hasse sie seit dem ersten Berufsschuljahr vor tausend Jahren^^)

Beta-User

regexr.com sagt mit deinem JSON und dieser regex
uuid.:.([^"]+).*coordinatorUuid.:.([^"]+)$1 RINCON_7828CAF427B201400
$2 RINCON_7828CAF427B201400...
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

87insane

#10
Dann würde ich das doch ein wenig anders machen... Die CID ist immer gleich aber der Logik nach, läuft das leider nicht....

Das hier ist deine Idee:
Master: ($1 eq CID, $2 ne CID)
Slave: ($1 ne CID, $2 eq CID)
Single: ($1 eq CID eq $2)

Damit geht aber kein Master/Slave/Single. Du hast mich aber auf einen guten Weg geworfen...

Master: uuid eq coordinatorid eq CID, groupName ne name
Slave: uuid eq CID ne coordinatorid, groupName ne name
Single: uuid eq coordinatorid eq CID, groupName eq name

In meinen Augen kann dann die Prüfung auf Name und Gruppe in der Theorie entfallen. Denn die ersten beiden ergeben das gleich und der letzte könnte ein else sein.
ABER wenn man mehrere Gruppen hat, sollte trotzdem sauber zugeordnet werden. Die coordinatorid sagt zwar wer Boss ist und auch jedem Slave wem er angehört. Aber ggf. macht es Sinn genau zu wissen, welche Player in eine Gruppe gehören. Man bekommt aber wie schon mal beschrieben immer nur Gruppennamen wie "Master + 2" oder wie es auch im Reading steht: "Wohnzimmer + 2". Die +2 wissen wieder nur die Slaves selber und die wiederum bekommen keine Reading Updates mehr auf Ihrem Zweig, wenn Sie einem Master angehören.
Das bedeutet - Alle Slaves bekommen noch schnell die Info wem sie angehören: groupName: Master +2, Single bleiben wie sie sind und Master bekommen nun nur noch Updates der Readings und müssen diese weitervererben. Deswegen der Versuch das direkt in der ReadingList sicher und sauber zu integrieren.

Ist das nun wieder eher im mqqt2sonos zu besprechen?
PS: Mich nervt es das wir alle hier nirgendwo ein Gespräch komplett führen können. Wir brauchen sowas wie MS Teams...

Bin aber noch hart am grübeln.... Du bist leider blind ... Ich Frage mich ab und an was du an Hardware besitzt. Hätte auch gern überall Kabel aber die Sonos laufen mit oder ohne Kabel genauso .... Dazu liefern sie super Klang. Ich selber würde mir keine Baustein Anlage mehr ins Wohnzimmer stellen.

Beta-User

...vermutlich macht es mehr Sinn, das mit denen auszufeilen, die die Geräte haben - ob es im Haupt-sonos2mqtt-Thread untergeht oder sehr speziell ist, ist eine andere Frage...

Wie dem auch sei:
Der Hauptfall düfte sein, dass eine Box solo unterwegs ist, also sollte diese Prüfung ($3 eq $4 ?) auch möglichst weit nach vorne, dabei muß aber doch abgesichert sein, dass es wirklich was mit der betreffenden Box zu tun hat, oder? Diese Prüfung (vermutlich: uuid eq CID?) müßte also bleiben (wobei ich annehmen würde, dass das dann auch immer über den zur CID passenden Zweig kommt? Was das ganze dahingehend vereinfachen könnte, dass man nur mir Variablen $1 bis $4 aus der regex arbeiten kann?)
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

87insane

In diese Richtung denke ich auch ... nur die Umsetzung ist bei mir etwas Zeit spieliger als bei dir....die Übung...
Ich versuche mal weiter... Danke Dir!

EDIT: (Muss mir das echt abgewöhnen!) - Du hast aber im ganzen Recht! Genau das würde ich weiter ausbauen. Bestehen auf 1-4. Die CID hatte ich zur Verbildlichung aufgenommen. Du hast das aber mal echt gut erklärt jetzt gerade. Das verstehe ich sogar und sagt genau was ich sagen wollte.. Du hast es verbessert mit der Info der 3,4 - die in der Tat (ohne das du es wissen konntest, da keine HW) aber meist der Fall sein sollten. Denn gepairt = auch nur ein Gerät habe ich von @Otto123 gelernt. (Wobei ich mir sicher bin im Sommer ein Stero Pair in der Garage hatte ähnliche Merkmale im original Modul...Will aber so ungern zum testen Pairen wegen dem Modul... Dann ist wieder alles durcheinander...).
Muss mich nochmal in Ruhe hinsetzen und mir das ansehen. Ich male mir sowas meist auf.. Hört sich doof an aber das klappt dann. Wie machst du das immer. Ab und an sind bei Dir die Lösungen in 2min hier drin!

87insane

Siehst du das hier ähnlich wie ich oder würdest du es noch anders machen?

sonos/RINCON_([0-9A-Z]+):.* { $EVENT =~ m,.*name.:.([^"]+)...groupName.:.([^"]+)...coordinatorUuid.:.([^"]+),; my $CID = InternalVal($NAME,"CID",""); $1 eq $2 ? {"TEST"=>"SINGLE"} : $CID ne $3 ? {"TEST"=>"SLAVE"} : {"TEST"=>"MASTER"} }

Klappt auf jeden Fall so. Hab es so kurz wie möglich nach diesen Regeln gebaut:
Master: uuid eq coordinatorid eq CID, groupName ne name (else)
Slave: uuid eq CID ne coordinatorid, groupName ne name
Single: uuid eq coordinatorid eq CID, groupName eq name

So brauchen wir die uuid aktuell nichtmal und es reicht $1-$3 + CID. Würde, wenn es passt so weiter brauen, was meinst du?  Ginge auch mit 1-4 wenn man die uuid als Vergleich nimmt. ABER es gibt bei 1-4 ganz kurz beim verlassen einer Gruppe einen falschen Schwenk. Denk gibt es im Vergleich zur immer festen CID nicht. Deswegen würde ich lieber die CID nehmen.

Beta-User

Zitat von: Beta-User am 08 Juli 2020, 16:36:22
(wobei ich annehmen würde, dass das dann auch immer über den zur CID passenden Zweig kommt? Was das ganze dahingehend vereinfachen könnte, dass man nur mir Variablen $1 bis $4 aus der regex arbeiten kann?)
Das ist vielleicht etwas kryptisch gewesen, daher nochmal die Langform des Gedankens:
Ist es nicht so, dass die CID sowieso _nur_ dann matcht, wenn der JSON über zu der CID gehörende Topic-Tree kommt? Dann kann man das weiter vereinfachen bzw. unnötige Prüfungen vermeiden...
Würde also testweise mal mit folgendem ins Rennen gehen:
sonos/RINCON_7828CAF427B201400:.* { $EVENT =~ m,uuid.:.([^"]+)...name.:.([^"]+)...groupName.:.([^"]+)...coordinatorUuid.:.([^"]+),; $2 eq $3 ? {"grouping"=>"SINGLE"} : $1 eq $4 ? {"grouping"=>"MASTER"} : {"grouping"=>"$4"} }
So hat man gleich die Info, unter wessen Kontrolle das Teil steht ;) .

Eventuell wäre es auch (mind.) in dem $2 eq $3-Fall sinnvoll, die (eigene) uuid in "grouping" (oder ein 2. Reading) zu schreiben; hängt halt auch davon ab, was man dann mit der Info weiter anstellen will... (z.B. "set Lautstärkeänderung" auf den Master umleiten usw.?)
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