Der eigentliche Fehler ist, dass Du die Timer Variable nicht definiert hast. Aber die Rules sind in der Form auch nicht optimal.
Code: Alles auswählen
// Globale Variablen immer vor der ersten Rule definieren
var Timer tPool = null // Pool-Timer
var Integer iPoolRemain = 0
rule "Poolreinigung starten"
when
Item Poolreinigung_starten received command // nicht changed!
then
tPool?.cancel // falls ein Timer existiert, abbrechen
if(receivedCommand == OFF) { // falls Befehl OFF
Verbleibende_Laufzeit_Poolreinigung.postUpdate(0) // Item auf 0
Laufzeit_Poolreinigung.postUpdate(0) // Item auf 0
Shelly_Pool_oben.sendCommand(OFF) // Pool aus
return; // und Ende
}
// Befehl war ON, also
var Integer iLaufzeit = 20 // default Laufzeit falls IOtem ungültig
if(Poolreingungszeit.state instanceof Number) // gültiger Wert im Item?
iLaufzeit = (Poolreingungszeit.state as Number).intValue // Wert übernehmen
if(iLaufzeit < 1) { // Falls unsinniger Wert
Shelly_Pool_oben.sendCommand(OFF) // ... nur zur Sicherheit
return; // und Ende
}
iPoolRemain = iLaufzeit // Counter setzen
Laufzeit_Poolreinigung.postUpdate(iLaufzeit) // und in statische Anzeige
Verbleibende_Laufzeit_Poolreinigung.postUpdate(iLaufzeit) // und in dynamische Anzeige
Shelly_Pool_oben.sendCommand(ON) // Pool an
val pushActions = getActions("pushover", "pushover:pushover-account:account") // Handle für Pushover Actions holen
pushActions.sendMessage("Poolreingung gestartet", "@ Home") // Nachricht schicken
tPool = createTimer(now.plusMinutes(1), [ // Timer starten
iPoolRemain -- // verbleibende Zeit verringern
Verbleibende_Laufzeit_Poolreinigung.postUpdate(iPoolRemain) // Anzeige updaten
if(iPoolRemain > 0) // Falls noch Zeit übrig ist
tPool.reschedule(now.plusMinutes(1)) // Timer erneut planen
else // ansonsten
Shelly_Pool_oben.sendCommand(OFF) // ausschalten
])
end
Es reicht also eine Rule, die sich um alles kümmert.
Du könntest das Item auch zum Zählen verwenden, es ist aber sinnvoller, das mit einer globalen Variablen zu machen, der Zugriff ist einfach um Größenordnungen schneller. Du könntest auch auf mindestens eines der Items verzichten (im Grunde auch auf zwei)
Nutze das Item Poolreinigungszeit zum Starten. Mutmaßlich wirst Du nicht jedes Mal andere Laufzeiten nutzen, sondern allenfalls drei oder vier verschiedene Werte? Du könntest dann ohne Probleme das Item mit Schaltflächen in der UI mit fixen Werten bestücken (alternativ auch als DropDown-Liste)
Code: Alles auswählen
// Globale Variablen immer vor der ersten Rule definieren
var Timer tPool = null // Pool-Timer
var Integer iPoolRemain = 0
rule "Poolreinigung"
when
Item Poolreinigungszeit received command // nicht changed!
then
if(!(receivedCommand instanceof Number)) // auf sinvollen Wert prüfen
return; // gegebenenfalls Ende
tPool?.cancel // falls ein Timer existiert, abbrechen
if(receivedCommand == 0) { // falls Befehl 0
Shelly_Pool_oben.sendCommand(OFF) // Pool aus
return; // und Ende
}
var Integer iLaufzeit = (receivedCommand as Number).intValue // Laufzeit übernehmen
Laufzeit_Poolreinigung.postUpdate(iLaufzeit) // statische Anzeige
iPoolRemain = iLaufzeit // Counter setzen
Shelly_Pool_oben.sendCommand(ON) // Pool an
val pushActions = getActions("pushover", "pushover:pushover-account:account") // Handle für Pushover Actions holen
val strMessage = "Poolreingung gestartet, Laufzeit " + iLaufzeit.toString + " Minuten."
pushActions.sendMessage(strMessage, "@ Home") // Nachricht schicken
tPool = createTimer(now.plusMinutes(1), [ // Timer starten
iPoolRemain -- // verbleibende Zeit verringern
Poolreinigungszeit.postUpdate(iPoolRemain) // Anzeige updaten
if(iPoolRemain > 0) // Falls noch Zeit übrig ist
tPool.reschedule(now.plusMinutes(1)) // Timer erneut planen
else // ansonsten
Shelly_Pool_oben.sendCommand(OFF) // ausschalten
])
end
Die Rule fällt nun wesentlich kürzer aus und Du brauchst nur zwei Items (das zweite nur, um die zuletzt gewählte Zeit dauerhaft zu sehen)
In einer Sitemap wäre das Item dann so abgebildet:
Code: Alles auswählen
Switch item=Poolreinigungszeit label="Poolreinigung noch [%d Min]" mappings=[0="Aus",20="20",40="40",60="1h"]
Ein Item, drei Laufzeiten. Falls es mehr Laufzeiten sein sollen, geht auch das:
Code: Alles auswählen
Selection item=Poolreinigungszeit label="Poolreinigung noch [%d Min]" mappings=[0="Aus",20="20",40="40",60="1h",80="1h20",100="1h40",12="zwölf"]
Aber ich gehe stark davon aus, dass Du quasi nur eine "Schnellreinigung", ein "Normalprogramm" und eine "Intensivreinigung" brauchst.
In der Main UI geht das natürlich genauso gut.
So oder so brauchst man aber nur einen Timer, der sich sowohl um die Abschaltung als auch um die Anzeige kümmert, wichtig ist aber, dass dieser Timer seinen Zeiger in einer globalen Variablen speichern kann.
Edit: Im Code Zuweisungs-Operator gegen unären Operator getauscht
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet