Weird light switching off

Hello,

I have two items:

Switch Film_Scene "Film Scene" <switch> [ "Switchable" ]
Switch BedroomPresence "Bedroom Presence" <presence>

Then I have this pair of rules that governs BedroomPresence (using several sensors to see if the room is occupied):

rule "bedroom presence on"
when
   Item BedroomMovement_MotionStatus changed to ON
   or Item BedroomPCMovement_MotionStatus changed to ON
then
    BedroomPresence.sendCommand(ON)
end

rule "bedroom presence off"
when
    Item BedroomMovement_MotionStatus changed to OFF
    or Item BedroomPCMovement_MotionStatus changed to OFF
then
    if ((BedroomPCMovement_MotionStatus.state === OFF) &&
       (BedroomMovement_MotionStatus.state === OFF)) {
        BedroomPresence.sendCommand(OFF)
    }
end

BedroomMovement_MotionStatus and BedroomPCMovement_MotionStatus are defined as

Switch BedroomMovement_MotionStatus "Bedroom Movement" <presence> { channel="mihome:sensor_motion:xxx:xxx:motion" }
Switch BedroomPCMovement_MotionStatus "Bedroom PC Movement" <presence> { channel="mihome:sensor_motion:yyy:yyy:motion" }

Film_Scene is only handled manually.
Then I have this pair of rules that actually work with the lights:

rule "bedroom_light_on"
when
    Item BedroomPresence changed to ON
then
    logInfo("bedroom.rules", "Presence detected")
    if (Film_Scene.state === ON) {
        logInfo("bedroom.rules", "Film scene on, exiting")
        return;
    }
    if (Sun.state === OFF) { 
        logInfo("bedroom.rules", "Sun is down, turning light on")
        BedroomLight_Color.sendCommand(def_hue.state + "," + def_sat.state + "," + def_bri.state)
    }
    else {
        logInfo("bedroom.rules", "Sun is up, exiting")
    }
end

rule "bedroom_light_off"
when
    Item BedroomPresence changed to OFF
then
    logInfo("bedroom.rules", "Presence no longer detected")
    if (Film_Scene.state === ON) {
        logInfo("bedroom.rules", "But film is running, exiting")
        return;
    }
    else {
        logInfo("bedroom.rules", "Moving on, film is not running")
        if ((Sun.state === OFF)) {
            logInfo("bedroom.rules", "And the Sun is down, dimming")
            var new_bri = (Math.round(Integer::parseInt(def_bri.state.toString) / 2)).toString
            BedroomLight_Color.sendCommand(def_hue.state + "," + def_sat.state + "," + new_bri)
            Thread::sleep(90000)
            if (BedroomPresence.state === OFF) {
                logInfo("bedroom.rules", "Presence is still off, switching light off")
                BedroomLight_Color.sendCommand(OFF)
            }
        }
        else if (BedroomPresence.state === OFF) {
            logInfo("bedroom.rules", "Sun is not down, simply switching off")
            BedroomLight_Color.sendCommand(OFF)
        }
    }
end

Rough idea is turn on with movement (unless film is on) and dim and then turn off when no presence is detected (unless the film is on). I use a fair bit of logging and this appears in my logfile:

01:41:26.048 Item 'BedroomPresence' received command OFF
01:41:26.062 BedroomPresence changed from ON to OFF
01:41:26.084 Presence no longer detected
01:41:26.102 But film is running, exiting <--- until now, it works fine
01:42:21.925 BedroomPCMovement_MotionStatus changed from ON to OFF
01:42:23.473 Item 'BedroomPresence' received command OFF <---- we recieve OFF again
01:42:25.083 BedroomLight_Color changed from 0,0,99 to 0,0,0 <--- where did this come from?
01:42:29.918 BedroomPCMovement_MotionStatus changed from OFF to ON
01:42:29.937 Item 'BedroomPresence' received command ON
01:42:29.953 BedroomPresence changed from OFF to ON
01:42:29.968 Presence detected
01:42:29.982 Film scene on, exiting <---- again working correctly

