Greeting with wait template

I have a couple of greeting automations, but they’ve been giving me some issues. First off, for a device tracker, I have both the android app, and also wifi presence detection using asuswrt. I know there’s been an issue with the asuswrt integration lately, but I’ve manually updated asuswrt to 1.2.7 so it functions. Both device trackers are assigned to person.d34dc3n73r

The issue I’m having is that the automation action happens pretty much any time I open the door. I have a couple of wait conditions in the action that should prevent this, but it doesn’t seem to be working as rock-solid as I’d like. Can anyone point out the issue to me, or think of a better way to accomplish what I’m trying to do here?

- id: '1577515982557'
  alias: Say Hi
  trigger:
  - entity_id: binary_sensor.garage_entry
    platform: state
    to: 'on'
  action:
  - continue_on_timeout: 'false'
    timeout: 00:03:00
    wait_template: '{{ (as_timestamp(states.sensor.time.last_changed) - as_timestamp(states.person.d34dc3n73r.last_changed)) < 180 }}'
  - continue_on_timeout: 'false'
    timeout: 00:03:00
    wait_template: '{{ is_state(''person.d34dc3n73r'', ''home'') }}'
  - delay: 00:00:08
  - data_template:
      message: '{{ (''Sup bro'', ''Welcome home'', ''Hey dude hows it goin'', ''Whats shakin bacon'', ''Whats crackalackin'', ''whats-up buttercup'')|random }}'
    entity_id: media_player.kitchen_display
    service: tts.google_cloud_say

is your person.d34dc3n73r attached to a device_tracker that uses GPS? If so, it’ll be changing constantly.

It’s attached to both the Home Assistant Android app, and the router presence detection. According to documentation, stationary device trackers have priority.

Edit: I’ll also mention, it happened twice this morning around 9:00am, and neither device tracker shows away states for today.

image
image

image

So first off, if binary_sensor.garage_entry changes to ‘on’ again while the automation is sitting in one of the delay or wait steps, it won’t work the way you expect. This behavior is being fixed in 0.113, and there will be more controls available to hopefully make the automation work the way you want.

Which brings me to, what exactly do you want this automation to do?

The first wait seems very odd. It seems to be waiting for the state of person.d34dc3n73r to change. Is that right?

But then it is immediately followed by a wait for the state of that entity to become ‘home’.

Are you trying to account for when that person leaves?

Why don’t you just use a trigger that fires when the person comes home? If you want to take binary_sensor.garage_entry into account, maybe add a condition that checks that it has changed within the last three minutes. That seems much simpler. But then again, it’s not completely clear what you’re trying to do with the automation.

I can’t just fire the automation when “home” because wifi will more than likely connect well in advance of actually opening the door. The automation would fire before the person is even inside the home to hear it. That’s the reason why the door is the trigger.

Which brings me to the second issue. I only want the automation to happen on arrival, this is why I check that the state has changed within the last 3 minutes. If it has, the automation isn’t waiting for anything, it moves on to the next command. If the wifi is lagging or not connecting, it has 3 minutes for the connection to happen.

And lastly, I don’t want it to greet me, when I’ve left within the last 3 minutes and my girlfriend opens the door to take out the trash etc.

Edit: these are essentially conditions, that have the benefit of waiting to become true.

Ok, so the main problem your automation has is the “bug” in the way automations currently work that have delays/waits.

You might still be able to trigger on the person changing to ‘home’, but instead of checking the door in a condition, use that in the wait_template. So only trigger on coming home, then wait (up to three minutes) for the door to open. Still could be affected by the bug, but probably not as likely, and in 0.113 that shouldn’t be an issue anymmore.

Thinking about your requirements, though, could maybe something like this work:

- id: '1577515982557'
  alias: Say Hi
  trigger:
  - entity_id: binary_sensor.garage_entry
    platform: state
    to: 'on'
  condition:
  - condition: state
    entity_id: person.d34dc3n73r
    state: home
  - condition: template
    value_template: "{{ (now() - states.person.d34dc3n73r.last_changed).total_seconds() < 180 }}"
  action:
  - delay: 00:00:08
  - data_template:
      message: '{{ (''Sup bro'', ''Welcome home'', ''Hey dude hows it goin'', ''Whats shakin bacon'', ''Whats crackalackin'', ''whats-up buttercup'')|random }}'
    entity_id: media_player.kitchen_display
    service: tts.google_cloud_say

