Innerhalb der Rule, die durch ein Update ausgelöst wird, fragst Du den Zustand eines Items
Bewegungsmelder ab, welches ansonsten nicht in Erscheinung tritt. Insbesondere wird des durch die Rule nicht gesteuert.
Ich gehe davon aus, dass es sich hierbei um einen Schalter handelt, der den Bewegungsmelder deaktivieren soll. Die Implementierung sorgt allerdings dafür, dass bei deaktiviertem Bewegungsmelder jede erfasse Bewegung das Licht ausschaltet. Ich denke nicht, dass dies die Idee dahinter ist.
Weiter: Du verwendest ein (absurd kompliziertes) Konstrukt mit
now.withTimeAtStartOfDay, das gibt es nicht mehr, und zwar schon seit openHAB3.
.withTimeAtStartOfDay gehört zu Joda Time,in JavaTime wäre der adäquate Ersatz
.with(LocalTime.MIDNIGHT)
Unter openHAB2 bedeutet
now.isAfter(now.withTimeAtStartOfDay.plusHours(3)): nach 3 Uhr. Das ist ab 03:00:00.001 erfüllt.
Da die Zeitumstellung immer um 3 Uhr (zurück auf 2) oder 2 Uhr (vor auf 3) stattfindet (das ist der Grund, warum man überhaupt
.withTimeAtStartOfDay einsetzen muss), ist diese Formulierung unnötig.
Du kannst stattdessen einfach
now.getHour > 2 schreiben.
.getHour liefert die Stundenanzeige einer Digitaluhr, einen Integerwert von 0 - 23, d.h. die Bedingung ist ab 03:00:00.000 Uhr erfüllt.
Ich denke, die eine Millisekunde wirst Du verschmerzen können
Es ergibt sich also als vollständiger Ausdruck:
Code: Alles auswählen
if((now.getHour > 2 && now.getHour < 5) || (now.getHour > 15 && now.getHour < 22))
Das heißt, zwischen 3 Uhr und 5 Uhr sowie zwischen 16 Uhr und 22 Uhr ist die Bedingung erfüllt. (wie gesagt... eine Millisekunde möchte ich hier unterschlagen)
Das
reschedule() ist eine durchaus übliche Variante, ich bevorzuge allerdings eine andere Lösung, nämlich den Timer erneut anzulegen.
Dein Code ist nicht thread safe, denn Du prüfst nur bei
Bewegungsmelder.state != ON überhaupt ab, ob die Timer Variable gesetzt ist, nicht aber, wenn Du den Timer erzeugst. Wenn die Rule neu geladen wird, während der Timer aktiv ist, führt das beim nächsten Trigger zu zwei laufenden Timern, und der erste ist dann nicht mehr erreichbar, wird also auch nicht gelöscht. In der Folge wird das Licht dann ausgeschaltet, obwohl der letzte Timer noch läuft.
Gegenvorschlag:
Code: Alles auswählen
var Timer tLicht = null // Globale Variablen vor der ersten Rule platzieren!
rule "Bewegungsmelder Flur"
when
Item FlurBewegungsmelder_Motion received update
then
if(Bewegungsmelder.state != ON) // Automatik inaktiv?
return; // dann raus!
if(now.getHour < 3 || (now.getHour > 4 && now.getHour < 16) || now.getHour > 21) // außerhalb des Zeitfensters?
return; // raus!
if(FlurLicht_Light.state != ON) // Falls Licht aus
FlurLicht_Light.sendCommand(ON) // einschalten
tLicht?.cancel // Falls Timer vorhanden, canceln
tLicht = createTimer(now.plusMinutes(5), [ // Setze Timer auf 5 Minuten
if(FlurLicht_Light.state != OFF)
FlurLicht_Light.sendCommand(OFF) // schalte das Licht aus
])
end
Zunächst wird geprüft, ob die Rule aktiv sein soll. Ist das nicht der Fall, wird sie abgebrochen. Dies passiert einmal für den Schalter Bewegungsmelder und einmal über die Zeitbedingung.
now.getHour < 3 ist von 00:00:00.000 bis 02:59:59:999 gültig,
(now.getHour > 4 && now.getHour < 16) ist von 05:00:00.000 bis 15:59:59.999 gültig.
now.getHour > 21 ist von 22:00:00.000 bis 23:59:59.999 gültig,
Läuft die Rule zu diesem Zeitpunkt noch, so muss das Licht eingeschaltet werden, falls das noch nicht geschehen ist.
Danach wird ein eventuell gerade laufender Timer gelöscht. Das ? bedeutet, .cancel wird nur ausgeführt, wenn tLicht !== null ist.
Zuletzt muss der Ausschalttimer auf 5 Minuten gesetzt werden, in dem ebenfalls geprüft wird, ob das Licht noch an ist.
Die ganzen anderen Befehle (Timer erneut mit null initialisieren usw.) sind nur unnötiger Ballast.
Durch den Einsatz von
return; wird die Schachtelung der Rule reduziert, was wiederum die Übersichtlichkeit erhöht
openHAB4.2.0 stable in einem Debian-Container (bookworm) (Proxmox 8.2.4, LXC), mit openHABian eingerichtet