JsonMod Probleme mit jsonPath

Begonnen von Pnemenz, 07 Dezember 2023, 14:31:28

Vorheriges Thema - Nächstes Thema

Pnemenz

Ich versuche bei einem Json Readings zu generiern.
Das json ist eigentlich simpel:
{
   2   "result": {
   3     "2023-12-07": 5329,
   4     "2023-12-08": 12607
   5   },
   6   "message": {
   7     "code": 0,
   8     "type": "success",
   9     "text": "",
  10     "pid": "36PS4bch",
  11     "info": {
  12       "latitude": XX.XXXX,
  13       "longitude": yy.yyyy,
  14       "distance": 0.033,
  15       "place": "XYXYXYX",
  16       "timezone": "Europe/Vienna",
  17       "time": "2023-12-07T07:01:50+01:00",
  18       "time_utc": "2023-12-07T06:01:50+00:00"
  19     },
  20     "ratelimit": {
  21       "period": 3600,
  22       "limit": 12,
  23       "remaining": 0
  24     }
  25   }
  26 }
Die beiden Zeilen result hätte ich gerne als Readings "Heute" und "Morgen" (oder zumindes immer als "Tag1" und "Tag2").
Die Zeile
single(jsonPath('$.result.2023-12-07'),'Heute','N/A');funktioniert. Wenn ich result über den Index ansprechen will kommt N/A.

