Der Fehler ist einfach: Du definierst einen Timer und nutzt eine Variable, um den Zeiger auf den Timer zu speichern. Unmittelbar danach löschst Du die Variable wieder.
Das ist ein sehr gern genommenes Missverständnis im Zusammenhang mit createTimer. Der Code im Lambda (das ist der Teil zwischen [ und ]) wird dem Scheduler übergeben und es geht unmittelbar weiter nach dem createTimer(), da gibt es keine Millisekunde Abstand.
Deshalb muss der Code so aussehen:
Code: Alles auswählen
var Timer tTest = null
//Test rule
rule "testen"
when
Item BewegungHelloweenPresence changed to ON // Bewegungsmelder löst aus
then
if(tTest !== null){ // prüft ob Timer läuft
logInfo("test", "Bewegung Timer verlängert")
tTest.reschedule(now.plusSeconds(120)) // Timer läuft und wird umgeplant
} else { // Timer läuft nicht
logInfo("test", "Bewegung Timer läuft")
Testschalter.sendCommand(ON) // Schalter ein
tTest = createTimer(now.plusSeconds(180), [| // Timer starten
Testschalter.sendCommand(OFF) // Timer abgelaufen, Schalter aus
logInfo("test", "Bewegung Timer abgelaufen")
tTest = null // Timer Variable auf "null"
])
}
end
Der kleine, aber feine Unterschied: Die Timer Variable wird innerhalb des Timers auf null gesetzt, nicht außerhalb. Das ist auch völlig logisch, denn solange der Timer läuft, darf der Zeiger keinesfalls gelöscht werden, sonst kann man ja gar nicht mehr auf den Timer zugreifen. Als Folge werden lauter neue Timer angelegt, jeder einzelne davon läuft nach drei Minuten ab und schaltet das Licht aus.
Ansonsten hilft die "korrekte" Einrückung, den Code besser zu verstehen. Alle Befehle auf einer Ebene laufen als Block ab.
Die Einrückung ist dabei aber nicht die Ursache für die Blockbildung, sondern dient lediglich der optischen Struktur.
Eine andere Variante der Rule (ohne logging):
Code: Alles auswählen
var Timer tTest = null
//Test rule
rule "testen"
when
Item BewegungHelloweenPresence changed to ON // Bewegungsmelder löst aus
then
tTest?.cancel // Timer abbrechen, falls existent
var Integer iTime = 120 // Zeit für Verlängerung
if(Testschalter.state != ON) { // Falls Licht aus
Testschalter.sendCommand(ON) // Schalter ein
iTime = 180 // Startlänge
}
tTest = createTimer(now.plusSeconds(iTime), [| // Timer starten
Testschalter.sendCommand(OFF) // Timer abgelaufen, Schalter aus
])
end
Der Timer wird in diesem Fall nicht verlängert, sondern erneut angelegt. Wenn man auf die unterschiedliche Länge verzichtet, kann man natürlich auf die zweite Variable iTime verzichten und damit drei Zeilen einsparen (da nur ein Befehl durch das if gesteuert werden muss, kann man auf die geschweiften Klammern verzichten).
openHAB5.1.3 stable in einem Debian-Container (trixie, OpenJDK 21 headless runtime - LXC, 4 Kerne, 3 GByte RAM)
Hostsystem Proxmox VE 9.1.9 - AMD Ryzen 5 3600 6 Kerne, 12 Threads - 64 GByte RAM - ZFS Pools: Raid Z1, 3 x 20 TB HDD -> 40 TByte und Raid Z0-Mirrored 4 x 1 TByte NVMe -> 2 TByte