Hallo,
ich habe ein HTTPMOD mit einem Radingsval und einem Regex erstellt, und möchte gerne jeweils nur den eigentlichen Wert erhalten, hier erstmal meine Eingangsdaten und der dazugehörige Regex:
https://regex101.com/r/mikSud/1
Im Prinzip habe ich eine über den Tag anwachsende Liste mit Werten, von denen mich immer der letzte Wert in der langen Liste interessiert. Die Werte kommen von einem Webserver, so sieht mein HTTPMOD-Device aus:
define SolarCurrentString1 HTTPMOD http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&StartDate=13.7.2022&EndDate=13.7.2022&&Channel=Current_DC_String_1
setuuid SolarCurrentString1 62cd6d32-f33f-6bf2-0dd8-2907fdb6e31d646a
attr SolarCurrentString1 devStateStyle style="text-align:right"
attr SolarCurrentString1 event-min-interval 180
attr SolarCurrentString1 icon solar_icon
attr SolarCurrentString1 reading1Name CurrentString1
attr SolarCurrentString1 reading1Regex (00" : )(?!(?s:.*)(00" : ))(.*)
attr SolarCurrentString1 room Hauswirtschaftsraum
Aus dem reading1Name macht FHEM dann sowas hier:
Readings
CurrentString1
1
2022-07-12 14:34:59
CurrentString1-1
00" :
2022-07-13 06:34:20
CurrentString1-2
"81000" : 0
2022-07-13 06:23:39
CurrentString1-3
0.29999999999999999
2022-07-13 06:34:20
CurrentString1-4
2022-07-13 06:23:39
Frage, warum so viele Matches, und wie stelle ich sicher dass ich hier immer nur den Wert erhalte, also im Prinzip nur das was in CurrentString1-3 steht (0.29999999999999999).
An den Timestamps sieht man außerdem, dass "ältere" Werte des Readings durch Experimente gar nicht mehr abgelöscht werden. Wie verhindere ich dieses Verhalten?
Danke für alle Tipps!
@Jackie
Ein gespeicherter Fall ist schon mal nicht schlecht - schade nur, dass die Schilderung nicht dazu passt ... 0.29999999999999999 z.B. gibt es nicht ...
Was wäre denn beim gespeicherten Fall der "gewünschte" Wert ? ... 6 ?
Der zu verarbeitende String sieht immer so aus und enthält mindestens ein key/value-Paar ?
@OdfFhem: es ist Json (https://forum.fhem.de/index.php/topic,113850.msg1227768.html#msg1227768) (Fronius Thread)...und es gibt noch einen Thread bezgl URL replace (https://forum.fhem.de/index.php/topic,128376.0.html).
Hallo zusammen,
sorry für die Verwirrung, ja in dem Regex-Sample wäre dann 6 der gewünschte Wert.
Ich poste mal das komplette JSON, vielleicht ist hier das Parsen des JSON der bessere Ansatz, aber auch hier habe ich noch nicht den gewünschten Erfolg. Erstmal das komplette JSON:
{
"Body" :
{
"Data" :
{
"inverter/1" :
{
"Data" :
{
"Current_DC_String_1" :
{
"Unit" : "A",
"Values" :
{
"17400" : 0,
"17700" : 0,
"18000" : 0,
"18300" : 0,
"18600" : 0,
"18900" : 0,
"19200" : 0,
"19500" : 0,
"19800" : 0,
"20100" : 0,
"20400" : 0,
"20700" : 0.050000000000000003,
"21000" : 0.070000000000000007,
"21300" : 0.089999999999999997,
"21600" : 0.13,
"21900" : 0.16,
"22200" : 0.19,
"22500" : 0.22,
"22800" : 0.25,
"23100" : 0.27000000000000002,
"23400" : 0.29999999999999999,
"23700" : 0.32000000000000001,
"24000" : 0.34000000000000002,
"24300" : 0.35999999999999999,
"24600" : 0.38,
"24900" : 0.40000000000000002,
"25200" : 0.41000000000000003,
"25500" : 0.42999999999999999,
"25800" : 0.45000000000000001,
"26100" : 0.46000000000000002,
"26400" : 0.47999999999999998,
"26700" : 0.48999999999999999,
"27000" : 0.5,
"27300" : 0.51000000000000001,
"27600" : 0.52000000000000002,
"27900" : 0.52000000000000002,
"28200" : 0.53000000000000003,
"28500" : 0.53000000000000003,
"28800" : 0.54000000000000004,
"29100" : 0.55000000000000004,
"29400" : 0.56000000000000005,
"29700" : 0.56000000000000005,
"30000" : 0.57000000000000006,
"30300" : 0.58999999999999997,
"30600" : 0.60999999999999999,
"30900" : 0.63,
"31200" : 0.68000000000000005,
"31500" : 0.83000000000000007,
"31800" : 1.1100000000000001,
"32100" : 1.21,
"32400" : 1.3700000000000001,
"32700" : 1.8200000000000001,
"33000" : 2.21,
"33300" : 2.4700000000000002,
"33600" : 2.8900000000000001,
"33900" : 3,
"34200" : 2.8500000000000001,
"34500" : 2.7600000000000002
},
"_comment" : "channelId=66050"
}
},
"DeviceType" : 232,
"End" : "2022-07-13T23:59:59+02:00",
"NodeType" : 97,
"Start" : "2022-07-13T00:00:00+02:00"
}
}
},
"Head" :
{
"RequestArguments" :
{
"Channel" :
[
"Current_DC_String_1"
],
"EndDate" : "2022-07-13T23:59:59+02:00",
"HumanReadable" : "True",
"Scope" : "System",
"SeriesType" : "Detail",
"StartDate" : "2022-07-13T00:00:00+02:00"
},
"Status" :
{
"Code" : 0,
"ErrorDetail" :
{
"Nodes" : []
},
"Reason" : "",
"UserMessage" : ""
},
"Timestamp" : "2022-07-13T09:37:48+02:00"
}
}
Was ich extrahieren will ist der Wert hinter dem letzten "<StringX>" : Wert, in diesem Beispiel also der Wert 2.7600000000000002.
Mein "naiver" Ansatz war jetzt, dass ich zumindest mal den ganzen "Values" Baum bekommen kann, wie auch immer ich dann da auf das letzte Element komme. Aber folgender Ansatz funktioniert schonmal nicht:
attr SolarCurrentString1 reading2Name CurrentStringJSON
attr SolarCurrentString1 reading2JSON Body.Data.inverter/1.Data.Current_DC_String_1.Values
Aber diese Syntax scheint noch fehlerhaft zu sein. Was ist denn der vorgesehene Weg sich durch den JSON-Baum zu hangeln? Und wie komme ich dann in der Values-Liste an den letzten Eintrag?
Laut https://jsonpath.herokuapp.com/ ist der JSON-Ausdruck gültig und liefert eigentlich schonmal die Liste der Values-Strings zurück. In fhem jedoch wird nicht einmal das Reading erzeugt.
Edit:
Die JSON.Abfrage scheint zu funktionieren, es wird mir jetzt eine Liste mit 69 einzelnen Readings angelegt. Die Frage ist nun: wie bekomme ich hier jetzt immer nur das letzte geliefert? Siehe auch Screenshot anbei, danke.
Vielen Dank!
JsonMod bietet sich für solch einfache Aufgaben an:
defmod jm_Demo JsonMod file:/bla.txt
attr jm_Demo readingList single(jsonPath('$.Body.Data.inverter/1.Data.Current_DC_String_1.Values.34500'),'Wert','nA')
setstate jm_Demo 2022-07-13 10:51:04 .computedReadings Wert
setstate jm_Demo 2022-07-13 10:51:04 Wert 2.76
Hallo TomLee,
Zitat:
attr jm_Demo readingList single(jsonPath('$.Body.Data.inverter/1.Data.Current_DC_String_1.Values.34500'),'Wert','nA')
das Problem hier ist, dass du den Property Name 34500 fest vorgibst, damit tut es bei mir auch. Das JSOn wächst aber, und der Property Name ist aufsteigend, aber letztlich unbekannt. Was ich brauche ist ein weg, immer das letzte Property dieser wachsenden "Values"-Liste (die ja in dem Sinn keine Liste ist...) zu bekommen.
Im Prinzip macht FHEM ja schon was sehr intelligentes, nämlich es erzeugt eine Liste von einzelnen Readings (siehe Screenshot aus meinem vorherigen Post), was jetzt noch fehlt ist ein MEchanismus jeweils nut das Letzte zu generieren und den Rest zu verwerfen.
Schau dir doch mal die Werte an. Du sagst ja selbst, dass es Sekunden seit Mitternacht sind. Und zwar alle 300 Sekunden kommt ein neuer Wert hinzu. Um diesen letzten Werk zu finden brauchst du eine Funktion welche dir a) die Sekunden seit Mitternacht und b) den letzten ganzen Wert teilbar durch 300 errechnet. Mit mathematischen Basics und Forumssuche findet man den vor kurzem geteilten Code von betateilchen:
Zitat von: betateilchen am 06 Juli 2022, 19:28:44die Funktion secondsFromMidnight() kann problemlos in der 99_myUtils.pm untergebracht werden:
sub secondsFromMidnight{
my @time = localtime();
return (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
}
Das ganze ergänzt du um eine Modulo Funktion um die Differenz zum nächsten durch 300 ganzzahlig teilbaren Wert (also der Rest) zu finden.
sub secondsFromMidnight {
my @time = localtime();
my $seconds = (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
$seconds = $seconds - ($seconds % 300);
return $seconds;
}
Dies Funktion packst du in deine myUtils (https://wiki.fhem.de/wiki/99_myUtils_anlegen).
Dann kannst du dies über JsonMod auslesen in dem die Funktion im readingsList aufrust:
defmod jm_Demo JsonMod http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&StartDate=13.7.2022&EndDate=13.7.2022&&Channel=Current_DC_String_1
attr jm_Demo interval */5 * * * *
attr jm_Demo readingList single(jsonPath('$.Body.Data.inverter/1.Data.Current_DC_String_1.Values.'.secondsFromMidnight()),'Wert','nA');;
attr jm_Demo webCmd reread
Das ist kein FHEM ,,Problem", sondern simpler perl Code.
Das letzte Element eines array bekommt man über den Index -1
Ich mach mal Popcorn...
300 Sekunden sind 5 Minuten. JsonMod arbeitet mit einer cron-Syntax für die Intervalle. Errechnete Zeiten stehen in Internals. Einfacher geht es doch nicht?
Zitat von: betateilchen am 13 Juli 2022, 11:44:52Das letzte Element eines array bekommt man über den Index -1
Aber dies kann JsonMod derzeit nicht (https://forum.fhem.de/index.php/topic,111489.0.html).
Weiterhin kann JsonMod die URL nicht so ohne weiteres zur Laufzeit ändern. Der TE muss dafür sorgen, dass, sollte er sich für JsonMod entscheiden, um Mitternacht das Datum in der URL wechseln muss.
Zitat von: betateilchen am 13 Juli 2022, 11:47:21Errechnete Zeiten stehen in Internals. Einfacher geht es doch nicht?
Mmh, ich seh keine verwendbaren Zeiten in den Internals - möglicherweise übersehe ich was. Und man kann (derzeit) nicht davon ausgehen, dass a) die Zeiten synchron zur Quelle sind und b) das Interval des JsonMod Devices bei 5 Minuten sein wird.
Danke für eure Vorschläge. @yersinia: der Ansatz von dir, den Timestamp zu errechnen ist gut, das wäre auch mein Woraround gewesen, für mich war es halt logischer (und auch robuster) immer den letzten Wert zu nehmen. Aber wie schon geschrieben wurde ist das mit den Arrays derzeit nicht, oder besser gesagt, fehlerhaft implementiert. Folgenden Aufruf habe ich getestet:
attr SolarCurrentString1 reading2JSON Body.Data.inverter/1.Data.Current_DC_String_1.Values.*[-1:]
Neu ist der Teil .*[-1:], der .* konvertiert das Ganze in ein Array, und über den Index -1: müsste das letzte Element zurückgegeben werden.
Die Liste and Readings wird dadurch auch tatsächlich kleiner, nämlich von zuvor 69 sind nun nur noch 27 generierte Readings da.
So gesehen nutze ich dann entweder den Ansatz und errechne die Sekunden seit Mitternacht, oder ich versuche den ursprünglichen Regex-Ansatz auszubauen, denn dieser liefert ja schon den passenden (letzten) Wert, nur eliminiert der eben derzeit noch nicht den vorherigen Match. Im Anhang ein Screenshot wie das gerade bei mir aussieht... (in CurrentStringDC-3 steht der derzeit korrekte Wert...)
Im Prinip über Capture groups wie hier beschrieben:
https://wiki.fhem.de/wiki/HTTPMOD#Regular_Expressions_with_multiple_capture_Groups
Nur ohne die überflüssigen Readings, also so dass im Regex direkt die richtige Capute-Group abgefragt wird, ohne für den Rest ebenfalls Readings zu erzeugen.
Erstens keine Screenshots schicken sondern immer ein list des Devices.
Zweitens bring JsonMod und HTTPMOD nicht durcheinander - verschiedene Module, Funktionen, Herangehensweise. Meine Aussage zu 'das funktioniert noch nicht' bezieht sich auf JsonMod.
Drittens nutze code tags für code.
Viertens: das ist HTTPMOD
attr SolarCurrentString1 reading2JSON Body.Data.inverter/1.Data.Current_DC_String_1.Values.*[-1:]
Und imho ist der *[-1:] eine RegEx Auswertung und gibt dir nicht das letzte Array Element wieder. Zudem ist es mAn auch kein Array unter dem Knoten Values - sondern 'normales' JSON mit Objekt:Wert. Das würde auch die erzeugten Readings erklären.
Wie sieht das JSON eigentlich aus, wenn du nicht auf Datum einschränkst?
http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&Channel=Current_DC_String_1
Hast du die Möglichkeiten andere Quellen/Formate zu nutzen?
Hallo yersinia,
vielen Dank für die Antwort, leider gibt es keine (bekannten) anderen Datenquellen für den Fronius Wechselrichter.
Ich habe inzwischen einen Workaround, der funktioniert, und der sieht so aus:
define SolarCurrentString1 HTTPMOD http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&StartDate=%%date%%&EndDate=%%date%%&&Channel=Current_DC_String_1 60
setuuid SolarCurrentString1 62ce636f-f33f-6bf2-71f8-5809dd0a2bd6ee30
attr SolarCurrentString1 devStateStyle style="text-align:right"
attr SolarCurrentString1 event-min-interval 60
attr SolarCurrentString1 icon solar_icon
attr SolarCurrentString1 reading1-1Name Helper01
attr SolarCurrentString1 reading1-2Name Helper02
attr SolarCurrentString1 reading1-3Name String1DCCurrent
attr SolarCurrentString1 reading1-4Name Helper04
attr SolarCurrentString1 reading1Name CurrentStringDC
attr SolarCurrentString1 reading1Regex (00" : )(?!(?s:.*)(00" : ))(.*)
attr SolarCurrentString1 room Hauswirtschaftsraum
Das ist zwar nicht schön, aber in String1DCCurrent steht jetzt immer der richtige Wert.
Nun ergibt sich ein weiteres Problem, denn ich benötige noch ein weiteres HTTPMOD-Device, da es einen zweiten String gibt (derzeit wird nur String 1 ausgelesen, in einem weiteren HTTPMOD wird String 2 ausgelesen). Im Prinzip eine Kopie des bestehenden HTTPMOD, nur überall (grob gesagt) wo bisher eine 1 steht im Aufruf steht jetzt eine 2:
define SolarCurrentString2 HTTPMOD http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&StartDate=%%date%%&EndDate=%%date%%&&Channel=Current_DC_String_2 60
attr SolarCurrentString2 devStateStyle style="text-align:right"
attr SolarCurrentString2 event-min-interval 60
attr SolarCurrentString2 icon solar_icon
attr SolarCurrentString2 reading1-1Name Helper01
attr SolarCurrentString2 reading1-2Name Helper02
attr SolarCurrentString2 reading1-3Name String2DCCurrent
attr SolarCurrentString2 reading1-4Name Helper04
attr SolarCurrentString2 reading1Name CurrentStringDC
attr SolarCurrentString2 reading1Regex (00" : )(?!(?s:.*)(00" : ))(.*)
attr SolarCurrentString2 room Hauswirtschaftsraum
attr SolarCurrentString2 stateFormat String2DCCurrent
attr SolarCurrentString2 replacement02Mode expression
attr SolarCurrentString2 replacement02Regex %%date%%
attr SolarCurrentString2 replacement02Value POSIX::strftime("%d.%m.%Y", localtime(time));;
Einzeln funktionieren beide HTTPMODs. Wenn ich beide in einer fhem.cfg definiere, funktioniert keines von beiden mehr. Ideen warum das so ist? Vielen Dank!
attr SolarCurrentString1 stateFormat String1DCCurrent
attr SolarCurrentString1 replacement02Mode expression
attr SolarCurrentString1 replacement02Regex %%date%%
attr SolarCurrentString1 replacement02Value POSIX::strftime("%d.%m.%Y", localtime(time));;
eventuell die requests entzerren mit attr aligntime.
2 get abfragen in einem httpmod geht übrigens auch. ;)
Zitat von: Jackie am 13 Juli 2022, 13:46:40Wenn ich beide in einer fhem.cfg definiere, funktioniert keines von beiden mehr. Ideen warum das so ist? Vielen Dank!
Du editierst doch nicht direkt in der fhem.cfg!? :o
Ansonsten spricht FHEM-seitig nichts gegen zwei HTTPMOD-Devices. Das RegEx ist schon ganz gut, ließe sich aber noch optimieren damit es nur eine Capturing group gibt. Möglicherweise stört sich der Wechselrichter über die zwei gleichzeitigen Verbindungen von einem client. Anbei mit alignTime von 00:01 und 00:02 für einen Versatz von einer Minute - und dem Interval von 300 (Sekunden), häufiger Abfragen lohnt nicht bei fünf-minütigen Werten.
define SolarCurrentString1 HTTPMOD http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&StartDate=%%date%%&EndDate=%%date%%&&Channel=Current_DC_String_1 300
attr SolarCurrentString1 devStateStyle style="text-align:right"
attr SolarCurrentString1 icon solar_icon
attr SolarCurrentString1 reading01Name String1DCCurrent
attr SolarCurrentString1 reading01Regex 00" : (?!(?s:.*)00" : )(.*)
attr SolarCurrentString1 room Hauswirtschaftsraum
attr SolarCurrentString1 stateFormat String1DCCurrent
attr SolarCurrentString1 replacement02Mode expression
attr SolarCurrentString1 replacement02Regex %%date%%
attr SolarCurrentString1 replacement02Value POSIX::strftime("%d.%m.%Y", localtime(time));;
attr SolarCurrentString1 alignTime 00:01
attr SolarCurrentString1 webCmd reread
define SolarCurrentString2 HTTPMOD http://192.168.178.105/solar_api/v1/GetArchiveData.cgi?Scope=System&StartDate=%%date%%&EndDate=%%date%%&&Channel=Current_DC_String_2 300
attr SolarCurrentString2 devStateStyle style="text-align:right"
attr SolarCurrentString2 icon solar_icon
attr SolarCurrentString2 reading01Name String2DCCurrent
attr SolarCurrentString2 reading01Regex 00" : (?!(?s:.*)00" : )(.*)
attr SolarCurrentString2 room Hauswirtschaftsraum
attr SolarCurrentString2 stateFormat String2DCCurrent
attr SolarCurrentString2 replacement02Mode expression
attr SolarCurrentString2 replacement02Regex %%date%%
attr SolarCurrentString2 replacement02Value POSIX::strftime("%d.%m.%Y", localtime(time));;
attr SolarCurrentString2 alignTime 00:02
attr SolarCurrentString2 webCmd reread
Vlt hat sich deine Mühe gerade auch erledigt:
Zitat von: michael.winkler am 13 Juli 2022, 13:57:58
Auf Seite 1 gibt es eine neue Version:
# 2022.07.13 v0.0.7
# - BUG: Doppelte Verwendung des Moduls z.B. 2x Fronius Wechselrichter
# - CHANGE: Keepalive = 0
# - FEATURE: MPPT1 & MPPT2 aus den Archivdaten
#
Habe seit dieser Woche einen weiteren Fronius WR am laufen. Dabei ist mir aufgefallen, dass das Modul mit beiden gleichzeitig nicht umgehen konnte. Zusätzlich habe ich die weiteren Anforderungen von Euch eingebaut.
Besteht Interesse folgende Infos noch mit einzubauen?
http://<IP WR>/components/readable
[98_Fronius.pm] Fronius API Modul (https://forum.fhem.de/index.php/topic,113850.0.html)
Hallo yersinia,
ja, umsonst war der Aufwand nicht, denn ich hab jetzt zum einen eine Lösung die funktioniert und habe dabei einiges gelernt, zum anderen werfe ich die jetzt weg und nutze die wesentlich bessere Implementierung von michael.winkler :-) Daher danke für die super Hile!
Finde ich übrigens interessant, er holt nur die letzten 5 Minuten (Starttime und Endtime) ab, damit hat er immer nur den letzten Eintrag in seinem JSON, hätte man auch drauf kommen können, somit nochmal eine Anregung für späetere Projekte...