Shelly Pro 3 EM "saldierend"

Geflasht oder ungeflasht ...

Moderator: seppy

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Shelly Pro 3 EM "saldierend"

Beitrag von PeterA »

Ok was der Zähler vom EVU macht ist erst mal nicht so Wichtig.

Was mir jetzt noch eingefallen ist wie ich nun von den momentanen WATT (negatives Vorzeichen) auf Wh und/oder kWh komme.
Der Faktor Zeit fehlt irgendwie noch in der Rule.

Gruß
Peter
- OpenHab 2.4
#PWRUP

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Shelly Pro 3 EM "saldierend"

Beitrag von PeterA »

Da ich mit meiner Suche hier und in der englischen Community und im Web nicht weiter komme
formuliere die Vorstellung meiner Rule noch mal hier:

Wenn der aktuelle Wert in Watt negativ ist soll dieser zu kWh auf summiert werden.
Wenn der aktuelle Wert in Watt positiv oder 0 ist soll die Rule abbrechen.
Wird der aktuelle Wert in Watt wieder negativ soll weiter das kWh Item summiert werden.

Gruß
Peter
- OpenHab 2.4
#PWRUP

Benutzeravatar
udo1toni
Beiträge: 13985
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Shelly Pro 3 EM "saldierend"

Beitrag von udo1toni »

Du kannst Watt nicht als Kilowattstunden aufaddieren, das sind nun mal unterschiedliche Größen.
Du könntest bei jeder Änderung bestimmen, wie lange die letzte Änderung her ist und z.B. für diese Zeit den gemessenen Wert multipliziert mit der Zeit in Sekunden als Wattsekunden aufaddieren.
Je nachdem, die die Leistung gemessen und geliefert wird, kann das auch funktionieren, darauf wetten würde ich nicht.

Aber ein Versuch:

Code: Alles auswählen

rule "Zähle Ws wenn negativ"
when
    Leistung changed
then
    if(!(previousState instanceof Number))                                                        // letzter(!) Wert ungültig?
        return;

    if(Leistung.previousState(true).timestamp === null)                                           // Zeitstempel von letztem Wert nicht vorhanden?
        return;

    val nWatt = (previousState as Number).floatValue
    if(nWatt >= 0)                                                                                // Wert positiv oder 0?
        return;

    var nSum = 0.0
    if(Energie.state instanceof Number) {                                                         // gültige Summe? 
        nSum = (Energie.state as Number).floatValue                                               // dann Summe in Variable übernehmen

    val dtTS  = (Leistung.previousState(true).timestamp as DateTimeType).getZonedDateTime()       // Zeitpunkt letzte Änderung
    val nSec  = ((now().toInstant.toEpochMilli - dtTS.toInstant.toEpochMilli) / 1000).floatValue  // Sekunden seit letzter Änderung
    val nWs   = nWatt * nSec
    nSum = nSum - nWs                                                                             // nWs ist negativ
    Energie.postUpdate(nSum)
end
Zu beachten: Die Rule triggert bei Wertänderung des Items (d.h., die bisherige Leistung hat sich geändert). Zu diesem Zeitpunkt können wir also die vergangene(!) Leistung aufaddieren (nicht die aktuelle!).
Deshalb prüft die Rule, ob der vorherige Wert eine gültige Zahl ist und bricht die Rule ab, falls das nicht der Fall ist.
Handelt es sich um eine gültige Zahl, interessiert uns, wann dieser Wert gesetzt wurde, also der Zeitstempel der letzten Änderung (das ist der Parameter true, false würde den Zeitstempel der letzten Aktualisierung liefern).
Leider kann auch der Zeitstempel ungültig sein, also prüfen wir, ob wir einen Wert ungleich null bekommen (man könnte auch explizit auf instanceof DateTimeType prüfen).
Wird kein gültiger Zeitstempel geliefert, muss die Messung verworfen werden, also Abbruch der Rule.
Nun steht also fest, dass wir einen gültigen Messwert haben und auch einen passenden Zeitstempel dazu. Aber handelt es sich um einen negativen Messwert? Das lässt sich erst nach Übernahme des vorherigen Wertes in eine lokale Konstante sicher feststellen :) und falls der Wert nicht negativ ist, kann die Rule wiederum abgebrochen werden.
Zu guter Letzt müssen wir uns noch die aktuelle Summe aus dem Item holen, welches die Ws (Watt * Sekunde) enthält. Wird hier kein gültiger Wert geliefert, geht die Rule davon aus, dass der Zählerstand 0 ist.
Ansonsten wird die aktuelle Summe in eine lokale Variable übernommen.
Nun wird noch die Differenz zwischen aktueller Zeit und dem Zeitstempel gebildet (in Sekunden), sowie das Produkt aus dem letzten Messwert und der Differenz. Dieser Wert wird abschließend von der Summe abgezogen :) denn da die Leistung ja negativ ist, ist auch das Produkt negativ und muss also abgezogen werden, um einen positiven Wert zu erhalten.
Das Ergebnis der Rechnung wird in das Summenitem übernommen.

