Notify Message Call Service Problem

Hi All,

I have a flow that will notify any family member that enters our home, via Alexa, who is currently away, and who is also home. (Credit to Tom Schneider for creating the original flow Let Alexa welcome you home).

In the flow, there is a function node that does a lot of stuff to prep and create a dynamic message based on who is home and not home. This function successfully creates the message, passes it off to to the Alexa Call Service Node, and Alexa successfully announces the message. No issues on this side. The Alexa notification works like a charm!

My issue is when attempting to pass the same message from the same function to a Call Service Node as a message to my cellphone (My alteration/addition to the original flow from Tom Schneider).

Instead of getting the actual same message that Alex announces, I get a cellphone notification that just says “object object, object object, object object”.

For the life of me I am unable to figure out why, and was hoping someone could assist me in a solution?

I have added my flow for anyone to review.

Any help in getting me back on track would be greatly appreciated.

Thanks in advance :slight_smile:

[{"id":"6e393969.673f5","type":"server-state-changed","z":"aea0d0f9624c9c25","name":"Someone comes 🏠","server":"e3c3c875.5a6578","version":3,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"person\\..*","entityidfiltertype":"regex","outputinitially":false,"state_type":"str","haltifstate":"home","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"for":"0","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":110,"y":300,"wires":[["49d067bc.f7f448"],[]]},{"id":"49d067bc.f7f448","type":"delay","z":"aea0d0f9624c9c25","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":235,"y":300,"wires":[["9dff5589.c12218"]],"l":false},{"id":"e01bf48d.d8b98","type":"function","z":"aea0d0f9624c9c25","name":"Filter family","func":"let family = ['person.john', 'person.mary', 'person.bob'];\n\nif(family.includes(msg.topic)) {\n    node.status({fill:\"green\",shape:\"dot\",text:\"Family\"});\n    return [msg, null];\n}\nnode.status({fill:\"green\",shape:\"dot\",text:\"Guest\"});\nreturn [null, msg];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":300,"wires":[["caef02e7.7fe64"],[]],"outputLabels":["Familie","Gäste"]},{"id":"9dff5589.c12218","type":"ha-wait-until","z":"aea0d0f9624c9c25","name":"Front door opened","server":"e3c3c875.5a6578","version":0,"outputs":2,"entityId":"binary_sensor.downstairs_front_door_on_off","entityIdFilterType":"exact","property":"state","comparator":"is","value":"on","valueType":"str","timeout":"20","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":370,"y":300,"wires":[["e01bf48d.d8b98"],[]]},{"id":"caef02e7.7fe64","type":"ha-get-entities","z":"aea0d0f9624c9c25","name":"🔎 Get all persons","server":"e3c3c875.5a6578","version":0,"rules":[{"property":"entity_id","logic":"is","value":"person\\..*","valueType":"re"}],"output_type":"array","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":730,"y":300,"wires":[["43b98a51.b5e6e4"]]},{"id":"43b98a51.b5e6e4","type":"deduplicate","z":"aea0d0f9624c9c25","name":"","keyproperty":"payload","expiry":"120","x":295,"y":400,"wires":[["f2c5ca0e.349a7"],[]],"l":false},{"id":"f2c5ca0e.349a7","type":"function","z":"aea0d0f9624c9c25","name":"Create message","func":"/** CONFIGURATION **/\n\n// These are the persons you want to include in the greeting.\nlet persons_whitelist = ['person.john', 'person.mary', 'person.bob'];\n\n// A random greeting will be played every time.\nlet r_greet = [\"Welcome home, \", \"It's nice to see you, \", \"Welcome back, \", \"Hey \", \"Hi, \"];\n\n/** Optional: Localization\n *  If you create a new localization, you can share it in the comments! **/\nlet l10n = {\n  \"is\": \"is\",\n  \"are\": \"are\",\n  \"and\": \"and\",\n  \"xyz_is_also_home\": (others, is_are) => others + \" \" + is_are + \" also at home. \",\n  \"since\": \"since\",\n  \"just_now\": \"just now\",\n  \"one_minute\": \"one minute\",\n  \"x_minutes\": (minutes) => minutes + \" minutes\",\n  \"one_hour\": \"one hour\",\n  \"x_hours\": (hours) => hours + \" hours\",\n  \"one_day\": \"one day\",\n  \"x_days\": (days) => days + \" days\",\n  \"away_text\": (persons_with_time) => smart_join(persons_with_time.map(pwt => pwt[0] + \" left \" + pwt[1]  + \" ago\")),\n  \"final_text\": (text) => hour >= 0 && hour < 6 ? \"<amazon:effect name='whispered'>\" + text + \"</amazon:effect>\" : text  \n}\n\n// // Below you find my template for German.\n// // You may also like my r_greet: let r_greet = [\"Willkommen zu Hause, \", \"Schön, dass du da bist, \", \"Willkommen zurück, \", \"Hallo \", \"Moin, \"];\n// let l10n = {\n//     \"is\": \"ist\",\n//     \"are\": \"sind\",\n//     \"and\": \"und\",\n//     \"xyz_is_also_home\": (others, is_are) => others + \" \" + is_are + \" auch zu Hause. \",\n//     \"since\": \"seit\",\n//     \"just_now\": \"gerade eben\",\n//     \"one_minute\": \"einer Minute\",\n//     \"x_minutes\": (minutes) => minutes + \" Minuten\",\n//     \"one_hour\": \"einer Stunde\",\n//     \"x_hours\": (hours) => hours + \" Stunden\",\n//     \"one_day\": \"einem Tag\",\n//     \"x_days\": (days) => days + \" Tagen\",\n//     \"away_text\": (persons_with_time) => smart_join(persons_with_time.map(pwt => pwt[0] + \" ist seit \" + pwt[1])) + \" unterwegs.\",\n//     \"final_text\": (text) => hour >= 0 && hour < 6 ? \"<amazon:effect name='whispered'>\" + text + \"</amazon:effect>\" : text  \n// }\n\n/** Optional: Relations. Replace a name for a person. E.g.: Call Peter \"Dad\" for the kids */\nlet relations = {\n  \"person.john\": {\n    \"person.mary\": \"Mom\",\n  },\n  \"person.bob\": {\n    \"person.john\": \"Dad\",\n    \"person.mary\": \"Mom\",\n  }\n}\n\n/** END CONFIGURATION.\n *  You don't have to change anything below, but if you have a great idea on\n *  how to improve this, please write a comment to share it with us! */\n\n// Join the array to a string separated by commas except the last, which gets replaced by \"and\".\nfunction smart_join(arr) { return arr.join(', ').replace(/, ([^,]*)$/, ' ' + l10n[\"and\"] + ' $1'); }\n\n// convert a Date object into a relative time\nfunction relative_time(time_value) {\n  var parsed_date = Date.parse(time_value);\n  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();\n  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);\n\n  if (delta < 60) {\n    return l10n[\"just_now\"];\n  } else if(delta < 120) {\n    return l10n[\"one_minute\"];\n  } else if(delta < (60*60)) {\n    return l10n[\"x_minutes\"](parseInt(delta / 60).toString());\n  } else if(delta < (120*60)) {\n    return l10n[\"one_hour\"];\n  } else if(delta < (24*60*60)) {\n    return l10n[\"x_hours\"](parseInt(delta / 3600).toString());\n  } else if(delta < (48*60*60)) {\n    return l10n[\"one_day\"]\n  } else {\n    return l10n[\"x_days\"](parseInt(delta / 86400).toString());\n  }\n}\n\n// The arriver is the person that just came home\nlet arriver = msg.data.entity_id;\nlet arriver_name = msg.data.new_state.attributes.friendly_name;\n\nlet hour = new Date().getHours();\nlet home = [];\nlet away = [];\n\n// Get all persons that are home excluding the arriver\nfor(var i=0; i<msg.payload.length; i++) {\n    let current = msg.payload[i];\n    if(current.entity_id != arriver) {\n\n        // Rewrite names for special relations\n        var other_name = (relations[arriver] || {})[current.entity_id] || current.attributes.friendly_name;\n\n        if(current.state == \"home\") {\n            home.push(other_name);\n        } else if(persons_whitelist.includes(current.entity_id)) {\n            away.push([other_name, relative_time(current.last_changed), current.last_changed]);\n        }\n    }\n}\n\n// Sort by away time (untested)\naway = away.sort(a => a[2]);\n\n// Create the message\n\n// Get a random greeting from r_greet\nlet greet = r_greet[Math.floor(Math.random()*r_greet.length)];\nlet is_are = home.length == 1 ? l10n[\"is\"] : l10n[\"are\"];\nlet others = smart_join(home);\n\nlet text = greet + arriver_name + \". \";\n\n// Just tell who is home when there is actually someone home\nif(home.length > 0) {\n    text += l10n[\"xyz_is_also_home\"](others, is_are);\n}\n\n// Just tell who is away when there is actually someone away\nif(away.length > 0) {\n    text += l10n[\"away_text\"](away);\n}\n\nmsg.payload.data = {\n  message: l10n[\"final_text\"](text)  \n};\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":400,"wires":[["5f00952f.0a657c","f82a557ea2bd1c32"]]},{"id":"5f00952f.0a657c","type":"api-call-service","z":"aea0d0f9624c9c25","name":"📢 Alexa","server":"e3c3c875.5a6578","version":3,"debugenabled":false,"service_domain":"notify","service":"alexa_media","entityId":"","data":"{\"data\":{\"type\":\"announce\",\"method\":\"all\"},\"target\":\"media_player.living_room_echo\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":620,"y":380,"wires":[[]]},{"id":"f82a557ea2bd1c32","type":"api-call-service","z":"aea0d0f9624c9c25","name":"Send notification to John's phone","server":"e3c3c875.5a6578","version":3,"debugenabled":false,"service_domain":"notify","service":"mobile_app_john_iphone","entityId":"","data":"{\"message\":\"{{payload}}\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":700,"y":440,"wires":[[]]},{"id":"e3c3c875.5a6578","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]

I seem to have narrowed down my issue to being the message object being passed to the Notify call service node for my phone. I believe the call service object for my phone is expecting a string, but the object is being passed.

I am new to Node Red, so I could be wrong.

If I create a debug node with the output pointing to:

payload.data.message
Debug_node

I get the actual message I want to pass to the Notify call service node for my phone.

What I don’t understand is why the same message object can be passed to the Alexa / Call service node, and the announcement plays successfully, but if I pass the same object to the call service for my phone, I only get “object, object”.

Found out the cause of my frustrations…lol.

As it turns out, there was a carriage return hidden in my message string which was throwing off the message when read by the call service node for my phone.

I created another function, which used the trim method to remove the hidden character before passing the message on to the call service node for my phone.

2 Likes

Hi eraush,

Being that I am brand new to using NodeRed could you please share your solution to this. I would love to get this working on my own system.

Thanks