Proper way of recursion in Rules

This is what the rule template Threshold Alert and Open Reminder [4.0.0.0;4.9.9.9] does.

  1. Install that template from the Add-on store → Automation screen.
  2. create the rule that implements your alert, the name of the Item will be alertItem
  3. Put your window Items into a Group
  4. 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.