How do I pass data from state node and use this in notification? Need some basic help

I am very new to Node Red, so I’m struggling to know how to correctly describe what I want to do, which makes it difficult to search for. I’m pretty sure this is possible, but I don’t even know where to start looking to learn how to do it.

As I expand my alerts, I find myself doing some tedious work of copying and pasting and then making the same change over and over again. For example, if I set up a door alert, I want the notification to say which door it is, so I have to edit it. Same with battery alerts, motion alerts, etc.

For example, I have this setup for door alerts. It is the events:state node, a state node to check an input boolean, and then a call service notify node to push out the notification.

Is there a way for me to make the events:state node put out some message payload (not sure if that’s the right term) that is then transferred through and the call service notify node grabs this and stuffs it into the notification? This would speed up the creation of making things like this, as I could have a single alert at the end and it builds the message based on what I put into the first node that is trigging the whole sequence. And it seems like a good thing to learn.

I’ve pasted the JSON into a gist here if that’s helpful.

Yes. Use a change node after the state nodes, feed them all in to the single change node, and set it to save msg.data to something else - like msg.mstate.

Now your check of the outside door alerts, does every one of those check the same state or does each door have a switch/input boolean or something?

Your notify nodes at the end can then all be changed to a single call, and you can access the name of the door at {{ mstate.new_state.name }}

Thanks. So I can’t quite get it to work. I have the state node for the door, the change node, and then the current state node which checks a single input boolean for all the doors.

However, is msg.mstate a thing? It doesn’t auto-populate when I start typing it in, and a google search returns this thread.

I was able to mess with the first state node to make it output the entity name, which seemed promising, but as soon as it goes through the current state node, that data is gone. So how would I pass the original data through the current state node, instead of outputting its own state?

Edit: okay, I might be on to something. I started just pulling the msg.topic as that has the door name in it. Then I pulled the binary_sensor. and the _ from it. Now the payload from the change node is front door or patio door.

Then for the state node which checks for the input boolean to see if the door alarms are on, I changed the debug node I had sitting there to look at msg.topic and then front door came out of the debug node right before the notify node! Progress!

Now I need to figure out this part:

Your notify nodes at the end can then all be changed to a single call, and you can access the name of the door at {{ mstate.new_state.name }}

The change node takes something that already exists and sets it as a new part of the msg object. Set msg.data to save to msg.mstate and that way you know it will still be available after the next step which is the outdoor alerts check. It doesn’t matter what you save it as, as long as you remember to use it in the final stage.

EDIT:
If you are using the topic then {{ topic }} will give you door name in the final node.

Got it!

I ended up using the topic and using the change node to strip the binary_sensor. from it and taking out the _.

Now the JSON in the notfiy node looks like this:

"message": "The {{ topic }} just opened!",

Any idea on how I could capitalize the first letter of {{ topic }} instead of having to put “The” in front of it?

Thanks so much, I knew this would be possible! (Now I get to remake all my current alerts to get the exact same product, but now it’s scalable for when I…add more doors to the house.

1 Like
"message": msg.topic.charAt(0).toUpperCase() + msg.topic.slice(1) + " just opened!",

Should achieve that.

Okay, something with the syntax is wrong as it doesn’t like the JSON. Says the m is unexpected. If I put the entire thing in quotes:

"message": msg.topic.charAt(0).toUpperCase() + msg.topic.slice(1) + "just opened!",

it’ll accept the JSON, but then it outputs all that stuff as the message. Maybe I need some { } in there? But I’ve tried putting the “code” part in {} and double {{}} and it just outputs the code as the message itself.

Also, why is there a difference between these in terms of syntax?

{{ mstate.new_state.name }}

{{ topic }}

That is, what is the first one three parts (I’m calling a “part” where each period is) and the second one just one? I never could get msg.data to save to msg.mstate. But I guess if I can do it through msg.topic that’s good enough, but it’s good to learn anyway.

You can combine the doors into one trigger state node and also check if the boolean is on. Then use the friendly name in the notification.

image

[{"id":"a7a3238d665444e3","type":"trigger-state","z":"7149093d84a252bd","name":"Outside doors","server":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"binary_sensor.basement_door_sensor, binary_sensor.doortwo, binary_sensor.door_three","entityidfiltertype":"substring","debugenabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"on","propertyValue":"new_state.state"},{"targetType":"entity_id","targetValue":"input_boolean.outside_door_alerts","propertyType":"current_state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"on","propertyValue":"new_state.state"}],"inputs":0,"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"str","enableInput":false,"x":228,"y":400,"wires":[["cec80615982ca865"],[]]},{"id":"cec80615982ca865","type":"api-call-service","z":"7149093d84a252bd","name":"Door Opened (Critical)","server":"","version":3,"debugenabled":true,"service_domain":"notify","service":"iphone_group","entityId":"","data":"{\t   \"title\":\"DOOR OPEN ALERT\",\t   \"message\": data.new_state.attributes.friendly_name & \" just opened!\",\t   \"data\":{\t       \"push\":{\t           \"sound\":{\t               \"name\":\"default\",\t               \"critical\":1,\t               \"volume\":1\t           }\t       },\t       \"actions\":[\t           {\t               \"action\":\"SILENCE_DOOR_ALERTS_30\",\t               \"title\":\"Silence Door Alerts 30 min\",\t               \"authenticationRequired\":\"false\",\t               \"destructive\":0,\t               \"icon\":\"sfsymbols:bell.slash\"\t           },\t           {\t               \"action\":\"TURN_OUTSIDE_DOOR_ALERTS_OFF\",\t               \"title\":\"Turn off outside door alerts\",\t               \"authenticationRequired\":\"false\",\t               \"destructive\":1,\t               \"icon\":\"sfsymbols:bell.slash\"\t           }\t       ]\t   }\t}","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":452,"y":400,"wires":[[]]}]

https://zachowj.github.io/node-red-contrib-home-assistant-websocket/guide/call-service.html

Oh, that’s really slick. Pulling the friendly name worked just fine.

However, it’s pulling more sensors than I want when the Entity ID is tagged as a substring. For example, with

binary_sensor.front_door

it also pulling

binary_sensor.front_door_lock_access_control_lock_jammed_front_door

and

binary_sensor.front_door_lock_low_battery_level

and

binary_sensor.front_door_lock_the_current_status_of_the_door

Do you know how to put in the substring and have it only pull those exact entities, rather than anything that has that entity name contained in it? I tried changing the dropdown to exact or putting quotes or { } around each entity, but neither worked.

Edit to add: if someone finds this later (or even for myself if I forget), there’s a few key things I just learned. I’m just learning, so these may not be generalizations or may be plain just wrong, but I wanted to put this out there. When you are writing the JSON in the notify node and you want to use the fancy coding to pull data out of the message object, you need to set it to J Expression, not just plain JSON. Also, if you put a debug node after your sensor that is checking whatever (door, battery level, whatever), and change the debug node to “display full message object” you’ll be able to see the structure of the message object and then pull data from it. This is super valuable to understand! For example:

"message": data.event.new_state.attributes.friendly_name & " is low.",
is something I figured out on my own to pull the friendly name from a message that was sending about an iPhone battery level. In the debug node, you’ll see data as a top level item, then when you expand data you’ll see event as another item with things nested under that, and then nested under event is new_state, etc etc. So that’s how you can figure out how to pull whatever you want out of a message object.

Use regex.
Show us what entities to capture and which one are close in name that you don’t want and we can help you with a pattern.

Oh cool! I looked into this briefly, but it seemed too steep of a learning curve for me to do it alone right now. Thanks!

Examples of entities I want to include:

binary_sensor.patio_door
binary_sensor.basement_door_sensor
binary_sensor.entry_door
binary_sensor.front_door

Examples of entities that I want to exclude:

binary_sensor.front_door_lock_low_battery_level
binary_sensor.entry_door_low_battery_level
binary_sensor.basement_door_sensors_sensor_low_battery_level

When the filter type is set to substring the entity id field accepts a comma-delimited list.

I believe:

binary_sensor\..*?_door(?:_sensor)?

When the filter type is set to substring the entity id field accepts a comma-delimited list.

Somehow I’m screwing it up though, even though it should take them as a comma-delimited list. I was googling this and I found previous posts you’ve made several years ago on this and the documentation, so you would know!

So this is what I have in the Entity ID box:

binary_sensor.basement_door_sensor, binary_sensor.entry_door, binary_sensor.front_door, binary_sensor.garage_man_door, binary_sensor.patio_door

But as you can see, I’m getting more than those sensors coming out:

Hmmm…I think I’m misunderstanding something. Maybe it’s with what the debug node is putting out?

I entered the regex in and I still get those other sensors. But when I look at that cool regex site you linked and add the ones in that the debug node is putting out, they aren’t showing they are matching.

Maybe I have something else wrong in HA somewhere?

I don’t know why that wouldn’t work.
It makes no sense.

But lets just try something else.
Set it to substring binary_sensor. and import this:

[{"id":"5e6ba5a49e009b8d","type":"debug","z":"ebaa69a9.649708","name":"door battery level","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":630,"y":660,"wires":[]},{"id":"491b00f00211a619","type":"function","z":"ebaa69a9.649708","name":"","func":"\nconst regex1 = /binary_sensor\\..*?door(?:_sensor)?/;\nconst r1 = msg.payload.event.text.match(regex1);\n\nconst regex2 = /binary_sensor\\..*?door(?:_sensor)?.*?battery_level/;\nconst r2 = msg.payload.event.text.match(regex2);\n\n\nif (r1 != null){\n    return [msg, null];\n}else if(r2 != null){\n    return [null, msg];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":620,"wires":[["cb96fedd5fc65db2"],["5e6ba5a49e009b8d"]]},{"id":"cb96fedd5fc65db2","type":"debug","z":"ebaa69a9.649708","name":"door activity","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":600,"wires":[]}]

This is regex in a function node instead. And it will give you battery warnings also.

Yeah, I don’t know. I’ve been doing this long enough to know that it’s probably something I’m screwing up on my end, some setting or some step that is so basic and obvious, but I haven’t been doing it long enough to know what it is!

Okay, I imported that. A few things to clarify:

  1. I’m checking the “output on connect” for easy testing. That’s when I’m seeing the other entities when I try it without the regex and instead use the substring approach. I don’t see how that would affect which entities it would be pulling though.
  2. I’m testing these by connecting to the false output on the event state node and sending that to the debug or function nodes. I assume the message object structure and everything is the same. Otherwise I’d be sitting next to a door and opening and closing it, which I can do, if needed. Or is there another way to manually change a sensor value for testing?
  3. I’m using the event state node. I know there is also a trigger state node which is similar. I tried both and compared the message object output with a debug node and their structure was not the same, so I’m guessing that matters.
  4. I compared the message object structure on the event state node with your regex and they don’t match up. What info are you trying to pull with the regex? I’m wondering how you can pull both the entity and the state? Here is the Regex: msg.payload.event.text.match(regex1) and here is the message payload

So when I tried your sequence the function node threw out some errors. It was the same one over and over.

"TypeError: Cannot read properties of undefined (reading 'text')"

Then I opened the door and got a nicer looking output

Hooked it up to my call service node to push the notification, and I’m not getting any notification there.

The easiest solution may be what Kermit is suggesting with figuring out why it’s not accepting a comma-delimitated list when set to substring.

My bad…
Let me fix it after dinner.

[{"id":"cb96fedd5fc65db2","type":"debug","z":"ebaa69a9.649708","name":"door activity","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":550,"y":580,"wires":[]},{"id":"491b00f00211a619","type":"function","z":"ebaa69a9.649708","name":"","func":"\nconst regex1 = /binary_sensor\\..*?door(?:_sensor)?/;\nconst r1 = msg.topic.match(regex1);\n\nconst regex2 = /binary_sensor\\..*?door(?:_sensor)?.*?battery_level/;\nconst r2 = msg.topic.match(regex2);\n\n\nif (r1 != null){\n    return [msg, null];\n}else if(r2 != null){\n    return [null, msg];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":600,"wires":[["cb96fedd5fc65db2"],["5e6ba5a49e009b8d"]]},{"id":"5e6ba5a49e009b8d","type":"debug","z":"ebaa69a9.649708","name":"door battery level","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":570,"y":640,"wires":[]}]

It’s supposed to regex on msg.topic.

This latest one is letting through out of the first output of the function node:
binary_sensor.garage_the_current_status_of_the_door
and
binary_sensor.key_free_push_button_deadbolt_the_current_status_of_the_door_basement
and
binary_sensor.front_door_lock_access_control_lock_jammed_front_door

Those shouldn’t be showing up anywhere in the debug output, right? We only want door open coming out of the first output of the function node and battery level info coming out of the second function, right? Just to make sure I understand the goal.

Can you explain the regex to me a little bit? Is there a way to block anything that doesn’t match the first two filters? How would I add another filter, as I’m not sure about this bottom part:

if (r1 != null){
    return [msg, null];
}else if(r2 != null){
    return [null, msg];
}

Why is the return argument/function/thing have msg and null switched in the first one and the last one?

The other issue is I have several interior doors that I’ll want to exclude as well, such as binary_sensor.office_door.