Issue of the topic:
I have tried different ways to cancel my timer. But no matter how it is not working as intended.
I have a light that I wan’t to get a notification from if turned on for more than 30 minutes. If turned off before timeout it should cancel the notification. The rule works “half way” meaning that if the light has been on for more than 30 minutes I get the notification. Also if the light is turned off before timeout the notification is canceled.
The problem is: If light is first turned on, then turned off, and then turned on again within the 30 minute timespan, the notification is send after 30 minutes from the first time the light is turned on. I wan’t it to cancel the timer the first time the light is turned off.
Items configuration related to the issue:
Dimmer Badevaerelse (Created in UI)
Trigger in UI: Item Badevaerelse changed
Rules code related to the issue (made in RuleDSL
var Timer BadevaerelseTimer = null
val actions = getActions("pushover", "pushover:pushover-account:XXXXXXXXXX")
BadevaerelseTimer?.cancel
BadevaerelseTimer = createTimer(now.plusSeconds(1800)) [
if ( Badevaerelse.state > 0 ) {
actions.sendMessage("Lys Badeværelse","openhab")
}
]
Timer in a dsl rule will only work if you defined the rule within a file, otherwise your variable / reference to the timer will not exists with the next execution of the rule.
If you want to stay with ui defined rules (what I would recommend) you can use JavaScript instead of dsl as a rule language and also try blockly, what will already produce the correct code for you
As mentioned before: as per my knowledge due to limitations of how variables defined, a dsl rule defined via gui can never work with timers add you want.
They with blockly first and if you there are some issues, we will find a solution l.
I have now tried different setups, and ended with putting the rule back into .rules file. And now it works again. I have changed from OH2 to OH3 and thought that I could just use UI in combination with RuleDSL the same way as in .rules file in OH2.
The solution for now was to create a .rules file like in OH2:
var Timer BadevaerelseTimer = null
val actions = getActions("pushover", "pushover:pushover-account:XXXXXXXX")
rule "Pushover Lys Badeværelse"
when
Item Badevaerelse changed
then
BadevaerelseTimer?.cancel
BadevaerelseTimer = createTimer(now.plusSeconds(1800)) [
if ( Badevaerelse.state > 0 ) {
actions.sendMessage("Lys Badeværelse", "openHAB")
}
]
end
The difference between rules file and a dsl rule via GUI is, that in your file the BadevaerelseTimer variable is outside of the rule, but when defining the same rule via GUI the variable is defined inside the rule and therefore is only existing within one single rule execution.
Even you code seems to work as you want, I would still add some if / else condition to it, as right now even when you turn off the light, the timer will start to run (but just not sending a message). You can do something like:
Btw: If you would do it with blockly it would look like this:
and would produce the following code that you can also use in a javascript rule created via UI (using standard openHAB notifications and not pushover):
if (typeof this.timers === 'undefined') {
this.timers = [];
}
var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');
var zdt = Java.type('java.time.ZonedDateTime');
var notifications = Java.type('org.openhab.io.openhabcloud.NotificationAction');
if (event.itemState == 0) {
if (typeof this.timers['MyTimer'] !== 'undefined') {
this.timers['MyTimer'].cancel();
this.timers['MyTimer'] = undefined;
}
} else {
if (typeof this.timers['MyTimer'] === 'undefined' || this.timers['MyTimer'].hasTerminated()) {
this.timers['MyTimer'] = scriptExecution.createTimer(zdt.now().plusMinutes(30), function () {
notifications.sendNotification('test@example.org','message');
})
}
}