Get motion for last 60 minutes

Hello, I'm have flow that will switch off the lights a a specific time. That is the easy part. But now I will extend this flow with the part that it is only allowed to switch of the light if there was no motion detected for the past 60 minutes. I have found the history node. This node will get the data that I need, than I'm stuck. I don't know how to continue on this I get an output msg.payload as an array, but I only want to continue if one of the payload.state is on. but sofar I'm only able to use the last one and that is always off.

Can someone help me, or has someone a flow that does tis?

Thanks in advance

Use a trigger node which prolongs the timeframe when a new message arrives. The motion should be true from the motion sensor and filtered out by a switch node before.

image

[
    {
        "id": "00e42b2e3c40cb2d",
        "type": "inject",
        "z": "7fd8fff652f013f7",
        "name": "motion true",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 600,
        "y": 3680,
        "wires": [
            [
                "3233ef1007c2d6b6"
            ]
        ]
    },
    {
        "id": "8934dbb58e69fc2d",
        "type": "inject",
        "z": "7fd8fff652f013f7",
        "name": "motion false",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "false",
        "payloadType": "bool",
        "x": 590,
        "y": 3740,
        "wires": [
            [
                "3233ef1007c2d6b6"
            ]
        ]
    },
    {
        "id": "3233ef1007c2d6b6",
        "type": "switch",
        "z": "7fd8fff652f013f7",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "true"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 790,
        "y": 3700,
        "wires": [
            [
                "9cc317a95216dcea"
            ]
        ]
    },
    {
        "id": "9cc317a95216dcea",
        "type": "trigger",
        "z": "7fd8fff652f013f7",
        "name": "",
        "op1": "",
        "op2": "false",
        "op1type": "nul",
        "op2type": "bool",
        "duration": "1",
        "extend": true,
        "overrideDelay": false,
        "units": "hr",
        "reset": "",
        "bytopic": "all",
        "topic": "topic",
        "outputs": 1,
        "x": 950,
        "y": 3700,
        "wires": [
            []
        ]
    }
]

If you motion sensor does not send booleans you have to adapt the payload. (i.e. on and off instead of true and false etc.)

Thanks for the reply, But this is not what I want. What I want is to check if there has been some motion for the past 60 minutes. If there was motion the lights should not put off. So I think I would need the history node, or something else if there is.

No I don't think so - the flow I posted does exactly what you requested. The trigger node sends false or switches lights off, when there was no longer than 60 minutes a motion detected. Any motion will retain the false message.

1 Like

@mickym2's use of a trigger node should work.

Have a look at the red circle below. When there has been no motion for 60 minutes, it sends a msg to switch the light off. If there is motion, then the 60 minute timer starts again, and the light stays on.

trigger

I will not get an input form the motion sensor, I will get an input from a timer node. So what I want is to leave the lights on if the timer gives an off command an there has been movement for the past 60 minutes. If I understand the flow here it will respond on actual motion and delay that. That is not what I want.

I will give you an example of my use case.

the light in the living room goes on a 6pm when there has been motion in the hallway. Than the light should go out at sunrise. But sometimes I have not opened the curtains so it is still dark inside. I than want the lights to remain on. I was thinking to do this based on the history of the motion sensor.

hope this explains my issue better. Hope you can help me

This should work for you it will not let timer pass if any motion within the past 5 seconds, adjust time to suit

