Randomized Arrival/Departure Announcement

As I finish my move to HA, I’m trying to recreate a WebCoRe piston that I use that announces a random welcome/departure message based on who comes home/leaves.

This by itself is fairly straight forward using individual presence as a trigger, a function node to insert the name and randomize the message and then make the announcement after the entry door closes.

Where I’m getting stuck is if both the wife and I come home together. I don’t want to make 2 individual announcements, I want to make a single announcement that combines both of our names. So I guess what I’m looking for is if 2 individual presence triggers have happened within X amount of time of each other.

For fun, here’s the piston I have in WebCoRe that I’m trying to recreate

Thinking out loud to myself I might be able to do this somehow using data.timeSinceChangedMs but then if the second person arrives within this time window would need to cancel the first announcement to prevent it from making 2.

I guess it all depends on your sensor and trigger setup. I’d probably have the door opening as the trigger and check who is home at that point of time. Not sure if that would work for your presence sensors though.

I don’t believe that would work out because if the wife was home and I arrive then the check would show both home and would announce both.

The WebCoRe version I’m using uses arriving home as a trigger and uses a “wait for condition” of the door being closed plus a few extra seconds before making the announcement.

In my head I’m picturing this:
Presence trigger, delay 30s-1min, check if the other has arrived home within that time period, if no send it to a singular random message, if yes send it to a multiple random message, wait for door to become closed, delay 2-5s, make announcement.

But the issue I’m picturing with this method is that when the second presence trigger fires, it’ll queue up a second message

Well, there was a custom component for this case that enhances the state of the presence sensor. But you could deal with that also yourself. If you set at time of arrival a state to: arrived, and that switches to home after a certain time. Then you can check against arrived vs home.
Anyway there are always lots of different ways to achieve the same result. To check against your second triggering you could employ a trafficlight node. With that you could for example stop a second triggering if you do not want that.

Here’s what I’ve got. Haven’t had the opportunity to test it live yet, but it works in testing using inject nodes to simulate arrival/departures. Multiple injects still only results in 1 spoken message which was my main concern.

For arrival, triggered by either presence device, the get entities node matches presence sensors that are on who’s states have updated in the last 5min. The function node takes the friendly names of the devices and strips it to just our first names, adds is or are depending on how many people, and then builds a randomized message. Wait for door to open and then close (Is there a way to do this with a single node?) and then finally speaks the message.
For departure it’s the same idea but no waiting on the door because the person will have already been gone so I just put a 5s delay for now but may increase to help prevent it from firing multiple times if we drive in and out of the geofence on our way out.

