Open Reminder

image

This rule template addresses the problem where one wants to do something periodically after an Item changes from a given state for long enough. For example, send an alert when a door has been open for 15 minutes and repeat the alert every five minutes until the door is closed. Or wait until a motion sensor stops triggering for five minutes and turn off the light.

This rule template is closely related to Threshold Alert. The primary difference is Threashold Alert looks for numerical values above or below a given value where this one looks for Item states that are exactly the same or exactly different from a given state. In other words, Threshold Alert is for number Items and this is for Switch, Contact, or looking for Items going to NULL or UNDEF. Some day I hope to merge them but the configuration is going to be challenging.

In addition to supporting an initial timeout (how long the Item should be in the alert state before alerting) and a potentially different repeat timeout (how often to generate the alert again), the template also supports an optional time period where the alerts are not allowed so, for example, you can prevent an alert on your phone every five minutes during the day when you don’t care as much if the window is open. Any alert that occurs during this time will be moved to the end of the period, as long as the Item remains in the alerting state.

The rule has a number of properties.

Property Required Default Description
Group of Triggering Items X The Group containing the Items this rule will monitor.
Alert State X The state the Item has to be different from for alerts. For example, an open door reminder would use CLOSED as the Alert State.
Invert false If checked, it inverts the meaning of Alert State so the alerts are sent when the Item is the same as Alert State instead of different.
Default Initial Timeout PT15m By default how long the Item needs to be different from the Good State before the first time the alert script is called. Set to “PT0s” to run immediately.
Default Item Initial Timeout Metadata rem_time The Default Initial Timeout can be overridden on a per Item basis by adding metadata to the Items. The value of the metadata is used and should be in duration format (see below).
Repeat Period How often to call the alert script again after the first initial timeout. If left blank no repeats will be performed.
Reschedule false If the rule is triggered again with the alerting state, whether to reschedule the looping timer or ignore the state change. Default is to ignore the state change.
Alert Rule Rule UID to be called after the initial timeout and again every repeat period.
Alert Starting Time 00:00 The time to start allowing the rule to call the alert rule.
Alerting Ending Time 00:00 The time to stop allowing the rule to call the alert rule.

If you need to have a different trigger type than changed, you can edit the rule after you create it. Unfortunately it appears that the trigger type cannot be a rule template parameter.

The initial timeout, value of the initial timeout metadata, and repeat period should all be in ISO-8601 Duration format. In general that will be a String starting with PT followed by numbers and a designator for time units. For example, one hour and two seconds would be PT1h2s.

You provide the Item metadata namespace for the default Item initial timeout metadata. The value of this metadata will be the initial timeout duration used for that Item. In a text Item, assuming the namespace is “rem_time” that will look like rem_time=PT10m. In the UI add metadata named rem_time and supply the timeout String as the value.

If the alerting starting time and ending time are the same, the rule will call the alert script with no time based restrictions. If the starting time is later than the ending time, the time period is assumed to span midnight (e.g. if starting time is 09:00 and ending time is 21:00, the do not disturb period will be between 9:00 pm and 9:00 AM the next morning). If an alert is looping/ongoing or an alert needs to start during the do not disturb period, the alerts will be moved to the end of the period, as long as the Item remains in the alerting state.

The call to your alerting rule will follow any conditions defined there so you can provide additional restrictions as desired (for example, only alert on an open window when the AC is ON).

If this rule is triggered and you manually edit it, be sure to run the rule manually to clear out the old looping timers or you will see “context has been closed” errors in the log.

Language: ECMAScript 2011

Dependencies:

  • JS Scripting add-on
  • openhab-js version after Aug. 17, 2022 (until the fix makes it into the release to install the fix from the $OH_CONF/autmation/js folder run npm install openhab). Remember to remove it or manually keep it up to date.
  • openhab-rules-tools 1.1.2 or later (to install navigate to the $OH_CONF/automation/js directory and run npm install openhab_rules_tools).

To Do

  • see if there is any way to merge this and Threashold Alert into one rule template

Changelog

Version 0.6

  • added an option to reschedule the timer in cases where the rule is triggered with the alerting state and an Item already has a Timer scheduled. This is useful for stuff like motion sensor timers where you want something to occur only after the Item has been in the alerting state for the timeout as opposed to wanting an alert from the first event.

Version 0.5

  • Changed how I avoid timers going off at the same time to be based on the actual scheduled timer’s times instead of when the rule is triggered. This avoids collisions when the timeout times are different for each Item as well as avoids the looping reschedules from colliding.

  • If an alert is looping, or a new alert occurs during the do not disturb period, move the next alert to the end of the do not disturb period instead of canceling it entirely.

  • Added the ability to choose the event that triggers the rule to support more use cases. Apparently this is not supported at this time.

Version 0.4

  • if a lot of Items match all at once, the timers will be triggered on top of each other causing “multithreaded” exceptions. This version staggers the timers half a second apart when they occur too close together. This staggering will eventually be moved to all the timer libraries in openhab-rules-tools.

Note this change corresponds with a requirement to upgrade openhab-rules-tools to v1.1.2.

Version 0.3

  • added the ability to invert the match so any Item that does match the “good state” triggers the alert.

Version 0.2

  • added ability to not repeat the alert by setting the repeatPeriod to the empty string.

Version 0.1

  • initial release

Resources

https://raw.githubusercontent.com/rkoshak/openhab-rules-tools/main/rule-templates/openReminder/open_reminder.yaml

3 Likes

hello
Quick question will be possible to have multiple states within a group :slight_smile: like ON or OFF 1 or 0?

This rule template only handles one “goodState”. The Items can have any number of states but the looping timer will only start when the Item changes from that one “goodState”.