Ein weiterer Versuch mit Multi und erzeugen von Readings mit index(), aus den Beispielen abgeleitet, führt im Log zu der Fehlermeldung:
multi(jsonPath('$.result[*]'),index(),'N/A');Fehlermeldung:
error: Not enough arguments for index  (#1) in multi(jsonPath('$.result[*]'),index(),'N/A')
Kann mich bitte irgendwer zu eine Ressource leiten, wie man jsonPath richtig einsetzt?
Auch ein Versuch (in einem Anderen json) mit filtern, wie ich  es im Netz fad, $..book[?(@.isbn)] führt zu keinem Ergebnis :(

Vielen Dank


betateilchen

Das mit den Namen für die readings ist einfach.

defmod jsonTest JsonMod file:///tmp/test.json
attr jsonTest readingList multi(jsonPath("\$.result.[*]"),concat("Tag_",count()),"bla","n/a")

setstate jsonTest 2023-12-07 17:23:14 .computedReadings Tag_1,Tag_0
setstate jsonTest 2023-12-07 17:23:14 Tag_0 bla
setstate jsonTest 2023-12-07 17:23:14 Tag_1 bla

Aber ich komme grade nicht drauf, was ich anstatt "bla" eintragen muss, um an den richtigen Wert für das reading zu kommen.
Bin einfach zu müde nach einem anstrengenden Tag.
Aber bestimmt kommt gleich jemand, der das ergänzt  :)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Pnemenz

Danke, das mit count() ist einr gute Idee. Ich verstehe aber nicht, warum die Funktion index() nicht funktioniert, so wie in den Beispielen.

Du hast genau mein Problem auf den Punkt gebracht, wie komme ich auf die Werte ohne die Namen zu kennen? Ich kenne nur die Position.

betateilchen

Zitat von: Pnemenz am 07 Dezember 2023, 18:25:06Ich verstehe aber nicht, warum die Funktion index() nicht funktioniert, so wie in den Beispielen.

Weil index() irgendwann durch count() ersetzt wurde und die Beispiele vermutlich älter sind als die aktuelle Modulversion.

JsonMod_Logger($hash, 1, 'use of \'index()\' as item counter is depraced in \'%s%s\'. Replace with \'count\'.', $cmd, $args);
Zitat von: Pnemenz am 07 Dezember 2023, 18:25:06Du hast genau mein Problem auf den Punkt gebracht, wie komme ich auf die Werte ohne die Namen zu kennen?

Das müsste vermutlich irgendwie mit node() funktionieren, aber ich habe selbst damit noch nie gearbeitet.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

yersinia

Die Herausforderung für JsonMod ist, dass du dynamisch auf das Element zugreifen möchtest, welches du vorher nicht kennst. Da kann @herrmannj besser supporten, ob und wie das mit JsonMod funktionieren könnte.

Mit node() müsstest du auf den Knoten zugreifen können, funktioniert aber zumindest bei mir nicht. Mit
multi(jsonPath("\$.result.[*]"),node(),node());bekommst du den Pfad als Readingwert angezeigt. Wenn du diesen Pfad dann als property-Definition mitgibst, bleibt der Eintrag leer.

Vielleicht hilft dir ein simples
complete();schon weiter.

Je nach eigentlicher Json-Struktur könntest du die Daten direkt abfragen, wenn du das Datum dynamisch setzt (wenn es zB immer für gestern und heute Daten gibt):
single(jsonPath("\$.result.".mydate(-1)), mydate(-1), "n/a");
single(jsonPath("\$.result.".mydate()), mydate(), "n/a");
mit einem myUtils Code:
sub mydate {
use DateTime qw( );

my $offset = shift // 0;
if(!looks_like_number($offset)) {
$offset = 0;
}

my $dateYMD = DateTime
      ->now(time_zone => 'local')
      ->set_time_zone('floating')
      ->truncate(to => 'day')
      ->add(days => $offset)
      ->strftime('%Y-%m-%d');

return $dateYMD;
}
Wenig sinnvoll wenn die Daten historisch wachsen - und es wird im JsonMod Device nicht persistent hinterlegt, jeder refresh löscht/überschreibt alte Readings.

Oder du machst es ganz ohne JsonMod und folgst dem Ansatz von betateilchen aus diesem Thread.
viele Grüße, yersinia
----
FHEM 6.4 (SVN) on RPi 4B with RasPi OS Bookworm (perl 5.36.0) | FTUI
nanoCUL->2x868(1x ser2net)@tsculfw, 1x433@Sduino | MQTT2 | Tasmota | ESPEasy
VCCU->14xSEC-SCo, 7xCC-RT-DN, 5xLC-Bl1PBU-FM, 3xTC-IT-WM-W-EU, 1xPB-2-WM55, 1xLC-Sw1PBU-FM, 1xES-PMSw1-Pl

betateilchen

Zitat von: yersinia am 08 Dezember 2023, 09:05:58Mit node() müsstest du auf den Knoten zugreifen können, funktioniert aber zumindest bei mir nicht. Mit
multi(jsonPath("\$.result.[*]"),node(),node());bekommst du den Pfad als Readingwert angezeigt. Wenn du diesen Pfad dann als property-Definition mitgibst, bleibt der Eintrag leer.

Genau das ist das Problem, das ich gestern mit node() meinte und der Effekt, dass der Zugriff auf den Wert des node-Elements nicht funktioniert, hat mich gestern zwei Stunden beschäftigt.

Das complete() liefert zwar die readings, man weiß aber trotzdem nicht, welchen Namen das reading am Ende haben wird, weil er dynamisch erzeugt wird.

Vielleicht kann Jörg dazu mal ein funktionierende Beispiel bauen, wenn er diesen Thread irgendwann entdeckt.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Pnemenz

Zitat von: yersinia am 08 Dezember 2023, 09:05:58Mit node() müsstest du auf den Knoten zugreifen können, funktioniert aber zumindest bei mir nicht. Mit
multi(jsonPath("\$.result.[*]"),node(),node());bekommst du den Pfad als Readingwert angezeigt. Wenn du diesen Pfad dann als property-Definition mitgibst, bleibt der Eintrag leer.
Genau das war auch mein Ergebnis.

Zitat von: yersinia am 08 Dezember 2023, 09:05:58Vielleicht hilft dir ein simples
complete();schon weiter.
Leider nein, da ich immer die Vorhersage für den aktuellen Tag und den Nächsten benötige.

Zitat von: yersinia am 08 Dezember 2023, 09:05:58Je nach eigentlicher Json-Struktur könntest du die Daten direkt abfragen, wenn du das Datum dynamisch setzt (wenn es zB immer für gestern und heute Daten gibt):
single(jsonPath("\$.result.".mydate(-1)), mydate(-1), "n/a");
single(jsonPath("\$.result.".mydate()), mydate(), "n/a");
mit einem myUtils Code:
sub mydate {
    use DateTime qw( );
   
    my $offset = shift // 0;
    if(!looks_like_number($offset)) {
        $offset = 0;
    }
   
    my $dateYMD = DateTime
                      ->now(time_zone => 'local')
                      ->set_time_zone('floating')
                      ->truncate(to => 'day')
                      ->add(days => $offset)
                      ->strftime('%Y-%m-%d');

    return $dateYMD;
}

Wenig sinnvoll wenn die Daten historisch wachsen - und es wird im JsonMod Device nicht persistent hinterlegt, jeder refresh löscht/überschreibt alte Readings.

Danke, das ist eine sehr gute Idee. Funktioniert in diesem Fall gut. Da bekomme ich die Summenprognose für den aktuellen Tag und den Darauffolgenden. Das die Werte bei jeder Abfrage überschrieben werden ist für meine Einsatzzwecke unerheblich. Falls ich die Daten historisch brauche, kann ich sie ja noch immer mitloggen.
Schaut bei mir jetzt so aus:
single(jsonPath("\$.result.".mydate()),"Heute",'N/A');
single(jsonPath("\$.result.".mydate(+1)), "Morgen", "N/A");

Etwas kompliziert wird es aber, wenn ich die Stundenprognosen abfrage, da das result immer mit der Stunde nach Sonnenaufgang beginnt und sich das im laufe des Jahres deutlich ändert :)
Da brauche ich dann die erste node um die Stunde der ersten Prognose zu kennen und ich muss im pfad suchen, wann der zweite Tag begint. Dann kann ich die stündliche Prognose für zwei Tage auswerten.


betateilchen

Zitat von: Pnemenz am 08 Dezember 2023, 16:52:31
Zitat von: yersinia am 08 Dezember 2023, 09:05:58Vielleicht hilft dir ein simples
complete();schon weiter.
Leider nein, da ich immer die Vorhersage für den aktuellen Tag und den Nächsten benötige.

Naja, das mit complete() geht schon, es gibt ja auch noch userReadings...

defmod jtest JsonMod file:///tmp/test2.json
attr jtest readingList complete();;
attr jtest userReadings today:result.* {ReadingsVal('jtest',strftime("result.%Y-%m-%d",localtime()),'n/a')},\
tomorrow:result.* {ReadingsVal('jtest',strftime("result.%Y-%m-%d",localtime(time()+DAYSECONDS)),'n/a')}
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!