How to deal with device command state that doesn't change back when in use (motion sensor)?

  • Platform information:
    • openHAB version: V2.5
  • Issue of the topic: I am trying to wrap my head around how to formulate a rule that can react even there is no change of state of the trigger.

Ex. My motion rule triggers lights on when the motion sensor goes from OFF to ON. The PIR sensor time out to go from OFF to ON when no motion is detected is min 1 min. But of course if motion is continuously detected the state never changes from ON.

In this case I would like to do something along the lines of: Motion sensor state still ON since 2 min of first trigger event (from OFF to ON) then change dimming level from 10 to 90.

It’s not quite clear if/how I would do this, I’ve recently started to read up about Design Patterns but am still not clear on how this can work since there is no state change of the PIR sensor due to consistent movement being detected.

Start a timer from your initial event.

If state changes while timer is running, cancel timer.

If timer expires (so there wasn’t a change during that time) do whatever.

See Design Pattern: Motion Sensor Timer and notice that it uses received update ON as the trigger. The rule will trigger even if the Item is already ON.

Ok thank you, that’s great news.

That said, it seems like it uses python libraries for this - where do I put that python script/rules (what directory?) and do I have to enable python somehow, etc? I cannot seem to find much about about the steps for making sure I have the prerequisites to do this correctly and not break anything.

Can I just put it in the rules folder like it seems to be? Do I need to use both Python and Rules DSL or is it only one of them?

BTW this is my current rule (for daytime), unfortunately it doesn’t do what I want because I have to leave the kitchen for the PIR to switch to off first to get the lights to go to 90%.

var Timer pirKitchenTimer = null
val int pirKitchentimeoutMinutes = 4 // choose an appropriate value

// Kitchen Motion Counter Lights not Evening

rule "Kitchen timed Counter lights PIR Daytime"
when
    Item KitchenMotion changed to ON
then    
	if (vTimeOfDay.state !== "EVENING" || vTimeOfDay.state !== "NIGHT") {   
  	  if (pirKitchenTimer !== null) 
    {            
        KitchenDimmer.sendCommand(90)
        sendCommand(KitchenLightShelf, ON)
        pirKitchenTimer.reschedule(now.plusMinutes(pirKitchentimeoutMinutes))
        logInfo("Lights","Kitchen light timer rescheduled for " + pirKitchentimeoutMinutes + " minutes")
    }
    else
    {            
        sendCommand(KitchenLightStove, ON)
        sendCommand(KitchenLightCounter, ON)
        logInfo("Lights","Kitchen light timer created for " + pirKitchentimeoutMinutes + " minutes")
        pirKitchenTimer = createTimer(now.plusMinutes(pirKitchentimeoutMinutes)) 
        [|        
            if (KitchenMotion.state ==  ON)   
            {
                pirKitchenTimer.reschedule(now.plusMinutes(pirKitchentimeoutMinutes))
                logInfo("Lights","Kitchen timer triggered, but rescheduled again for " + pirKitchentimeoutMinutes + " minutes") 
            } 
            else 
            {            
            logInfo("Lights","Kitchen light timer expired")
                sendCommand(KitchenLightStove, OFF)
                sendCommand(KitchenLightCounter, OFF)
                sendCommand(KitchenLightShelf, OFF)
                KitchenDimmer.sendCommand(OFF)
                pirKitchenTimer = null
            
            }
        ]
    }
}
end

I’ve attempted to adapt the Design pattern timer rule to my situation, and it triggers the first part accordingly but doesn’t reschedule the timer and turn on the lights to full, it just lets the initial timer expire (30s) and turns off the lights again.

var Timer occupancyTimer = null

var int rescheduleminutesadded = 5

rule "Kitchen lights PIR Daytime"
when
    Item KitchenMotion received update ON
then
    if(vTimeOfDay.state !== "EVENING" || vTimeOfDay.state !== "NIGHT" && occupancyTimer === null || occupancyTimer.hasTerminated()) 
    {
        sendCommand(KitchenLightStove, ON)
        sendCommand(KitchenLightCounter, ON)
        logInfo("Kitchen Lights","Kitchen counter light timer created for 30 seconds")
        occupancyTimer = createTimer(now.plusSeconds(30),
        [|
            logInfo("Lights","Kitchen light timer expired")
            KitchenMotion.sendCommand(OFF)
            sendCommand(KitchenLightStove, OFF)
            sendCommand(KitchenLightCounter, OFF)
            sendCommand(KitchenLightShelf, OFF)
            KitchenDimmer.sendCommand(OFF)
            occupancyTimer = null
        ])
    }
    else 
    {
        KitchenDimmer.sendCommand(90)
        sendCommand(KitchenLightShelf, ON)
        occupancyTimer.reschedule(now.plusMinutes(rescheduleminutesadded))
        logInfo("Kitchen Lights","Kitchen light full + timer rescheduled for " + rescheduleminutesadded + " minutes")
    }
end

Log:

2020-01-18 11:43:00.826 [INFO ] [marthome.model.script.Kitchen Lights] - Kitchen counter light timer created for 30 seconds
==> /var/log/openhab2/events.log <==
2020-01-18 11:43:00.838 [ome.event.ItemCommandEvent] - Item 'KitchenLightStove' received command ON
2020-01-18 11:43:00.841 [ome.event.ItemCommandEvent] - Item 'KitchenLightCounter' received command ON
2020-01-18 11:43:00.850 [vent.ItemStateChangedEvent] - KitchenLightStove changed from OFF to ON
2020-01-18 11:43:00.851 [vent.ItemStateChangedEvent] - KitchenLightCounter changed from OFF to ON
2020-01-18 11:43:14.898 [vent.ItemStateChangedEvent] - Azimuth changed from 167.98259991498603 to 168.23692591300428
2020-01-18 11:43:14.908 [vent.ItemStateChangedEvent] - Elevation changed from 24.802973282532456 to 24.840339074596336
2020-01-18 11:43:14.911 [vent.ItemStateChangedEvent] - DiffuseRadiation changed from 109.45523989362364 to 109.5220650077409
2020-01-18 11:43:14.914 [vent.ItemStateChangedEvent] - TotalRadiation changed from 282.93861299503527 to 283.5482320912065
2020-01-18 11:43:15.169 [vent.ItemStateChangedEvent] - SCHNELLPIXEL3Uptime changed from 66358 to 66372
2020-01-18 11:43:15.174 [vent.ItemStateChangedEvent] - SCHNELLPIXEL3LastSeen changed from 2020-01-18T11:42:54.000-0500 to 2020-01-18T11:43:08.000-0500
2020-01-18 11:43:15.187 [vent.ItemStateChangedEvent] - KLAUDIASAMSUNGLastSeen changed from 2020-01-18T11:42:54.000-0500 to 2020-01-18T11:43:08.000-0500
2020-01-18 11:43:19.375 [me.event.ThingUpdatedEvent] - Thing 'yamahareceiver:zone:5f9ec1b3_ed59_1900_4530_00a0deb68d70:Main_Zone' has been updated.
2020-01-18 11:43:25.222 [vent.ItemStateChangedEvent] - SCHNELLPIXEL3Uptime changed from 66372 to 66384
2020-01-18 11:43:25.227 [vent.ItemStateChangedEvent] - SCHNELLPIXEL3LastSeen changed from 2020-01-18T11:43:08.000-0500 to 2020-01-18T11:43:20.000-0500
2020-01-18 11:43:25.237 [vent.ItemStateChangedEvent] - KLAUDIASAMSUNGLastSeen changed from 2020-01-18T11:43:08.000-0500 to 2020-01-18T11:43:20.000-0500
2020-01-18 11:43:30.611 [ome.event.ItemCommandEvent] - Item 'DenDeskLED' received command ON
2020-01-18 11:43:30.660 [ome.event.ItemCommandEvent] - Item 'DenDeskLED' received command ON
==> /var/log/openhab2/openhab.log <==
2020-01-18 11:43:30.833 [INFO ] [clipse.smarthome.model.script.Lights] - Kitchen light timer expired
==> /var/log/openhab2/events.log <==
2020-01-18 11:43:30.849 [ome.event.ItemCommandEvent] - Item 'KitchenMotion' received command OFF
2020-01-18 11:43:30.850 [nt.ItemStatePredictedEvent] - KitchenMotion predicted to become OFF
2020-01-18 11:43:30.867 [ome.event.ItemCommandEvent] - Item 'KitchenLightStove' received command OFF
2020-01-18 11:43:30.871 [ome.event.ItemCommandEvent] - Item 'KitchenLightCounter' received command OFF
2020-01-18 11:43:30.881 [ome.event.ItemCommandEvent] - Item 'KitchenLightShelf' received command OFF
2020-01-18 11:43:30.893 [ome.event.ItemCommandEvent] - Item 'KitchenDimmer' received command OFF
2020-01-18 11:43:30.894 [vent.ItemStateChangedEvent] - KitchenMotion changed from ON to OFF
2020-01-18 11:43:30.903 [nt.ItemStatePredictedEvent] - KitchenLightShelf predicted to become OFF
2020-01-18 11:43:30.911 [nt.ItemStatePredictedEvent] - KitchenDimmer predicted to become OFF
2020-01-18 11:43:30.918 [vent.ItemStateChangedEvent] - KitchenLightStove changed from ON to OFF
2020-01-18 11:43:30.920 [vent.ItemStateChangedEvent] - KitchenLightCounter changed from ON to OFF

