Zur ersten Rule fehlt ein wichtiger Bestandteil, der mit hoher Wahrscheinlichkeit im Originalcode vorhanden war, nämlich die Definition der Variablen. StartTime, StopTime und RunTime. Mindestens StartTime muss global definiert sein, die anderen beiden können auch lokal definiert werden. Sieht dann mit ein paar Verbesserungen so aus:
Code: Alles auswählen
var Long StartTime = null
rule "Pool Pumpe Tageslaufzeit rechnen"
when
Item Sonoff_1 changed
then
if(previousState == NULL) // kein alter Wert -> Abbruch da Systemstart
return;
var Integer iTagSec = 0 // Default Wert
if(pool_pumpe_laufzeit_tag.state instanceof Number) // Falls Item gültigen Wert liefert
iTagSec = (pool_pumpe_laufzeit_tag.state as Number).intValue // nimm diesen Wert
if(newState == ON) // neuer Status ON -> Startzeit merken
StartTime = now.millis
else if(StartTime !== null) { // neuer Status OFF UND StartTime ist nicht null
val Integer iRunSec = ((now.Millis - StartTime)/1000).intValue // Differenz bilden und durch 1000 teilen
logInfo("Pool Pumpe","Einschaltzeit: {} Sek, ({} Sek heute)",iRunSec, iTagSec + iRunSec)
pool_pumpe_laufzeit_tag.postUpdate(iTagSec + iRunSec)
}
end
Die erste Zeile definiert ein Objekt vom Typ Long (now.millis liefert Long). Diese Variable (var) ist global definiert und hält ihren Wert solange die Rule-Datei nicht verändert oder das System neu gestartet wird.
Die erste Zeile des eigentlichen Codes prüft, ob das Item einen gültiger Wert hatte, bevor die Rule getriggert wurde. Ist das nicht der Fall, so wurde das System neu gestartet und die Rule muss abgebrochen werden.
Im nächsten Block wird der Wert des Anzeige Items bestimmt. Ist dieser Wert keine Zahl, so wird 0 als Zahl verwendet (ansonsten gäbe es später nullPointerExeptions). Es bietet sich an, das über eine weitere Variable zu erledigen.
Nun wird geprüft, welchen Zustand das triggernde Item aktuell hat. Bei ON merkt sich die Rule die aktuelle Zeit, bei OFF wird die Berechnung der Laufzeit ausgeführt, unter der Voraussetzung, dass der Startzeit Speicher auch einen Wert enthält (sonst nullPointerException...)
Das Ergebnis der Berechnung ist die aktuelle Einschaltdauer in Sekunden, die direkt in einer lokalen Konstanten gespeichert wird (val, nicht var)
Die neue Summe wird gemeinsam mit der Einschaltdauer ausgegeben und ins Item geschrieben.
Es ist nicht korrekt, ein Item zu beschreiben (mit postUpdate) und unmittelbar wieder auszulesen (mit .state), denn openHAB arbeitet asynchron. Es gbit keine garantierten Laufzeiten, das heißt, es kann vorkommen, dass .state unmittelbar nach .postUpdate den Wert VOR dem .postUpdate liefert, es kann aber auch den Wert NACH dem .postUpdate liefern. Das Verhalten ist nicht deterministisch und von vielen Faktoren abhängig.
openHAB4.3.6 stable in einem Debian-Container (bookworm) (Proxmox 8.4.1, LXC), mit openHABian eingerichtet