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.