I want to create a rule that whenever I open my window OH will wait 15 minutes to say “window is open for 15 mins” and then every 5 minutes it will remind me about it.
val ADD_MINUTES = 5
val HUMIDITY_MAX_LEVEL = 55
val INIT_DELAY = 15
rule "super-duper-rule"
when
Item window received update OPEN
then
var secondsPassed = 0;
var nextMinutesToSay = INIT_DELAY
while(secondsPassed / 60.0 < MAX_MINUTES_TO_RUN && window.state == OPEN) {
Thread::sleep(1_000)
secondsPassed++
if (secondsPassed / 60.0 > nextMinutesToSay) {
say(nextMinutesToSay+ " minutes passed")
nextMinutesToSay += ADD_MINUTES
}
}
end
I’m not super happy with this solution cause it has Thread::sleep that will block whole rule, but I did not found a way to run createTimer with recursive calls.
val ADD_MINUTES = 5
val INIT_DELAY = 15
var Timer tWindow = null
rule "super-duper-rule"
when
Item window changed
then
tWindow?.cancel
if(newState == OPEN)
tWindow = createTimer(now.plusMinutes(INIT_DELAY), [
val iMinutes = (now.toEpochSecond - window.previousState().timestamp.toEpochSecond)/60
say(iMinutes.toString + " minutes passed")
tWindow.reschedule(now.plusMinutes(ADD_MINUTES))
])
end
Don’t use received update if you don’t need to. You only want to execute the rule when the Item changed.
First thing, the rule will do is to cancel the timer, if there is any.
Then, only if the new state is OPEN, the timer will be created.
When the timer expires, the time from the last state change is queried from the default persistence. This is used to calculate the time since the last change. I’m pretty sure that it should be previousState(true), but I got an error with a strange message rrd4j does not allow querys without a begin date which makes no sense at all. Maybe there is an issue with rrd4j for this query.
after saying the amount of time which has passed, the timer gets rescheduled and that’s it.
Install that template from the Add-on store → Automation screen.
create the rule that implements your alert, the name of the Item will be alertItem
Put your window Items into a Group
Instantiate an instance of the rule template with:
Triggering Group: the Group created in 3
Threshold State: OPEN
Comparison: ==
Alert Delay: PT15M
Reminder Period: PT5M
Alert Rule: Rule created in 2
Leave everything else set to the default and the rule you create in step 2 will get called when ever any member of the Group created in a step 3 remains in the OPEN state for 15 minutes and it gets called again every five minutes thereafter until the Item is no longer OPEN.
It also has features like the ability to call a rule when the window first changes to OPEN, when it changes to something other than OPEN (e.g. CLOSED), and you can define do not disturb periods where the alert rules will not be called. Custom timeouts can be defined on an Item by Item basis trough Item metadata so each door (in my case) can have it’s own unique alerting time and repeated alert times.
The only code you should need to write is your alert. The rule template handles the rest.
Here’s my rule that tells me when I leave a door open for too long which gets called by this rule template. You will see all I have to mess with is the alerting logic. All the Timer stuff is handled by the rule template.
configuration: {}
triggers: []
conditions: []
actions:
- inputs: {}
id: "1"
configuration:
type: application/javascript
script: >
var {alerting} = require('rlk_personal');
var KEY = 'hasAlerted';
var hasAlerted = cache.private.get(KEY, () => false);
var item = items[alertItem];
console.info(item.label + ' is now ' + item.state + ': alerting - ' + isAlerting + ' has alerted - ' + hasAlerted + ' initial alert - ' + isInitialAlert);
if(!isAlerting && hasAlerted && !isInitialAlert) {
alerting.sendAlert(item.label + ' is now closed: initial - ' + isInitialAlert, logger);
cache.private.put(KEY, false);
}
else if(isAlerting && !hasAlerted) {
alerting.sendAlert(item.label +' has been open for a long time! initial - ' + isInitialAlert, logger);
cache.private.put(KEY, true);
}
else {
console.log('Not alerting or alert not ended');
}
type: script.ScriptAction
Rule templates support a lot of common use cases like this. They are a great resource.