Ja, Ja und Ja.
Für historische Werte nutzt Du am besten einfach die Persistence Services. Da es dort verschiedene Möglichkeiten gibt: jdbc verbindet zu einer sql-Datenbank (PostGre, MySQL, MariaDB...) influxdb tut dies zu einer InfluxDB Datenbank und rrd4j nutzt eine interne RoundRobinDB. Die interne rrd hat den Vorteil, dass man nichts weiter tun muss, man kann das Teil einfach nutzen, nachdem rrd4j einmal installiert und konfiguriert wurde (mit einer rrd4j.persist bestimmen, was gespeichert werden soll). Da es sich um eine RoundRobinDB handelt, ist die Dateigröße fix, man muss sich also nicht sorgen, dass die Persistence das Dateisystem volllaufen lässt. Auf der anderen Seite gibt es immer wieder Probleme mit rrd4j, wo diese liegen, bleibt oft im Dunkeln.
InfluxDB ist eine auf Messwerterfassung spezialisierte Datenbank, es gibt verschiedene Tools, die auf InfluxDB optimiert sind, Grafana kann z.B. hübsche dynamische Graphen aus den Daten erzeugen.
Wenn Du ohnehin irgendwo im Netz eine SQLdb laufen hast, kannst Du auch diese bequem nutzen, um dort Deine Messdaten zu speichern.
Wenn das Topic einfach aufsummiert, könnte es auch sein, dass es zu bestimmten Zeitpunkten wieder auf 0 springt, was dann den Negativwert erklären könnte (müsste man halt mal genau schauen - im Zweifel gibt es auch einen Befehl, um das Topic gezielt auf 0 zu setzen).
Du kannst einfach ein Dummy Item erstellen, indem Du keinen Link setzt, also z.B. so:
Aufaddieren wäre dann z.B. so:
Code: Alles auswählen
rule "Stromzaehler kWh"
when
Time cron "5 * * * * ?" // jede Minute in der 5. Sekunde
then
var Number nkwh = 0
if(myDummyItem.state instanceof Number)
nkwh = myDummyItem.state as Number
nkwh = nkwh + (( ShellyPlugS_267A58_Verbrauch.state as Number) /60000) // dann sollte das Topic aber den Momentanverbrauch in WattMinuten liefern...
myDummyItem.postUpdate(nkwh)
end
Wenn Du mehrere gleichartige Items einsetzt, die jeweils identisch behandelt werden sollen, musst Du die Items gruppieren und die Rule so umbauen, dass die Items der Gruppe bearbeitet werden. Eine Herausforderung kann dabei sein, wenn ein bestimmtes Item durch ein bestimmtes Item verändert wird. Dann musst Du die Items günstig benennen, um einigermaßen bequem zu arbeiten. z.B. :
Code: Alles auswählen
Group gRealVerbrauch
Group gVerbrauch
Number ShellyPlugS_267A58_Verbrauch "Verbrauch real" (gRealVerbrauch) { channel="..." }
Number Dummy_267A58_Verbrauch "Verbrauch addiert" (gVerbrauch)
Die Items gehören jeweils zusammen, je eines pro Gruppe. Die Rule:
Code: Alles auswählen
rule "Stromzaehler kWh"
when
Time cron "5 * * * * ?" // jede Minute in der 5. Sekunde
then
gRealVerbrauch.members.forEach[i|
var Number nkwh = 0
val myItem = gVerbrauch.members.filter[f|f.name.split("_").get(1) == i.name.split("_").get(1)].head // passendes Item
if(myItem.state instanceof Number)
nkwh = myItem.state as Number
nkwh = nkwh + ((i.state as Number) /60000)
myItem.postUpdate(nkwh)
]
end
Die Gruppe gRealVerbrauch wird nun durchlaufen, für jedes Item der Gruppe wird der Befehlsblock ausgeführt. Dabei steht i für das aktuelle Item der Gruppe gRealVerbrauch.
Zunächst wird eine Variable nkwh definiert und mit 0 initialisiert.
Anschließend wird das zum aktuellen Item passende Gegenstück gesucht und als Objekt myItem definiert. Das geschieht über einen Filter auf die Gruppe gVerbrauch. Der Filter prüft, ob der 2. Teil des Item Namens identisch mit dem 2. Teil des aktuellen Items der Gruppe gRealVerbrauch ist. Das trifft auf genau ein Item der Gruppe zu. Als Ergebnis wird eine Liste zurückgeliefert, von der wir das erste Item verwenden (.head)
Nun prüft die Rule, ob es sich beim Status des gefundenen Items um eine gültige Zahl handelt, falls das der Fall ist, wird sie in die Variable geschrieben. Anschließend wird der Status des aktuellen Items der Gruppe gRealVerbrauch zu der Variablen addiert (bzw. der 60000ste Teil).
Danach wir die Variable in das gefundene Item geschrieben.
Diese Rule erledigt das also für alle Itempaare auf einmal.
Soll eine Rule auf ein Update der Items triggern, geht das genauso, nur muss man nun den Trigger ändern:
Code: Alles auswählen
rule "Stromzaehler kWh"
when
Member of gRealVerbrauch received update
then
val myItem = gVerbrauch.members.filter[f|f.name.split("_").get(1) == triggeringItem.name.split("_").get(1)].head // passendes Item
// ... whatever ...
]
end
In diesem Fall wird also das passende Item in Abhängigkeit des triggernden Items gesucht.
Die DSL ist mit relativ wenigen Befehlen überaus mächtig und erlaubt sehr effizientes Programmieren, wenn man mal verstanden hat, was die Idee dahinter ist

openHAB4.3.6 stable in einem Debian-Container (bookworm) (Proxmox 8.4.1, LXC), mit openHABian eingerichtet