This runs the actions when the door opens, but only if the person entity’s state is currently “home”, and it changed within the last three minutes. Not sure if you need the 8 sec delay, so I left that in.

The problem with triggering on “home” and waiting for the door is that if wifi connects after the door has already been opened, the automation will fail.

The issue with the code you proposed is that the automation will immediately fail if wifi hasn’t connected by the time the door is opened.

Some phones tend to lag when connecting to wifi, while others are connecting before even entering the garage.

So trigger on coming home or the door opening, and then use a condition that you have to be home and the door is open (and you can even add a condition that says you came home within the last three minutes if you want.)

EDIT: Unless it’s possible for the person entity to change to home after the door has already closed???

yeah but you aren’t looking for away. You’re looking for home. My point is that you’re trying to suppress messages only for when you just arrive home but you have 2 things happening:

  1. person.d34dc3n73r is attached to a gps device. Every time your gps wobbles, you get a state change to lat and lon. This will update last_changed.
  2. You’re already home, so that second wait template doesn’t even happen. It’s instant because you’ve already met the conditions.

Then couple those issues with the scripting issues @pnbruckner brings up and you’ll get false triggers all the time.

That should only affect last_updated, not last_changed.

if that’s the case then the only thing that could be causing the failing wait templates is that scripting bug.

I guess I’ll wait for 0.113 and see if I’m still running into issues.

If you don’t want to wait for 0.113, the typically work around has been to move the actions into a script, and then in the automation cancel and then start the script like this

- service: script.turn_off
  entity_id: script.my_script
- service: script.my_script

Yes that’s entirely possible. From what I’ve noticed, the phones that do lag, lag more when they’re in a “sleep state” meaning the screen isn’t active and it hasn’t been used recently. If the phone is active, it usually connects a bit quicker, but still not reliably before the door is opened.

Thanks I’ll look into this if I have a little free time before 0.113 releases.

Is this still required with mode: restart in the script?

So still kind of trying to get my head around what you’re trying to do here. Let me see if I have it right…

You’re trying to play a message when you come home. You’re monitoring two entities, a binary_sensor that represents the door, and a person. The problem is that the person entity may change to home before the door is opened, while the door is open, or after the door is closed. But you don’t want to play the message if the door is opened but the person entity does not change to home in the period surrounding the door opening & closing.

Is that it?

If so, how about something like this:

- trigger:
  - platform: state
    entity_id: binary_sensor.garage_entry
    to: 'on'
  mode: restart
  action:
  - choose:
    # Is person home?
    - conditions:
      - {condition: state, entity_id: person.d34dc3n73r, state: home}
      sequence:
      # Person is home. Check that they came home within the last 3 minutes
      - condition: template
        value_template: >
          {{ (now() - state.person.d34dc3n73r.last_changed).total_seconds() <= 180 }}
    # Person is not home. Wait up to 3 minutes for them to come home.
    default:
    - wait_template: "{{ is_state('person.d34dc3n73r', 'home') }}"
      timeout: "00:03"
      continue_on_timeout: false
  # Person either came home no more than 3 minutes before door opened,
  # or within 3 minutes after door opened.
  - data_template:
      message: '{{ (''Sup bro'', ''Welcome home'', ''Hey dude hows it goin'', ''Whats shakin bacon'', ''Whats crackalackin'', ''whats-up buttercup'')|random }}'
    entity_id: media_player.kitchen_display
    service: tts.google_cloud_say

Yes, that’s correct. For what it’s worth, the initial automation I had posted used to accomplish this without false positives, but recently had become unreliable. I took your advice and moved the action sequence to a script, (which I later found out coincided with the release of 0.113). So, maybe that’s why it’s working now, but here’s what I’m using at the moment. It hasn’t been tested thoroughly but has worked 100% of the time so far with 0 false positives.

script

say_hi:
  alias: say_hi
  mode: restart
  sequence:
  - continue_on_timeout: 'false'
    timeout: 00:03:00
    wait_template: '{{ (now() - states.person.d34dc3n73r.last_changed).total_seconds() < 180 }}'
  - continue_on_timeout: 'false'
    timeout: 00:00:10 #lowered the timeout here, at this point the 3 minute window has passed
    wait_template: '{{ is_state(''person.d34dc3n73r'', ''home'') }}'
  - delay: 00:00:08
  - data_template:
      message: '{{ (''Sup bro'', ''Welcome home'', ''Hey dude hows it goin'', ''Whats shakin bacon'', ''Whats crackalackin'', ''whats-up buttercup'')|random }}'
    entity_id: media_player.kitchen_display
    service: tts.google_cloud_say

