In my last post about using Node-Red to make automations with Home Assistant, I showed some very simple flows for turning lights on and off. While it is important to get used to the Node-Red way of doing things and it’s interface, none of the examples in my post are very compelling. All of that can easily be accomplished in Home Assistant already, so what makes Node-Red so awesome?

Let’s examine some of Node-Red’s features a little closer to get a better idea of what’s going on, how we can use that to create dynamic automations with Home Assistant, and an example of an alarm clock radio flow that uses some advanced logic nodes.





GETTING THE MSG

The simplest explanation of Node-Red is that it a way to route messages. Input nodes create a msg that has several parts, the nodes in the flow examine this message to decide where to send it next, & this ends in an output that acts on the message.

Usually, we are most interested in the msg.payload, but that’s not the only information the msg carries. By setting a debug node to output the entire message, we can see all the information:

If I hook this debug node up to my location device_tracker, I get this in the Debug panel:

That’s a lot more info than just the payload! Both the new and the old state are here, as well as the full range of attributes that Home Assistant tracks.

But how to use this information? To get the latitude and longitude here we would refer to them as:

msg.data.new_state.attributes.latitude msg.data.new_state.attributes.longitude

This can get slightly more complicated if the information is contained in a different data type, such as an array or object. If, like me, you are not a programmer you may want to keep this basic overview of data types in javascript handy if you are having trouble figuring out the syntax.

DYNAMIC SERVICE CALLS

Now that we can see there’s more to the msg than the payload, let’s use it to make our automations more useful. It’s great to be able to turn a light on or off, but what if we want our automation to set the brightness dynamically?

MSG.PAYLOAD.DATA

The call service Home Assistant node will look for a data object in the msg.payload. Anything it finds in the data object will be used to override the settings you entered in the call service node. The syntax for this looks like:

msg.payload = { "data": {"entity_id":"light.bedroom","brightness": 255 } }

Using an inject node, set the msg.payload to JSON and enter the above value. Since we are sending all the information necessary to make the service call, we can just leave the “Data” field blank in the output with a pair of brackets { }.

Settings:

Flow JSON:

[{"id":"aa2c6a07.d910d8","type":"inject","z":"86cf38de.45d048","name":"","topic":"","payload":"{ \"data\": {\"entity_id\":\"light.bedroom\",\"brightness\": 255 } }","payloadType":"json","repeat":"","crontab":"","once":false,"x":170,"y":260,"wires":[["992a58f4.573ad8"]]},{"id":"992a58f4.573ad8","type":"api-call-service","z":"86cf38de.45d048","name":"Service Call","server":"8ac3cd7f.58d3e","service_domain":"light","service":"turn_on","data":"{ }","x":430,"y":260,"wires":[]},{"id":"8ac3cd7f.58d3e","type":"server","z":"","name":"Home Assistant","url":"http://localhost:8123","pass":"YOURPASS"}]

Deploy the flow and press the button on the inject node: boom! Now our service call outputs can accept a range of commands from upstream in the flow, determined programmatically instead of hardcoded into the automation.

TIPS

You can easily set values for msg.payload.data in your flows using function, change, and set nodes (among others). Another way, pointed out by a very helpful poster on the Hass forums, is to use a template node set to output JSON.





EXAMPLE: MORNING RADIO FADE IN

As part of my alarm clock sequence, I want to gradually fade in the volume of the local public radio station so I can wake up to the morning news and traffic. I have an inexpensive Onkyo TX stereo receiver that integrates really well with Home Assistant.

This flow turns on the receiver, which requires some delays for it to power up and connect to the network before it will accept commands. Once it’s online, it begins a simple loop using the looptimer node.

THE LOOP

Once started, the loop runs every 25 seconds. It gets the current stereo volume, adds 5 points to that value with a function node, and sends that new volume as a data override to the service call output.

Function nodes use javascript (if you prefer Python, there’s a node for that). Again, take careful note of the data types. The msg.payload in this case comes in as a string, in order to perform math on it I had to convert it to a float. I then returned the new volume as a data object in the payload.

newmsg = Object(); old_vol = parseFloat(msg.payload); new_vol = old_vol + 0.05; newmsg.payload = { data: { 'entity_id': 'media_player.stereo','volume_level': new_vol } }; return newmsg;

Now, I could just set the upper maximums on the looptimer node to quit when it’s reached the level I want. I’m going to make this more complicated than necessary though because I can.

STOP THE LOOP WITH A THRESHOLD

