Shelly Verbrauchswerte Speichern

Geflasht oder ungeflasht ...

Moderator: seppy

danielm83
Beiträge: 23
Registriert: 14. Dez 2021 20:51

Re: Shelly Verbrauchswerte Speichern

Beitrag von danielm83 »

Hallo Udo

danke für die Erklärung.
Die 3Em kosten zwar eh 100 € aber ich verstehe es nun. Interessanterweise ist bei den meisten SW Updates von den 3EM der Gesamtwert stehen geblieben nur beim Letzten eben nicht - darum hat es mich da etwas gewundert.

Die Impulse zähle ich bei meiner WP mit einem KNX Tasterinterface. Das funktioniert eigentlich ganz gut.

Jetzt habe ich ja vom EVU auch einen supertollen SMART METER bekommen, aber das Ding auszulesen - dazu reichen meine Fähigkeiten bei weitem nicht aus - das musste man ja so kompliziert wie möglich machen.

Grüße
Daniel

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

Re: Shelly Verbrauchswerte Speichern

Beitrag von udo1toni »

Gewöhnlich haben Smart Meter eine serielle Schnittstelle die mit SML als Protokoll arbeitet. Meist ist diese Schnittstelle optisch ausgelegt, weil man damit gleich mehrere Fliegen erwischt :)

Ich habe hier einen eigenen Raspberry zur Zählerstandserfassung laufen, und zwar mit vzlogger, was Teil von vokszaehler.org ist. vzlogger liest die absoluten Zählerstände aus und kümmert sich auch um die Erfassung von S0 Impulsen. Ist nicht weiter schwer in Betrieb zu nehmen.
Alternativ kannst Du auch das SML Binding in openHAB verwenden. Allerdings fehlt dabei ein Teil, und zwar kann man nicht frei konfigurieren, welche Pullsequentz gesendet wird, falls der Zähler im Pull-Modus arbeitet.

Push-Betrieb: Der Zähler sendet einfach fröhlich seine Daten aus, es ist ihm egal, ob es einen Empfänger gibt.
Pull-Betrieb: Der Zähler wartet auf einen Read Request und sendet erst dann ein Datenpaket.
Pull-Betrieb mag etwas (wenig) effizienter sein, erfordert aber bidirektionale Kommunikation, während Push auch unidirektional funktioniert und somit potenziell weniger (keine) Angriffsfläche bietet.
vzlogger kann beides frei konfigurierbar nutzen, es gibt kaum Zähler, die man nicht einfach anbinden kann, indem man die erforderlichen Daten aus dem Forum in die Konfiguration übernimmt.
vzlogger kann auch so konfiguriert werden, dass es Änderungen am Zählerstand über mqtt sendet (das habe ich aber bei mir bisher nicht umgesetzt).
vokszaehler.org bietet ein Webfrontend und speichert die Daten in einer MySQL Datenbank, von wo man sie auch selbst analysieren kann . oder man nutzt eben das WebFE und greift dort die Daten per http mit JSON ab, oder, oder...
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

danielm83
Beiträge: 23
Registriert: 14. Dez 2021 20:51

Re: Shelly Verbrauchswerte Speichern

Beitrag von danielm83 »

Hallo Udo

danke für deine Erläuterungen - werde ich mir ansehen.

Zur Info: Rich Koshak hat nun für das Shelly (und andere) Problem ein Rule Template geschrieben.
https://community.openhab.org/t/meter-reading/132693

Damit funktioniert die Summenbildung meiner garstigsten Shellies auch auf Change - ich wünsche das wäre früher online gewesen, das hätte mir viel Zeit und Nerven gespart :-)

Grüße
Daniel

Benutzeravatar
KellerK1nd
Beiträge: 432
Registriert: 17. Jun 2019 16:45
Answers: 1
Wohnort: Griesheim

Re: Shelly Verbrauchswerte Speichern

Beitrag von KellerK1nd »

danielm83 hat geschrieben: 11. Feb 2022 10:24 Hallo Udo

danke für deine Erläuterungen - werde ich mir ansehen.

Zur Info: Rich Koshak hat nun für das Shelly (und andere) Problem ein Rule Template geschrieben.
https://community.openhab.org/t/meter-reading/132693

Damit funktioniert die Summenbildung meiner garstigsten Shellies auch auf Change - ich wünsche das wäre früher online gewesen, das hätte mir viel Zeit und Nerven gespart :-)

Grüße
Daniel

Code: Alles auswählen

uid: rules_tools:meter
label: Meter Reading
description: Keeps a sum from a counting meter Item that can randomly be reset back to zero.
configDescriptions:
  - name: meter
    type: TEXT
    context: item
    filterCriteria:
      - name: type
        value: Number
    label: Meter Item
    required: true
    description: Item that holds the meter readings.
  - name: total
    type: TEXT
    context: item
    filterCriteria:
      - name: type
        value: Number
    label: Total Item
    required: true
    description: Item that holds the running total.
