Member of triggered Timer works...but why

openHAB version: 2.5.12

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” :smile:

Greetings Andy

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.

Greetings
Andy

Why? Wouldn’t you want only one message per incident i.e. only one Timer needed?

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.

Tanks in advantage
Grteetings
Andy

If you give whatever-it-is you are for-eaching through a temporary name, then you can do stuff with it,

bunchOfNumbers.forEach[ banana | banana = banana + 1]

Just a syntax shortcut I did not even know existed.