Rule Timer help!

Hey All,

So after many attempts at this I refer to the gods :wink:

Basically what I am trying to do, And its not working…

//* Send selected temperature to MyTotalConnect *)
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer==null) {
    timer = createTimer(now.plusSeconds(10)) [|
    logInfo("Security", "Timer Set")
    sendCommand(SendTemp, receivedCommand)    ]

} else {

    if(timer!=null) {
    timer.reschedule(now.plusSeconds(10))
    logInfo("Security", "Rescheduling Timer")

    }
}
end

Goal:
When the thermostat app sends a temp to it it timers it to 10 seconds before it sends it out If you hit the temperature up a few degrees at a time it just resets the timer instead of sending EVERY change out…

No luck…

I assume you declared timer as a global.

You never reset the timer to null when it finally does execute. The last line of the timer should set it back to null.

The receivedcommand variable does not get updated. Your timer will be using stale state data so you should use the item’s state in timers instead.

Without knowing exactly how it isn’t working those are my only suggestions.

Yes. Top of rules has:

var Timer timer = null

Well depending on how I set it it either always starts fresh or always send the command on every post. You know my goal so I’m open to a rewrite :).

Try doing my two suggestions. Set timer to null and use the item state instead of received command.

Tried this:

//* Send selected temperature to MyTotalConnect *)
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer==null) {
    timer = createTimer(now.plusSeconds(10)) [|
    logInfo("Security", "Timer Set")
    sendCommand(SendTemp, receivedCommand)    ]
    timer==null
} else {

    if(timer!=null) {
    timer.reschedule(now.plusSeconds(10))
    logInfo("Security", "Rescheduling Timer")

    }
}
end

Still no joy…

Also not sure what you mean on the item state thing… Not that familiar. If you mean like " If item == ON" kinda thing Im not sure how i would do that with a setpoint.

You can try
SendTemp.sendCommand(receivedCommand as DecimalType)
or, as Rich suggested,
SendTemp.sendCommand(IndHeatSet.state)
IndHeatSet.state should be the very same as receivedCommand, as IndHeatSet is the Item that triggers the rule.
receivedCommand as DecimalType would cast the state to number, just to ensure there is a valid value.

Please note that “==” is not an assignment operator, but rather a comparion operator (like you would use in an if (...) statement).

Try to use timer = null instead.

Secondly (this is not the cause of your problems!):

The following part of your code:

if(timer!=null) {

is inside the else clause of the following test:

if(timer==null) {

This means the test will always evaluate to true, and consequenlty it can be removed.

Ok,

This is my current setup which isnt working. Tried all of the above.

var Timer timer = null


//* Send selected temperature to MyTotalConnect *)
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer = null) {
    timer = createTimer(now.plusSeconds(10)) [|
    logInfo("Security", "TIMER: Heat Timer Set")
    //* SendTemp.sendCommand(IndHeatSet.state) ]
    SendTemp.sendCommand(receivedCommand as DecimalType) ]
    timer = null
} else {

    timer.reschedule(now.plusSeconds(10))
    logInfo("Security", "TIMER: Rescheduling Heat Timer")

    }
}
end

Error:
2016-04-13 08:48:12.936 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule ‘IndHeatSet’: cannot invoke method public abstract boolean org.openhab.model.script.actions.Timer.reschedule(org.joda.time.base.AbstractInstant) on null.

Same error for Udo and Rich’s ideas.

What did i forget?? :wink:

Beware of mixing “//” style comments and “/"style comments. It doesn’t appear to be a problem here but some languages will have a hard time when you use "//”. And for all I know it mght be causing problems here.

You are assigning timer to null inside your if statement. You need to use “==” to compare for equality and “=” for assignment.