Allein an der Anzahl der Prüfungen vor der Berechnung kann man schon sehen, was da alles schief gehen kann :) und ob die Leistung nun wirklich über den gesamten Zeitraum zwischen zwei unterschiedlichen Messwerten konstant war, ist nur eine Mutmaßung, aber ich habe ja schon weiter oben darauf hingewiesen, dass wir vermutlich kein belastbares Ergebnis erhalten werden.

Du kannst den Wert auch in kWh berechnen, dann musst Du halt die Watt durch 1000 teilen und die Sekunden durch 3600 teilen. Allerdings solltest Du dann unbedingt überall Double (.doubleValue) als Zahlenformat wählen. Ich möchte dringend die Einheit Ws empfehlen, auch im Hinblick auf ein hoffentlich bald erfolgendes Upgrade auf openHAB4 ;) wo Du Dir die Ws einfach als kWh anzeigen lassen kannst (oder als Joule, Kalorie, wie auch immer es beliebt). Notfalls kannst Du bis zum Upgrade in einem zweiten Item die Ws in kWh speichern, jedoch ohne die Genauigkeit des Wertes zu verlieren. Die Rule wird alle paar Sekunden triggern, die dann addierte Energiemenge ist so klein, dass kWh hier vermutlich schlicht zu ungenau wird, denn das interne Format des Items kannst Du nicht beeinflussen.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Shelly Pro 3 EM "saldierend"

Beitrag von PeterA »

OH Wow! Mein Gehirn kann so was nicht :)

Es gibt noch gemaule im Log:

Code: Alles auswählen

2023-07-27 13:53:32.988 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'test.rules', using it anyway:

Cannot cast from Date to DateTimeType
und:

Code: Alles auswählen

2023-07-27 13:53:35.008 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Zähle Ws wenn negativ': rrd4j does not allow querys without a begin date, unless order is descending and a single value is requested
Hab die Rule auf meine Items angepasst und noch ein "Item" beim Trigger Item davor gesetzt und eine geschweifte Klamme entfernt die da so
alleine rumstand.

Code: Alles auswählen

rule "Zähle Ws wenn negativ"
when
    Item em0_total_act_power changed
then
    if(!(previousState instanceof Number))                                                        // letzter(!) Wert ungültig?
        return;

    if(em0_total_act_power.previousState(true).timestamp === null)                                // Zeitstempel von letztem Wert nicht vorhanden?
        return;

    val nWatt = (previousState as Number).floatValue
    if(nWatt >= 0)                                                                                // Wert positiv oder 0?
        return;

    var nSum = 0.0
    if(Energie_shelly_phasen_sum.state instanceof Number)                                         // gültige Summe? 
        nSum = (Energie_shelly_phasen_sum.state as Number).floatValue                             // dann Summe in Variable übernehmen

    val dtTS  = (em0_total_act_power.previousState(true).timestamp as DateTimeType).getZonedDateTime()       // Zeitpunkt letzte Änderung
    val nSec  = ((now().toInstant.toEpochMilli - dtTS.toInstant.toEpochMilli) / 1000).floatValue             // Sekunden seit letzter Änderung
    val nWs   = nWatt * nSec
    nSum = nSum - nWs                                                                             // nWs ist negativ
    Energie_shelly_phasen_sum.postUpdate(nSum)
Ja und Umrechnung auf Wh und / oder kWh wäre noch nice.
- OpenHab 2.4
#PWRUP

Benutzeravatar
udo1toni
Beiträge: 13985
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Shelly Pro 3 EM "saldierend"

Beitrag von udo1toni »

PeterA hat geschrieben: 27. Jul 2023 14:00 Hab die Rule auf meine Items angepasst und noch ein "Item" beim Trigger Item davor gesetzt und eine geschweifte Klamme entfernt die da so
alleine rumstand.
Sehr gut! Prüfung bestanden... (Spaß, eigene Fehler übersehe ich genauso wie jeder andere auch...)

