Hi, ich habe ein Verständnisproblem bei Kalkulationen, die in userReadings bei mir stattfinden.
Problemstellung:
Ich habe eine Solaranlage mit 2 Panels laufen, die im FHEM mittels HTTPMOD eingebunden ist.
FHEM fragt zyklisch Werte von dem Inverter ab.
Übertragung und Anzeige in Form von userReadings finktioniert alles - scheinbar problemlos.
Bei der Anzeige der bis dato (am Tag) erzeugten Energie werden die userReadings e1 und e2 befüllt.
Sobald diese userReadings (e1 und e2) befüllt werden schreibe ich dieselben Werte noch in
zwei zusätzliche userReadings energy_Panel_1 und energy_Panel_2
Das erfolgt auf Grund der definition im Attribut userReadings:
energy_Panel_1:e.* monotonic { ReadingsNum($name, "e1", 0)},
energy_Panel_2:e.* monotonic { ReadingsNum($name, "e2", 0)},
Meine Erwartung wäre, das die Werte von e1 denen von energy_Panel_1 entsprechen müssten und
analog die Werte von e2 den werten von energy_Panel_2
Das ist aber nicht der Fall, wie auf dem Bild im Anhang zu sehen.
Woran liegt das ? Rührt das von der Verwendung von monotonic her ?
Was ich auch nicht verstehe:
Wenn ich den Trigger für das Befüllen des userReadings energy_Panel_2:e.* monoto... auf e1 oder e2 ändere wird das userReadings überhaupt nicht aktualisiert.
Nach meinem Verständnis müsste das doch aber.
Verständnisfrage: Warum geht das nicht und es muss eine "Wildcard" angegeben werden?
Zitat von: Spook112 am 18 März 2025, 12:37:53Verständnisfrage: Warum geht das nicht und es muss eine "Wildcard" angegeben werden?
Es würde schon helfen, eine korrekte regexp im userReading anzugeben, damit "energy_Panel_2" wirklich nur dann aktualisiert wird, wenn "e2" sich ändert. Aktuell werden beide userReadings sowohl bei Änderungen an e1 e2 ... e(n) aktualisiert, weil "e.*" quasi ein Wildcard ist und in beiden userReadings verwendet wird.
Wozu brauchst Du monotonic, wenn Du ohnehin nur den gleichen Wert übertragen möchtest?
Vielleicht liefert ja das hier das Ergebnis, das Du erwartest?
energy_Panel_1:e1.* {ReadingsNum($name, "e1", 0)},
energy_Panel_2:e2.* {ReadingsNum($name, "e2", 0)},
Danke für den Tipp.
Werde ich morgen ausprobieren, da im Moment keine Sonne scheint :-)
Trotzdem noch mal die Frage: Warum geht es mit e1 nicht sondern nur mit e.* oder e1.* und analog mit e2 nicht sondern nur mit e2.* ?
e.* sagt doch auch nichts anderes aus als e1 und e2 und e3 etc.
Und zu der Frage wozu ich monotonic benötige.
Aus mir unerklärlichen Gründen setzt FHEM den Wert für e1 und e2 auf 0 wenn keine Werte mehr geliefert werden, wenn die Sonne nicht mehr scheint.
Ich will aber auch abends noch sehen, was tagsüber an Energie produziert worden ist. Deshalb monotonic - da bleibt der letzte, höchste Wert dann stehen.
Zitat von: Spook112 am 19 März 2025, 00:53:07Trotzdem noch mal die Frage: Warum geht es mit e1 nicht sondern nur mit e.* oder e1.* und analog mit e2 nicht sondern nur mit e2.* ?
Es geht nicht darum, dass es mit e.* NICHT geht, sondern dass es ZU OFT geht. Du überschreibst mit e.* immer alle userReadings und nicht nur das eine, bei dem sich der Wert gerade geändert hat.
Und e1 ist etwas anderes als e1.* weil die Angabe e1 als regex von FHEM als ^e1$ verwendet wird. Deshalb passt diese regexp nicht, wenn nach e1 noch etwas weiteres im Event steht (der Zahlenwert...)
Zitat von: Spook112 am 19 März 2025, 00:53:07e.* sagt doch auch nichts anderes aus als e1 und e2 und e3 etc.
Doch, es sagt schon was anderes aus. Ich hoffe, das wurde jetzt durch meine Erklärungen verständlich.
Zitat von: Spook112 am 19 März 2025, 00:53:07Und zu der Frage wozu ich monotonic benötige.
Aus mir unerklärlichen Gründen setzt FHEM den Wert für e1 und e2 auf 0 wenn keine Werte mehr geliefert werden, wenn die Sonne nicht mehr scheint.
Was ist denn daran unerklärlich? Was steht denn auf der mit HTTPMOD gelesenen Seite, wenn keine Werte mehr geliefert werden?
Zitat von: Spook112 am 19 März 2025, 00:53:07Ich will aber auch abends noch sehen, was tagsüber an Energie produziert worden ist. Deshalb monotonic - da bleibt der letzte, höchste Wert dann stehen.
Das kannst Du auch einfach dadurch lösen, dass Du im userReading den Wert nur dann schreibst, wenn er auch wirklich sinnvoll ist. Das kann man z.B. so machen:
energy_Panel_1:e1.* {ReadingsNum($name, "e1", 0) ? ReadingsNum($name, "e1", 0) : undef},
Bei einem Rückgabewert "undef" wird ein userReading nicht verändert.
Danke sehr schön erklärt.
Das mit den regEx habe ich verstanden.
ZitatWas ist denn daran unerklärlich? Was steht denn auf der mit HTTPMOD gelesenen Seite, wenn keine Werte mehr geliefert werden?
Muss ich heute Abend mal ausprobieren.
Ich meine dann wird gar nichts geliefert, da der Inverter dann nicht mehr erreichbar ist.
Zu dem Codebeispiel - das geht m.E. nicht so einfach, da die userReadings e1 und e2 (und andere) über Attribute definiert werden.
Nachdem ich blauäugig da einfach :undef hinten angefügt habe ist nun ein neues userReading e1:undef entstanden, was ich bis jetzt auch nicht löschen konnte.
Fehlermeldung: Bad older-than-seconds format undef
Hast Du einen Vorschlag wie ich das :undef in diesem Falle richtig nutzen/einbauen/verwenden kann ?
Im Anhang mal ein Screenshot was jetzt bei Sonnenschein zurückgeliefert wird.
Es geht nicht darum, einfach ":undef" irgendwo anzuhängen, sondern darum, die von mir vorgegebene Syntax in dem perl-Konstrukt für das userReading zu beachten und zu verwenden.
Da hast Du natürlich recht.
Es war ein, zugegebenermaßen nicht sehr aussichtsreicher, Versuch.
Zurück zu Deiner Frage - Was steht denn auf der mit HTTPMOD gelesenen Seite, wenn keine Werte mehr geliefert werden?
The connection has timed out
The server at nnn.nnn.nnn.nnn is taking too long to respond.
Hatte ich schon vermutet, denn der Inverter schaltet sich ab, wenn kein Sonnenlicht mehr Strom erzeugt.
Wie HTTPMOD mit dem Ergebnis des Aufrufs der URL http://nnn.nnn.nnn.nnn:8050/getOutputData dann bzw. generell im Detail umgeht weiss ich leider auch nicht.
Die aufzurufenden URLs und die zu befüllenden userReadings sind wie schon geschrieben über Attribute definiert.:
Attributes
alias Solaranlage auf dem Gartenhaus deleteattr
event-on-change-reading .* deleteattr
get1JSON data_maxPower deleteattr
get1Name MaxPower deleteattr
get1Poll 1 deleteattr
get1URL http://nnn.nnn.nnn.nnn:8050/getMaxPower deleteattr
get2Name OutputData deleteattr
get2Poll 1 deleteattr
get2URL http://nnn.nnn.nnn.nnn:8050/getOutputData deleteattr
get3Name Alarm deleteattr
get3Poll 1 deleteattr
get3URL http://nnn.nnn.nnn.nnn:8050/getAlarm deleteattr
get4Name Disabled deleteattr
get4Poll 1 deleteattr
get4URL http://nnn.nnn.nnn.nnn:8050/getOnOff deleteattr
get5Name DeviceInfo deleteattr
get5Poll 1 deleteattr
get5PollDelay 3600 deleteattr
get5URL http://nnn.nnn.nnn.nnn:8050/getDeviceInfo deleteattr
group Solaranlage deleteattr
icon measure_photovoltaic_inst deleteattr
oldreadings total_power deleteattr
reading101JSON data_maxPower deleteattr
reading101Name MaxPower deleteattr
reading201JSON data_e1 deleteattr
reading201Name e1 deleteattr
reading202JSON data_e2 deleteattr
reading202Name e2 deleteattr
reading203JSON data_te1 deleteattr
reading203Name te1 deleteattr
reading204JSON data_te2 deleteattr
reading204Name te2 deleteattr
reading205JSON data_p1 deleteattr
reading205Name Panel_1 deleteattr
reading206JSON data_p2 deleteattr
reading206Name Panel_2 deleteattr
Die get Befehle hohlen mit den dort angegebenen URLs die jeweiligen JSON Dateien, in denen dann die benötigten Informationen stehen.
Wie FHEM dann "im Hintergrund" diese Informationen in die weiter unten definierten userReadings schreibt und wo auf dem Weg der richtige Ansatzpunkt wäre das :undef einzubauen weiss ich aber beim besten Willen nicht.
Hast Du/jemand dazu Ideen?
Zitat von: Spook112 am 19 März 2025, 23:26:55Die get Befehle hohlen mit den dort angegebenen URLs die jeweiligen JSON Dateien, in denen dann die benötigten Informationen stehen.
Wie FHEM dann "im Hintergrund" diese Informationen in die weiter unten definierten userReadings schreibt und wo auf dem Weg der richtige Ansatzpunkt wäre das :undef einzubauen weiss ich aber beim besten Willen nicht.
Das undef kommt doch nicht in die Attribute der originären readings, sondern müssen im Attribut userReadings angegeben werden.
Und nochmal ganz klar gesagt: es geht nicht um :undef! Der Doppelpunkt ist Teil der verwendeten Syntax im perl Code, der für die userReadings verwendet wird.
Das hier:
energy_Panel_1:e1.* {ReadingsNum($name, "e1", 0) ? ReadingsNum($name, "e1", 0) : undef},
muss in das Attribut userReadings, um beispielsweise das reading energy_Panel_1 zu erzeugen.
Erneut danke für die Erklärungen.
Dort, im Attribut userReadungs habe ich es eingetragen und es funktioniert wie gewünscht.
Zugegebenermaßen habe ich den Perl-Ausdruck trotzdem noch nicht richtig verstanden:
energy_Panel_1:e1.* {ReadingsNum($name, "e1", 0) ? ReadingsNum($name, "e1", 0) : undef},
Was klar ist: - energy_Panel_1 ist der Name des userReadings, welches befüllt werden soll
- :e1.* nach dem Doppelpunkt kommt der Trigger/das Event, der/das das Auswerten oder Lesen der Daten veranlasst, die in das userReadings geschrieben werden sollen
- in den {} kommt das eigentliche Perl Statement, ReadingsNum liest einen numerischen Wert aus dem Reading e1 in diesem Device und wenn es keinen Wert findet wird defaultmäßig der Wert 0 genommen
Und dann kommt die spannende Frage: was bewirkt das ? und der Teil ReadingsNum($name, "e1", 0) : undef
danach?
Ich bin kein Perl Programmierer, aber was ich meine verstanden zu haben ist, dass der Teil vor dem ? mit dem Teil hinter dem Fragezeichen verglichen wird.
Was dann der : und das dahinter stehende undef (vermutlich gleichbedeutend mit nicht definiert) bewirken habe ich noch nicht verstanden.
Sorry an die Spezialisten und Programmierer für die vermutlich für Euch einfache Frage :-)
Der Vergleich steht vor dem Fragezeichen, nach dem ? ist der Teil, der gilt, wenn der Vergleich "true" ergibt, nach dem Doppelpunkt kommt der Teil, der bei "false" ausgeführt wird.
Es ist eine Kurzform für
if ReadingsNum($name, "e1", 0) {
return ReadingsNum($name, "e1", 0);
} else {
return undef;
}
Und ich weiß genau, welche Frage als Nächstes kommt 🙃
Zitat von: betateilchen am 20 März 2025, 21:26:54Und ich weiß genau, welche Frage als Nächstes kommt
ZitatWo ist denn da ein Vergleich?
Wenn ReadingsNum() das Ergebnis 0 liefert, entspricht das automatisch "false", jedes andere numerische Ergebnis entspricht "true".
Deshalb kann man sich den expliziten Vergleich
if (ReadingsNum(...) != 0) {...}
einfach ersparen.
Coole Lösung - vielen Dank für die Erklänrung.
Nur um zu checken, ob ich es tatsächlich verstanden habe.
- Wenn also das userReadings "e1" den Wert "0" liefert ist das Ergebnis des Vergleichs "false" und es greift das elsif "undef" --> soll heissen tue gar nichts, was zur Folge hat, dass das im userReadings "energy_Panel_1" drin stehen bleibt was schon vorher drin stand
- wenn das userReadings "e1" überhaupt keinen Wert liefert greift der Defaultwert "0" mit dem Ergebnis wie oben
- wenn das userReadings "e1" einen anderen Wert als "0" liefert wird das userReadings "energy_Panel_1" mit dem Wert von "e1" befüllt
Trifft es das ?
Genau so.
Perfekt - danke nochmal für die geduldigen Erläuterungen.
Das ursprüngliche Problem, dass die Werte von e1/e2 und energy_Panel_1/energy_Panel_2 voneinander abgewichen sind tritt nicht mehr auf.
Bzgl. Perl Abfragen/Vergleichen habe ich einiges gelernt :-)