Use proper indentation to more easily see what context your lines are in. Any time you start a new context (i.e. “{” or “[”) indent the lines inside that new context.


var Timer timer = null


// Send selected temperature to MyTotalConnect 
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer = null) {
        timer = createTimer(now.plusSeconds(10)) [|
            logInfo("Security", "TIMER: Heat Timer Set")
            // SendTemp.sendCommand(IndHeatSet.state) 
            SendTemp.sendCommand(receivedCommand as DecimalType) 
        ]
        timer = null
    } else {

        timer.reschedule(now.plusSeconds(10))
        logInfo("Security", "TIMER: Rescheduling Heat Timer")
    }
}
end

With the proper indentation additional problems become obvious. You are resetting the timer to null outside the timer.

There is an extra “}” at the end of your rule. I’m surprised OH was able to even load your file but I suspect that any rule in the file after this one does not exist because of this syntax error. Errant opening and closing brackets can cause massive problems. I highly recommend using Designer to write rules at it will point out these types of errors.

Also, you are using receivedCommand which will only have the state as it was when the timer was first created. Don’t you really want to send the current state (i.e. if the timer has been rescheduled you want to send the new/current value, not that first value). If not realize that any changes made while the timer is active will be lost.

The rule should be:

var Timer timer = null

// Send selected temperature to MyTotalConnect
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer == null) {
        timer =createTimer(now.plusSeconds(10), [|
            logInfo("Security", "TIMER: Heat Timer triggered")
            SendTemp.sendCommand(IndHeatSet.state as DecimalType)
            timer = null
        ])
        logInfo("Security", "TIMER: Heat Timer Set")
    } else {
        timer.reschedule(now.plusSeconds(10))
        logInfo("Security","TIMER: Rescheduling Heat Timer")
    }
end

Ok,

So this throws java errors:

var Timer timer = null


//* Send selected temperature to MyTotalConnect *)
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer == null) {
    timer = createTimer(now.plusSeconds(10)) [|
    logInfo("Security", "TIMER: Heat Timer Set")
    SendTemp.sendCommand(IndHeatSet.state) ]
    //* SendTemp.sendCommand(receivedCommand as DecimalType) ]
    //* SendTemp.sendCommand(receivedCommand) ]
    timer = null

} else {

    timer.reschedule(now.plusSeconds(10))
    logInfo("Security", "TIMER: Rescheduling Heat Timer")

    }
}
end

and this works but only sets the heat over and over. It dont reset the timer and start over.

var Timer timer = null


//* Send selected temperature to MyTotalConnect *)
rule "IndHeatSet"
when
    Item IndHeatSet received command
then
    if(timer == null) {
    timer = createTimer(now.plusSeconds(10)) [|
    logInfo("Security", "TIMER: Heat Timer Set")
    //* SendTemp.sendCommand(IndHeatSet.state) ]
    SendTemp.sendCommand(receivedCommand as DecimalType) ]
    //* SendTemp.sendCommand(receivedCommand) ]
    timer = null

} else {

    timer.reschedule(now.plusSeconds(10))
    logInfo("Security", "TIMER: Rescheduling Heat Timer")

    }
}
end

Thanks RLK!

Your example worked flawlessly! :wink: But I’m sure you knew that already. lol

Instead of creating a new topic, i will recycle this one:

i have a problem with a timer, which helps me setting a global variable for human presence in the living room, which is used for switching lights:

var Timer timer = null

rule "Presence Wohnzimmer"
when
    Item alarm_multisensor_3 received update or
    Item sw_tv_wohnzimmer changed
then
    if (timer != null) {
        timer.cancel
        timer = null
    }
    Thread::sleep(10000)
    presence_wohnzimmer = 1
    timer = createTimer(now.plusMinutes(20)) [|
        presence_wohnzimmer = 0
    ]
end

I thought that was working so far. But yesterday i mentioned, that my lights turned off when i didn’t expect it, because i went through the living room and saw, that the movement sensor recognized me (led). My events say:

2016-10-05 19:23:05 - alarm_multisensor_3 state updated to 0
2016-10-05 19:24:18 - alarm_multisensor_3 state updated to 0