[{"id":"6e626df3.6bd5d4","type":"inject","z":"bf9e1e33.030598","name":"motion","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"motion","payload":"1","payloadType":"num","x":110,"y":1380,"wires":[["8effd20a.5098a8"]]},{"id":"8effd20a.5098a8","type":"trigger","z":"bf9e1e33.030598","name":"","op1":"","op2":"0","op1type":"pay","op2type":"num","duration":"5","extend":true,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":270,"y":1380,"wires":[["c3792689.435a1"]]},{"id":"c3792689.435a1","type":"join","z":"bf9e1e33.030598","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":440,"y":1420,"wires":[["786562d5.a8f914"]]},{"id":"7fe6cb89.f7a8dc","type":"change","z":"bf9e1e33.030598","name":"","rules":[{"t":"set","p":"complete","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":1460,"wires":[["c3792689.435a1"]]},{"id":"786562d5.a8f914","type":"switch","z":"bf9e1e33.030598","name":"","property":"payload.motion","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":580,"y":1420,"wires":[["7efaab7a.ef4ce4"]]},{"id":"96e2f424.f31c18","type":"inject","z":"bf9e1e33.030598","name":"timer","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"timer","payload":"1","payloadType":"num","x":120,"y":1460,"wires":[["7fe6cb89.f7a8dc"]]},{"id":"7efaab7a.ef4ce4","type":"change","z":"bf9e1e33.030598","name":"","rules":[{"t":"move","p":"payload.timer","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":790,"y":1420,"wires":[["e3589b7c.bb306"]]},{"id":"e3589b7c.bb306","type":"debug","z":"bf9e1e33.030598","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":1360,"wires":[]}]

[edit] Added the word past, as that's what it does.

unfortunately this is also not what I'm looking for. I want motion in the past (history node). Not motion from the moment the time trigger triggers.

hopefully someone can help me.

https://flows.nodered.org/node/node-red-contrib-mytimeoutWhat should happen if you detect motion and then 45 minutes later you detect motion again?

You might want to look at the node-red-contrib-mytimeout node

This looks more like what I want, The only thing is that I get an array as output. Now it only should continue if the state is on.

[{"id":"68d81fb0.78a26","type":"debug","z":"ffbd7f06.4a014","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":950,"y":704,"wires":[]},{"id":"6d13bcbf.56d2f4","type":"inject","z":"ffbd7f06.4a014","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":476,"y":704,"wires":[["c214238f.fcf0a"]]},{"id":"c214238f.fcf0a","type":"api-get-history","z":"ffbd7f06.4a014","name":"","startdate":"","enddate":"","entityid":"sensor.motion","entityidtype":"is","useRelativeTime":true,"relativeTime":"10 minutes","flatten":true,"output_type":"array","output_location_type":"msg","output_location":"payload","x":630,"y":704,"wires":[["8a45d50.3e87328"]]},{"id":"8a45d50.3e87328","type":"function","z":"ffbd7f06.4a014","name":"","func":"if(msg.payload.filter(item => item.state == \"on\").length) {\n    return msg;\n}","outputs":1,"noerr":0,"x":802,"y":704,"wires":[["68d81fb0.78a26"]]}]

I’m a little confused at what is suppose to happen. You say:

You say “…when there has been motion…” when does the motion have to have happened? During the hour before 6? Exactly at 6? What happens if motion is detected at 6:01?

And if the light goes on, you don’t shut it off till sunrise? So the light will remain on all night as long as there was motion…correct?

So to rephrase it, if motion is detected during the hour before 6PM, at 6PM turn on the light and leave it on till sunrise. Otherwise leave the light off even if motion is detected any time after 6pm.

Sorry I mean AM, so 6AM the light goes on when motion is detected in the hallway. That means then, when we wake up and walk to the living room we come trough the hallway and then the light goes on. But that actually doesn't matter. What I want is that the light doesn't go off at sunrise if there has been motion in the hour before sunrise. How I then put it off at a later time is another concern. I Just don't want it to shutdown at sunrise if there was motion detection before that time. Hope this makes it more clear.

If you store a timestamp in a flow.variable each time motion is detected then you can check against this time. It's hard to understand your logic so it would be better to write it out as a list like a flow chart.

This is what I want, hope that explains more

I found this one online, and I think this should do what I want.

But then I get this output:

So in the msg.payload you see now 2 times state "off" and 1 state "on". That means then that on the "on" state there has been motion. Based on this "on' state I want to do nothing. But I'm bot able to filter that state out. Note that if there was a lot more motion there will be more "on" states in the array.

Hope this makes my question a lot more clear and someone can help me.

store the pir to flow var then test against it like this -

[{"id":"9eeccce524d52e44","type":"inject","z":"ec5a1f5f47a9879b","name":"PIR ","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":390,"y":120,"wires":[["27632150a2fed856"]]},{"id":"27632150a2fed856","type":"change","z":"ec5a1f5f47a9879b","name":"store time","rules":[{"t":"set","p":"PIR_time","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":120,"wires":[[]]},{"id":"5bc8409fd7e15218","type":"inject","z":"ec5a1f5f47a9879b","name":"sunrise timer","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":410,"y":180,"wires":[["918590c4bf51cf19"]]},{"id":"79075c71e73c6b77","type":"debug","z":"ec5a1f5f47a9879b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":730,"y":180,"wires":[]},{"id":"918590c4bf51cf19","type":"function","z":"ec5a1f5f47a9879b","name":"","func":"\nif (Date.now() - flow.get(\"PIR_time\") < 5000) { return } // set to 5 sec use 3600000 for an hour\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":180,"wires":[["79075c71e73c6b77"]]}]

Unfortunately this is not working for me. I really need to use the history node. Does someone knnow how to extract the state "on" from the arry

Can you explain why it is not working ?

The sunrise message is blocked if the PIR has triggered in the last (5 seconds for testing)
You don't need the history nodes as you are only interested in the last time the PIR was triggered.

After this duration the message is passed through to output.

As far as I can tell this is what you asked for ?

I changed this to 1 hour in case you didn't see the 5 second setting in the function node

Updated flow -

[{"id":"9eeccce524d52e44","type":"inject","z":"624963ed82f87a01","name":"PIR ","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":530,"y":680,"wires":[["27632150a2fed856"]]},{"id":"27632150a2fed856","type":"change","z":"624963ed82f87a01","name":"store time","rules":[{"t":"set","p":"PIR_time","pt":"flow","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":680,"wires":[[]]},{"id":"5bc8409fd7e15218","type":"inject","z":"624963ed82f87a01","name":"sunrise timer","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":550,"y":740,"wires":[["918590c4bf51cf19"]]},{"id":"79075c71e73c6b77","type":"debug","z":"624963ed82f87a01","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":870,"y":740,"wires":[]},{"id":"918590c4bf51cf19","type":"function","z":"624963ed82f87a01","name":"","func":"\nif (Date.now() - flow.get(\"PIR_time\") < 3600000) { return } // use 3600000 for an hour\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":740,"wires":[["79075c71e73c6b77"]]}]

Unfortunately it is still not working. It does not save the time. Is it possible to use the history node and extract the state "on" from the array?

I do not understand why the flow I posted is not "working" for you.

If you click the pir inject node it does store the time in flow.PIR_time

image

If you then click the sunrise inject node nothing will be sent to output.

After 1 hour clicking the sunrise inject WILL pass the message to output, this will then turn off the light.

I'm not sure what you hope to get from the history node that this doesn't already do ?
Because it sends an array of off and on messages which one would you look at, I assume the one with the latest timestamp, but you already get that time in my flow anyway.?