For what you are doing, we have three places where the notification data object could be built. We need the events: state node to trigger the flow, we need the call service node to call the notification service. The raw output of the first does not match what we want for the input to the second, and yes I guess most people would opt to build the data object inside the call service node. And why not - as long as the variables required are in the input message then yes it is a sensible place to do the work.
The next place would be a change node in between the two other nodes. This is a good option as it makes it visually clear that the output of the state change is being modified before it becomes the desired input to the call service. In terms of what Node-RED is about, then yes this makes for visual and clear programming.
Moving yet further back ‘up stream’ we can do the work in the output of the event: state change node. This is the approach I have used in my example for you above.
Which is the best way? Well, whatever works for you really. My approach today (different to two years ago when I first started) is to industrialise my code, trying to make it as tidy as possible and to remove the unnecessary. I am aware that sloppy coding can result in memory leakage, and I now try to keep the message payload as tidy as possible - hence the idea of building the data I want as early as possible, only keeping what is required, and removing unnecessary nodes. In reality, for easier maintenance and distribution, using a change node to do the work would be a better option - the event: state node does the work of getting the event, the change node does the work of setting up the data, the call service node does the work of calling the service. All very easy to see, understand, modify, and debug.
What is $entity()?
Good question (there is documentation, and thanks very much for your feedback this will be useful as I am trying to work out if / how to possibly improve the docs and their availability… one reason for answering posts like this).
The Home Assistant WebSocket nodes - all these wonderful ones that connect Node-RED and Home Assistant - have both ‘mustache’ templating and ‘JSONata’ coding available to use to do the stuff we are talking about here. Substituting variables into strings and the like.
In general terms, mustache templating (based on Jinja templates) is used throughout Home Assistant, and does work in a number of UI fields in the WebSocket nodes. However, JSONata is a better option to use, particularly when building objects, just like the Data field here.
JSONata (another language) comes as standard in Node-RED (look for the ‘J: expression’ option), and has a number of inbuilt functions. Kermit has added some special extra functions, just for the WebSocket nodes.
https://zachowj.github.io/node-red-contrib-home-assistant-websocket/guide/jsonata.html
I know the docs say ‘three extra functions’ when there are now nine of them, yes the docs need a refresh!
These extra functions only work inside the WebSocket nodes (so you can’t use this one in a change node). Another reason for doing as much work as possible in the event: state node (or the call service node).
$entity() returns a data object with details of the entity that has triggered the node. In the node output properties, the default is to put ‘entity state’ directly into msg.payload, and the ‘event data’ directly into msg.data. However, if we use $entity() then we can get the state value using $entity().state, but more usefully we can get at the friendly name and other details from the entity attributes.
Hence $entity().attributes.friendly_name
So, the code above is JSONata (langauge that works on JSON).
The { } builds an object, expecting a valid JSON “key”: value structure, and therefor
{“data”: { “message”: message_value, “title”: title_value} }
gives me what I want - and the neat thing about JSONata is I can use any expression for the values, so here I am using $entity() to get the information I want.
The advantage of doing this here is that I can build the data object and put this into msg.payload, which is then merged into the call service node UI settings. This means it is possible to have just one call service node, and to pass different msg.payloads with the different messages in them. Another ‘good programming’ technique to refactor code to remove duplication.
In the end - just do what works for you! Using a change node in the middle is a good approach, however $entity() will not work there, so
retain the output property setting msg.data = ‘event data’ in the event: state node, and in a new change node, set msg.payload to the value of the JSONata expression below (use J: option)
{
"data": {
"message": data.new_state.attributes.friendly_name & " is " & data.new_state.state,
"title": data.new_state.state & " at " & $substringBefore(data.new_state.last_changed,".")
}
}
which should work (I have tested it, honest!)