I got a Rule, which sends an notification to my Smartphone when some Doors or Windows (and some else) state changes and no one is at home.
I use the Networkbinding for Presence detection which works pretty well. My problem was, when someone came home it took about one minute till the Smartphone was is detected and all Doors and so on were send as notification. Therefore I wanted a buffer time.
rule "Abwesend Fenster"
when
Member of gWd changed
then if(gAw.state == 0 && Notify.state==ON) {
buffer = createTimer(now.plusSeconds(120))[|
logInfo("Abwesend", "The item " + triggeringItem.label + " changed state from " + previousState + " to " + triggeringItem.state)
if( Notify_A.state == ON && Notify_AB_A.state==ON ) {
sendNotification ("xxx@gmx.de", "ABWESEND! " + triggeringItem.label + " von " + previousState + " to " + triggeringItem.state)
}
if( Notify_S.state == ON && Notify_AB_S.state==ON ) {
sendNotification ("xxx@gmx.de", "ABWESEND! " + triggeringItem.label + " von " + previousState + " to " + triggeringItem.state)
}
]
}
end
rule "Buffer"
when
Item gAw changed
then if (gAw.state != 0 && buffer !== null) {
buffer.cancel()
buffer = null
}
end
I made a simulation and it works, even if more items change their state within the 120sec., I get a notification for each after 120sec.
I just wonder why, cause the timer variable “buffer” is always the same, so I expected only one message for the last item which changed within the 120sec.
Is Openhab creating a new timer for each change automatically?
Looking forward to someone who knows what´s going on in detail, as I am no Programming “Expert”
It’s just a reference, a pointer, to the completely independent Timer code proper.
You can overwrite the reference, it does nothing to the existing Timer. So your code simply creates lots of timers and keeps the reference to just the last one.
If you look at other Timer examples, the usual thing to do is check to see if a Timer already exists before creating another one.
There is a difference between the actual timer object running and the variable “buffer” that’s storing only a reference to the timer.
If the rule will run 2nd time you are only overwriting the reference to the first timer, but not cancelling the first timer itself.
If you want to have multiple timers running I would recommend using a map to store them and using the triggering item name as a key.
If you just want to have one timer you should check if your variable is (un)defined or referencing to a timer and if the timer is active or not. There should be enough examples in the forum related to this
PS: have a look if you trigger the rule multiple times within the 120 seconds, if the first notification will include the correct item name (name of the door/window opened first) or only the name of the item opened last
Thank you both for the detailed answer, when triggering the rule multiple times, the names are correct, but when the same item changes (OFF → ON → OFF) only the last state is correct.
In addition only the last timer ist canceled in my rule (magic word “pointer”) and the others are still running, missed that yesterday when I tested.
I´ll try with storing them in a map to solve this.
Thanks both of you for your help.
In the End you are right, one message is better than a lot of messages for each change, maybe I was to focused on getting a message for each changed item.
Anyway, I already wrote a rule for that and just for interest I have one more question:
//Decl
val buffer = <String, Timer>newHashMap
//Code
rule "Abwesend Licht"
when
Member of gLi changed
then if(gAw.state == 0 && abwesend_auto_aktion.state == OFF && Notify.state==ON) {
buffer.put(triggeringItem.name, createTimer(now.plusSeconds(20)) [ |
logInfo("Abwesend", "The item " + triggeringItem.label + " changed state from " + previousState + " to " + triggeringItem.state)
if( Notify_A.state == ON && Notify_AB_A.state==ON ) {
sendNotification ("xxx@gmx.de", "ABWESEND! " + triggeringItem.label + " von " + previousState + " to " + triggeringItem.state)
}
if( Notify_S.state == ON && Notify_AB_S.state==ON ) {
sendNotification ("xxx@gmx.de", "ABWESEND! " + triggeringItem.label + " von " + previousState + " to " + triggeringItem.state)
}
])
}
end
rule "Buffer"
when
Item gAw changed
then if (gAw.state != 0) {
buffer.values.forEach[timer | timer.cancel()]
buffer.clear
}
end
this seams to work but the timer cancel works in two ways, ist there any difference between the following:
rule "Buffer"
when
Item gAw changed
then if (gAw.state != 0) {
buffer.values.forEach[timer | timer.cancel()]
buffer.clear
}
end
or this way:
rule "Buffer"
when
Item gAw changed
then if (gAw.state != 0) {
buffer.values.forEach[cancel()]
buffer.clear
}
end
just for interest, maybe I have some other use case.