Statt .timestamp muss es wohl .getTimestamp heißen. Das kommt davon, wenn man zu faul ist, noch mal in der Doku nachzuschlagen (Achtung, zweimal im Code).

Es ist auch möglich, dass .getTimestamp (so wie in der ersten INFO zu lesen) gar kein DateTimeType zurückliefert, dann nehmen wir es halt so:

Code: Alles auswählen

val dtTS  = em0_total_act_power.previousState(true).getTimestamp
Die Meldung von wegen
rrd4j does not allow querys without a begin date
ergibt für mich allerdings keinen Sinn, .previousState(true) bietet gar keine Möglichkeit, noch mehr Parameter anzugeben (außer halt, gezielt eine andere Persistence als die Default Persistence zu nutzen). Aber vielleicht hängt das auch mit dem fehlerhaften .timestamp zusammen.
Für Wh und/oder kWh nutzt Du am besten ein zweites Item, meinetwegen Energie_shelly_phasen_sumkWh und schreibst den entsprechend reduzierten Wert zusätzlich dort rein:

Code: Alles auswählen

Energie_shelly_phasen_sumkWh.postUpdate(nSum/3600000)
Du solltest dennoch die Wattsekunden für die Summierung nutzen, nicht die kWh.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Shelly Pro 3 EM "saldierend"

Beitrag von PeterA »

So sieht die Rule jetzt aus:

Code: Alles auswählen

rule "Zähle Ws wenn negativ"
when
    Item em0_total_act_power changed
then
    if(!(previousState instanceof Number))                                                        // letzter(!) Wert ungültig?
        return;

    if(em0_total_act_power.previousState(true).getTimestamp === null)                              // Zeitstempel von letztem Wert nicht vorhanden?
        return;

    val nWatt = (previousState as Number).floatValue
    if(nWatt >= 0)                                                                                // Wert positiv oder 0?
        return;

    var nSum = 0.0
    if(Energie_shelly_phasen_sum.state instanceof Number)                                         // gültige Summe? 
        nSum = (Energie_shelly_phasen_sum.state as Number).floatValue                             // dann Summe in Variable übernehmen

    val dtTS  = em0_total_act_power.previousState(true).getTimestamp                              // Zeitpunkt letzte Änderung
    val nSec  = ((now().toInstant.toEpochMilli - dtTS.toInstant.toEpochMilli) / 1000).floatValue             // Sekunden seit letzter Änderung
    val nWs   = nWatt * nSec
    nSum = nSum - nWs                                                                             // nWs ist negativ
    Energie_shelly_phasen_sum.postUpdate(nSum)
end
Die DateTime Fehlermeldung ist jetzt weg.

Aber die rrdj4 kommt noch:

Code: Alles auswählen

2023-07-27 17:51:32.599 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Zähle Ws wenn negativ': rrd4j does not allow querys without a begin date, unless order is descending and a single value is requested
- OpenHab 2.4
#PWRUP

Benutzeravatar
udo1toni
Beiträge: 13985
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Shelly Pro 3 EM "saldierend"

Beitrag von udo1toni »

Das Item em0_total_act_power ist aber auch über rrd4j mit everyMinute,everyChange persistiert, oder?
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Shelly Pro 3 EM "saldierend"

Beitrag von PeterA »

Code: Alles auswählen

// Shelly Pro 3 EM
    em0_total_act_power                     : strategy = everyMinute, everyChange, restoreOnStartup
Klaro

Habe mal über die RestApi geschaut da ist auch was in der DB:

Code: Alles auswählen

{
  "name": "em0_total_act_power",
  "datapoints": "360",
  "data": [
    {
      "time": 1690387200000,
      "state": "149.55857916666668"
    },
    {
      "time": 1690387440000,
      "state": "137.40427083333333"
    },
    {
      "time": 1690387680000,
      "state": "94.35439583333334"
- OpenHab 2.4
#PWRUP

Benutzeravatar
udo1toni
Beiträge: 13985
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Shelly Pro 3 EM "saldierend"

Beitrag von udo1toni »

Kann auch sein, dass die ganze Berechnung an rrd4j scheitert, weil rrd4j nicht beliebig feingranular persistieren kann.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Shelly Pro 3 EM "saldierend"

Beitrag von PeterA »

Welche Persistenz könnte das ?
- OpenHab 2.4
#PWRUP

Antworten