and my lights turned off

2016-10-05 19:25:00 - sw_light_wohnzimmer received command OFF

but shouldn’t, because presence_wohnzimmer should have been 1, because of the 2 events before.

is there an obvious mistake in that rule?
thanks!

My first question is: where is the definition of presence_wohnzimmer?
2nd: why doing a Thread::sleep()?
3rd: which rule did switch of sw_light_wohnzimmer?

Hi,
thanks for your reply. Here the answers of your questions:

1st:
In the global part of the file:

var Number presence_wohnzimmer = 0

2nd:
The presence_wohnzimmer is a condition for switching on lights (see also 3rd). The 10seconds are a small time window, if you want to ventilate the room and open the terrasse door, to avoid toggeling the light, because opening the door will switch off the lights immediately.

3rd:

rule "Automatik Wohnzimmer"
when
    Time cron "0 0/1 * * * ?"
then
    // Einschalten bei Anwesenheit in Wohnung und Wohnzimmer, nach 16:00Uhr
    if (sw_lueften.state == OFF && auto_on_light_wohnzimmer == 0 && presence.state == ON && now.getHourOfDay() >= 16 && presence_wohnzimmer == 1) {
        // Einschalten nach Sonnenuntergang
        if (now.isAfter((sunset_time.state as DateTimeType).calendar.timeInMillis)) {
            if (sw_light_wohnzimmer.state != ON) sendCommand(sw_light_wohnzimmer, ON)
            auto_on_light_wohnzimmer = 1
        }
        // Einschalten nach Helligkeitssensor
        else if (lumen_multisensor_3.state <= thres_lumen) {
            if (sw_light_wohnzimmer.state != ON) sendCommand(sw_light_wohnzimmer, ON)
            auto_on_light_wohnzimmer = 1
        }
    }
    // Abschalten bei fehlender Anwesenheit und abgeschaltetem TV im Wohnzimmer nach mindestens 10min Leuchtdauer
    if (auto_on_light_wohnzimmer == 1 && sw_tv_wohnzimmer.state != ON && presence_wohnzimmer == 0 && !sw_light_wohnzimmer.changedSince(now.minusMinutes(10))) {
        if (sw_light_wohnzimmer.state != OFF) sendCommand(sw_light_wohnzimmer, OFF)
        auto_on_light_wohnzimmer = 0
    }
end

To paste code, you have to use code fences (2nd right button at the edit area, or type three backticks in a row before and after the code:
```

your code goes here

```
It’s essential to leave the backticks in it’s own rows.

In question of your code, I think, Thread::sleep() will not work as you expected. Did you define timer within the global vars? Maybe it’s unhandy to call the timer timer, as this is a keyword (at least Timer is).

Thanks for the hint with the code fences.
Yes, the Timer is defined in the global variables.
The thing i don’t understand is, that the timer does work - and the sleep also does work, but not in this one case i mentioned.
Maybe i should try to rename the timer, that was a thing i also thought about.

In question of Thread::sleep(), in case of rule trigger, timer will be cancelled (if running), then thread will sleep for 10 seconds, then presence_wohnzimmer will be set to 1, regardless, if someone left the room already, so the lights will turn on (and off after another 20 minutes). I think your intention was, not to switch on the lights at all, if leaving the room within 10 seconds.

There is a known issue about using global vars/vals in multiple rules files with the same name. I can’t remember where I read this on the wiki, probably a note in the Rules wiki page. If you have other rules files with a timer global var this might be a problem.

@Udo:
No, the intension is, that the ambient lights are on if someone has been in the area within the last 20minutes and with any new movement in that area (or switching tv on or off), the timer should reset and there are 20minutes again. But that doesn’t work right in the current setting.
The 10seconds delay is only for preventing, that the lights turn on if someone just walks through the area to open the terrace door for ventilation (dont’ want to get mosquitoes between june and september).

@Rich: This is the only timer i have, so that can not be the problem :confused: