Node-Red MotionLight3
This flow allows you to enable your lights based on motion. It contains a subflow for a delay which is needed because the normal delay node does not provide the functionality I needed and a motionLight3 subflow which does the actual light logic.
Settings
Status
The node-red status which is shown on the node and provide some information regarding the ... well ... status of the node
ON
Turn on lightsOFF
Turn off lightsWAITING
Node is waiting for delay. And index value shows in which phase the node is.
Properties
id
Must be a unique value. E.g. hallway_lightconfig
Allows to define multiple phases. A phase contains a config of an delay and a brightness value. E.g. the following config would enable the light to 100 bri when a motion is detected. Then wait for 60s as soon as no motion is detected anymore and set bri to 20. Then again wait for 60s and then turn off the lights.[{"delay":60,"bri":100},{"delay":20,"bri":60}]
msg.topic
Node-Red only allows one input so you need to set a topic for different values
dark
msg.payload must be of type boolean.dark==true
means it is dark in your room and you want that your light is triggered by motion.dark==false
means it is enough light available in your room. Lights will not be triggered by motionmotion
msg.payload must be of type boolean.motion==true
means a motion is detected.motion==false
means no motion is detected. Both values are expected by the node. As long as a motion is detected the node stay inlight
msg.payload must be of type boolean.light==true
means the light you want to control is on.light==false
means the light you want to control is off. This information is needed so that the node can ignore lux input for dark in case lights are on.
Output
The output is an object which contains two properties. On and brightness. On is of type boolean and brightness is an integer which represents the brightness of the light in percent.
msg.payload = {
on: true,
brightness: 100
}
[{"id":"281dd0bd.0dabd","type":"subflow","name":"delay","info":"","category":"","in":[{"x":120,"y":200,"wires":[{"id":"5b8bf0e1.61b1"}]}],"out":[{"x":760,"y":200,"wires":[{"id":"20545206.45f35e","port":0}]}],"env":[],"color":"#C0C0C0","icon":"node-red/timer.svg","status":{"x":840,"y":40,"wires":[{"id":"93b1569d.e3b158","port":0}]}},{"id":"20545206.45f35e","type":"delay","z":"281dd0bd.0dabd","name":"","pauseType":"delayv","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":640,"y":200,"wires":[["ef688d9f.cca36"]]},{"id":"6967a541.f3989c","type":"change","z":"281dd0bd.0dabd","name":"","rules":[{"t":"delete","p":"reset","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":160,"wires":[["20545206.45f35e","f5f7df50.20b23"]]},{"id":"5b8bf0e1.61b1","type":"function","z":"281dd0bd.0dabd","name":"reset & delay","func":"const isDefined = (val) => {\n return val !== null && typeof val !== 'undefined';\n};\n\nconst isUndefined = (val) => {\n return !isDefined(val);\n}\n\n\n\nif(isDefined(msg.reset)) {\n return [null, msg];\n} else {\n msg.reset = true;\n return [msg, null];\n}\n","outputs":2,"noerr":0,"x":250,"y":200,"wires":[["6967a541.f3989c","20545206.45f35e"],["20545206.45f35e","4b9a646c.7fbadc"]],"outputLabels":["reset & delay","reset"]},{"id":"4b9a646c.7fbadc","type":"change","z":"281dd0bd.0dabd","name":"status.reset","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"fill\":\"grey\",\"shape\":\"dot\",\"text\":\"reset\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":280,"wires":[["e05486d1.5180c8"]]},{"id":"93b1569d.e3b158","type":"link in","z":"281dd0bd.0dabd","name":"status","links":["e05486d1.5180c8","45e72cf8.b30194","aa5c1a7e.c7eb48"],"x":755,"y":40,"wires":[[]]},{"id":"e05486d1.5180c8","type":"link out","z":"281dd0bd.0dabd","name":"","links":["93b1569d.e3b158"],"x":575,"y":280,"wires":[]},{"id":"45e72cf8.b30194","type":"link out","z":"281dd0bd.0dabd","name":"","links":["93b1569d.e3b158"],"x":555,"y":100,"wires":[]},{"id":"f5f7df50.20b23","type":"function","z":"281dd0bd.0dabd","name":"status.delay","func":"msg.payload = {\n fill:\"blue\",\n shape:\"dot\",\n text:msg.delay\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":440,"y":100,"wires":[["45e72cf8.b30194"]]},{"id":"ef688d9f.cca36","type":"function","z":"281dd0bd.0dabd","name":"status.clear","func":"msg.payload = {}\nreturn msg;","outputs":1,"noerr":0,"x":810,"y":140,"wires":[["aa5c1a7e.c7eb48"]]},{"id":"aa5c1a7e.c7eb48","type":"link out","z":"281dd0bd.0dabd","name":"","links":["93b1569d.e3b158"],"x":935,"y":140,"wires":[]},{"id":"77777aff.84bdf4","type":"subflow","name":"MotionLight3","info":"","category":"","in":[{"x":60,"y":340,"wires":[{"id":"af26f54.565e608"}]}],"out":[{"x":1300,"y":300,"wires":[{"id":"1aa88c7e.610494","port":0}]}],"env":[{"name":"ML_ID","type":"str","value":"","ui":{"icon":"font-awesome/fa-info","label":{"en-US":"id"},"type":"input","opts":{"types":["str"]}}},{"name":"ML_CONFIG","type":"json","value":"","ui":{"icon":"font-awesome/fa-sun-o","label":{"en-US":"config"},"type":"input","opts":{"types":["json"]}}}],"color":"#3FADB5","icon":"node-red/light.svg","status":{"x":940,"y":40,"wires":[{"id":"6f9a1a24.a16e54","port":0}]}},{"id":"9a29c581.e9fd28","type":"function","z":"77777aff.84bdf4","name":"DARK","func":"const id = env.get('ML_ID');\nconst dark = flow.get(id + '_DARK');\nconst light = flow.get(id + '_LIGHT');\nconst state = flow.get(id + '_STATE');\n\nflow.set(id + '_ACTUAL_DARK', msg.payload);\n\n\nif(dark) {\n // DARK\n if(!msg.payload && !light){\n flow.set(id + '_DARK', false);\n }\n} else {\n // LIGHT\n if(msg.payload) {\n flow.set(id + '_DARK', true);\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":310,"y":300,"wires":[["544a7b6e.f3fa54"]]},{"id":"af26f54.565e608","type":"switch","z":"77777aff.84bdf4","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"dark","vt":"str"},{"t":"eq","v":"motion","vt":"str"},{"t":"eq","v":"light","vt":"str"}],"checkall":"false","repair":false,"outputs":3,"x":170,"y":340,"wires":[["9a29c581.e9fd28"],["67a8910d.7db78"],["318ae806.258c38"]]},{"id":"e13b6ff6.b2456","type":"link in","z":"77777aff.84bdf4","name":"status","links":["8aeaaec2.bcccc","c1468555.6d9cc8","9e52885.8868b78","306e3664.7122ba","ddc0dc98.14c54","544a7b6e.f3fa54","8baac2e1.32f23","e9f9e8f8.2a13b8","e42d921b.ce53c","8a132997.e585b8"],"x":715,"y":40,"wires":[["6f9a1a24.a16e54"]]},{"id":"40c6e519.b2309c","type":"function","z":"77777aff.84bdf4","name":"INIT","func":"const id = env.get('ML_ID');\nflow.set(id + '_DARK', true);\nflow.set(id + '_ACTUAL_DARK', true);\nflow.set(id + '_LIGHT', false);\nflow.set(id + '_STATE', 'OFF');\nflow.set(id + '_INDEX', 0);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":350,"y":100,"wires":[["ddc0dc98.14c54"]]},{"id":"318ae806.258c38","type":"function","z":"77777aff.84bdf4","name":"LIGHT","func":"const id = env.get('ML_ID');\nconst light = flow.get(id + '_LIGHT');\nconst state = flow.get(id + '_STATE');\n\n\nif(light) {\n // LIGHT ON\n if(!msg.payload){\n flow.set(id + '_LIGHT', false);\n }\n} else {\n // LIGHT OFF\n if(msg.payload && state === 'OFF') {\n flow.set(id + '_LIGHT', true);\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":380,"wires":[["9fdc30e1.12806","e42d921b.ce53c"]]},{"id":"6f9a1a24.a16e54","type":"function","z":"77777aff.84bdf4","name":"status","func":"const id = env.get('ML_ID');\nconst dark = flow.get(id + '_DARK');\nconst light = flow.get(id + '_LIGHT');\nconst state = flow.get(id + '_STATE');\nconst config = env.get('ML_CONFIG');\nconst index = flow.get(id + '_INDEX');\nconst delay = config[index].delay;\n\nvar color = \"grey\";\n\nif(state === 'ON') {\n color = \"green\"\n} else if (state === 'WAITING') {\n color = \"yellow\";\n}\n\n\nlet text = `state=${state}, light=${light}, dark=${dark}`;\n\nif(state === 'WAITING') {\n text = text + `, index=${index}, delay=${delay}s`;\n}\n\n\n\nmsg.payload = {\n fill: color,\n shape: \"dot\",\n text: text\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":830,"y":40,"wires":[[]]},{"id":"67a8910d.7db78","type":"function","z":"77777aff.84bdf4","name":"STATE","func":"const id = env.get('ML_ID');\nconst dark = flow.get(id + '_DARK');\nconst light = flow.get(id + '_LIGHT');\nconst state = flow.get(id + '_STATE');\n\n\nif(state === 'OFF') {\n // OFF\n if(msg.payload && dark && !light) {\n flow.set(id + '_STATE', 'ON');\n } else {\n return null;\n }\n\n} else if(state === 'ON') {\n // ON\n if(!msg.payload) {\n flow.set(id + '_STATE', 'WAITING');\n } else {\n return null;\n }\n} else {\n // WAITING\n if(msg.payload) {\n flow.set(id + '_STATE', 'ON');\n } else {\n return null;\n }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":340,"wires":[["f950537f.1440a"]]},{"id":"9fdc30e1.12806","type":"function","z":"77777aff.84bdf4","name":"STATE","func":"const id = env.get('ML_ID');\nconst dark = flow.get(id + '_DARK');\nconst light = flow.get(id + '_LIGHT');\nconst state = flow.get(id + '_STATE');\n\n\nif(state === 'OFF') {\n // OFF\n return null;\n} else if(state === 'ON') {\n // ON\n if(!msg.payload) {\n flow.set(id + '_STATE', 'OFF');\n } else {\n return null;\n }\n} else {\n // WAITING\n if(!msg.payload) {\n flow.set(id + '_STATE', 'OFF');\n } else {\n return null;\n }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":380,"wires":[["f950537f.1440a"]]},{"id":"f950537f.1440a","type":"function","z":"77777aff.84bdf4","name":"getState","func":"const id = env.get('ML_ID');\nconst state = flow.get(id + '_STATE');\n\nmsg.payload = state;\n\nreturn msg;","outputs":1,"noerr":0,"x":600,"y":340,"wires":[["4256367f.6e39d8"]]},{"id":"d345b42c.fe0998","type":"comment","z":"77777aff.84bdf4","name":"[{\"delay\":60,\"bri\":100},{\"delay\":20,\"bri\":60}]","info":"[{\"delay\":60,\"bri\":100},{\"delay\":20,\"bri\":60}]","x":320,"y":60,"wires":[]},{"id":"5b2a1cc.9ca82e4","type":"comment","z":"77777aff.84bdf4","name":"Config example","info":"","x":240,"y":20,"wires":[]},{"id":"4256367f.6e39d8","type":"switch","z":"77777aff.84bdf4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"OFF","vt":"str"},{"t":"eq","v":"ON","vt":"str"},{"t":"eq","v":"WAITING","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":750,"y":340,"wires":[["4fa7b30.f9ec54c"],["8e710d88.ae14b"],["88be62aa.3cc31"]]},{"id":"8e710d88.ae14b","type":"function","z":"77777aff.84bdf4","name":"ON","func":"const id = env.get('ML_ID');\nconst config = env.get('ML_CONFIG');\n\nmsg.payload = {\n on: true,\n brightness: config[0].bri\n}\nflow.set(id + '_INDEX', 0);\nreturn msg;","outputs":1,"noerr":0,"x":910,"y":340,"wires":[["38dccd88.e3edd2","1aa88c7e.610494"]]},{"id":"88be62aa.3cc31","type":"function","z":"77777aff.84bdf4","name":"getState","func":"const id = env.get('ML_ID');\nconst index = flow.get(id + '_INDEX');\nconst config = env.get('ML_CONFIG');\n\nmsg.delay = config[index].delay * 1000;\n\nreturn msg;","outputs":1,"noerr":0,"x":920,"y":420,"wires":[["d68068b0.b3bf18","e9f9e8f8.2a13b8"]]},{"id":"38dccd88.e3edd2","type":"link out","z":"77777aff.84bdf4","name":"","links":["6f3f4608.7bc438"],"x":1015,"y":300,"wires":[]},{"id":"6f3f4608.7bc438","type":"link in","z":"77777aff.84bdf4","name":"reset","links":["38dccd88.e3edd2"],"x":875,"y":480,"wires":[["60061594.f180dc"]]},{"id":"60061594.f180dc","type":"change","z":"77777aff.84bdf4","name":"","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":1020,"y":480,"wires":[["d68068b0.b3bf18"]]},{"id":"4fa7b30.f9ec54c","type":"function","z":"77777aff.84bdf4","name":"OFF","func":"const id = env.get('ML_ID');\nconst config = env.get('ML_CONFIG');\n\nmsg.payload = {\n on: false\n}\nflow.set(id + '_INDEX', 0);\nreturn msg;","outputs":1,"noerr":0,"x":910,"y":260,"wires":[["38dccd88.e3edd2","1aa88c7e.610494"]]},{"id":"ddc0dc98.14c54","type":"link out","z":"77777aff.84bdf4","name":"","links":["e13b6ff6.b2456"],"x":455,"y":100,"wires":[]},{"id":"544a7b6e.f3fa54","type":"link out","z":"77777aff.84bdf4","name":"","links":["e13b6ff6.b2456"],"x":415,"y":300,"wires":[]},{"id":"8baac2e1.32f23","type":"link out","z":"77777aff.84bdf4","name":"","links":["e13b6ff6.b2456"],"x":1295,"y":260,"wires":[]},{"id":"1aa88c7e.610494","type":"function","z":"77777aff.84bdf4","name":"combine","func":"\nreturn msg;","outputs":1,"noerr":0,"x":1180,"y":300,"wires":[["8baac2e1.32f23"]]},{"id":"d68068b0.b3bf18","type":"subflow:281dd0bd.0dabd","z":"77777aff.84bdf4","name":"","x":1070,"y":420,"wires":[["8166807e.2108e"]]},{"id":"e9f9e8f8.2a13b8","type":"link out","z":"77777aff.84bdf4","name":"","links":["e13b6ff6.b2456"],"x":1024,"y":367,"wires":[]},{"id":"8166807e.2108e","type":"function","z":"77777aff.84bdf4","name":"","func":"const id = env.get('ML_ID');\nlet index = flow.get(id + '_INDEX');\nconst config = env.get('ML_CONFIG');\n\nif(index === config.length - 1) {\n msg.payload = {\n on: false\n }\n index = 0;\n flow.set(id + '_INDEX', 0);\n flow.set(id + '_STATE', 'OFF');\n flow.set(id + '_DARK', true); // overrule sensor for next change\n return [msg, null];\n} else {\n index++;\n msg.payload = {\n on: true,\n brightness: config[index].bri\n }\n flow.set(id + '_INDEX', index);\n return [msg, msg];\n}","outputs":2,"noerr":0,"x":1210,"y":360,"wires":[["1aa88c7e.610494","c353a743.6cbb08"],["88be62aa.3cc31"]]},{"id":"323ca683.dc003a","type":"inject","z":"77777aff.84bdf4","name":"","repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":100,"wires":[["40c6e519.b2309c"]]},{"id":"c353a743.6cbb08","type":"switch","z":"77777aff.84bdf4","name":"","property":"payload.on","propertyType":"msg","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":1370,"y":340,"wires":[["24fa9630.f897fa"]]},{"id":"24fa9630.f897fa","type":"trigger","z":"77777aff.84bdf4","name":"","op1":"","op2":"true","op1type":"nul","op2type":"bool","duration":"2","extend":true,"overrideDelay":false,"units":"min","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":1530,"y":340,"wires":[["45325305.2ad84c"]]},{"id":"45325305.2ad84c","type":"function","z":"77777aff.84bdf4","name":"reset dark","func":"const id = env.get('ML_ID');\nflow.set(id + '_DARK', flow.get(id + '_ACTUAL_DARK'));\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1700,"y":340,"wires":[["8a132997.e585b8"]]},{"id":"e42d921b.ce53c","type":"link out","z":"77777aff.84bdf4","name":"","links":["e13b6ff6.b2456"],"x":415,"y":420,"wires":[]},{"id":"8a132997.e585b8","type":"link out","z":"77777aff.84bdf4","name":"","links":["e13b6ff6.b2456"],"x":1815,"y":340,"wires":[]}]