Passing data to a notification node

Brand new to NodeRed. Trying to trigger a notification message to a user, when any person arrives home.

I am trying to get the message to show the person name, as I am triggering it when an entity that starts with “person.” gets home.

I can’t wait, so I am trying to inject a payload and get my notification working. So I created an Inject node and sent it to my notification node.

I am trying to access the payload in my notification node. But the payload is unknown. How can I get this data in my notification?

You can only use mustache templates if the type is JSON, so it looks like you currently have it set to JSONata. If it was JSON you’d have “format JSON” at the top right instead of “format expression”.

However, the output of the “events: state” node will not have the payload in this format - unless you’ve modified the default, the payload will be the state (‘home’ if it’s the person entity). From memory, the field you want will be in data.new_state.attributes.friendly_name (include a debug node to confirm).

1 Like

As michaelblight says, you are using mustache templates {{ something }} which does not work in JSONata.

Yes, you should use JSONata to build objects like this, so this is the right way to construct the Data object in a call service node.

Yes, your inject node is doing the right thing, using {} JSON construct and building a valid JSON literal.

So, inside the call service node, using JSONata, you should be able to use

{"message": payload.friendly_name & " just arrived", "title": "my title"}

Note that in JSONata you just need to refer to the message field names, and as you have an object in msg.payload (you don’t need the msg.) you can use

payload.friendly_name

to get ‘Craig’.

Using the ‘&’ string concatenation operator will do the rest.

So why the error? Well, you are trying to set the “title” field to {{payload}}. In JSONata this is a valid construct for a nested object, but payload is already an object. The result is probably

{“title”: {{{“friendly_name”: “Craig”}}}}

and as the call service API is just looking for a string value in “title” at this point, finding an object quite likely ends up as ‘undefined’.

You just need to set {“friendly_name”: “Craig”, “title_is”: “Craig Title”} in your inject node, then use

{"message": payload.friendly_name & " just arrived", "title": payload.title_is}

to get both the message and title set in the call service node.

That being said, the call service node has a special feature whereby you can input the UI values by setting msg.payload as an object. For example, msg.payload set to {“data”: {“message”: “Craig”, “title”: “Title Is”}} would set the UI data field for you.

This feature works by checking msg.payload, and if it is an object (not a primative number, string, Boolean) then it will try to use msg.payload to set the UI values. This is what is most likely the issue - since the node or the API call is looking in payload for things that are not there.

It would be safer to use anything but payload here, so try using msg.mydata to set your object in the inject node, then

{“message”: mydata.friendly_name etc

Hope this helps!

1 Like

That is amazing help. Thank you both! My inject now works, to test the service. But now, I need to make the real instigator work.

So I have an event state node that wait for a person to become “home”. It looks for any “person.”

So I am trying to do what I did with my inject, but for real.

Now I am trying to build that output field to do the same thing (This might not be the right way to go?).

And I am hoping to show the friendly name of the entity that arrived home.

So for now, I’d just like to show the (ugly) entity_id, so my json looks like this:

{
    "friendly_name": entity_id
}

BUT… I’m not sure that will work. I’ll need to go for a walk with my phone to test it. :slight_smile: But am I on the right track?

The call service node quite possibly prompts the most questions as it can be difficult to understand what is required, but yes you are doing the right things by testing the service call first, then getting the data format and values correct.

So, a common use case is (as you are doing)

Event: state (state changes) node → Call service (send notification) node

For your state change node

“person.” (as substring) works (use the Q search to check what it will find…) but you may wish to set the timer - this prevents short bursts of going ‘unknown’ or ‘home’ / ‘away’ from firing the message.

If state (is) (home)
For (5) (minutes)

Then you may wish also to set

Ignore state change event when

  • previous state is unknown
  • current state is unknown & unavailable & equal previous state

This does take a bit of experimenting…

For your call service (notification) node, yes you need a Data object. This can be set in the node UI, or you can build it using a change node between the event: state node and the call service node, or you can do the entire lot in the event: state node.

As the call service node can look at msg.payload for an object, and merge in anything it finds in this, we can make the output msg.payload of the event: state node an object {“data”: { -object I want to be in Data field - } }

It does take a bit of JSONata to do this, but the WebSocket nodes have an extra function as $entity(), and using this I can build the entire Data field and drop it into msg.payload, just as you are attempting to do.

So, with event: state node
Output properties
msg.payload = J:

use something like the following

{
   "data": {
       "message": $entity().attributes.friendly_name & " is " & $entity().state,
       "title": $entity().state & " at " & $substringBefore($entity().last_changed,".")
   }
}

I have tested this, it works, and it saves a change node.

The $entity().state is evaluated as the state value ‘home’
The $entity().attributes.friendly_name is evaluated as required
The $substringBefore($entity().last_changed,“.”) picks up the date time of the state change (although this may be in UTC and not local time - I can’t tell as I am in the UK on GMT so they are the same :slight_smile: and we could well do with removing the ‘T’ as well).

Should all work - it does for me!

Customer Survey
These sort of questions about the call service node and formating data field are asked regularly. It would be great to be able to improve the documentation (not that it is inaccurate at the moment) but I do wonder how best to provide useful, useable documentation.

May I ask you:

Appreciate your feedback - thanks!

1 Like

Thanks for that! I am trying this now. So the message for the notification is built in the State Change node? Could this be done in the notify node, as I feel (Maybe incorrectly) that the construction of the message should be owned by the notification service call.

  • Did you search the forum for help on this question before you posted. If so, what did you search for, what did you find, did it help, if not why not?

I did attempt a search, but as I am on day one of NodeRed, I feel my vocabulary wasn’t suitable for building a clear question. I didn’t use these forums. I did use google, and landed up on Reddit most of the time. I also tried ChatGPT which gave me an invalid answer.

  • Are you aware that there is node information that can be read in the Node-RED debug window? Did you look at this for the event: state node, for the call service node? Was this of help?

I thought I could, but for some reason, unable to see the object. It says string[56] sometimes, but can’t expand the object. I believe this is a novice error.

No.

I did not, but will now.

I’m trying to work out what the status check node json is doing.

{
   "data": {
       "message": $entity().attributes.friendly_name & " is " & $entity().state,
       "title": $entity().state & " at " & $substringBefore($entity().last_changed,".")
   }
}

What is $entity()?

When trying to read about it, it seems it’s (been) depreciated.
Entity | node-red-contrib-home-assistant-websocket (zachowj.github.io)

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!)