However, you could use two Groups and two instances of rules created from this template, one for OFF and another for 0. They both can be configured to call the same rule you write to generate the alert.

The nice thing about rule templates is it’s really easy to just instantiate and configure them. It’s no big deal if you have more than one copy of the rule with different configurations.

Hi,

I added the template to learn more about it but I received a failure when I ran it. I believe it is because the item word on line 130 has an extra ‘m’

Console Log

2022-09-19 20:15:05.356 [DEBUG] [.script.rules_tools.reminderswitches] - WemoPlug_Switch is in the alert state of OFF
2022-09-19 20:15:05.359 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: ReferenceError: "itemm" is not defined

Rule Script

  // Item changed to a not alertState, create a looping timer if one doesn't already exist
  else if(isAlertState(state)) {
    logger.debug(item + ' is in the alert state of ' + state);

    // There shouldn't be a Timer if the Item just changed to the alertState, log to show
    // something went wrong.
    if(timers.has(item) && reschedule) {
      logger.debug('Rescheduling timer for ' + item + ' with ' + timeout);
      timers.get(item).timer.reschedule(time.toZDT(timeout));
    }
    else if(timers.has(itemm) && !rescedule) {
      logger.warn(item + ' state is now ' + state + ' but an alert timer already exists! This should not have happened!');

The rule partially works after I correct it but I receive a new error. Any suggestions on how to troubleshoot this error. I have installed the prerequisites (sudo npm install openhab & openhab_rules_tools)

2022-09-19 20:37:52.289 [DEBUG] [.script.rules_tools.reminderswitches] - Running door alert rule with: 
  item:           WemoPlug_Switch
  state:          ON
  alertState:     ON
  invert:         true
  defaultTimeout: PT0
  repeatPeriod:   PT1m
  dndStart:       00:00
  dndEnd:         00:00
  noAlertPeriod:  true
  alertRuleUID:   door_open
2022-09-19 20:37:52.291 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'ReminderSwitches' failed: java.lang.IllegalStateException: The Context is already closed.

That’s weird. I’m pretty sure I installed and used the latest version. Maybe it reinstalled a cached version and there latest remained untested. This is a huge pain with rule templates.

Yes, line 130 had a typo.

That last error is ready to deal with and in fact I mentioned it in the docs for the template above. If you edit and save the rule for any reason, you have to run it at least once manually so it can clear the stale timers out of the cache. Otherwise it’ll will generate that error.

When you fixed the typo, you didn’t trigger the rule manually.

I’m on travel but I can manage to remove that extra m from my phone at least.

Let me know if you have any more problems with it.

edit: looks like I can’t edit it from my phone easily. I’ll try to fix it when I get back to a computer.
Edit: It’s fixed now

Can I somehow get the name of the trigger Item in the “Alert Rule”, e.g. to use the item name in a notification.

What language is the called rule written in? If it’s ECMAScript 11, the Item is passes as alertItem and the state the Item was in to generate the call is in currState. These are just injected into your called rule as is.

console.log('Received alert from ' + alertItem + ' in state ' + currState);

If ECMAScript 5.1, it comes over in a variable called context.

logger.info('test', 'Received alert from ' + context.alertItem + ' in state ' + context.currState);

I think the other JSR223 rules languages will also get them in that context variable. I’ve no idea how it works/if it works in Rules DSL. I would guess it works like ECMAScript 11, if it works at all.

You can see my use of these in several examples at How I Use Rule Templates

I ran the script in the rule manually but I still see that error

2022-09-21 10:54:23.629 [INFO ] [openhab.event.RuleStatusInfoEvent   ] - Door_Status updated: RUNNING
==> /var/log/openhab/openhab.log <==
2022-09-21 10:54:23.633 [INFO ] [ation.script.rules_tools.door_status] - Resetting looping timers
==> /var/log/openhab/events.log <==
2022-09-21 10:54:23.633 [INFO ] [openhab.event.RuleStatusInfoEvent   ] - Door_Status updated: IDLE
2022-09-21 10:54:33.449 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'WemoPlug_Switch' received command OFF
2022-09-21 10:54:33.450 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'WemoPlug_Switch' predicted to become OFF
2022-09-21 10:54:33.453 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WemoPlug_Switch' changed from ON to OFF
2022-09-21 10:54:33.453 [INFO ] [hab.event.GroupItemStateChangedEvent] - Item 'gTutorial' changed from ON to OFF through WemoPlug_Switch
==> /var/log/openhab/openhab.log <==
2022-09-21 10:54:33.455 [DEBUG] [.script.rules_tools.reminderswitches] - Running door alert rule with: 
  item:           WemoPlug_Switch
  state:          OFF
  alertState:     ON
  invert:         true
  defaultTimeout: PT0m
  repeatPeriod:   PT5m
  dndStart:       00:00
  dndEnd:         00:00
  noAlertPeriod:  true
  alertRuleUID:   door_open
2022-09-21 10:54:33.455 [DEBUG] [.script.rules_tools.reminderswitches] - WemoPlug_Switch is in the alert state of OFF
==> /var/log/openhab/events.log <==
2022-09-21 10:54:33.456 [INFO ] [openhab.event.RuleStatusInfoEvent   ] - ReminderSwitches updated: RUNNING
==> /var/log/openhab/openhab.log <==
2022-09-21 10:54:33.456 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'ReminderSwitches' failed: java.lang.IllegalStateException: The Context is already closed.

That error only occurs when a rule tries to reference something from the cache that was created by a rule that no longer exists (e.g. you edited the rule, therefore replacing it with a new rule). All I can recommend is to run it manually again or reboot to see if the problem persists. I can’t reproduce this behavior. Once I run the rule manually and I see that “Resetting looping timers” log statement the context errors go away.

Thanks Rich, rebooting cleared the error.