Node Red Experiences

Just made a blog post on this exact topic :slight_smile:

edit: good tip with the template node! I hadn’t thought of that to set the { data { } }

2 Likes

I read your blog before jumping on node-red and I like what you have there. If you haven’t read this yet - https://nodered.org/docs/writing-functions - you should check it out. Basically, you can skip the var newMsg = Object(); call by using var newMsg = {payload: blahblahblah… } It’ll shorten your code by a bit, and if your functions get really complicated like mine, then eliminating a few lines is appriciated.

1 Like

Quick question for the Node Red gurus: how do you replicate both the “from” and “to” parts of a Home Assistant automation state trigger?

Here’s what I’m trying to figure out: a notification when my device_tracker changes from “not_home” to “home” and vice-versa. Currently my Node Red flow is:

  • HA Events:State node for my device_tracker entity
  • Switch node for “home” and “not_home” strings
  • Two HA Call Service nodes (one attached to each output of the switch), to call the notify service to send a message to my iPhone; if “home”, send “Mark is arriving home!”, if “not_home”, send “Mark is leaving home!”

But the problem is that my device must be updating my location fairly regularly while I’m out, and so there are lots of “not_home” events that get fired on the event bus, which triggers my “Mark is leaving home!” notification.

If I was doing it in a HA automation, I would do:

trigger:
  - platform: state
    entity_id: device_tracker.marks_iphone
    from: "not_home"
    to: "home"

Which would ensure that I only got a notification when the state changed from one state to another, not when the same state was fired on the event bus.

Any suggestions for how I can replicate this? Thanks!

You could try a function node that checks the states and passes the message

var newState = msg.data.new_state.state;
var oldState = msg.data.old_state.state;
if(oldState == 'off' && newState == 'on'){
    return msg;
}
else { return null; }

Is there a guide for installing and using with ha by chance? I wanna start playing with this. Thanks

Take a look at the rbe node (one of the defaults). Will only send the message if the value has changed.

@Darbos There’s an addon for Hassio
https://community.home-assistant.io/t/repository-notoriousbdg-add-ons-node-red-ha-bridge-and-gogs/

Otherwise it’s in the Debian repositories etc. You need to install the additional integration for Home Assistant. Detailed info - http://diyfuturism.com/hass-and-nodered-smarthome

Thanks @flamingm0e! I modified it slightly and it’s working as follows:

var newState = msg.data.new_state.state;
var oldState = msg.data.old_state.state;
if(oldState != newState){
    return msg;
}
else { return null; }

This function only passes message if the old_state differs from the new_state, so in my case only allows a notification to fire if the transition is from not_home to home or vice-versa.

I like to use the actual states, for use in my input_select options, so I can control how it responds based on what the previous state was, and what the new state is.

How did you do this please? I would love to do something like this to track my movements over the months.

Cheers
Mark

@flamingm0e very good point. I’ve changed it to this:

var newState = msg.data.new_state.state;
var oldState = msg.data.old_state.state;
if (oldState == "not_home" && newState == "home") {
    return [ msg, null ];
}
else if (oldState == "home" && newState == "not_home") {
    return [ null, msg ];
}
else { return [ null, null ]; 
}

This has actually let me get rid of the switch node also - now, the function checks if the old state and new state differ and routes the message to one of two outputs depending on what the new state is. And the else makes sure that other payloads or mismatching logic stops the flow (though I’m not sure the else is necessary since no messages should pass if the logic in either if or else if don’t match).

Thanks for your help!

These are great examples on how to make flows smarter. One that I’m still struggling with, and its probably super easy, is how to compare 2 inputs from Home Assistant. For example, lets says I want to compare inside temperature vs outside temperature for some HVAC notification logic. How do I pull two different states into one flow and compare them? I think that the Home Assistant Get Template component might do it, but I’m not sure how to format everything properly.

Thanks.

You would use the ‘get current state’ node

I’m just using the sqldb nodes that work with any SQL database:

I do not know much about SQL to be honest, but I just made a database & table to hold the location information. For me this is MySQL since that’s what I use with HASS. Whenever a GPS change is detected, I have Node-Red insert that information into the database.

Then anything that uses SQL can access and select from the info. ie. I just wrote a very simple python script with gmplot to generate the map https://github.com/vgm64/gmplot

You could just do it in a Home Assistant template node, test your template on the dev tools page in HA and then just copy and paste it into the node.

If you want to do it in the Node-Red flow, you would trigger 2 ‘current state’ nodes and then have them both go into a join node, combine the messages, then evaluate the output of the join node. Here’s an example that compares two times to trigger my alarm clock:

JSON:

