Script does not work as expected

I know this question has been answered before because I remember seeing the code but I just can’t find it again.

I have a very sensitive sensor to detect when mail is in the mailbox so I want to avoid sending notices because of vibrations. I want the contact to be continuously in the closed position before an e-mail announcing that the mail has come is sent

This is the code I am using in a script triggered by the contact closing

var Timer mailboxTimer = null
if(Mailbox_Contact.state == CLOSED){
mailboxTimer = createTimer(now.plusSeconds(30)) [|
          val mailActions = getActions("mail","mail:smtp:dd7055cab0")
          mailActions.sendMail("XXXX@xxx.com","Openhab","There is something in the mailbox")
        ]
  }else{
          mailboxTimer.cancel
          mailboxTimer = null
                }

I thought this would stop and reset the timer if the script is triggered but then the contact opens within 30 seconds. However that is not happening I get an e-mail every time the contact closes no matter how briefly.

I know the problem is me not understanding the programming language but if someone can show me what is wrong I would appreciate it.

Thank you
carlos

All you’ve done is wait 30 seconds before sending the email notification. You need an if statement to cancel the timer if the contact opens before thirty seconds are up.

I thought that was what the else statement did.

If state is closed
then run timer
else // if state is open
then cancel timer

I know there is something wrong because it does not work, but I don’t see where to add an additional if statement.

The problem appears to be your parentheses. Here you close the createTimer with the second ) before you ever define the function the timer should run. So you create a blank timer and the immediately run the function that sends the mail. The function that the timer should execute needs to be the second parameter in the createTimer call and the second ) comes after the function definition.

mailboxTimer = createTimer(now.plusSeconds(30), [|
  val mailActions = getActions("mail","mail:smtp:dd7055cab0")
  mailActions.sendMail("XXXX@xxx.com","Openhab","There is something in the mailbox")
  ])
1 Like

That makes sense

Thank you

Your problem is that the mailboxTimer variable gets reinitialized (and set to null) every time the rule runs, so when the script runs and hits the else-block, there is no reference to the timer. I could expect a NullPointerException every time this happens, since it tries to call .cancel on null.

Are you using .rules-files? In that case you need to declare the variable outside the rule. If you are using UI-rules I’m not sure global variables are possible to use.

He never got one as the if statement is meaningless. The rule is “triggered by the contact closing” so the else part will never be reached.

MainUI does not have the ability to use global scope variables. You can however, achieve the same persistent functionality by declaring an Item to keep the state needed to reset the timer.

2 Likes

Yeah, sorry. I missed the else statement sandwiched between the parentheses. That’s what I get for reading code on my phone, particularly since I’m kind of a neat freak when it comes to formatting.

As @JustinG pointed out, you need the function to be a parameter within the timer. You might have gotten confused by people using createTimer as simple delays:

createTimer(now.plusSeconds(30)) [ DO STUFF ]

I do this whenever I’m not worried about cancelling the timer.

This might be the post you were thinking of. For future reference, I searched “timer.cancel” to find it.

Note that the example uses two separate rules: one to start the timer and another to cancel it. I’m not sure if that works in MainUI (I haven’t tried it). The IF/ELSE should work fine, except for this:

As @Netboy3 points out, you stated that your rule only triggers on a CLOSED state. You need it to trigger whenever the contact changes to any state, so that it can react to CLOSED or OPEN.

I’m curious, how could an Item be used to keep the state of a Timer? Do you mean by using the expire functionality instead of a regular Timer?

I was wondering how Openhab kept track the state of the item within the script to cancel the timer if the item changed state, now I get it.

Sorry for the delay in responding. I didn’t say it should keep the state of the timer, but keep the state needed for the timer. This script needs a persistent state remembered outside of the rule to tell the rule that it’s in “cooldown” and should not start yet another timer instance.

Did you try to trigger this rule by contact change ? Otherwise the “else” part will not be called at all.

Yes, it did work, now I don’t get 100 e-mails every time the mail comes.
Thanks