triggers:
  - id: "1"
    configuration:
      itemName: "{{meter}}"
    type: core.ItemStateChangeTrigger
conditions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: "!items.getItem(event.itemName).isUninitialized;"
    type: script.ScriptCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: >-
        var totalItem = items.getItem('{{total}}');

        var reading = event.itemState.floatValue();

        var lastReading = (event.oldItemState.toString() == 'NULL' || event.oldItemState.toString() == 'UNDEF') ? 0 : event.oldItemState.floatValue();

        var currTotal = (totalItem.isUninitialized) ? 0 : totalItem.rawState.floatValue();


        // If the device counter was reset, use the current reading as the delta

        var delta = (reading < lastReading) ? reading : (reading - lastReading);


        totalItem.postUpdate((currTotal + delta).toString());
    type: script.ScriptAction
Kann mir das jemand auf DSL übersetzen? :lol:
Betriebssystem: Proxmox 7.3-4
openHAB Container: debian11 LXC
openHAB Version: 3.4
Hardware: HomeServer Eigenbau mit einem Intel i5 9600K
Smarthome-Equipment:
- Rasperrymatic
- deConz
- HUE
- Shellys
- Mosquitto
- AVM Fritz!Box

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

Re: Shelly Verbrauchswerte Speichern

Beitrag von udo1toni »

Das sollte das Äquivalent des Code-Blocks sein:

Code: Alles auswählen

    var reading     = (newState as Number).floatValue
    var lastReading = if(previousState instanceof Number) (previousState as Number).floatValue else 0
    var currTotal   = if(total.state   instanceof Number) (total.state   as Number).floatValue else 0

    var delta       = if(reading < lastReading) reading else reading - lastReading

    total.postUpdate((currTotal + delta).toString)
Wobei ich darauf verzichtet habe, das Item in einer Variablen zu speichern.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
KellerK1nd
Beiträge: 432
Registriert: 17. Jun 2019 16:45
Answers: 1
Wohnort: Griesheim

Re: Shelly Verbrauchswerte Speichern

Beitrag von KellerK1nd »

Ich danke dir.
Betriebssystem: Proxmox 7.3-4
openHAB Container: debian11 LXC
openHAB Version: 3.4
Hardware: HomeServer Eigenbau mit einem Intel i5 9600K
Smarthome-Equipment:
- Rasperrymatic
- deConz
- HUE
- Shellys
- Mosquitto
- AVM Fritz!Box

danielm83
Beiträge: 23
Registriert: 14. Dez 2021 20:51

Re: Shelly Verbrauchswerte Speichern

Beitrag von danielm83 »

Hallo Zusammen

Ich habe noch einmal eine Frage zu den Summenzählern oder besser gesagt zu dem Problem mit NULL.

Um bei Stromausfall oder anderem nicht wieder bei 0 anfangen zu zählen, benutze ich folgende Rule (das Tool aus dem Forum hat leider andere Schwächen, weshalb ich darauf nicht zurück greife)

Code: Alles auswählen

rule "Gesamtverbrauch KWL"
when
    //Item Shelly_KWL_energy  15 Minuten --> 0 0/15 * * * ? *
    Time cron "0 0/15 * * * ? *" 
then
    logInfo("Gesamtverbrauch KWL", "Summe KWL berechnet")
    var currentkwh = (Shelly_KWL_energy.state as Number).floatValue	// aktueller Wert vom Shellyin kWh
    var delta = (Shelly_KWL_energy.deltaSince(now.minusMinutes(15)) as Number).floatValue		//vorhergehender Wert des Shelly in kWh
    logInfo("Gesamtverbrauch KWL", "Das Delta seit 15 Minuten beträgt  " + (delta.toString) )
    if((delta) >= 0){		//Wenn das Delta größer 0 ist
        Shelly_KWL_energy_sum.postUpdate(Shelly_KWL_energy_sum.state as Number + (delta))		//Gesamtverbrauch aus dem Delta in Item schreiben
    }
    else if((delta) < 0){		//Wenn das Delta kleiner 0 ist (nach einem Reset des Shellies)
        Shelly_KWL_energy_sum.postUpdate(Shelly_KWL_energy_sum.state as Number + currentkwh)		//Gesamtverbauch nur des aktuellen Wertes nach einem Reset schreiben
    }
