Hooking up IKEA TRADFRI motion sensor in NodeRED takes about 1 min and it would make it for a very boring and very much obvious tutorial. If you have seen my stuff before, you know I like to complicate things, mostly because I can! I’d like to introduce you to a much smarter version of the IKEA TRADFRI motion sensor – which you can control like a real IoT device!

IKEA TRADFRI motion sensor in NodeRED

If you want to use the sensor “as is” there isn’t much to it, simply read the state from msg.payload.occupancy which comes as true or false and use the change node to send the appropriate message back to the device of your choice. Simple! You will have to get a CC2531 USB Zigbee sniffer and follow this 3 min guide to flash it (no cc debugger needed!). Follow this guide to pair your sensor with cc2531.

FUNCTION NODE: Format var x = msg.payload.occupancy; if(x === true){ msg.payload = {"state": "ON"}; } if(x === false){ msg.payload = {"state": "OFF"}; } return msg;

I’m here to extend the features of the IKEA TRADFRI motion sensor and show you how to add the following functions:

dashboard access

extended timeout (10 min+)

(10 min+) delay mode (up to 10 min)

(up to 10 min) latching

time condition (ie day, night, 24h)

You have to admit this is pretty impressive especially, that the IKEA TRADFRI motion sensor comes with a timeout 1-10 min and night/ anytime options of operation only. Not very smart if I’m honest.

This project uses one of my previous articles about getting sunset and sunrise information to NodeRED. Make sure you get yourself familiar with it and have the flow deployed.

Motion Sensor Dashboard & more

Unfortunately, this is one of these flows that are a bit mad to explain as there are many multiple interactions going on. I will break it down to GUI dependent elements and the NodeRED.

The design principle was simple. Set the time on/off timers (“SensorON” & “SensorOFF”) and check every minute if the light should be turned on or turned off. To make it work I need to set the IKEA TRADFRI motion sensor dials to “sun” (operating in any light conditions) and 1 min (one-minute timeout). I will use NodeRED to process that behaviour.

The Dashboard

The 3 buttons are using the global variable “TimeOfDay” to compare the value of the button payload ( night, day, 24 ) against the value assigned to the global variable ( night, day ). In addition to that, I use 4 different outputs of the function node to change the colours of the buttons using {{msg.background}} .

FUNCTION NODE: Update GUI var topic = msg.payload; if(topic === "day"){ var msg1 = {background: "#04a3f2"}; var msg2 = {background: "#c3c7c9"}; var msg3 = {background: "#c3c7c9"}; } if(topic === "night"){ msg1 = {background: "#c3c7c9"}; msg2 = {background: "#055277"}; msg3 = {background: "#c3c7c9"}; } if(topic === "24"){ msg1 = {background: "#c3c7c9"}; msg2 = {background: "#c3c7c9"}; msg3 = {background: "#1e8c26"}; } var msg4 = {payload: msg.payload}; flow.set("24", msg.payload); return [msg1, msg2, msg3, msg4];

An INSERT node in the repeat mode (1 min) is used to check if the day conditions has changed. If you want to, you can convert this into a time keeping system.

FUNCTION NODE: Is it night? var x = flow.get("24"); var y = global.get("TimeOfDay"); if(x === y){ flow.set("day", true); } if(x === "24"){ flow.set("day", true); } if(x !== y && x !== "24"){ flow.set("day", false); } return msg;

This setup controls the SWITCH node (“Day?“) in the main flow. Setting the flow context “day” to false stops the messaged from going through.

Both sliders and the latch toggle have unique topics assigned ( delay, timeout, latch ) which are processed by the FUNCTION node (“Set GUI vars“) and the data is saved as flow contexts.

FUNCTION NODE: Set GUI vars var topic = msg.topic; var payload = msg.payload; if(topic === "latch"){ flow.set("IKEA_motionsensor1_latch", payload); if(payload === true){ flow.set("latchpass", false); } if(payload === false){ flow.set("latchpass", true); } return msg; } if(topic === "delay"){ var x = payload *60; flow.set("delay", x); return msg; } if(topic === "timeout"){ var y = payload * 60; flow.set("timeout", y); return msg; }

Lastly there is a reset button which feeds back the default values to the user interface, turns off the light and overrides all important flow variables. It is linked to a notification so you could see the feedback of your action. There is a template node there just for the good measure – it just shows the picture.

FUNCTION NODE: Reset var msg1 = { payload: 1 }; var msg2 = { payload: 0 }; var msg3 = { payload: false }; var msg4 = { payload:"IKEA Motion Sensor has been reset" }; var msg5 = { spotlight: false}; flow.set("SensorOFF", 0); flow.set("latchpass", true); flow.set("state", false); flow.set("timeout", 1); flow.set("delay", 0); flow.set("SensorON", 0); return [msg1, msg2, msg3, msg4, msg5];

The main flow

IKEA TRADFRI motion sensor in NodeRED reports true or false – I’m only interested in true value coming from msg.payload.occupancy as I will set the timing programmatically. I mentioned before, that the flow is interrupted by “day” variable, but also by “latch“.

Latching stops the subsequent variables from being sent further, as only the initial variable should set the timer.

The first function node uses all GUI flow contexts to set the correct times for “SensorON” and “SensorOFF”. These values will control when the light should toggle. These values are updated each time the motion sensor triggers if the latching is disabled.

FUNCTION NODE: Set Sensor ON var delay = flow.get("delay"); var timeout = flow.get("timeout"); var latch = flow.get("IKEA_motionsensor1_latch"); var latchpass = flow.get("latchpass"); var x = new Date(); var time = Math.round( x.getTime() / 1000); //check if values are set var y = isNaN(delay); var z = isNaN(timeout); if(y === true ){ delay = 0; flow.set("delay", delay); } if(z === true ){ timeout = 1; flow.set("timeout", timeout); } //set timers if(delay => 0){ var mod = time + delay flow.set("SensorON", mod); } if(timeout => 0){ var timer = time + timeout + delay; flow.set("SensorOFF", timer); } //latching behaviour if(latch === true ){ flow.set("latchpass", false); } if(latch === false ){ flow.set("latchpass", true); } return msg;

I can get the time in milliseconds in the function node, but since I need the time in seconds, I used Math.round(time/1000) to get the time in seconds. The timers are set using the offsets from “delay” and “timeout“. It’s worth noting that the “SensorOFF” is the combination of time, delay and timeout – so it would never be set to a value smaller than “SensorON“.

There is one more flow control measure – flow “state” which will interrupt messages going forward when the alarm is set. This is done to prevent the non-latching signals causing issues.

Every minute NodeRED is checking if the lights should be set on or off. The script is comparing the current time vs the time in seconds set in flow variables “SensorON” and “SensorOFF”. If the conditions match, a correct message is being sent further to compose the payload and topic controlling my Zemismart Downlight.

FUNCTION NODE: Turn OFF if(msg.spotlight === false){ msg.topic = "zigbee2mqtt/spotlight1/set"; msg.payload = { "state": "OFF" }; flow.set("SensorOFF", 0); flow.set("latchpass", true); flow.set("state", false); flow.set("timeout", 1); flow.set("delay", 0); flow.set("SensorON", 0); return msg; }

FUNCTION NODE: Turn ON if(msg.spotlight === true){ msg.topic = "zigbee2mqtt/spotlight1/set"; msg.payload = { "state": "ON" }; return msg; }

Conclusion

While it’s easy to use IKEA TRADFRI motion sensor in NodeRED as is, making an extra effort enables more options and real IoT approach to sensors. After all, is it a truly connected device if we have to take it off the wall and use a screwdriver to change its settings? Let me know what do you think about this project in this Reddit thread.