Moin!
Zu Deinen Fragen:
1. Die Funktion heißt now.getHourOfDay() und liefert die Stunde des Tages. Die Uhrzeit kann von 0:00:00 bis 23:59:59 gehen. Somit liefert die Funktion um 20:59:59 eine 20 zurück, um 21:00:00 Uhr dann eine 21. Du könntest auch auf <21 testen, statt auf <=20. Sinngemäß gilt das gleiche für die andere Seite, Du könntest also für "Ab 8 Uhr" auch >7 abfragen. Eine etwas verschwurbelte Version wäre diese hier:
Code: Alles auswählen
val Integer hVon = 8
val Integer hBis = 21
if(now.minusHours(hVon).getHourOfDay < hBis-hVon) //klingeln
else //nicht klingeln
Um 8 Uhr wäre es vor 8 Stunden (minusHours(8)) 0 Uhr gewesen. Eine Sekunde vorher wäre es 23:59:59 Uhr gewesen.
Um 21 Uhr wäre es vor 8 Stunden (minusHours(8)) 13 Uhr gewesen. Eine Sekunde vorher wäre es 12:59:59 Uhr gewesen.
So kommt man mit nur einer Bedingung aus.
Prinzipiell gibt es einen Stolperstein, nämlich, wenn Sommer/Winterzeitumstellung stattfindet. Das spielt natürlich nur eine Rolle, wenn dieses Ereignis im Zeitfenster liegt, außerdem hat sich das ja spätestens im November 2019 erstmal erledigt.
Ansonsten kann man sich trefflich streiten, welche Version eleganter ist...
openHAB arbeitet komplett asynchron und multithreaded, das heißt in diesem Fall, wenn Du ein Thread::sleep() absetzt, schickst Du zwar den Thread schlafen, der die Rule ausführt, das hindert openHAB aber nicht daran, die Rule ein weiteres Mal zu starten, sobald sie wieder getriggert wird, die Rule läuft dann also n-mal (n = Anzahl erkannte Trigger, n < 6)
Die Einschränkung auf 5 Threads rührt daher, dass openHAB default 5 Threads zur Ausführung von Rules zur Verfügung stellt. Damit ist auch sofort klar, dass Thread::sleep() nur für kleine Verzögerungen (erfahrungsgemäß weniger als 500 Millisekunden) verwendet werden sollte, weil sonst die Gefahr steigt, dass Rules nicht ausgeführt werden, obwohl es ein Trigger Ereignis gab.
Und jetzt? Man kann das Problem elegant umschiffen, indem man einen Timer verwendet.
Code: Alles auswählen
var Timer tKlingel = null //Definition zu Beginn des Rule File, diese Variablen sind global gültig!
rule "Klingel von 08:00 bis 21:00 Uhr"
when
Channel "mihome:sensor_switch_aq2:xxxx:button" triggered SHORT_PRESSED or
Channel "mihome:sensor_switch_aq2:xxxx:button" triggered DOUBLE_PRESSED
then
if (now.getHourOfDay > 7 && now.getHourOfDay < 21) { //zwischen 8 Uhr und 21 Uhr
if(tKlingel === null) { // Timer läuft noch nicht?
sendBroadcastNotification("Es klingelt!")
sendLogNotification("Es klingelt!")
GateU_SoundVolume.sendCommand(10)
GateU_SoundSelector.sendCommand(10)
tKlingel = createTimer(now.plusMillis(2500),[
GateU_SoundVolume.sendCommand(0)
GateU_SoundSelector.sendCommand(10000)
tKlingel = null
])
}
} else {
sendBroadcastNotification("Es klingelt außerhalb der Sprechzeiten!")
sendLogNotification("Es klingelt außerhalb der Sprechzeiten!")
}
end
Diese Rule sollte sich genauso verhalten wie Deine, mit dem Unterschied, dass der Klingelsound nicht neu gestartet wird (und auch keine weitere Notification erfolgt), falls innerhalb der 2,5 Sekunden erneut geklingelt wird. Nebenbei wird die Rule ohne weitere Verzögerung beendet, so schnell das geht. Nach 2,5 Sekunden endet der Timer und das übergebene Lambda (alles zwischen [ und ]) wird ausgeführt. Wichtig (da wir darauf testen) ist das Zurücksetzen der Variable am Schluss.
Je länger man pausieren möchte, desto wichtiger ist es, Timer zu verwenden.
Eine Alternative wäre ein lock-Mechanismus, aber das ist mit Vorsicht zu genießen
Wie Du im Code sehen kannst, habe ich die Methode Item.sendCommand(Value) statt der Action sendCommand(Item, Value) verwendet. Im vorliegenden Fall sollte es unerheblich sein, aber zum einen ist das besserer Stil, zum anderen gibt es Situationen (genau dann, wenn man Primitives übergibt), wo die Methode wunderbar funktioniert, die Action aber nicht mehr, denn die Action erwartet immer zwingend zwei Strings, während die Methode den Wert abhängig vom Itemtyp erwartet.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet