[SOLVED] Motion Sensor / Occupancy Detection Issue

Hi, I currently bought an “PIR Motion Sensor v2.5 Z-Wave Motion Sensor” and I have troubling with updates on the motion sensor. I currently use this code to identify if our playroom is occupied:

> rule "Playroom - Motion sensor triggered - Corner"
> when
>     Item BA_Playroom_CornerMotionSensor_PIR received update ON
> then
>     BA_Playroom_Occupancy.sendCommand(ON)
> 	logInfo("MotionSensor", "Playroom Motion Detect!")
> end

My living room item:

> Switch   BA_Playroom_Occupancy   "Playroom Room Occupancy"    {expire="30m,OFF"}

For my other sensors in the house, whenever I have a movement in the house it sends an update but this one isn’t sending one, so if I have movement for continues 30 min the GF_LivingRoom_Occupancy expires but I still have movement (e.g. when we are playing “Just Dance” :slight_smile:)

Below is a print screen of my Grafana Log that clearly shows the behavior (the Occupancy variable is multiply by 2 so I can difference easily both charts).

Try changing the trigger?

Item BA_Playroom_CornerMotionSensor_PIR changed
then
if (BA_Playroom_CornerMotionSensor_PIR.state == ON) {
BA_Playroom_Occupancy.sendCommand(ON)
//other actions/commands
}

The above was done free hand, and may have typos/errors; double check with Visual Studio. My first though is that your original rule is waiting until it receives an update to ON implying its changing to ON after first being OFF. All the movement may be keeping the switch stuck in an ON position?

Another spot to verify, in PaperUI on the PIR Thing you can confirm timeout settings (at least on the model I have I can).

Thanks anonymous.one! Tried but didn’t work, I did some debugging and looks like the device doesn’t send any update to the controller when it has movement (unless it’s the 1st trigger), it’s only ON and OFF when stop seen movement for a while (I’m guessing 2-3 min). I tried to look the configurations but couldn’t find anything that looks helpful to this issue. The only config options are:

So far, my solution is to have a cron job every minute checking if the sensor is ON and updating the Occupancy item:

> rule "Playroom - Motion sensor Check every minute if its triggered"
> when 
>     Time cron "0 0/1 * * * ?"   // every minute
> then
>     if (BA_Playroom_CornerMotionSensor_PIR == ON) {
> 		BA_Playroom_Occupancy.sendCommand(ON)
> 	}
> end

Looks like I have the ZP3102 motion sensor (monoprice one). Perhaps instead of a cron job you could set an expire on the PIR and flip it off every 5 mins (or 25 mins); should keep sending refresh updates to the expire on the BA_Playroom_Occupancy, and not require the 1 min cron check.

See root article Automation/Orchestration Design Patterns for highly-relevant parallel.

TL:DR version – send commands to PROXY items in this kind of circumstance, then intercept in the proxy-handler for countermanding circumstances.

This is the kind of situation where you need to break down your rules logic into smaller steps.
What you’d like to happen, I think -
When Motion begins, turn on the light or enable occupation etc.
When Motion stops, start the timer to eventually turn off light or cancel occupation.

A complete solution would probably also need to cancel any existing timer when Motion begins.

Expire binding can be useful, but it is not best suited to this case (when you need to create a band-aid rule to prevent expire working, you can tell there’s a problem).

Using a separate Timer would be my way forward.

Thanks bob_dickenson and rossko57, looks like I need to change my approach! :slight_smile: Will work in a new code over the weekend and I will post the results!

Couldn’t sleep thinking about this issue, so decided to give it a try! It worked on my limited testing! I will know more tomorrow in the in the “real life” usage!

Switch   BA_Playroom_Occupancy 					"Playroom Occupancy"

Ps: I removed the Expire binding function

var timer_playroom = null

rule "Playroom - Motion Sensor Corner - Occupancy"
when
    Item BA_Playroom_CornerMotionSensor_PIR received update
then
	if (BA_Playroom_CornerMotionSensor_PIR.state == ON) {
		logInfo("MotionSensor", "Playroom Initial Motion Detect!")
		if (timer_playroom !== null) timer_playroom.cancel 
		BA_Playroom_Occupancy.sendCommand(ON)
	} else {
		logInfo("MotionSensor", "Playroom Motion Detector expired - Create 20 Min Timer")
		timer_playroom = createTimer(now.plusMinutes(20), [| 
			BA_Playroom_Occupancy.sendCommand(OFF)
			timer_playroom = null // reset timer
		])
	}
end

Hopefully you have got this working, but have you read the manual? I think this is your device… https://www.cd-jackson.com/index.php/zwave/zwave-device-database/zwave-device-list/devicesummary/525. If so, it definitely sends an OFF. It looks like the timeout can’t be set, and is fixed at 4 minutes. If your never getting the OFF, then the device is faulty, or more likely, not configured properly.

I read the issue is not complete failure to send off. If timeout is 4 minutes, and motion recurs at 2 minute intervals, no timeout occurs so no OFF sent.
This is sensible behaviour in many cases e.g. for directly controlling a light without blinking.

But if you derive other logic from the on/off signal, like occupancy, it’s no good starting your own timeout from the ON event.

After some testing, the code below worked! Thank everyone for the support!

Switch   BA_Playroom_Occupancy 					"Playroom Occupancy"
var Timer timer_playroom = null

rule "Playroom - Motion Sensor Corner - Occupancy"
when
    Item BA_Playroom_CornerMotionSensor_PIR received update
then
	if (BA_Playroom_CornerMotionSensor_PIR.state == ON) {
		logInfo("MotionSensor", "Playroom Initial Motion Detect!")
		if (timer_playroom !== null) { 
			timer_playroom.cancel // stop timer
			timer_playroom = null // reset timer
		}
		BA_Playroom_Occupancy.sendCommand(ON)
	} if (BA_Playroom_CornerMotionSensor_PIR.state == OFF)  {
		logInfo("MotionSensor", "Playroom Motion Detector expired - Create 30 Min Timer")
		if (timer_playroom !== null) { 
			timer_playroom.reschedule(now.plusMinutes(30), [| 
				BA_Playroom_Occupancy.sendCommand(OFF)
				timer_playroom = null // reset timer
			])
		} else {
			timer_playroom = createTimer(now.plusMinutes(30), [| 
				BA_Playroom_Occupancy.sendCommand(OFF)
				timer_playroom = null // reset timer
			])
		}
	}
end
1 Like