Deine Rule ist momentan so ausgelegt, dass sie, wenn sie ausgelöst wird, prüft, ob der Zeitraum für die Benachrichtigung gegeben ist. Ist das der Fall, startest Du den Timer.
Jetzt stelle Dir folgendes vor: es ist 19:00 Uhr. Du öffnest die Garage. Der Timer wird angelegt. Um 19:02 schließt Du die Garage. Um 19:05 fällt Dir ein, dass Du noch etwas aus der Garage brauchst, Du öffnest die Garage. Ein zweiter Timer wird angelegt. Der Handle auf den ersten Timer wird mit dem Handle auf den zweiten Timer überschrieben, der erste Timer ist aber immer noch vorhanden und aktiv, nur halt ohne Handle. Um 19:07 schließt Du die Garage. Dummerweise hast Du noch etwas vergessen, Du öffnest die Garage nochmals, um 19:13. Ein dritter Timer wird angelegt (das gleiche Spiel wie beim 2. Timer).
Du brauchst diesmal etwas länger, nämlich 10 Minuten, bis Du die Garage wieder schließt. In der Zwischenzeit hast Du um 19:15 eine Nachricht bekommen, denn der 1. Timer läuft ab, und das Tor ist um 19:15 geöffnet. Um 19:20 bekommst Du eine zweite Nachricht, denn da läuft der 2. Timer ab und das Tor ist immer noch offen, trotzdem war das Tor nie mehr als 10 Minuten geöffnet.
Es reicht also nicht, beim Ablauf des Timer zu prüfen, ob das Tor geöffnet ist, Du müsstest dann schon prüfen, ob das Tor
ohne Unterbrechung immer noch geöffnet ist. Also ist ein anderer Aufbau eleganter:
Code: Alles auswählen
var Timer tGarage = null //vermeide unspezifische Variablen
rule "Garage Timer"
when
Item Garage_kontakt changed
then
if(Garage_kontakt.state == OPEN) { //falls Garage geöffnet wurde
tGarage?cancel // falls noch ein Timer existiert, löschen
tGarage = createTimer(now.plusMinutes(15), [|
if(now.getMinuteOfDay > 19 * 60 + 14 || now.getHourOfDay < 5) // Falls Uhrzeit 19:15:00 - 04:59:59
sendTelegram("Dennis", "Garage ist laenger als 15min. auf! ")
tGarage = null // nur der Ordnung halber...
])
}
else { //falls Garage geschlossen wurde
tGarage.cancel
tGarage = null // nur der Ordnung halber...
}
end
Der Unterschied ist: Der Timer wird immer angelegt, wenn das Garagentor geöffnet wird. Der Timer wird immer gelöscht, wenn das Garagentor geschlossen wird (die Rule triggert für beide Events und entscheidet anhand des Zustands, was zu tun ist). Wenn der Timer abläuft, wird die Uhrzeit geprüft und gegebenenfalls die Meldung ausgegeben.
Wenn wir auf unnötigen Code verzichten wollen, verkürzt sich die Rule nochmals:
Code: Alles auswählen
var Timer tGarage = null //vermeide unspezifische Variablen
rule "Garage Timer"
when
Item Garage_kontakt changed
then
tGarage?cancel // falls noch ein Timer existiert, löschen - unabhängig vom Zustand!
if(Garage_kontakt.state == OPEN) //nur falls Garage geöffnet wurde den Timer erstellen
tGarage = createTimer(now.plusMinutes(15), [|
if(now.getMinuteOfDay > 1154 || now.getHourOfDay < 5) // Falls Uhrzeit 19:15:00 - 04:59:59 (19*60 + 14 = 1154)
sendTelegram("Dennis", "Garage ist laenger als 15min. auf! ")
])
end
der Codeschnipsel
ist funktionsgleich zu
Wie oben erwähnt, ist es nicht notwendig, die Timer-Variable wieder auf null zu initialisieren. Bei der Definition könnte man auch darauf verzichten, aber das ist besserer Stil
Es ist in der DSL egal, ob man nun das Lambda (der Teil innerhalb []) als Teil des Funktionsaufrufs createTimer() oder dahinter schreibt, logisch gehört es aber zum Timer, so dass man besser
createTimer(timestamp,lambda) schreibt statt
createTimer(timestamp) lambda.
Der Import sollte unter OH2 übrigens nicht nötig sein. Der Code sollte (dann mit passenden Imports) uneingeschränkt auch unter OH1.x laufen (eigentlich sogar schon unter OH0.8 oder OH0.9, aber die müssen wir, glaube ich, nicht mehr berücksichtigen

)