[{"id":"cd69ed99.27fa3","type":"ha-get-entities","z":"d614ccff.478af","server":"94fdcfdf.a00b","name":"","rules":[{"property":"entity_id","logic":"includes","value":"binary_sensor.mike_presence_presence, binary_sensor.ashley_presence_presence","valueType":"str"},{"property":"state","logic":"is","value":"on","valueType":"str"},{"property":"timeSinceChangedMs","logic":"lt","value":"300000","valueType":"num"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":310,"y":2920,"wires":[["463dcd68.92c6f4"]]},{"id":"463dcd68.92c6f4","type":"template","z":"d614ccff.478af","name":"Format Names","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.attributes.friendly_name}}","output":"str","x":480,"y":2920,"wires":[["55d03dbd.b2e1b4"]]},{"id":"55d03dbd.b2e1b4","type":"join","z":"d614ccff.478af","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":", ","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":630,"y":2920,"wires":[["313faa46.736746"]]},{"id":"313faa46.736746","type":"function","z":"d614ccff.478af","name":"Random message","func":"var device=msg.payload\nmsg.payload = {};\nmsg.payload.domain = {};\nmsg.payload.service = {};\nmsg.payload.data = {};\nmsg.payload.data.data = {};\nmsg.payload.data.data.type = {};\nmsg.payload.data.message = {};\n\nif (device == 'Mike - Presence presence') {\n    var name = 'Mike';\n    var isAre = 'is';\n} else if (device === 'Ashley - Presence presence') {\n    var name = 'Ashley';\n    var isAre = 'is';\n} else if (device == 'Mike - Presence presence, Ashley - Presence presence' || device == 'Ashley - Presence presence, Mike - Presence presence') {\n    var name ='Mike, Ashley and Hailey';\n    var isAre = 'are';\n}\n\nvar messageOpening = [\n  \"Welcome Home\",\n  \"How you doing\",\n  \"What's up\",\n  \"Long time no see\",\n  \"Hey\",\n  \"Nice to see you\",\n  \"Look who's home, it's\",\n  \"Nice to have you back\",\n  \"Howdy do\",\n  \"What's going on\",\n  \"How is everything\",\n  \"It's feels like ages since I've seen you\",\n  \"Where have you been hiding\",\n  \"How's it hanging\",\n  \"What's cookin\",\n  \"What's shakin\",\n  \"Greetings and salutations\",\n  \"How goes it\",\n  \"What's happening\",\n  \"How goes it\",\n  \"Roll out the red carpet for\"\n];\n\nvar messageClosing = [\n  \"in the house! Ooo oooo\",\n  \"here.\",\n  \"home.\",\n  \"joining the party\",\n  \"crashing the party\",\n  \"gracing us with their presence\",\n  \"dropping anchor\",\n  \"dropping in\",\n  \"making the scene\",\n  \"barging in\",\n  \"showing up\",\n  \"blowing in\",\n  \"appearing\",\n  \"breezing in\",\n  \"rolling in\",\n  \"popping in\",\n  \"finally home\"\n];\n\n\nvar randomOpening = messageOpening[Math.floor(Math.random()*messageOpening.length)];\nvar randomClosing = messageClosing[Math.floor(Math.random()*messageClosing.length)];\nvar message = randomOpening + \" \" + name + \".\" +  \" \" + name +  \" \" + isAre +  \" \" + randomClosing\n\nmsg.payload.domain = \"notify\"\nmsg.payload.service = \"alexa_media_front_entrance_echo_dot\"\nmsg.payload.data.data.type = \"announce\"\nmsg.payload.data.message = message\n\nreturn msg;","outputs":1,"noerr":0,"x":790,"y":2920,"wires":[["fdd42ad2.a90ec8"]]},{"id":"a5b8bb83.088348","type":"api-call-service","z":"d614ccff.478af","name":"Speak Message","server":"94fdcfdf.a00b","version":1,"debugenabled":false,"service_domain":"notify","service":"alexa_media_front_entrance_echo_dot","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"msg","mustacheAltTags":false,"x":1300,"y":2920,"wires":[[]]},{"id":"fdd42ad2.a90ec8","type":"ha-wait-until","z":"d614ccff.478af","name":"Door Opens","server":"94fdcfdf.a00b","outputs":2,"entityId":"binary_sensor.garage_door","entityIdFilterType":"exact","property":"state","comparator":"is","value":"on","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":970,"y":2920,"wires":[["c2c00135.96b8d"],[]]},{"id":"c2c00135.96b8d","type":"ha-wait-until","z":"d614ccff.478af","name":"Door Closes","server":"94fdcfdf.a00b","outputs":2,"entityId":"binary_sensor.garage_door","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1130,"y":2920,"wires":[["a5b8bb83.088348"],[]]},{"id":"21d72e3e.645d92","type":"ha-get-entities","z":"d614ccff.478af","server":"94fdcfdf.a00b","name":"","rules":[{"property":"entity_id","logic":"includes","value":"binary_sensor.mike_presence_presence, binary_sensor.ashley_presence_presence","valueType":"str"},{"property":"state","logic":"is","value":"off","valueType":"str"},{"property":"timeSinceChangedMs","logic":"lt","value":"300000","valueType":"num"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":310,"y":3000,"wires":[["23a17f82.48a09"]]},{"id":"23a17f82.48a09","type":"template","z":"d614ccff.478af","name":"Format Names","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.attributes.friendly_name}}","output":"str","x":480,"y":3000,"wires":[["ede567df.388938"]]},{"id":"ede567df.388938","type":"join","z":"d614ccff.478af","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":", ","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":630,"y":3000,"wires":[["dc985425.dbbe68"]]},{"id":"dc985425.dbbe68","type":"function","z":"d614ccff.478af","name":"Random message","func":"var device=msg.payload\nmsg.payload = {};\nmsg.payload.domain = {};\nmsg.payload.service = {};\nmsg.payload.data = {};\nmsg.payload.data.data = {};\nmsg.payload.data.data.type = {};\nmsg.payload.data.message = {};\n\nif (device == 'Mike - Presence presence') {\n    var name = 'Mike';\n    var hasHave = 'has';\n} else if (device === 'Ashley - Presence presence') {\n    var name = 'Ashley';\n    var hasHave = 'has';\n} else if (device == 'Mike - Presence presence, Ashley - Presence presence' || device == 'Ashley - Presence presence, Mike - Presence presence') {\n    var name ='Mike, Ashley and Hailey';\n    var hasHave = 'have';\n}\n\nvar messageOpening = [\n  \"Goodbye\",\n  \"See you later\",\n  \"Bye\",\n  \"Live long and prosper\",\n  \"Farewell\",\n  \"Hope you have a great time\",\n  \"Take care\",\n  \"Smell you later\",\n  \"Adios\",\n  \"Caio\",\n  \"Au revoir\",\n  \"Sayonara\",\n  \"Ta Ta for now\",\n  \"Catch you later\",\n  \"To-da-loo\",\n  \"See you in the funny papers\",\n  \"Toodles\",\n  \"Godspeed\",\n  \"So long\",\n  \"Cheerio\",\n  \"Arrivederci\"\n];\n\nvar messageClosing = [\n  \"left the building\",\n  \"gone out\",\n  \"popped out\",\n  \"left\",\n  \"buggered off\",\n  \"departed\",\n  \"split\",\n  \"vamoosed\",\n  \"high tailed it\",\n  \"escaped\",\n  \"eight-six'd it\",\n  \"bid farewell\",\n  \"flaked off\",\n  \"took a hike\",\n  \"withdrawn\",\n  \"exited\",\n  \"vanished\",\n  \"disappeared\",\n  \"evacuated\",\n  \"retreated\",\n  \"taken their leave\"\n];\n\n\nvar randomOpening = messageOpening[Math.floor(Math.random()*messageOpening.length)];\nvar randomClosing = messageClosing[Math.floor(Math.random()*messageClosing.length)];\nvar message = randomOpening + \" \" + name + \".\" +  \" \" + name +  \" \" + hasHave +  \" \" + randomClosing\n\nmsg.payload.domain = \"notify\"\nmsg.payload.service = \"alexa_media_front_entrance_echo_dot\"\nmsg.payload.data.data.type = \"announce\"\nmsg.payload.data.message = message\n\nreturn msg;","outputs":1,"noerr":0,"x":790,"y":3000,"wires":[["6652ec19.c20604"]]},{"id":"b65ea10e.90b65","type":"api-call-service","z":"d614ccff.478af","name":"Speak Message","server":"94fdcfdf.a00b","version":1,"debugenabled":false,"service_domain":"notify","service":"alexa_media_front_entrance_echo_dot","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"payload","output_location_type":"msg","mustacheAltTags":false,"x":1120,"y":3000,"wires":[[]]},{"id":"6652ec19.c20604","type":"delay","z":"d614ccff.478af","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":960,"y":3000,"wires":[["b65ea10e.90b65"]]},{"id":"88615cb1.52921","type":"server-state-changed","z":"d614ccff.478af","name":"Mike Presence","server":"94fdcfdf.a00b","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.mike_presence_presence","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"x":100,"y":2920,"wires":[["cd69ed99.27fa3"],["21d72e3e.645d92"]]},{"id":"4f15dd42.fd1fc4","type":"server-state-changed","z":"d614ccff.478af","name":"Ashley Presence","server":"94fdcfdf.a00b","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.ashley_presence_presence","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"output_only_on_state_change":true,"x":100,"y":3000,"wires":[["cd69ed99.27fa3"],["21d72e3e.645d92"]]},{"id":"7b483db6.6cf044","type":"comment","z":"d614ccff.478af","name":"Announce arrival and departure","info":"","x":150,"y":2860,"wires":[]},{"id":"94fdcfdf.a00b","type":"server","z":"","name":"Home Assistant","addon":true}]

Any updates on this? Looking for the same thing but have no idea how to build it in Node-Red. Just wondering if you got it working the way you wanted.

Thanks

The above worked great. The only change I made to it was adding a time range node so it only announces between 7:30am and 10pm.

1 Like

I am using this but having some issues where I get “undefined, undefined has arrived”… etc instead of saying their names. Can you share how you have your template sensors setup?

Thanks

I use the Friendly name of the device. So in my case it’s Mike Presence.

From there in the function node I shorten it to how I want it spoken

if (device == 'Mike Presence') {
    var name = 'Mike';
    var hasHave = 'has';

Just change device == to the friendly name of your device and the var name = to the name you want spoken.

Hi @MRobi I’ve cribbed your flow and made some adjustments. Mainly using the Person entity…I can get things to work if I bypass the get entities, format names and join…but then I get “Hello Undefined Undefined Undefined welcome home.” I’ve looked at the Friendly name and believe I have it right in function node…but noticed that there were some warnings and out of scope in the node that I can’t decipher. Have any thoughts? Happy to share what I have once I figure out how to post it.

[{"id":"3601c3e8.628edc","type":"server-state-changed","z":"729d4aa5.48ac54","name":"Paul","server":"e0e5de46.64d5","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"person.paul_carson","entityidfiltertype":"exact","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,"x":70,"y":120,"wires":[["c287b2d.1e7eb5"],["65b42cb7.666674"]]},{"id":"e38c2fac.a325b","type":"server-state-changed","z":"729d4aa5.48ac54","name":"Cris","server":"e0e5de46.64d5","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"person.cris","entityidfiltertype":"exact","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,"x":70,"y":220,"wires":[["c287b2d.1e7eb5"],["65b42cb7.666674"]]},{"id":"6a94e4c7.d74b7c","type":"template","z":"729d4aa5.48ac54","name":"Format Names","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.attributes.friendly_name}}","output":"str","x":620,"y":120,"wires":[["fb0a5779.ee1c58"]]},{"id":"304b1171.50662e","type":"ha-wait-until","z":"729d4aa5.48ac54","name":"Door Opens","server":"e0e5de46.64d5","outputs":2,"entityId":"binary_sensor.garage_entry","entityIdFilterType":"exact","property":"state","comparator":"is","value":"on","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1150,"y":120,"wires":[["1a7a6aba.989e95"],[]]},{"id":"1a7a6aba.989e95","type":"ha-wait-until","z":"729d4aa5.48ac54","name":"Door Closes","server":"e0e5de46.64d5","outputs":2,"entityId":"binary_sensor.garage_entry","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1310,"y":120,"wires":[["775558cb.446388"],[]]},{"id":"775558cb.446388","type":"api-call-service","z":"729d4aa5.48ac54","name":"Speak Message","server":"e0e5de46.64d5","version":1,"debugenabled":false,"service_domain":"tts","service":"cloud_say","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1480,"y":120,"wires":[["2b5d3c6b.d68bb4"]]},{"id":"cbda386f.4adc48","type":"delay","z":"729d4aa5.48ac54","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1140,"y":220,"wires":[["377022e6.90fcee"]]},{"id":"d39d5629.85c438","type":"comment","z":"729d4aa5.48ac54","name":"Announce arrival and departure","info":"","x":150,"y":60,"wires":[]},{"id":"65b42cb7.666674","type":"ha-get-entities","z":"729d4aa5.48ac54","server":"e0e5de46.64d5","name":"","rules":[{"property":"entity_id","logic":"is","value":"person.paul_carson","valueType":"str"},{"property":"state","logic":"is","value":"not_home","valueType":"str"},{"property":"timesincechangedms","logic":"lt","value":"300","valueType":"num"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":450,"y":220,"wires":[["a2c056b0.6be538"]]},{"id":"a2c056b0.6be538","type":"template","z":"729d4aa5.48ac54","name":"Format Names","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.attributes.friendly_name}}","output":"str","x":620,"y":220,"wires":[["45736ef.47d189"]]},{"id":"fb0a5779.ee1c58","type":"join","z":"729d4aa5.48ac54","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":", ","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":790,"y":120,"wires":[["accacb7c.51bee8"]]},{"id":"45736ef.47d189","type":"join","z":"729d4aa5.48ac54","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":", ","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":790,"y":220,"wires":[["e82660b3.157e6"]]},{"id":"accacb7c.51bee8","type":"function","z":"729d4aa5.48ac54","name":"Random message","func":"var device=msg.payload\nmsg.payload = {};\nmsg.payload.domain = {};\nmsg.payload.service = {};\nmsg.payload.data = {};\nmsg.payload.data.message = {};\n\nif (device == 'person.paul_carson') {\n    var name = 'Paul';\n    var isAre = 'is';\n}else if (device === 'person.cris') {\n   var name = 'Cris';\n    var isAre = 'is';\n}else if (device == 'person.paul_carson, person.cris' || device == 'person.cris, person.paul_carson') {\n    var name ='Paul and Cris';\n    var isAre = 'are';\n}\n\nvar messageOpening = [\n  \"Welcome Home\",\n  \"How you doing\",\n  \"What's up\",\n  \"Long time no see\",\n  \"Hey\",\n  \"Nice to see you\",\n  \"Look who's home, it's\",\n  \"Nice to have you back\",\n  \"Howdy do\",\n  \"What's going on\",\n  \"How is everything\",\n  \"It's feels like ages since I've seen you\",\n  \"Where have you been hiding\",\n  \"How's it hanging\",\n  \"What's cookin\",\n  \"What's shakin\",\n  \"Greetings and salutations\",\n  \"How goes it\",\n  \"What's happening\",\n  \"How goes it\",\n  \"Roll out the red carpet for\"\n];\n\nvar messageClosing = [\n  \"in the house! Ooo oooo\",\n  \"here.\",\n  \"home.\",\n  \"joining the party\",\n  \"crashing the party\",\n  \"gracing us with their presence\",\n  \"dropping anchor\",\n  \"dropping in\",\n  \"making the scene\",\n  \"barging in\",\n  \"showing up\",\n  \"blowing in\",\n  \"appearing\",\n  \"breezing in\",\n  \"rolling in\",\n  \"popping in\",\n  \"finally home\"\n];\n\n\nvar randomOpening = messageOpening[Math.floor(Math.random()*messageOpening.length)];\nvar randomClosing = messageClosing[Math.floor(Math.random()*messageClosing.length)];\nvar message = randomOpening + \" \" + name + \".\" +  \" \" + name +  \" \" + isAre +  \" \" + randomClosing\n\nmsg.payload.domain = \"tts\"\nmsg.payload.service = \"cloud_say\"\nmsg.payload.data.entity_id = \"media_player.office_display\"\nmsg.payload.data.message = message\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":120,"wires":[["304b1171.50662e"]]},{"id":"377022e6.90fcee","type":"api-call-service","z":"729d4aa5.48ac54","name":"Speak Message","server":"e0e5de46.64d5","version":1,"debugenabled":true,"service_domain":"tts","service":"cloud_say","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1320,"y":220,"wires":[["4589e16c.0fd36"]]},{"id":"e82660b3.157e6","type":"function","z":"729d4aa5.48ac54","name":"Random message","func":"var device=msg.payload\nmsg.payload = {};\nmsg.payload.domain = {};\nmsg.payload.service = {};\nmsg.payload.data = {};\nmsg.payload.data.message = {};\n\nif (device == 'person.paul_carson') {\n    var name = 'Paul';\n    var hasHave = 'has';\n}else if (device == 'person.cris') {\n    var name = 'Cris';\n    var hasHave = 'has';\n}else if (device == 'person.paul_carson, person.cris' || device == 'person.cris, person.paul_carson') {\n    var name ='Paul and Cris';\n    var hasHave = 'have';\n}\n\nvar messageOpening = [\n  \"Goodbye\",\n  \"See you later\",\n  \"Bye\",\n  \"Live long and prosper\",\n  \"Farewell\",\n  \"Hope you have a great time\",\n  \"Take care\",\n  \"Smell you later\",\n  \"Adios\",\n  \"Caio\",\n  \"Au revoir\",\n  \"Sayonara\",\n  \"Ta Ta for now\",\n  \"Catch you later\",\n  \"To-da-loo\",\n  \"See you in the funny papers\",\n  \"Toodles\",\n  \"Godspeed\",\n  \"So long\",\n  \"Cheerio\",\n  \"Arrivederci\"\n];\n\nvar messageClosing = [\n  \"left the building\",\n  \"gone out\",\n  \"popped out\",\n  \"left\",\n  \"buggered off\",\n  \"departed\",\n  \"split\",\n  \"vamoosed\",\n  \"high tailed it\",\n  \"escaped\",\n  \"eight-six'd it\",\n  \"bid farewell\",\n  \"flaked off\",\n  \"took a hike\",\n  \"withdrawn\",\n  \"exited\",\n  \"vanished\",\n  \"disappeared\",\n  \"evacuated\",\n  \"retreated\",\n  \"taken their leave\"\n];\n\n\nvar randomOpening = messageOpening[Math.floor(Math.random()*messageOpening.length)];\nvar randomClosing = messageClosing[Math.floor(Math.random()*messageClosing.length)];\nvar message = randomOpening + \" \" + name + \" \" + name +  \" \" + hasHave +  \" \" + randomClosing\n\nmsg.payload.domain = \"tts\"\nmsg.payload.service = \"cloud_say\"\nmsg.payload.data.entity_id = \"media_player.office_display\"\nmsg.payload.data.message = message\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":220,"wires":[["cbda386f.4adc48"]]},{"id":"2b5d3c6b.d68bb4","type":"debug","z":"729d4aa5.48ac54","name":"Coming Home","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1660,"y":240,"wires":[]},{"id":"4589e16c.0fd36","type":"debug","z":"729d4aa5.48ac54","name":"Leaving home","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1660,"y":320,"wires":[]},{"id":"c287b2d.1e7eb5","type":"ha-get-entities","z":"729d4aa5.48ac54","server":"e0e5de46.64d5","name":"","rules":[{"property":"entity_id","logic":"is","value":"person.paul_carson","valueType":"str"},{"property":"state","logic":"includes","value":"home","valueType":"str"},{"property":"timesincechangedms","logic":"lt","value":"300","valueType":"num"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":450,"y":120,"wires":[["6a94e4c7.d74b7c"]]},{"id":"e0e5de46.64d5","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

I’m not the expert but I’ll try to help as best I can. I’m using an input_boolean to trigger and you’re using the person entities so things are a little different.

1: In your get entities node you only have person.paul so currently person.cris isn’t being considered in this at all.
2: You have the “time since change” set to 300ms. I had this set at 5min for when we arrive together. What will happen at 300ms is 1 message will override the other and you won’t get both names announced. The 5 minutes gives some extra time in case you arrive in separate vehicles, or if 1 entity updates slightly before the other.
3: This is where your main issue is, and I see 2 options to fix it.
Using the person entity, the Friendly name is located in a different spot than the input_boolean. It’s at data.attributes.friendly_name
You must update the template node with the correct path of the friendly name, but then you’ll also have to change the if (device == 'person.paul…) section of the function node to just say “Paul” or whatever the friendly name is.
Alternatively, since you’ve already setup the function node setup with the entity id, I would personally update the template node with the entity_id location which should be data.entity_id and from there your formula in the function node should work.

The warnings you’re seeing in the function node are because the same variable is defined in the if, else-if and else statements. It shouldn’t be an issue. I personally use the “unsafe-function” node since it’s said to be a bit faster and if I paste your function node details into it, it returns no errors.

Thanks very much for your time. I see what you are saying and I’m experimenting with the “get entities” node to try and find the right combination of settings to work with the person entity that I’m using…I’ll look at the other function node once I get things flowing that far. Here’s to tinkering!

Between Mike’s nudge and finding that timesincechangedms is not the same as timeSinceChangedMs I was able to get it to work using the person entity and tts cloud_say on google speakers. For those looking for something similar ( I added a third person and an everyone )

[{"id":"3601c3e8.628edc","type":"server-state-changed","z":"729d4aa5.48ac54","name":"Paul","server":"e0e5de46.64d5","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"person.paul_carson","entityidfiltertype":"exact","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,"x":70,"y":120,"wires":[["c287b2d.1e7eb5"],["65b42cb7.666674"]]},{"id":"e38c2fac.a325b","type":"server-state-changed","z":"729d4aa5.48ac54","name":"Cris","server":"e0e5de46.64d5","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"person.cris","entityidfiltertype":"exact","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,"x":70,"y":220,"wires":[["c287b2d.1e7eb5"],["65b42cb7.666674"]]},{"id":"6a94e4c7.d74b7c","type":"template","z":"729d4aa5.48ac54","name":"Format Names","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.attributes.friendly_name}}","output":"str","x":640,"y":120,"wires":[["fb0a5779.ee1c58"]]},{"id":"304b1171.50662e","type":"ha-wait-until","z":"729d4aa5.48ac54","name":"Door Opens","server":"e0e5de46.64d5","outputs":2,"entityId":"binary_sensor.garage_entry","entityIdFilterType":"exact","property":"state","comparator":"is","value":"on","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1170,"y":60,"wires":[["1a7a6aba.989e95"],[]]},{"id":"1a7a6aba.989e95","type":"ha-wait-until","z":"729d4aa5.48ac54","name":"Door Closes","server":"e0e5de46.64d5","outputs":2,"entityId":"binary_sensor.garage_entry","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1330,"y":60,"wires":[["775558cb.446388"],[]]},{"id":"775558cb.446388","type":"api-call-service","z":"729d4aa5.48ac54","name":"Speak Message","server":"e0e5de46.64d5","version":1,"debugenabled":false,"service_domain":"tts","service":"cloud_say","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1500,"y":100,"wires":[[]]},{"id":"cbda386f.4adc48","type":"delay","z":"729d4aa5.48ac54","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1140,"y":260,"wires":[["377022e6.90fcee"]]},{"id":"d39d5629.85c438","type":"comment","z":"729d4aa5.48ac54","name":"Announce arrival and departure","info":"","x":150,"y":60,"wires":[]},{"id":"65b42cb7.666674","type":"ha-get-entities","z":"729d4aa5.48ac54","server":"e0e5de46.64d5","name":"","rules":[{"property":"entity_id","logic":"includes","value":"person.paul_carson , person.cris, person.sara","valueType":"str"},{"property":"state","logic":"is","value":"not_home","valueType":"str"},{"property":"timeSinceChangedMs","logic":"lt","value":"300000","valueType":"num"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":450,"y":260,"wires":[["a2c056b0.6be538"]]},{"id":"a2c056b0.6be538","type":"template","z":"729d4aa5.48ac54","name":"Format Names","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.attributes.friendly_name}}","output":"str","x":640,"y":260,"wires":[["45736ef.47d189"]]},{"id":"fb0a5779.ee1c58","type":"join","z":"729d4aa5.48ac54","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":", ","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":810,"y":100,"wires":[["accacb7c.51bee8"]]},{"id":"45736ef.47d189","type":"join","z":"729d4aa5.48ac54","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":", ","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":810,"y":260,"wires":[["e82660b3.157e6"]]},{"id":"accacb7c.51bee8","type":"function","z":"729d4aa5.48ac54","name":"Random message","func":"var device=msg.payload\nmsg.payload = {};\nmsg.payload.domain = {};\nmsg.payload.service = {};\nmsg.payload.data = {};\nmsg.payload.data.message = {};\n\nif (device == 'Paul') {\n    var name = 'Paul';\n    var isAre = 'is';\n}else if (device === 'Cris') {\n   var name = 'Cris';\n    var isAre = 'is';\n}else if (device === 'Sara') {\n   var name = 'Sara';\n    var isAre = 'is';\n}else if (device == 'Paul, Cris' || device == 'Cris, Paul') {\n    var name ='Paul and Cris';\n    var isAre = 'are';\n}else if (device == 'Cris, Sara' || device == 'Sara, Cris') {\n    var name = 'Cris and Sara';\n    var isAre = 'are';\n}else if (device == 'Paul, Sara' || device == 'Sara, Paul') {\n    var name = 'Paul and Sara';\n    var isAre = 'are';\n}else if (device == 'Paul, Cris, Sara' || device == 'Cris, Sara, Paul' || device == 'Sara, Paul, Cris' || device == 'Paul, Sara, Cris' || device == 'Sara, Cris, Paul' || device == 'Cris, Paul, Sara') {\n    var name = 'Everyone';\n    var isAre = 'is';\n}\n\nvar messageOpening = [\n  \"Welcome Home\",\n  \"How you doing\",\n  \"What's up\",\n  \"Long time no see\",\n  \"Hey\",\n  \"Nice to see you\",\n  \"Look who's home, it's\",\n  \"Nice to have you back\",\n  \"Howdy do\",\n  \"What's going on\",\n  \"How is everything\",\n  \"It's feels like ages since I've seen you\",\n  \"Where have you been hiding\",\n  \"How's it hanging\",\n  \"What's cookin\",\n  \"What's shakin\",\n  \"Greetings and salutations\",\n  \"How goes it\",\n  \"What's happening\",\n  \"How goes it\",\n  \"Roll out the red carpet for\"\n];\n\nvar messageClosing = [\n  \"in the house! Ooo oooo\",\n  \"here.\",\n  \"home.\",\n  \"joining the party\",\n  \"crashing the party\",\n  \"gracing us with their presence\",\n  \"dropping anchor\",\n  \"dropping in\",\n  \"making the scene\",\n  \"barging in\",\n  \"showing up\",\n  \"blowing in\",\n  \"appearing\",\n  \"breezing in\",\n  \"rolling in\",\n  \"popping in\",\n  \"finally home\"\n];\n\n\nvar randomOpening = messageOpening[Math.floor(Math.random()*messageOpening.length)];\nvar randomClosing = messageClosing[Math.floor(Math.random()*messageClosing.length)];\nvar message = randomOpening + \" \" + name + \".\" +  \" \" + name +  \" \" + isAre +  \" \" + randomClosing\n\nmsg.payload.domain = \"tts\"\nmsg.payload.service = \"cloud_say\"\nmsg.payload.data.entity_id = \"media_player.front_door_speaker\"\nmsg.payload.data.message = message\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":990,"y":100,"wires":[["304b1171.50662e","62b90986.e004b8"]]},{"id":"377022e6.90fcee","type":"api-call-service","z":"729d4aa5.48ac54","name":"Speak Message","server":"e0e5de46.64d5","version":1,"debugenabled":true,"service_domain":"tts","service":"cloud_say","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1320,"y":260,"wires":[[]]},{"id":"e82660b3.157e6","type":"function","z":"729d4aa5.48ac54","name":"Random message","func":"var device=msg.payload\nmsg.payload = {};\nmsg.payload.domain = {};\nmsg.payload.service = {};\nmsg.payload.data = {};\nmsg.payload.data.message = {};\n\nif (device == 'Paul') {\n    var name = 'Paul';\n    var hasHave = 'has';\n}else if (device === 'Cris') {\n   var name = 'Cris';\n    var hasHave = 'has';\n}else if (device === 'Sara') {\n   var name = 'Sara';\n    var hasHave = 'has';\n}else if (device == 'Paul, Cris' || device == 'Cris, Paul') {\n    var name ='Paul and Cris';\n    var hasHave = 'have';\n}else if (device == 'Cris, Sara' || device == 'Sara, Cris') {\n    var name = 'Cris and Sara';\n    var hasHave = 'have';\n}else if (device == 'Paul, Sara' || device == 'Sara, Paul') {\n    var name = 'Paul and Sara';\n    var hasHave = 'have';\n}else if (device == 'Paul, Cris, Sara' || device == 'Cris, Sara, Paul' || device == 'Sara, Paul, Cris' || device == 'Paul, Sara, Cris' || device == 'Sara, Cris, Paul' || device == 'Cris, Paul, Sara') {\n    var name = 'Everyone';\n    var hasHave = 'has';\n}\n\nvar messageOpening = [\n  \"Goodbye\",\n  \"See you later\",\n  \"Bye\",\n  \"Live long and prosper\",\n  \"Farewell\",\n  \"Hope you have a great time\",\n  \"Take care\",\n  \"Smell you later\",\n  \"Adios\",\n  \"Caio\",\n  \"Au revoir\",\n  \"Sayonara\",\n  \"Ta Ta for now\",\n  \"Catch you later\",\n  \"To-da-loo\",\n  \"See you in the funny papers\",\n  \"Toodles\",\n  \"Godspeed\",\n  \"So long\",\n  \"Cheerio\",\n  \"Arrivederci\"\n];\n\nvar messageClosing = [\n  \"left the building\",\n  \"gone out\",\n  \"popped out\",\n  \"left\",\n  \"buggered off\",\n  \"departed\",\n  \"split\",\n  \"vamoosed\",\n  \"high tailed it\",\n  \"escaped\",\n  \"eight-six'd it\",\n  \"bid farewell\",\n  \"flaked off\",\n  \"took a hike\",\n  \"withdrawn\",\n  \"exited\",\n  \"vanished\",\n  \"disappeared\",\n  \"evacuated\",\n  \"retreated\",\n  \"taken their leave\"\n];\n\n\nvar randomOpening = messageOpening[Math.floor(Math.random()*messageOpening.length)];\nvar randomClosing = messageClosing[Math.floor(Math.random()*messageClosing.length)];\nvar message = randomOpening + \" \" + name + \" \" + name +  \" \" + hasHave +  \" \" + randomClosing\n\nmsg.payload.domain = \"tts\"\nmsg.payload.service = \"cloud_say\"\nmsg.payload.data.entity_id = \"media_player.front_door_speaker\"\nmsg.payload.data.message = message\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":260,"wires":[["cbda386f.4adc48"]]},{"id":"c287b2d.1e7eb5","type":"ha-get-entities","z":"729d4aa5.48ac54","server":"e0e5de46.64d5","name":"","rules":[{"property":"entity_id","logic":"includes","value":"person.paul_carson , person.cris, person.sara","valueType":"str"},{"property":"state","logic":"is","value":"home","valueType":"str"},{"property":"timeSinceChangedMs","logic":"lt","value":"300000","valueType":"num"}],"output_type":"split","output_empty_results":false,"output_location_type":"msg","output_location":"payload","output_results_count":1,"x":450,"y":120,"wires":[["6a94e4c7.d74b7c"]]},{"id":"d3851dd2.c4e2","type":"server-state-changed","z":"729d4aa5.48ac54","name":"Sara","server":"e0e5de46.64d5","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"person.sara","entityidfiltertype":"exact","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,"x":70,"y":320,"wires":[["c287b2d.1e7eb5"],["65b42cb7.666674"]]},{"id":"62b90986.e004b8","type":"ha-wait-until","z":"729d4aa5.48ac54","name":"Door Opens","server":"e0e5de46.64d5","outputs":2,"entityId":"binary_sensor.front_door","entityIdFilterType":"exact","property":"state","comparator":"is","value":"on","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1170,"y":140,"wires":[["205a1043.6bf86"],[]]},{"id":"205a1043.6bf86","type":"ha-wait-until","z":"729d4aa5.48ac54","name":"Door Closes","server":"e0e5de46.64d5","outputs":2,"entityId":"binary_sensor.front_door","entityIdFilterType":"exact","property":"state","comparator":"is","value":"off","valueType":"str","timeout":"5","timeoutType":"num","timeoutUnits":"minutes","entityLocation":"","entityLocationType":"none","checkCurrentState":true,"blockInputOverrides":true,"x":1330,"y":140,"wires":[["775558cb.446388"],[]]},{"id":"e0e5de46.64d5","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
2 Likes

Sorry to revive, this is fantastic. It works great but I’m facing a bug, not sure if I’m alone. I’m not sure there’s an easy workaround :frowning: Let’s see.

First of, we are 4 members here, it was a lot of if to add for the random message and a bit later, I’ll publish the changes here.

What is the issue? The node-red app randomly triggers “person X left home” and 30 seconds later, “person X back home”. In the logbook I confirm the devices [ device_tracker.<device_name> ] are getting disconnected from the WiFi and reconnects quickly after. Maybe this has to do with DHCP expiration? :thinking: I’ll check that a little later (it’s late here).

Where’s the best place to get around such momentary disconnects? From the wifi ap logs, the devices do disconnect… the omada add-on works as expected.

Is this the solution?

On "away home" , wait 30 (31?) seconds, check if device shows home... if so, exit.

How would someone prevent the “at home” state change (+30 sec) not to play a “welcome home” message but to exit?

I might end up asking everyone in the house to install hass iOS app, I’m positive that would work better and it’s probably what I’m going to do. Just wish I could control what they can and can’t see.

What you’re seeing with the device tracking going to away and then momentarily back to home is not a node-red quirk, it’s being caused by however you’re tracking presence. Typically wifi only isn’t the best indicator of presence and I think your idea to have everyone install the HA app on their phone for geolocation would greatly improve your accuracy for presence.

If that’s not going to work for you, your idea of implementing a delay and a check would be one way to do it. Use your device_tracker entity as the trigger, put a delay node for however long you’d like (ie: 30s) and then check state to make sure it’s still away. You’ll want that delay to be as short as you can make it for things to still work on the arrival side of the flow though otherwise somebody will already be fully into the house before it announces their arrival.

if you came with a working solution, can you share your flow?

thanks