Another useful logic node is the traffic light. It can be turned red or green, and accordingly will either drop or forward the messages through based on it’s state. In order for this to make sense, read the documentation on both the traffic light and the looptimer to see how these nodes are controlled via messages.

In my example, the traffic light is turned to GREEN (messages allowed through) when the loop starts. The volume of the stereo is monitored with a state change node through another function – if above 45, send a STOP message to the traffic light. Because the light is GREEN, the STOP message is forwarded to the looptimer node, which is the signal to turn itself off. On completion of the loop, the looptimer outputs a stopped message through it’s second output, which goes back to the traffic light and switches the traffic light to RED, blocking future volume changes from activating the loop again.

I thought it was kind of interesting that these two nodes, which effectively cancel each other out, visually form an “X” with their wires.

THE JSON

Copy this to import the whole flow into Node-Red:

[{"id":"ec1c1cc0.89f0a","type":"link in","z":"20e65bf6.292fb4","name":"","links":["829f9430.fc3088","b73a76c2.703498"],"x":60.00002670288086,"y":1669.9999589920044,"wires":[["fee08205.45787"]]},{"id":"41b5a4e4.9cae8c","type":"comment","z":"20e65bf6.292fb4","name":"Fade in NPR with Alarm","info":"","x":143.33335494995117,"y":1623.3333101272583,"wires":[]},{"id":"d844d3fa.5a26d","type":"switch","z":"20e65bf6.292fb4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"}],"checkall":"true","outputs":1,"x":335.66672134399414,"y":1923.3331894874573,"wires":[["99146127.9daf4","6b99dd1f.172194"]]},{"id":"1b9b043f.e39a8c","type":"server-state-changed","z":"20e65bf6.292fb4","name":"Stereo Volume","server":"8ac3cd7f.58d3e","entityidfilter":"sensor.stereo_volume","haltifstate":"","x":194.66672134399414,"y":2010.3331894874573,"wires":[["350a9df1.760542"]]},{"id":"350a9df1.760542","type":"function","z":"20e65bf6.292fb4","name":"> 45?","func":"newmsg = Object();

if (msg.payload > 0.44) {

newmsg.payload = \"STOP\";

} else {

newmsg.payload = \"Not Yet\";

}

return newmsg;","outputs":1,"noerr":0,"x":195.66672134399414,"y":2063.3331894874573,"wires":[["49e87859.3c9e68"]]},{"id":"49e87859.3c9e68","type":"switch","z":"20e65bf6.292fb4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"STOP","vt":"str"}],"checkall":"true","outputs":1,"x":335.66672134399414,"y":2063.3331894874573,"wires":[["6b99dd1f.172194"]]},{"id":"7d6b19a8.1c3058","type":"switch","z":"20e65bf6.292fb4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"STOP","vt":"str"}],"checkall":"true","outputs":1,"x":546.6667404174805,"y":1984.6664643287659,"wires":[["99146127.9daf4"]]},{"id":"99146127.9daf4","type":"looptimer","z":"20e65bf6.292fb4","duration":"25","units":"Second","maxloops":"15","maxtimeout":"10","maxtimeoutunits":"Minute","name":"Turn Up Volume","x":732.3333702087402,"y":1922.3331718444824,"wires":[["3632c93f.a0b866"],["6b99dd1f.172194"]]},{"id":"6b99dd1f.172194","type":"traffic","z":"20e65bf6.292fb4","name":"","property_allow":"payload","filter_allow":"on","ignore_case_allow":false,"negate_allow":false,"send_allow":false,"property_stop":"payload","filter_stop":"stopped","ignore_case_stop":false,"negate_stop":false,"send_stop":false,"default_start":false,"differ":false,"x":555.6667442321777,"y":2062.3332085609436,"wires":[["7d6b19a8.1c3058"]]},{"id":"325e1bca.fc58d4","type":"comment","z":"20e65bf6.292fb4","name":"Loop","info":"","x":960.0000610351562,"y":1931.3332405090332,"wires":[]},{"id":"3632c93f.a0b866","type":"api-current-state","z":"20e65bf6.292fb4","name":"Stereo Volume","server":"8ac3cd7f.58d3e","halt_if":"","entity_id":"sensor.stereo_volume","x":990.5000495910645,"y":1973.3332934379578,"wires":[["1aeb6c59.1a9474"]]},{"id":"1aeb6c59.1a9474","type":"function","z":"20e65bf6.292fb4","name":"+5 Volume","func":"newmsg = Object();



old_vol = parseFloat(msg.payload);

new_vol = old_vol + 0.05;



newmsg.payload = { data: { 'entity_id': 'media_player.stereo','volume_level': new_vol } }



return newmsg;","outputs":1,"noerr":0,"x":998.0000076293945,"y":2019.9999270439148,"wires":[["d001ed10.c8e12"]]},{"id":"d001ed10.c8e12","type":"api-call-service","z":"20e65bf6.292fb4","name":"Turn Up Volume","server":"8ac3cd7f.58d3e","service_domain":"media_player","service":"volume_set","data":"{\"entity_id\":\"media_player.stereo\"}","x":1199.1666679382324,"y":2020.3333044052124,"wires":[]},{"id":"99e3766f.1769d8","type":"api-current-state","z":"20e65bf6.292fb4","name":"Receiver On?","server":"8ac3cd7f.58d3e","halt_if":"","entity_id":"switch.dualplug_right","x":181.3333854675293,"y":1729.9999380111694,"wires":[["ee90183e.999a08"]]},{"id":"ee90183e.999a08","type":"switch","z":"20e65bf6.292fb4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","outputs":2,"x":344.3333854675293,"y":1729.9999380111694,"wires":[["84655780.58a0f8"],["4caef560.20d36c","84655780.58a0f8"]]},{"id":"4caef560.20d36c","type":"api-call-service","z":"20e65bf6.292fb4","name":"Turn On Receiver","server":"8ac3cd7f.58d3e","service_domain":"switch","service":"turn_on","data":"{\"entity_id\":\"switch.dualplug_right\"}","x":760.3333854675293,"y":1733.9999380111694,"wires":[]},{"id":"84655780.58a0f8","type":"delay","z":"20e65bf6.292fb4","name":"Let it Turn On - 50s","pauseType":"delay","timeout":"50","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":286.8333854675293,"y":1783.9999589920044,"wires":[["813154b7.868cc8","6d45ef3c.29bba"]]},{"id":"813154b7.868cc8","type":"api-call-service","z":"20e65bf6.292fb4","name":"Set Volume to 0","server":"8ac3cd7f.58d3e","service_domain":"media_player","service":"volume_set","data":"{\"entity_id\":\"media_player.stereo\",\"volume_level\":\"0.10\"}","x":750.3333854675293,"y":1783.9999380111694,"wires":[]},{"id":"e42b6f68.f7683","type":"api-call-service","z":"20e65bf6.292fb4","name":"Switch Receiver to FM","server":"8ac3cd7f.58d3e","service_domain":"media_player","service":"select_source","data":"{\"entity_id\":\"media_player.stereo\",\"source\":\"fm\"}","x":771.3333854675293,"y":1832.9999380111694,"wires":[]},{"id":"585bee5f.37de9","type":"change","z":"20e65bf6.292fb4","name":"Turn On Loop","rules":[{"t":"set","p":"payload","pt":"msg","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":304.58337783813477,"y":1875.8332796096802,"wires":[["d844d3fa.5a26d"]]},{"id":"6d45ef3c.29bba","type":"delay","z":"20e65bf6.292fb4","name":"","pauseType":"delay","timeout":"50","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":515.8333854675292,"y":1824.9999380111692,"wires":[["e42b6f68.f7683","585bee5f.37de9"]]},{"id":"fee08205.45787","type":"api-current-state","z":"20e65bf6.292fb4","name":"Want Music?","server":"8ac3cd7f.58d3e","halt_if":"off","entity_id":"input_boolean.alarmradio","x":168.1667137145996,"y":1670.6666860580444,"wires":[["99e3766f.1769d8"]]},{"id":"21f780ba.d339d","type":"comment","z":"20e65bf6.292fb4","name":"Turn On Receiver & Prep it","info":"","x":776.6666679382324,"y":1679.999924659729,"wires":[]},{"id":"b0732620.9a2ae8","type":"comment","z":"20e65bf6.292fb4","name":"Volume Threshold","info":"","x":201.66669845581055,"y":1968.333176612854,"wires":[]},{"id":"8ac3cd7f.58d3e","type":"server","z":"","name":"Home Assistant","url":"http://localhost:8123","pass":"YOURPASS"}]

CONCLUSION

Hopefully by now, you can start to see the power of using Node-Red for your Home Assistant automations. With an understanding of how the message is handled and how to dynamically interact with Home Assistant almost anything is possible.

I have only used a few nodes here, there are many, many more – each of which can be added to your flows to greatly expand the possibilities. Take a look through Node Red’s library to see a list of community contributed nodes.

If you’ve found any novel nodes or made cool things with them, please post in the comments below!

RESOURCES