end
Jetzt habe ich aber das Problem, dass beim Ersten durchlauf, das Item Shelly_KWL_energy_sum noch NULL ist, und damit funktioniert die Rule nicht.
Das habe ich umgangen, indem ich beim ersten Mal einfach manuell einen Wert vergeben habe. Nur gab es aus irgend einem Grund einen Neustart des Systems (denke Stromausfall) und nun sind sämtliche Summenwerte wieder NULL.

Müsste das nicht über das Restore on Startup aus der Persistence vermieden werden?

Ich verwende in diesem System nur rrd4j mit folgender Konfiguration:

Code: Alles auswählen

Strategies {
    
    everyMinute : "0 * * * * ?"
    everyHour   : "0 0 * * * ?"
    everyDay    : "0 0 0 * * ?"

    default = everyMinute

}

Items {

    rrd4j_ec* : strategy = everyMinute, everyChange, restoreOnStartup
    rrd4j_eh* : strategy = everyMinute, everyHour, restoreOnStartup
    ComfoAir* : strategy = everyMinute, everyHour, restoreOnStartup
}
Die Summenitems sind in der Gruppe rrd4j_eh.

Ich habe es ausch schon versucht mit: * = everyChange, restoreOnStartup
damit alle Items geloggt werden, aber das machte keinen unterschied.

Danke für eure Hilfe
Daniel

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

Re: Shelly Verbrauchswerte Speichern

Beitrag von udo1toni »

Grundsätzlich ist die Persistence schon mal der richtige Punkt, um anzusetzen.

Da Deine Rule auf fixe Zeitpunkte schaut (immer zur vollen Viertelstunde) ist es essenziell, dass zu diesen Zeitpunkten unter allen Umständen gültige Werte vorliegen. Ich vermute mal, dass die Rule daran scheitert.

Zunächst solltest Du allerdings die rrd4j.persist von Ballast befreien :)
rrd4j benötigt zwingend eine Strategy everyMinute. everyHour ist zwar nett, aber komplett sinnlos (vor allem, wenn sie immer zeitgleich mit everyMinute triggert). Gleiches gilt für everyDay. Da Du die Werte ohnehin minütlich speichern musst, kannst Du die unnützen Strategien auch sein lassen.

Das restoreOnStartup sollte dafür sorgen, dass der letzte in der Persistence gespeicherte Wert beim Restart von openHAB als Status in das entsprechende Item geladen wird. Es gibt Fälle, wo das nicht funktioniert. Zuerst fällt mir dazu das Stichwort UoM ein. Handelt es sich um Items, die eine Einheit im Wert mit sich führen, also z.B. kWh? Allerdings sollte dann die restliche Rule auch nicht funktionieren, aber wer weiß...

Du kannst versuchen, das Restore über eine andere Persistence zu erreichen, mapDB böte sich da an. Genau wie rrd4j benötigt mapDB immer genau gleich viel Platz für die persistierten Daten. Nur ist es bei rrd4j so, dass durch die RoundRobin Funktion einfach jeweils die ältesten Werte überschrieben werden, während mapDB gleich nur den aktuellen Status speichert. Es gibt also keine historischen Werte, sondern nur den zuletzt gültigen, der sich dafür aber easy wiederherstellen lässt.

Man kann Items von beliebig vielen Persistence Services gleichzeitig persistieren lassen. Man sollte natürlich darauf achten, immer maximal bei einer aktiven Persistence das restoreOnStartup anzugeben :)

Zur Berechung: Im Grunde musst Du zwei Items führen, das erste, welches immer den Wert im Zähler speichert. Bei jeder Änderung des Wertes vergleichst Du alten und neuen Wert. Ist der alte Wert kleiner, nimmst Du die Differenz, ist der alte Wert größer, nimmst Du den neuen Wert. So macht das die Rule ja auch. Aber warum nur alle Viertelstunde? Besser so:

Code: Alles auswählen

rule "Gesamtverbrauch KWL"
when
    Item Shelly_KWL_energy  changed
then
    val oldVal = if(!(previousState instanceof Number)) 0 else (previousState as Number).floatValue
    val newVal = if(!(newState instanceof Number))      0 else (newState as Number).floatValue
    val diff = newVal - oldVal

    logInfo("consumption", "Messwert Alt: {} Neu: {} Differenz: {}",oldVal,newVal,diff)

    val sum = if(!(Shelly_KWL_energy_sum.state instanceof Number)) 0 else (Shelly_KWL_energy_sum.state as Number).floatValue
    var newSum
    if(diff >= 0)
        newSum = sum + diff
    else
        newSum = sum + newVal

    logInfo("consumption","Summe alt: {} Summe neu: {}",sum,newSum)
    Shelly_KWL_energy_sum.postUpdate(newSum)