And the automation

- id: '1577515982557'
  alias: Say Hi 
  trigger:
  - entity_id: binary_sensor.garage_entry
    platform: state
    to: 'on'
  action:
  - service: script.say_hi

Now, I’m thinking about how to combine the other greeting automations into this single automation. I think I could use scripts for each greeting and then just list them in the action of the automation?
For example

  action:
  - service: script.say_hi
  - service: script.say_hi_other

Is there any reason this would fail? Would the second script not run until the first one plays or times out? I’m wondering about the condition of 2 people coming home at the same time, and how that would be handled. Regardless looks like I’ll have to read up on the new automation options. I also wanted to say thanks a bunch for all your help with this, along with all of your contributions to home assistant!

I think your current solution is still flawed. E.g., what if person changes to “not_home” (say, from a zone name) within 3 minutes after the door is opened, and then changes to “home” 11+ seconds later (but still within 3 minutes of the door opening)?

The other problem is that you have restart mode for the script, but single mode (which is the default) for the automation. Which means, in effect, the sequence will not be restarted if the door opens again while the script is still running, because the automation won’t be triggered again to call it.

BTW, there’s now no point in having the actions in a separate script. At the very least I’d suggest moving them back to the automation and changing the mode of the automation to restart.

I think the solution I suggested does exactly what you want. I’d be interested to see if it works for you.

See Waiting for Scripts to Complete for the answer.

To handle multiple people, I think it might be easier to reverse the logic. I.e., trigger on a person changing to home, and then check if the door changed within the previous 3 minutes (shouldn’t matter if it opened or closed, just that it changed), or if it changes within the next 3 minutes (which actually might be easier with a new feature I’m working on – wait_for_trigger, lol!)

Now bear with me here. In this case the automation should be parallel mode, since it needs to do the same, potentially lengthy thing, for multiple person entities. However, what it does for each needs to run in restart mode, just in case the person entity changes from something to “home” to something else and then back to “home” again quickly. So it makes sense to put the actual actions into a separate script so it and the automation can have different modes. BUT, and this is the “tricky” part, if the same script was used for each person, then it would restart when a second person changed to home while it was still running from a first person changing to home. SOOOO…, that means we actually need multiple scripts. One that does the grunt work, which uses parallel mode so it can do the work for multiple person entities. But we need an intermediary between the parallel automation and the parallel script to do the restart function for each person.

Ok, if you’re not lost yet, here’s what I’d suggest:

Automation:

- trigger:
  - platform: state
    entity_id:
    - person.PERSON1
    - person.PERSON2
    ...
    to: home
  mode: parallel
  action:
  - service_template: "script.{{ trigger.to_state.object_id }}_arrived_home"

Person script (duplicate for each person entity):

PERSON1_arrived_home:
  mode: restart
  sequence:
  - service: script.person_arrived_home
    data:
      person: PERSON1

Script that does the real work:

person_arrived_home:
  mode: parallel
  sequence:
  - choose:
    # Did door open or close within the last 3 min?
    - conditions:
      - condition: template
        value_template: >
          {{ (now() - state.binary_sensor.garage_entry.last_changed)
             .total_seconds() > 180 }}
      # No. Wait up to 3 min for door to open. (We'll assume it's still closed.)
      sequence:
      - wait_template: "{{ is_state('binary_sensor.garage_entry', 'on') }}"
        timeout: "00:03"
        continue_on_timeout: false
  # Either door opened/closed within the last 3 min,
  # or it did within 3 min of person changing to home.
  - data_template:
      message: >
        {{ state_attr('person.' ~ person, 'friendly_name') }} arrived home.
        {{ ('Sup bro', 'Welcome home', 'Hey dude hows it goin', 'Whats shakin bacon',
            'Whats crackalackin', 'whats-up buttercup')|random }}
    entity_id: media_player.kitchen_display
    service: tts.google_cloud_say

This makes sense. I like the multiple person, multi script approach. The last hurdle to overcome is each person has a set of personalized greetings.

For the time being, I’m going to switch over the automations to use your previous example.