Welcome message with Alexa

Hello everybody. I’m struggling with a very basic automation but I can’t find a solution. Basically the automation should use the person presence (from away to home) as trigger and the detection of a PIR sensor on the front door as condition, to play a welcome message on Alexa.
Below you can find the automation, any lead will be welcome.
Thank you in advance

> alias: annuncio arrivo
> description: Alexa talks when I come back home
> trigger:
>   - entity_id:
>       - person.luca
>     from: not_home
>     platform: state
>     to: home
>     for:
>       hours: 0
>       minutes: 0
>       seconds: 0
> condition:
>   - type: is_motion
>     condition: device
>     device_id: 19cd2b470d2316
>     entity_id: 303bd759a842b0
>     domain: binary_sensor
>     enabled: true
> action:
>   - delay:
>       hours: 0
>       minutes: 0
>       seconds: 10
>       milliseconds: 0
>     enabled: true
>   - service: media_player.volume_set
>     data:
>       entity_id: media_player.echo_dot_di_luca
>       volume_level: 0.5
>   - service: notify.alexa_media
>     data:
>       message: >
>         {% if now().strftime("%H")|int < 5 %} Buonasera  {% elif
>         now().strftime("%H")|int < 12 %} Buongiorno  {% elif
>         now().strftime("%H")|int < 18 %} Buon pomeriggio  {% else %} Buonasera
>         {% endif %} e bentornato Luca, la temperatura media dellappartamento è
>         di {{states.sensor.average_appartamento.state}} °C
>       target: media_player.echo_dot_di_luca
>   - service: media_player.volume_set
>     data:
>       entity_id: media_player.echo_dot_di_luca
>       volume_level: 0.2
> mode: single

Conditions do not wait around to become true. If they are not true immediately after the trigger, the automation stops. For this reason it is often preferable to use the event closest in time to your action sequence as the trigger.

In your automation the most proximal event to the action is likely the detection of motion at the front door. This is likely a better trigger. You would then use conditions to determine if a person entity’s state recently change to “home”.

If you are determined to trigger off presence detection, you will need to use a wait action, such as Wait for Trigger instead of a condition to hold the automation until the motion is detected.

Thank you Didgeridrew
I’ve also tried swapping the person and PIR detection, but didn’t work neither

alias: Welcome 2
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.pir_sensor_oxa1
    from: "off"
    to: "on"
condition:
  - condition: state
    entity_id: person.luca
    attribute: device_trackers
    state: home
action:
  - service: notify.alexa_media_echo_dot_di_luca
    data:
      message: >-
        {% if now().strftime("%H")|int < 5 %} Buonasera  {% elif        
        now().strftime("%H")|int < 12 %} Buongiorno  {% elif        
        now().strftime("%H")|int < 18 %} Buon pomeriggio  {% else %}
        Buonasera         {% endif %} e bentornato Luca, la temperatura media
        dellappartamento è         di
        {{states.sensor.average_appartamento.state}} °C
mode: single

The value of the attribute device_trackers will never be “home”. Leave attribute blank when your condition is based off the state…

  - condition: state
    entity_id: person.luca
    state: home

Thank you for the lead, but now the problem is that every time the PIR is activated I got the notification on Alexa. The aim of the automation would be that notification comes out only once, when I get in home.

UPDATE: I’ve reformed the automation taking in account your first suggestion “wait for trigger” and now works like a charm :+1:

That means you didn’t fully build out the conditional logic to include when not to execute the action sequence. Instead of just checking that the person entity is home, you need to also examine the properties of the person entity so you now how long they have been home.

alias: Welcome 2
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.pir_sensor_oxa1
    from: "off"
    to: "on"
condition:
  - condition: state
    entity_id: person.luca
    state: home
  - alias: Don't continue if Luca has been home longer than 10 minutes
    condition: template
    value_template: |-
      {{ states.person.luca.last_changed >= now() - timedelta(minutes=10) }}
  - alias: Don't play the message more than once every 6 hours
    condition: template
    value_template: |-
      {{ this.attributes.last_triggered < now() - timedelta(hours=6) }}
action:
  - service: notify.alexa_media_echo_dot_di_luca
    data:
      message: >-
        {% set hora = now().hour%}
        {%- if hora < 5 -%} Buonasera 
        {%- elif hora < 12 -%} Buongiorno
        {%- elif hora < 18 -%} Buon pomeriggio
        {%- else -%} Buonasera {%- endif %}
        e bentornato Luca, la temperatura media
        dellappartamento è di {{ states('sensor.average_appartamento') }} °C
mode: single

Even with the wait-for-trigger method you will likely want to include additional conditions to reduce the number of times the message gets played in a given time period.

1 Like

I took your suggestion partially:
I just used in condtion : states.person.luca.last_changed <= now() - timedelta(hours=6) }}
I really didn’t get how the below sentence works … so I avoided it
{{ this.attributes.last_triggered < now() - timedelta(hours=6) }}