end
Die Summe wird also bei jeder Änderung aktualisiert, nicht nur viertelstündlich. das hat auch den Vorteil, dass man sich das ganze Rumgeeiere mit der Persistence schenken kann, denn beim Ereignis changed stehen die impliziten Variablen previousState und newState zur Verfügung. Man muss nun lediglich sicherstellen, dass diese beiden Werte auch tatsächlich eine Zahl enthalten, was am elegantesten über
den ternären Operator if(a) b else c geht.
Auch für die Summe muss man diese extra Meile gehen, um sicherzustellen, dass die Rule nicht an dieser Stelle scheitert.
Falls es nun zum Reset der Summe kommen sollte, weil die Persistence aus irgendeinem Grund die Summe noch nicht zurückgeschrieben hat, könnte man die Rule an der Stelle auch abbrechen lassen, mittels

Code: Alles auswählen

if(!(Shelly_KWL_energy_sum.state instanceof Number))
    return;
Das ist natürlich nur sinnvoll, wenn das Restore einfach etwas verspätet auftritt, aber grundsätzlich funktioniert. Lieber ein kleiner Messfehler (erster Messwert nach Neustart verschluckt) als gar kein Messwert oder ein genullter Summenzähler.

EDIT: Typo in Rule rorrigiert.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

danielm83
Beiträge: 23
Registriert: 14. Dez 2021 20:51

Re: Shelly Verbrauchswerte Speichern

Beitrag von danielm83 »

Hallo Udo

erstmal vielen Dank für deine ausführliche Rückmeldung. Ja das mit dem eveyHour etc. dachte ich mir auch dass es sinnlos ist.
Ich habe das deshalb alle viertel Stunde gemacht, weil ich es sonst nicht zum Laufen bekommen habe, und so hat es halt irgendwann funktioniert.

Ich habe deine Rule mal 1:1 kopiert (die alte Rule entfernt) und bekomme folgende Meldungen:

Code: Alles auswählen

[{
	"resource": "/x:/rules/summe_energie.rules",
	"owner": "_generated_diagnostic_collection_name_#0",
	"code": "org.eclipse.xtext.xbase.validation.IssueCodes.missing_type",
	"severity": 8,
	"message": "Type cannot be derived",
	"startLineNumber": 158,
	"startColumn": 9,
	"endLineNumber": 158,
	"endColumn": 15
	
	[{
	"resource": "/x:/rules/summe_energie.rules",
	"owner": "_generated_diagnostic_collection_name_#0",
	"code": "org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types",
	"severity": 8,
	"message": "Type mismatch: type float is not applicable at this location",
	"startLineNumber": 160,
	"startColumn": 18,
	"endLineNumber": 160,
	"endColumn": 28
	
	[{
	"resource": "/x:/rules/summe_energie.rules",
	"owner": "_generated_diagnostic_collection_name_#0",
	"code": "org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types",
	"severity": 8,
	"message": "Type mismatch: type float is not applicable at this location",
	"startLineNumber": 162,
	"startColumn": 18,
	"endLineNumber": 162,
	"endColumn": 30
}]

}]
}]
Und wenn ich dich richtig verstanden habe, dann nehme ich das restore on Startup in der rrd4j besser raus und mache dafür extra die MapDB?

An welcher Stelle im code müsste der return erfolgen? Einfach am Ende nach dem Postupdate der Summe?

Danke
Daniel

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

Re: Shelly Verbrauchswerte Speichern

Beitrag von udo1toni »

Ja, das wird die ungenügende Definition von newSum sein. Schreib stattdessen bitte mal

Code: Alles auswählen

var newSum = 1.5
Den Typ sollte man nicht festlegen müssen, wenn man einen Wert des entsprechenden Typs vorgibt.

Alternativ kannst Du auch den Typ direkt festlegen:

Code: Alles auswählen

var Number newSum 
Das return; sähe so aus:

Code: Alles auswählen

rule "Gesamtverbrauch KWL"
when
    Item Shelly_KWL_energy  changed
then
    val oldVal = if(!(previousState instanceof Number)) 0 else (previousState as Number).floatValue
    val newVal = if(!(newState instanceof Number))      0 else (newState as Number).floatValue
    val diff = newVal - oldVal

    logInfo("consumption", "Messwert Alt: {} Neu: {} Differenz: {}",oldVal,newVal,diff)

    if(!(Shelly_KWL_energy_sum.state instanceof Number))
        return;

    val sum = (Shelly_KWL_energy_sum.state as Number).floatValue
    var newSum = 1.5
    if(diff >= 0)
        newSum = sum + diff
    else
        newSum = sum + newVal

    logInfo("consumption","Summe alt: {} Summe neu: {}",sum,newSum)
    Shelly_KWL_energy_sum.postUpdate(newSum)
end
EDIT: Typo in Rule korrigiert.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten