Simple dynamic notify message text

Hi there,

I’m relatively new to HA and node-red, and intermediate level programming skills.

This seems like a very simple thing to do, but I must be missing something.
I want to send a notification to iPhone via the notify node. But I need the message text to be dynamic.

I have read a bunch of documents and forum posts on the topic, and others seem to get this going, but I must be missing something, or need it dumbed down perhaps.

Firstly, clearly, the notify node can’t extract actual values from msg.* or flow.* locations. It must be a pre-formed, JSON formatted “data” argument.
One common theme I have found with online solutions to this is the use of a template node. This puts things in a {"data":{"message":{{payload}}} structure. Only, when it is sent to the notify node, it sends a message like this as an example “message text (object) [Object] additional message text”. Literally, says object Object in my notification message. Alternatively, trying other things, the template node also doesn’t extract the values I want from the msg.* or flow.* locations. Have tried so many alternatives. I ended up just writing a javascript function that coerces the notify message text into the JSON statement required by the notify node, with the dynamic text added in the function.
What am I missing? Seems like a really basic thing that I am just not understanding

I don’t know what you mean with notify node but you don’t need template node for this.
here is the most simple notification. just pass the message in payload to a service call node, data box of the service call node should be like this: {"message":"{{payload}}"}

image

[{"id":"30f9cb24.31c2c4","type":"api-call-service","z":"294e4f5f.46b07","name":"Notify ","server":"e447d17a.16a64","version":1,"debugenabled":true,"service_domain":"notify","service":"mobile_app_pixel_3","entityId":"","data":"{\"message\":\"{{payload}}\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":590,"y":1660,"wires":[[]]},{"id":"a7e2371d.a3e098","type":"inject","z":"294e4f5f.46b07","name":"","topic":"","payload":"my notification message","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":380,"y":1660,"wires":[["30f9cb24.31c2c4"]]},{"id":"e447d17a.16a64","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true}]
3 Likes

Thanks. So, how would I go about addressing something that’s stored within the payload object
msg.payload.results[0].formatted
When I use it like this in Notify it returns nothing in the notify message

However, when I use a debug node with the same expression, it returns the correct value

drop the msg and just use {{payload.results[0].formatted}}

or alternatively, you can use a change node before service call, and move msg.payload.results[0].formatted to msg.payload.data.message and leave the data box empty in the service call node. like this:

image

so as long as service call node receives a payload like this, it will process it.

{
    "data": {
        "message": "my notification message"
    }
}
1 Like

thanks.
So, I tried it like this:


and it still turned out like this:

It’s as if notify node can’t extract the data from the within the payload object.
I also tried the change node and bind the value to the msg.payload.data.message , but then I can’t concatenate text in the text message. I would have thought concatenating text would have been easier than this. :frowning:

can you post your flow in text format (like i did)? let’s see where it goes wrong.
and also the message object, how does it look like…

ok here it is, i don’t know exactly how the original message is but pretending you receive something like this:

{
    "results": [
        {
            "formatted": "my address"
        }
    ]
}

put a change node before service call and set it with JSONATA expression:

image

than it works. at least for me.

here is my flow:

import this flow and adapt to your config.

[{"id":"30f9cb24.31c2c4","type":"api-call-service","z":"294e4f5f.46b07","name":"Notify ","server":"e447d17a.16a64","version":1,"debugenabled":true,"service_domain":"notify","service":"mobile_app_pixel_3","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":830,"y":1660,"wires":[[]]},{"id":"a7e2371d.a3e098","type":"inject","z":"294e4f5f.46b07","name":"","topic":"","payload":"{\"results\":[{\"formatted\":\"my address\"}]}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":330,"y":1660,"wires":[["7c0df91f.5eeae8"]]},{"id":"7c0df91f.5eeae8","type":"change","z":"294e4f5f.46b07","name":"","rules":[{"t":"set","p":"payload.data.message","pt":"msg","to":"\"The address is \" & payload.results[0].formatted","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":1660,"wires":[["30f9cb24.31c2c4"]]},{"id":"e447d17a.16a64","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true}]
2 Likes

Thanks for your response. Appreciate the help. Apologies for the delay, Australia here, just now morning. I’ll try this later in the day and get back to you. If there are still issues, i will paste in the entire flow.
Thanks again

Yes, this worked! Okay the last part I was missing was using JASONata J: expressions to coerce strings together within the change node, as they are set/moved from payload to another context. It makes sense to me now. Thanks for your patience with me and help. Greatly appreciate it!

rnodern

3 Likes

I am trying to send the status is a person in HA via the contents of msg.payload to the companion app like shown in the picture but I only receive a blank message.

Does anyone know what I am doing wrong?

When using {{ }} use the json rather than j expression.

5 Likes

Tiny detail which solved it for me! Thanks.

I found this thread very helpful in creating a notification to my phone when my Yale Lock batteries go below a certain percentage.

Export of functioning Flow:

[{"id":"b010c1fc8eb4a2fa","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"aa26eac7293450fc","type":"api-call-service","z":"b010c1fc8eb4a2fa","name":"","server":"59c431be.e53a8","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_oneplus_7_pro","areaId":[],"deviceId":[],"entityId":[],"data":"{\"title\":\"House - Front Door\",\"message\":\"Currently {{payload}}%\",\"data\":{\"actions\":[{\"action\":\"none\",\"title\":\"Replace Batteries!\"}],\"image\":\"https://i.pinimg.com/originals/c8/22/59/c82259514947c719f080e98ae5d3d475.jpg\"}}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":680,"y":220,"wires":[[]]},{"id":"3e6c7950525b036f","type":"server-state-changed","z":"b010c1fc8eb4a2fa","name":"","server":"59c431be.e53a8","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"sensor.front_door_battery","entityidfiltertype":"exact","outputinitially":true,"state_type":"num","haltifstate":"20","halt_if_type":"num","halt_if_compare":"lte","outputs":2,"output_only_on_state_change":true,"for":"1","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":160,"y":220,"wires":[["aa26eac7293450fc"],[]]},{"id":"59c431be.e53a8","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Thank you All! :slight_smile:

1 Like

I’ve found this thread absolutely fascinating, and it finally got me to move over to Node Red - and I’m shocked I got it to work so far haha. I have all my cameras now passing variables via Node Red to create notifications which is awesome.

I’m now at a stage where I’m trying to customise the notification to my phone, and having trouble splitting out the variables. The current notification I get is:

My current setup in BI for MQTT is simply: &ALERT_DB;&MEMO;&ALERT_PATH

Node Red then splits it…

var str = msg.payload;
var parts = str.split(";");
msg.db = {
    db: parts[0]
}
msg.memo = {
    memo: parts[1]
}
msg.path = {
    path: parts[2]
}
return msg;

Once split Node Red then throws passes to the notify function with the below:

{
   "message": $split(topic,'/',3)[1] & ": " & memo.memo,
   "data": {
         "image": "http://192.168.1.246:81/alerts/" & path.path,
         "actions": [
               {
                  "action": "URI",
                  "title": "Live",
                  "uri": "http://192.168.1.246:81/ui3.htm?maximize=1&cam=" & $split(topic,'/',3)[1]
               },
               {
                   "action": "URI",
                   "title": "Clip",
                   "uri": "http://192.168.1.246:81/ui3.htm?maximize=1&tab=alerts&cam=" & $split($lowercase(topic),'/',3)[1] & "&rec=" & db.db
               }
         ]
   }
}

Can anyone point out in the split funciton what I would do so that the text in the notification becomes something to the effect of “A (item detected) was detected at the (location)”

The call service allows you to pass in data. This allows you to format the data field all in the function node.

image

[{"id":"051dfda870d2e0c1","type":"inject","z":"265e4c64d108bbce","name":"2 persons","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"blueiris/front","payload":"ALERT_DB;person:80%,person:78%;ALERT_PATH","payloadType":"str","x":108,"y":576,"wires":[["30ea80513a028e07"]]},{"id":"30ea80513a028e07","type":"function","z":"265e4c64d108bbce","name":"format data","func":"const [db, memo, path] = msg.payload.split(\";\");\nconst location = msg.topic.split(\"/\")[1];\n\nconst things = joinThings(memo.split(\",\").reduce((acc, thing) => {\n    return [...acc, thing.split(\":\")[0]];\n}, []));\n\nconst message = `A ${things} was detected at the ${location}`;\nmsg.payload = {\n    data: {\n        message,\n        data: {\n            image: `http://192.168.1.246:81/alerts/${path}`,\n            actions: [\n                {\n                    action: \"URI\",\n                    title: \"Live\",\n                    uri: `http://192.168.1.246:81/ui3.htm?maximize=1&cam=${location}`,\n                },\n                {\n                    action: \"URI\",\n                    title: \"Clip\",\n                    uri: `http://192.168.1.246:81/ui3.htm?maximize=1&tab=alerts&cam=${location.toLocaleLowerCase()}&rec=${db}`\n                }\n            ]\n        }\n    }\n}\n\nreturn msg;\n\nfunction joinThings(arr)  {\n    const unique = [...new Set(arr)];\n    const last = unique.pop();\n    return unique.length > 0\n        ? `${unique.join(', ')} and ${last}`\n        : last ?? '';\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":282,"y":576,"wires":[["9fdb7c26eef97154"]]},{"id":"0ad97b3555ec8ea1","type":"inject","z":"265e4c64d108bbce","name":"2 persons and a dog","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"blueiris/front","payload":"ALERT_DB;person:80%,person:78%,dog:66%;ALERT_PATH","payloadType":"str","x":138,"y":624,"wires":[["30ea80513a028e07"]]},{"id":"9fdb7c26eef97154","type":"api-call-service","z":"265e4c64d108bbce","name":"","server":"","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_person","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":514,"y":576,"wires":[[]]}]
const [db, memo, path] = msg.payload.split(";");
const location = msg.topic.split("/")[1];

const things = joinThings(memo.split(",").reduce((acc, thing) => {
    return [...acc, thing.split(":")[0]];
}, []));

const message = `A ${things} was detected at the ${location}`;
msg.payload = {
    data: {
        message,
        data: {
            image: `http://192.168.1.246:81/alerts/${path}`,
            actions: [
                {
                    action: "URI",
                    title: "Live",
                    uri: `http://192.168.1.246:81/ui3.htm?maximize=1&cam=${location}`,
                },
                {
                    action: "URI",
                    title: "Clip",
                    uri: `http://192.168.1.246:81/ui3.htm?maximize=1&tab=alerts&cam=${location.toLocaleLowerCase()}&rec=${db}`
                }
            ]
        }
    }
}

return msg;

function joinThings(arr)  {
    const unique = [...new Set(arr)];
    const last = unique.pop();
    return unique.length > 0
        ? `${unique.join(', ')} and ${last}`
        : last ?? '';
}

1 Like

Woah - that’s way more than I expected to see, and quite impressive - thank you!

At the Notify function it looks like I need to call ‘message’ and ‘msg.payload’ but I’m not sure how to do that in the Notify step. Are you able to point me in the right direction? On how to complete the last step?

The call service allows you to pass in data via the message and not have to be configured in the node itself. That’s what’s happening here.

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

1 Like