Ich habe ein JSON-File mit Wetterprognosedaten. Ich möchte daraus die Daten nach dem, im File angegebenen Timestams als Readings bekommen. Die Readings sollen den Timestamp aus dem File (Zeitpunkt, für den die Werte Vorhergesagt werden) | Parameter| Wert enthalten.
Ich bekommen beim versuch
multi(jsonPath("\$.timestamps"),property('grad_p10'))
immer diese Fehlermeldung:
warning: JsonPath filter property timestamps failure at ./FHEM/98_JsonMod.pm line 1368. in 'multi(jsonPath("\$.timestamps"),property('timestamps'))'
Wie bekomme ich die Die Daten aus meinem Json in diese Form?
Wenn Du mit multi() arbeitest, muss der jsonPath zu einem array auflösen.
Steht auch explizit in der commandref:
ZitatJsonpath expression must translate into an array of objects or values.
Außerdem ist die Syntax in Deinem multi() unvollständig, es werden drei Parameter benötigt und Du hast nur zwei angegeben.
Hallo Betateilchen,
Danke für deine Antwort, die lässt mich genauso ratlos zurück, wie davor :)
Wenn ich den jsonPath \$.timestamps in den JsonPath online Evaluuator eingebe (https://jsonpath.com/) bekomme ich ein Array der Timestamps zurückgeliefert.
Meine Frage war ja, wie muss der jsonPath aussehen, damit ich Timestamp und Values der Vorhersagen bekomme. Bzw. kann der Timestamp der Vorhersage überhaup der Timstamp im Devices sein? Ich habe bereits eine Tag lang versucht aus dem Json eine für mich sinnvolle Tabelle zu bekommen und bin daran kläglich gescheitert. Deswegen bitte ich ja auch hier um Hilfe.
Anscheinend hab ich da grundsätzliches nicht begriffen und alle Anleitungen bzw Erklärungen gehen immer von einen json Struktur aus, die "key":"Value" Paare beinhaltet und nicht so wie in meinem json keys mit einer Liste von Values, und auch nochdazu unterschiedlichen tiefen.
Um Dir helfen zu können, muss ich mir Dein Json erstmal näher anschauen. Dazu hatte ich aber gestern Abend keine Zeit und heute wird es auch noch ein bisschen dauern.
Du könntest hier aber schonmal ein konkretes Beispiel posten, wie ein reading aus Deinem Json am Ende tatsächlich aussehen soll.
Ich bin mir nicht sicher, wie es am besten ist. Ich möchte die Prognose für zwei Dinge verwenden:
1) zur grafischen Darstellung als SVG: Da möchte ich die Prognosen in meine mySQL Datenbak schreiben und benötige daher den Timestamp aus der Spalte Timestamp aus dem json, jeweils features.properties.parameters als Reading und data als Value.
2) zur Berechung der Stündlichen Erzwugung meiner PhV Anlage. Da könnte das Reading so ausshen:
timestamp_Parametername | jeweiliges dazugehörige data
($timestamp_$.$.features.properties.parameters."name" | $.features.properties.parameters."name".data
ergibt pro name 60 Readings
Wenn das jsonMod nur die Variante 2 erzeugen kann, dann kann ich die Einträge in die Datenbank, bzw das aufteilen in mehrere Dummy Devices scripten.
Ich weiss nicht was gescheiter ist, alles in einem Device zu haben oder für jeden parameter ein Dummy anlegen.
Für das, was Du machen möchtest, solltest Du das parsen besser in eine eigene Funktion in die 99_myUtils.pm verpacken.
Du möchtest ja letztendlich Werte aus mehreren im json-Input vorhandenen arrays zu einem "FHEM Datensatz" für das Logging zusammenfügen und verwenden. Dafür ist JsonMod nicht vorgesehen.
Zitat von: betateilchen am 16 November 2024, 16:45:40Für das, was Du machen möchtest, solltest Du das parsen besser in eine eigene Funktion in die 99_myUtils.pm verpacken.
Mal eben schnell aus der Hüfte geschossen - relevant sind nur die letzten 5 Zeilen.
sub wt {
my $input = '{
"reference_time": "2024-11-15T00:00+00:00",
"media_type": "application/json",
"type": "FeatureCollection",
"version": "v1",
"timestamps": [
"2024-11-15T09:00+00:00",
"2024-11-15T10:00+00:00",
"2024-11-15T11:00+00:00",
"2024-11-15T12:00+00:00",
"2024-11-15T13:00+00:00",
"2024-11-15T14:00+00:00",
"2024-11-15T15:00+00:00",
"2024-11-15T16:00+00:00",
"2024-11-15T17:00+00:00",
"2024-11-15T18:00+00:00",
"2024-11-15T19:00+00:00",
"2024-11-15T20:00+00:00",
"2024-11-15T21:00+00:00",
"2024-11-15T22:00+00:00",
"2024-11-15T23:00+00:00",
"2024-11-16T00:00+00:00",
"2024-11-16T01:00+00:00",
"2024-11-16T02:00+00:00",
"2024-11-16T03:00+00:00",
"2024-11-16T04:00+00:00",
"2024-11-16T05:00+00:00",
"2024-11-16T06:00+00:00",
"2024-11-16T07:00+00:00",
"2024-11-16T08:00+00:00",
"2024-11-16T09:00+00:00",
"2024-11-16T10:00+00:00",
"2024-11-16T11:00+00:00",
"2024-11-16T12:00+00:00",
"2024-11-16T13:00+00:00",
"2024-11-16T14:00+00:00",
"2024-11-16T15:00+00:00",
"2024-11-16T16:00+00:00",
"2024-11-16T17:00+00:00",
"2024-11-16T18:00+00:00",
"2024-11-16T19:00+00:00",
"2024-11-16T20:00+00:00",
"2024-11-16T21:00+00:00",
"2024-11-16T22:00+00:00",
"2024-11-16T23:00+00:00",
"2024-11-17T00:00+00:00",
"2024-11-17T01:00+00:00",
"2024-11-17T02:00+00:00",
"2024-11-17T03:00+00:00",
"2024-11-17T04:00+00:00",
"2024-11-17T05:00+00:00",
"2024-11-17T06:00+00:00",
"2024-11-17T07:00+00:00",
"2024-11-17T08:00+00:00",
"2024-11-17T09:00+00:00",
"2024-11-17T10:00+00:00",
"2024-11-17T11:00+00:00",
"2024-11-17T12:00+00:00"
],
"features": [
{
"type": "Feature",
"properties": {
"parameters": {
"grad_p10": {
"name": "surface global radiation (10th percentile)",
"unit": "W m-2",
"data": [
125.5,
165.1,
220.2,
116,
99.7,
47.8,
21.4,
0.4,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
31.5,
142.7,
252.5,
329.4,
359.7,
342.2,
278.2,
176.9,
62.2,
0.7,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
9.2,
44.1,
106,
199.6,
281.9,
266.4
]
},
"grad_p50": {
"name": "surface global radiation (50th percentile)",
"unit": "W m-2",
"data": [
201.7,
239.5,
282.2,
221.3,
142,
86.8,
34.4,
0.6,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
33.9,
144.6,
253.9,
330.7,
361.6,
343.9,
279.6,
178.1,
62.8,
0.8,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
12.9,
60,
143.5,
298.8,
353.1,
337
]
},
"grad_p90": {
"name": "surface global radiation (90th percentile)",
"unit": "W m-2",
"data": [
210.5,
312.5,
346.9,
312.2,
215.9,
145.7,
55.2,
0.9,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
34.1,
145.3,
254.7,
332.6,
364,
346.8,
282.2,
179.9,
63.4,
0.9,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
15.4,
75.8,
206.3,
326,
359.2,
342.1
]
}
}
}
}
]
}';
my $prognose = json2nameValue($input);
for (my $i = 1; $i <=52; $i++) {
Debug $prognose->{'timestamps_'.$i}." - ".$prognose->{'features_1_properties_parameters_grad_p10_data_'.$i};
}
}
Damit bekommst Du eine Zuordnung von timestamp zu p10_data.
Anstatt Debug() könnte man natürlich auch ein setreading erzeugen, das dann auch entsprechend gelogged würde. Oder die Daten direkt in die Datenbank loggen, ohne erst readings erzeugen zu müssen, wenn man sie wirklich nur für SVG braucht.
Zitat von: Pnemenz am 16 November 2024, 09:17:41Ich bin mir nicht sicher, wie es am besten ist. Ich möchte die Prognose für zwei Dinge verwenden:
1) zur grafischen Darstellung als SVG: Da möchte ich die Prognosen in meine mySQL Datenbak schreiben und benötige daher den Timestamp aus der Spalte Timestamp aus dem json, jeweils features.properties.parameters als Reading und data als Value.
2) zur Berechung der Stündlichen Erzwugung meiner PhV Anlage. Da könnte das Reading so ausshen:
timestamp_Parametername | jeweiliges dazugehörige data
($timestamp_$.$.features.properties.parameters."name" | $.features.properties.parameters."name".data
ergibt pro name 60 Readings
Moin,
für die PV Leistungsprognose gibt es bereits zwei Varianten, die Dir ja eventuell gefallen könnten.
1) 76_SolarForecast Modul
2) Mit einer MySQL Procedure und einem Python Skript , dass "KI" verwendet.
https://wiki.fhem.de/wiki/Kostal_Plenticore_10_Plus#Wetter-/Leistungs-Prognose
Als MySQL wird der original Oracle MySQL docker Container verwendet SQLight reicht in den meisten Fällen nicht aus.
Dort findest Du auch Links zu den verwendeten Devices.
Die stundenbasierte Aufbereitung der Prognose Daten findet in den userReadings der Devices statt.
VG Christian
ZitatDamit bekommst Du eine Zuordnung von timestamp zu p10_data.
Anstatt Debug() könnte man natürlich auch ein setreading erzeugen, das dann auch entsprechend gelogged würde. Oder die Daten direkt in die Datenbank loggen, ohne erst readings erzeugen zu müssen, wenn man sie wirklich nur für SVG braucht.
Vielen Dank, ich schau mir das mal genauer an. Hab inzwischen eine Ähnliche Lösung für myUtils geschrieben.
Als Reading in einem Dummy hab ich immer nur den letzten Wert, ist das dbLog schnell genug um alle Prognosen zu schreiben, wenn ich in einer Schleife die Readins erzeuge?
Irgendwie funktioniert der setreading aufruf
setreading GeospherePrognose "2024-11-16 23:00" t2m_p90 1.9
nicht, es wird der Timestamp nicht übernommen. Das Reading sieht dann so aus:
2024-11-16 | 23:00 t2m_p90 1.9 | 2024-11-18 18:49:23
erwarte mir dieses:
2m_p90 | 9.7 | 2024-11-16 23:00
Zitat von: ch.eick am 17 November 2024, 13:30:37Moin,
für die PV Leistungsprognose gibt es bereits zwei Varianten, die Dir ja eventuell gefallen könnten.
1) 76_SolarForecast Modul
2) Mit einer MySQL Procedure und einem Python Skript , dass "KI" verwendet.
https://wiki.fhem.de/wiki/Kostal_Plenticore_10_Plus#Wetter-/Leistungs-Prognose
Als MySQL wird der original Oracle MySQL docker Container verwendet SQLight reicht in den meisten Fällen nicht aus.
Dort findest Du auch Links zu den verwendeten Devices.
Die stundenbasierte Aufbereitung der Prognose Daten findet in den userReadings der Devices statt.
VG Christian
Soweit ich sehe werden hier Daten verwendet, die für Wien zu ungenau sind. Meine Daten stammen von der Geosphere Austria. Sowohl DWD als auch die anderen Dienste sind zu ungenau bzw liefern keine Strahlungsdaten für Wien.
DbLog ist auf jeden Fall schnell genug für Dein Vorhaben.
Du kannst Werte auch direkt in die Datenbank schreiben, ohne den Umweg über setreading gehen zu müssen.
Schau mal in der commandref zu DbLog unter "set ... addCacheLine ...":
set <name> addCacheLine YYYY-MM-DD HH:MM:SS|<device>|<type>|<event>|<reading>|<value>|[<unit>]
Zitat von: betateilchen am 18 November 2024, 19:54:46DbLog ist auf jeden Fall schnell genug für Dein Vorhaben.
Du kannst Werte auch direkt in die Datenbank schreiben, ohne den Umweg über setreading gehen zu müssen.
Schau mal in der commandref zu DbLog unter "set ... addCacheLine ...":
set <name> addCacheLine YYYY-MM-DD HH:MM:SS|<device>|<type>|<event>|<reading>|<value>|[<unit>]
Danke, werd ich mir anschauen.
zu setreading:
laut Commanmdref:
setreading <devspec> [YYYY-MM-DD HH:MM:SS] <reading> <value>
was ist dan an meinem Befehl falsch?
Zitat von: Pnemenz am 18 November 2024, 20:10:17zu setreading:
laut Commanmdref:
setreading <devspec> [YYYY-MM-DD HH:MM:SS] <reading> <value>
was ist dan an meinem Befehl falsch?
setreading GeospherePrognose "2024-11-16 23:00" t2m_p90 1.9
Fehler 1: die Sekunden fehlen in der Zeitangabe
Fehler 2: die Anführungszeichen um Deine Zeitangabe sind falsch
Es müsste also so aussehen:
setreading GeospherePrognose 2024-11-16 23:00:00 t2m_p90 1.9
Danke, alle möglichen Varianten hab ich probiert, auf die fehlenden Sekunden bin ich nicht gekommen.
Zitat von: Pnemenz am 19 November 2024, 06:39:29auf die fehlenden Sekunden bin ich nicht gekommen.
Ohne die Sekunden passt halt die regex nicht, mit der setreading prüft und erkennt, ob eine Zeitangabe mitgegeben wurde :)
Nachdem ich die Prognosen alle 12 Stunden bekomme, habe ich mit der "set ... addCacheLine ..." Methode, die super Funktioniert, Duplikate. Gibt es mit FHEM Bordmtteln eine Möglichkeit bereits vorhandene Daten zu aktualisieren? Das Kriterium wäre mEn Timestamp Device Reading ist vorhanden.
Moin
In meinem EVU_Tibber_connect Device habe ich hier mal ein Beispiel aus den userRedings mit einem SQL INSERT und ON DUPLICATE KEY UPDATE
fc_DbLog:fc0_00_total.* {
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;
for (my $loop_fc = 0; $loop_fc <= 1; $loop_fc++) {
$loop_fc_next = $loop_fc +1;
$date = ReadingsVal("$NAME","fc".$loop_fc."_00_startsAt","null");
if ($date ne "null" and $date ne "") {
$date =~ /([\d+-]+)/; $date = $1 ;
for (my $loop_hour = 0; $loop_hour <= 23; $loop_hour++) {
$hour = sprintf("%02d",$loop_hour);
$timestamp = $date." ".$hour.":00:00";
$value = ReadingsVal("$NAME","fc".$loop_fc."_".$hour."_total","null");
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking
INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)
VALUES('".$timestamp."','$NAME','Tibber','fc".$loop_fc."_total','".$value."')
ON DUPLICATE KEY UPDATE
VALUE='".$value."';") ;
}
if (ReadingsVal("$NAME","fc".$loop_fc."_00_startsAt","null") eq ReadingsVal("$NAME","fc".$loop_fc_next."_00_startsAt","null")) {
fhem("deletereading $NAME fc".$loop_fc_next."_.*");
}
} else {
fhem("deletereading $NAME fc1_.*");
}
}
ReadingsTimestamp("$NAME","fc0_00_startsAt","null");
},
Das läuft über eine Schleife mit fc readings und verwendet ein DbRep Device zum Schreiben ins DbLog. Da ich pro Device ein separates DbRep verwende wird der Name generiert.
Aber Achtung, ich verwende eine Oracle MySQL Datenbank im Docker Container, damit ich den vollen MySQL Umfang zur Verfügung habe. Bei SQLite sind Kommandos anders oder auch komplett nicht verfügbar.
Nicht mehr gültige readings werden im Device dann auch noch gelöscht, falls die forecasts nicht mehr aktuell sind. Das ist aber nur im übertragenen Sinne als Beispiel anzusehen.
VG Christian
Zitat von: Pnemenz am 19 November 2024, 21:07:30Gibt es mit FHEM Bordmtteln eine Möglichkeit bereits vorhandene Daten zu aktualisieren?
Vor dem Schreiben prüfen, ob es schon einen Wert mit dem TimeStamp gibt, wenn ja, löschen und erst dann schreiben. Geht vermutlich sowohl direkt im DbLog-device
get <name> ReadingsVal [Timestamp] <Device> <Reading> <default>
wie auch per DbRep.
Mach Dir halt mal die Mühe, die commandref zu DbLog vollständig zu lesen. Es lohnt sich.
Danke für Eure Antworten, @betateilchen: ich verwende DbLog seit 2014, anscheinend habe ich da einige Änderungen verschlafen bzw. als nicht Programmierer auch nicht komplett verstanden.
@ch.eick: danke für diesen Codeschnippsel, konnte ich für meine Bedürftnisse anpassen.
Zitat von: Pnemenz am 21 November 2024, 10:00:52ich verwende DbLog seit 2014, anscheinend habe ich da einige Änderungen verschlafen
inzwischen gibt es elektrischen Strom und Tonfilm...
ist wenigsten das Fernsehen noch schwarz-weiß und nur 2 Programme?