this is a self-referencing variable that holds the state object of the automation. The last_triggered attribute of an automation only changes when the actions are executed. The Template condition compares the time the automation’s action were last executed to the current time offset by however long you want, I chose 6 hours arbitrarily. The condition basically reduces down to “Were the automation’s actions last executed more than 6 hours ago?”

At least in my household, overly repetitive TTS notification can quickly become a source of annoyance to everyone. Throttling notifications so that they don’t play too often can go a long way towards reducing friction.

Thank you very much for your clear explanation. Now I understood as “this” works.
In my case, I’m not going in/out from home very often, therefore my cellphone is always connected to the wifi, therefore only seldom the automation will trigger. I could avoid completely the condition section in the automation. Anyway, I like to learn and you taught me some new good stuff. Thanks again.

Can you share the YAML that works like a charm. I’m a bit new and would love to get this done.

HI,

I did something like this - it’s in Nod Red.
If something can be improved, I would be happy to receive suggestions


[{"id":"c2b4a66de860f695","type":"delay","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":395,"y":100,"wires":[["9a872b97e54b2b76"]],"l":false},{"id":"9a872b97e54b2b76","type":"function","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"Filter family","func":"let family = ['person.yuval', 'person.rozi', 'person.adele', 'person.Assaf'];\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,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":100,"wires":[["e36da9cea5209e95","18b72a81ce3e0920"],[]],"outputLabels":["Familie","Gäste"]},{"id":"10161e5bf8b68a0c","type":"function","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"Create message","func":"/** CONFIGURATION **/\n\n// These are the persons you want to include in the greeting.\nlet persons_whitelist = ['person.yuval', 'person.rozi', 'person.adele', 'person.Assaf'];\n\n// A random greeting will be played every time.\nlet r_greet = [\"Welcome home, \", \"It's nice to see you, \", \"Welcome back, \", \"Hey \", \"Howdy, \"];\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.celine\": {\n    \"person.yuval\": \"Dad\",\n    \"person.rozi\": \"Mom\",\n  },\n  \"person.adele\": {\n    \"person.yuval\": \"Dad\",\n    \"person.rozi\": \"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":1200,"y":140,"wires":[["d46a276ee71342b3"]]},{"id":"011f05c2bdcab253","type":"api-call-service","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"📢 Alexa","server":"ca349d57.bd11e","version":5,"debugenabled":false,"domain":"notify","service":"alexa_media","areaId":[],"deviceId":[],"entityId":[],"data":"{\"data\":{\"type\":\"announce\",\"method\":\"all\"},\"target\":\"media_player.yuval_s_echo_dot_3,media_player.yuval_s_echo_show_8,media_player.computer_echo_show\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1500,"y":140,"wires":[[]]},{"id":"e36da9cea5209e95","type":"api-current-state","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"Front door opened","server":"ca349d57.bd11e","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"binary_sensor.door_main_open_or_close","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":0,"forType":"num","forUnits":"minutes","x":550,"y":220,"wires":[["18b72a81ce3e0920"],[]]},{"id":"ca7945ba6a03d41f","type":"server-state-changed","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"Someone comes 🏠","server":"ca349d57.bd11e","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"person\\..*","entityIdType":"regex","outputInitially":false,"stateType":"str","ifState":"home","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":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":270,"y":100,"wires":[["c2b4a66de860f695"],[]]},{"id":"18b72a81ce3e0920","type":"ha-get-entities","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"🔎 Get all persons","server":"ca349d57.bd11e","version":1,"rules":[{"property":"entity_id","logic":"is","value":"person\\..*","valueType":"re"}],"outputType":"array","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":970,"y":160,"wires":[["10161e5bf8b68a0c"]]},{"id":"013ec97f6e17f0e5","type":"ha-wait-until","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"Front door opened","server":"056e71f70138b09c","version":2,"outputs":2,"entityId":"binary_sensor.door_main_open_or_close","entityIdFilterType":"exact","property":"state","comparator":"is","value":"on","valueType":"str","timeout":"3","timeoutType":"num","timeoutUnits":"milliseconds","checkCurrentState":true,"blockInputOverrides":true,"outputProperties":[],"x":710,"y":100,"wires":[["18b72a81ce3e0920"],[]]},{"id":"0b97712e1b595e99","type":"deduplicate","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"","keyproperty":"payload","expiry":"120","x":1055,"y":100,"wires":[[],[]],"l":false},{"id":"d46a276ee71342b3","type":"time-range-switch","z":"aa3761987da6cf5d","g":"f983b0a0a6657714","name":"07:00-20:30","lat":"32.0167","lon":"34.7667","startTime":"07:00","endTime":"20:30","startOffset":0,"endOffset":0,"x":1370,"y":200,"wires":[["011f05c2bdcab253"],[]]},{"id":"ca349d57.bd11e","type":"server","name":"Home Assistant","addon":true},{"id":"056e71f70138b09c","type":"server","name":"yuval_Home Assistant","version":5,"addon":false,"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}]