Links with instructions here…

There is both the Scripted Automation version using Python and Rules DSL versions presented. If you are not ready for Scripted Automation, just look at the Rules DSL version of the rule.

If you do want to use Python, see the link 5iver provided.

Only use === and !== If null if on one side it the other. In all other cases use == or !=.

You probably need to put parens around your if statement because it relates from left to right and fails fast. So, for example, if it’s EVENING, the if will return true no matter what state your timer is in.

Thanks I appreciate the link - that said I have a feeling that it’s either python or Rules DSL not both to be used? Since with my limited knowledge it seems both scripts do the exact same thing (int he example).

Thanks for that clarification.

That said the Evening part seemed to work just fine with !==, I have now changed it either way.

What I cannot understand is why the timer example with my changes expires instead of reschedules.

Well it seems after some more tinkering with my old rules that seemed to do 90% of what I wanted I finally have the result I am looking for…

var Timer pirKitchenTimer = null
val int pirKitchentimeoutMinutes = 4 // choose an appropriate value

// Kitchen Motion Counter Lights not Evening
rule "Kitchen timed Counter lights PIR Daytime"
when
    Item KitchenMotion received update ON
then    
    if (vTimeOfDay.state != "EVENING" || vTimeOfDay.state != "NIGHT") 
    {   
      if (pirKitchenTimer !== null) 
        {            
        pirKitchenTimer.reschedule(now.plusMinutes(pirKitchentimeoutMinutes))
        logInfo("Lights","Kitchen light timer rescheduled for " + pirKitchentimeoutMinutes + " minutes")
    }
    else
    {            
        sendCommand(KitchenLightStove, ON)
        sendCommand(KitchenLightCounter, ON)
        logInfo("Lights","Kitchen light timer created for 1 Minute")
        pirKitchenTimer = createTimer(now.plusMinutes(1)) 
        [|        
            if (KitchenMotion.state == ON)   
            {
                sendCommand(KitchenLightShelf, ON)
                KitchenDimmer.sendCommand(90)
                pirKitchenTimer.reschedule(now.plusMinutes(pirKitchentimeoutMinutes))
                logInfo("Lights","Kitchen timer triggered, but rescheduled again for " + pirKitchentimeoutMinutes + " minutes") 
            } 
            else 
            {            
            logInfo("Lights","Kitchen light timer expired")
                sendCommand(KitchenLightStove, OFF)
                sendCommand(KitchenLightCounter, OFF)
                sendCommand(KitchenLightShelf, OFF)
                KitchenDimmer.sendCommand(OFF)
                pirKitchenTimer = null
            }
        ]
    }
}
end

Because the else clause never runs. The if condition always evaluates to true.

Well I have no idea what is going on - the rule works for a while and then stops working without any messages in the logs. Starts to work again after rebooting for a while and then stops again.

I’m testing now if it’s because I have near two identical rule files (one for evening and one for not evening)… not sure why it would cause it but it’s all I have to go on right now.

EDIT: seems like it might be related to Time Of Day Design Pattern not working anymore… why I have no idea… took 2 reboots for it to start working again… Didn’t change anything.

Something that catches people out is that “description” part of a rule is actually a name that must be unique in the system.
That gives non-obvious weirdness like the last edited version of a rule from alternate files being the active one.

Ah-ha! Well, although I always attempted to make them unique I did screw up just recently when I copy/pasted the working PIR rule above for the evening .rules file and the rule name I didn’t edit!

Thanks for the heads up.

It was just that chance mention started that thought. Dupe rule names can drive you mad.