Add delay to action

I have just created a rule that triggers when the temperature changes. If it’s above 73.5 degrees and the motion sensor is ON it turns on a fan.

What I want is to set a delay next, then turn the fan off. Of course, it should start over every time there is motion and the temp is above the threshold so the fan stays on (as long as the temp is up) until the delay times out because nobody has been in the room for a while.

Can someone help me with some javascript for the delay?

Code:
triggers:

  • id: “1”
    configuration:
    itemName: Attic_Temp
    type: core.ItemStateChangeTrigger
    conditions:
  • inputs: {}
    id: “2”
    configuration:
    itemName: Attic_Temp
    state: “73.5”
    operator: “>”
    type: core.ItemStateCondition
  • inputs: {}
    id: “4”
    configuration:
    itemName: AtticMultisensor_MotionAlarm
    state: ON
    operator: =
    type: core.ItemStateCondition
    actions:
  • inputs: {}
    id: “3”
    configuration:
    itemName: OnOffLightApplianceModule_Switch
    command: ON
    type: core.ItemCommandAction

First, please use code fences.

What you need here is a timer. See Design Pattern: Motion Sensor Timer for a full discussion.

You will need to create a Script Action. Choose ECMAScript as the language. The code will look something like this:

var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Motion Timer");
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var ZonedDateTime = Java.type("java.time.ZonedDateTime"); 
var now = ZonedDateTime.now();

var runme = function(){ 
    // code that executes later goes here
    this.timer = undefined; // reset the timer back to undefined
}

if(this.timer === undefined) {
    this.timer = ScriptExecution.createTimer(now.plusSeconds(1), runme);
}
else {
    this.timer.reschedule(now.plusSeconds(1));
}
2 Likes

Wow, this is so confusing. I went to the link you included but the examples are in python or Rules DSL. But this javascript is so hard for me to understand and the Rules DSL example seemed to make sense to I tried this but it didn’t turn off after 5 minutes:

var Timer occupancyTimer = null

        rule "Motion_Timer_Test"
        when
            Item AtticMultisensor_MotionAlarm received update ON
        then
            if(occupancyTimer === null || occupancyTimer.hasTerminated()) {
                occupancyTimer = createTimer(now.plusMinutes(5), [|
                    AtticMultisensor_MotionAlarm.sendCommand(OFF)
                    occupancyTimer = null
                ])
            }
            else {
                occupancyTimer.reschedule(now.plusMinutes(timeoutMinutes ))
            }
        end

So then I tried the script you included above with the change that I thought was needed (a command to turn the item off inserted just before “// code that executes later goes here”:


var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Motion Timer");
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var ZonedDateTime = Java.type("java.time.ZonedDateTime"); 
var now = ZonedDateTime.now();

var runme = function(){ 
    AtticMultisensor_MotionAlarm.sendCommand(OFF) // code that executes later goes here
    this.timer = undefined; // reset the timer back to undefined
}

if(this.timer === undefined) {
    this.timer = ScriptExecution.createTimer(now.plusSeconds(300), runme);
}
else {
    this.timer.reschedule(now.plusSeconds(300));
}

Just to be clear, I created a rule with a trigger, then added an action for the appliance module to turn on, then another action with the script.

I also tried having the command turn the appliance module off instead of the motion sensor.

Oh, just curious why you are suggesting I used javascript instead of Rules DSL. I’m assuming it’s more limited which may cause me a problem somewhere down the line?

Don’t you want to command the fan off, not the sensor?

In openhab 3 I have been using the expire metadata option where you can set the time to set the device off . If you resend on ON command to the item the expire time resets.

When you create the expire time make sure you set the command option at the very top of the expire selections (under the DO section) because if you don’t set it then it won’t do what you expect it to do. I have done that so many times.

I don’t know if this is what you want or not but it save a lot a coding. I also add comments to say that this item is controlled by an expire time.

1 Like

rossko57, yes the example I saw was turning off the motion sensor so that’s what I tried first but then tried turning off the fan because that’s what made sense to me, but still no good.

ubeaut, can you tell me the steps to take to use the expire metadata option? I’ve searched and see references to it but no step by step. It sounds like maybe I create a virtual device (haven’t looked in to how to do that) and then I’ll have an option to use expire?

But the concept is the same. Only the implementations are different and I provided the skeleton of a JavaScript implementation in my reply. That design pattern is to explain how it works.

The problem with Rules DSL in the UI is you can’t save the timer from one run of the rule to the next. So you can’t reschedule it. You’ll have to write the code in a .rules file and put the timer variable outside the rule. That’s why I provided the JavaScript version.

That’s not valid syntax for a UI rule. You have to put that into a .rules file.

That’s not valid JavaScript. To send a command in JavaScript you would use

events.sendCommand("AtticMultisensor_MotionAlarm", "ON");

One of your requirements is to reschedule the timer when motion occurs again while the timer is running. Another requirement is to create this rule in the UI. At this time JavaScript is the only way to meet both requirements.

Navigate to the fan Item in Settings -> Items. Click on “Add metadata” and select “Expiration Timer” and fill in the form.

OK, it works! I used the expiration. I suppose the shortcoming of this method is that it applies to the item instead of being in the rule so you don’t have the flexibility of using the timer sometimes & not others, if you have the item involved in more than one rule?

Thanks for all the other answers. Starting to form a picture…

I know this is old but
Thanks Rich, worked perfectly for me.
Cheers