[{"id":"4b54aa6b.60c2c4","type":"comment","z":"45760804.d260f8","name":"Trigger Alarm Clock","info":"Other condition I was using for work day only:\n\ncondition:\n    - condition: template\n      value_template: \"{%- if is_state('input_boolean.alarmworkday', 'on') and is_state('sensor.cal_work_day', 'True') -%}True{%- elif is_state('input_boolean.alarmworkday','off') -%}True{%- else -%}False{%- endif %}\"\n","x":133.54586029052734,"y":60,"wires":[]},{"id":"69da9ca6.175774","type":"inject","z":"45760804.d260f8","name":"Once a Minute","topic":"","payload":"","payloadType":"date","repeat":"60","crontab":"","once":true,"x":122.62890625,"y":103.84805965423584,"wires":[["780b96a3.8cb9c8","a1d9f94b.c736b8"]]},{"id":"780b96a3.8cb9c8","type":"api-current-state","z":"45760804.d260f8","name":"Get Alarm Time","server":"8ac3cd7f.58d3e","halt_if":"unknown","entity_id":"input_datetime.alarm_time","x":121.52182006835938,"y":152.01167106628418,"wires":[["b00268be.c8d818"]]},{"id":"b00268be.c8d818","type":"moment","z":"45760804.d260f8","name":"Subtract 10min","topic":"","input":"payload","inputType":"msg","inTz":"America/Los_Angeles","adjAmount":"10","adjType":"minutes","adjDir":"subtract","format":"HH:mm","locale":"C","output":"payload","outputType":"msg","outTz":"America/Los_Angeles","x":347.0657272338867,"y":168.81338024139404,"wires":[["a79c59f.64675a8"]]},{"id":"a79c59f.64675a8","type":"join","z":"45760804.d260f8","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","x":574.9669036865234,"y":120.19454622268677,"wires":[["290bba5e.eca976"]]},{"id":"a1d9f94b.c736b8","type":"moment","z":"45760804.d260f8","name":"Current Time","topic":"","input":"payload","inputType":"msg","inTz":"America/Los_Angeles","adjAmount":"0","adjType":"hours","adjDir":"add","format":"HH:mm","locale":"C","output":"payload","outputType":"msg","outTz":"America/Los_Angeles","x":354.6716537475586,"y":120.57068347930908,"wires":[["a79c59f.64675a8"]]},{"id":"290bba5e.eca976","type":"function","z":"45760804.d260f8","name":"Compare Times","func":"newmsg = Object();\nif (msg.payload[0] == msg.payload[1]) {\n    newmsg.payload = \"True\";\n} else {\n    newmsg.payload = \"False\";\n}\n\nreturn newmsg;","outputs":1,"noerr":0,"x":578.2886734008789,"y":168.714213848114,"wires":[["23eef6bc.db82fa"]]},{"id":"23eef6bc.db82fa","type":"switch","z":"45760804.d260f8","name":"Is it Time?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"True","vt":"str"}],"checkall":"true","outputs":1,"x":746.6219635009766,"y":139.12392044067383,"wires":[["c4ef2b28.929ef8"]]},{"id":"8ac3cd7f.58d3e","type":"server","z":"","name":"Home Assistant","url":"http://localhost:8123","pass":"PASSWORD"}]

Thanks. Turns out my Home Assistant template node was actually working but a state check that I ran through a switch ran into a case issue. It was trying to match “heat” or “cool” when my template sensor was “Heat” and “Cool.”

Hi. I have hassio running on a pi 3b with addons {duckdns, mqtt, samba, ssh}. I’m thinking of going the node red route as well. I have a spare pi 3b not doing anything. Should i install node red on the pi running hass, or should i install it on the separate spare pi? Thanks.

I have hassbian on a pi 3B and also run node-red on the same box. It seems to cope fine. Mind you, I am not doing anything terribly complex yet.

Also running mqtt, duckdns, ssh etc.

Hi, I’ve been trying to setup simple flow based on sensor value (Xiaomi Gateway illumination sensor). I figured way to convert string to number and made switch node to call light.turn_on. Problem is that both messages seem to get merged and HA is giving errors:
ERROR (MainThread) [homeassistant.core] Invalid service data for light.turn_on: extra keys not allowed @ data[‘attributes’]. Got {‘friendly_name’: ‘Illumination_xxxxx’, ‘icon’: ‘mdi:weather-sunset’, ‘unit_of_measurement’: ‘lm’}
Any hints?
I’m using HA 0.65.5, node-red-contrib-home-assistant 0.3.0, node-red 0.18.3

Just FYI I solved this by recreating message in “custom function”. It’s not elegant but works :slight_smile:

Hi,

Anyone knows why i’m having the error “Unexpected end of JSON input” in this template node?
The input message seems ok to me… :sweat:


Edit: Solved… missing “}” at the end of the template… :sweat_smile:
Edit2: Now the flow is working, but the service call is looping sending notify messages… any tips ?

[{"id":"8f846648.5ab6a","type":"server-events","z":"3d4a89ef.a1404e","name":"test","server":"5f1105eb.41f46c","x":150,"y":280,"wires":[["1c9e63a9.90c514"]]},{"id":"1c9e63a9.90c514","type":"switch","z":"3d4a89ef.a1404e","name":"","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"call_service","vt":"str"}],"checkall":"false","repair":false,"outputs":1,"x":300,"y":280,"wires":[["3fcd77ed.1f7e7"]]},{"id":"3fcd77ed.1f7e7","type":"switch","z":"3d4a89ef.a1404e","name":"","property":"payload.event.service_data.title","propertyType":"msg","rules":[{"t":"eq","v":"Login attempt failed","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":460,"y":280,"wires":[["f50a1594.051c9"]]},{"id":"e4056083.40a5d","type":"api-call-service","z":"3d4a89ef.a1404e","name":"","server":"5f1105eb.41f46c","service_domain":"notify","service":"push","data":"{}","mergecontext":"","x":890,"y":280,"wires":[[]]},{"id":"f50a1594.051c9","type":"template","z":"3d4a89ef.a1404e","name":"notify template","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{ \"data\": {\n \"title\": \"{{payload.event.service_data.title}}\",\n \"message\": \"{{payload.event.service_data.message}}\"\n }\n}","output":"json","x":660,"y":280,"wires":[["e4056083.40a5d"]]},{"id":"5f1105eb.41f46c","type":"server","z":"","name":"Home Assistant","url":"http://LANIP:PORT","pass":"HOMEPASSOWORD"}]

@s3Pol
I’m just having a look at this for you but I keep getting a “TypeError: states.reduce is not a function” in the debug panel/sidebar. Do you get this as well?
John