[SOLVED] Cancel timer (or logical) problem

Hi,

I am running OH 2.5.8 on openhabian, with the following rule:

val Long_Window_Open_Delay_sec  = 3540
var Timer Bath_EG_Window_Open_Timer

rule "EG Bad Fenster auf"
when
    Time cron "0 4 * * * ?"
then
    if (Fenster_EG_Bad.state == OPEN) {
            if (Bath_EG_Window_Open_Timer !== null){
                    Bath_EG_Window_Open_Timer.cancel()
                    Bath_EG_Window_Open_Timer = null
            } else if (Bath_EG_Window_Open_Timer === null){
                    Bath_EG_Window_Open_Timer = createTimer(now.plusSeconds(Long_Window_Open_Delay_sec), [ |
                            sendTelegram("XXXX", "EG Bad Fenster ist seit mindestens 1h auf!")
                            Bath_EG_Window_Open_Timer = null
                    ])
            }
    } else if (Fenster_EG_Bad.state == CLOSED || Fenster_EG_Bad.state == NULL) {
            if (Bath_EG_Window_Open_Timer !== null){
                    Bath_EG_Window_Open_Timer.cancel()
                    Bath_EG_Window_Open_Timer = null
            }
    }
end

This is basically what I produced from this topic:

The problem that i am experiencing is, that if i opened the window, left it open for a longer time, received a Telegram notification and then closed the window, i still receive one more notification after the window was already closed.

How should I modify the rule in a way, that this is not happening anymore? I guess I have a logical error here, but currently i seem to be too blind to spot it myself.

Thanks, Martin

This seems a poor choice of rule trigger.
Why wouldn’t you run the rule when the window state changes? That’s the only time you need to do stuff.

Because I want an other notification, if the window is still open after 2, 3, 4, … hours.

Do you suggest, I should do

when
    Time cron "0 4 * * * ?" or
    Item Fenster_EG_Bad received update

to cancel the timer this way?

The problem is, that you are creating a new timer, each minute (if i read the cron correct) if no Timer is set.

So in the example you gave the following happen:

Window Open -> Timer created -> Telegram message send -> Timer created -> Window closed -> Telegram message send

If you want to stay with your cron as rule trigger, you have to check if the window is still open, and only if its open, the Telegram message should be triggered

Time "0 4 * * * ?"

to my understanding this should be every hour at 4 minutes past the full hour.

Isn’t that was my else if code block is doing?

You are right, the cron will be triggered every hour at 4 minutes.
But it make no sense for this rule.
Cause when you open your Window at 14:05, it is open since 59 minutes before a timer is created.

I think you should add some logs to your rule, to see when the timer is created, the message is send (timer expired) and next cron run is triggered.

If your Timer is expired before the next cron run, your message will be send even the window is closed.

But without logs, we won’t see if the cancel of the timer is not working or the above mentioned scenario is happening

That’s fine. No cron rule trigger is needed here, ever, at all. It takes a while to get your head around events-driven proramming.

The action you are describing is something to do at the moment your timer goes off. Send a message, then reschedule itself to send another in an hours time.

When the window closes, cancel the timer.

While it makes little difference to openHAB, sometimes it is easier to grasp what is going on by using several rules. Don’t be afraid to make many little rules instead of one cumbersome thing.

In this case -
When window opens, make a timer.
When window closes, cancel timer.
When timer expires, send a message and reschedule.

I found Looking for a beginner guide about timers and Effective use of Timers in Rules in the mean time, and will try to rework my rules based on those topics and tell then if this works.

And yes, i agree, splitting the rules into smaller pieces sounds the right thing to do.

Thanks all for the feedback so far.

Okay, my rule looks now like this, and seems to work.

val Long_Window_Open_Delay_sec  = 3600
var Timer Bath_EG_Window_Open_Timer = null

rule "EG Bad Fenster auf"
when
        Item Fenster_EG_Bad changed
then
        logInfo("FensterBad", "EG Fenster Bad rule triggered")
        switch Fenster_EG_Bad.state {
                case OPEN: {
                        logInfo("FensterBad", "EG Fenster Bad opened")
                        Bath_EG_Window_Open_Timer = createTimer(now.plusSeconds(Long_Window_Open_Delay_sec), [ |
                                logInfo("FensterBad", "EG Fenster Bad - Telegram sent")
                                sendTelegram("XXXX", "EG Bad Fenster ist seit mindestens 1h auf!")
                                logInfo("FensterBad", "EG Fenster Bad - reschedule")
                                Bath_EG_Window_Open_Timer.reschedule(now.plusSeconds(Long_Window_Open_Delay_sec))
                        ])
                }
                case CLOSED: {
                        logInfo("FensterBad", "EG Fenster Bad closed, canceling timer")
                        Bath_EG_Window_Open_Timer.cancel()
                        logInfo("FensterBad", "EG Fenster Bad closed, timer set to null")
                        Bath_EG_Window_Open_Timer = null
                }
        }
end

Logging is a very verbose at the moment, but it helped to understand at which time which part of the rule was triggered.

I ran into the problem that
case "OPEN:" and case OPEN: (note the missing quotation marks) are not the same, and with the quotation marks the case stanza is not triggered, but due to the verbose logging that issue i found very fast.

1 Like