I used grep on all the rules just to be sure and Nowhere do I set BedroomLight_Color ot either OFF or “0,0,0”.
I’m clueless. Any ideas?

Ok a few issues in the rule:

  • Use == instead of ===. Use == for OH states like NULL, ON…, Use === for java null
  • Add .toString in your colour command: BedroomLight_Color.sendCommand(def_hue.state.toString + "," + def_sat.state.toString + "," + new_bri)
  • VERY dangerous to use a loooonnnng Thread::sleep like this: Why have my Rules stopped running? Why Thread::sleep is a bad idea
    Use a timer instead
rule "bedroom_light_off"
when
    Item BedroomPresence changed to OFF
then
    logInfo("bedroom.rules", "Presence no longer detected")
    if (Film_Scene.state == ON) {
        logInfo("bedroom.rules", "But film is running, exiting")
        return;
    } else {
        logInfo("bedroom.rules", "Moving on, film is not running")
        if (Sun.state == OFF) {
            logInfo("bedroom.rules", "And the Sun is down, dimming")
            var new_bri = (Math.round(Integer::parseInt(def_bri.state.toString) / 2)).toString
            BedroomLight_Color.sendCommand(def_hue.state.toString + "," + def_sat.state.toString + "," + new_bri)
            //Thread::sleep(90000)
            createTimer(now.plusSeconds(90), [ |
                if (BedroomPresence.state == OFF) {
                    logInfo("bedroom.rules", "Presence is still off, switching light off")
                    BedroomLight_Color.sendCommand(OFF)
                }
            ])
        }
        else if (BedroomPresence.state == OFF) {
            logInfo("bedroom.rules", "Sun is not down, simply switching off")
            BedroomLight_Color.sendCommand(OFF)
        }
    }
end

If the item Film_Scene has no binding, it make no sense to send a command to it.
And you can combine these two rules into one:

rule "bedroom presence"
when
   Item BedroomMovement_MotionStatus changed or
   Item BedroomPCMovement_MotionStatus changed
then
    if (BedroomPCMovement_MotionStatus.state == ON || BedroomMovement_MotionStatus.state == ON) {
        BedroomPresence.postUpdate(ON)
    } else if (BedroomPCMovement_MotionStatus.state == OFF && BedroomMovement_MotionStatus.state == OFF) {
        BedroomPresence.postUpdate(OFF)
    }
end

Thank you for a thorough reply!
I was kind of accustomed to tripple equal signs from php programming and was not aware that it might be a problem here
The .toString should AFAIK be implicit, am I wrong about it? I get it that it’s probably safer to cast the value explcitly.
And finally thank you for a very useful link about timers and threads in openhab. I had no idea these limitations exist and will rewrite all my rules using timers instead.

I have a little trouble understanding the difference between sendCommand and postUpdate - I read a post about the difference but I am no more enlightened than before. I believe it is correct to sendCommand to an item linked to thing (that will execute that command and change state accordingly on its own) and postUpdate to “virtual” items since they change state but can’t execute anything. Does it make any sense doing

item.sendCommand(something)
item.postUpdate(something)

or is it duplication? My main concern is that I need to read value from a real sensor, pass it to presence virtual item and some rules read those changes and switch the lights on and off, for example. Will both sendCommand and postUpdate propagate further down?

Yes this is duplication UNLESS you add { …, autoupdate=“false” } in the item’s binding definition
OpenHAB “assumes” that when you send a command you also want the item to change state.
By setting the autoupdate to false, you can disable this behaviour and the item’s state will be update with the binding (i.e. on the next poll or the next state update from the device…)

See: https://www.openhab.org/docs/configuration/rules-dsl.html#manipulating-item-states

It makes no sense doing a sendCommand on a virtual item UNLESS you want a rule to trigger on this item’s received command

The penny will drop, as they say.
Think of commands as actions, usually sent to a real device - “turn the light ON”
Think of states (and so also updates) as status reports coming in from a real device - “the light is ON”

The separation becomes clearer in the case of a dimmer. Command - “INCREASE” - state update “70%”

1 Like