Using zone triggers with "for"

Having some challenges solving a problem that I thought would be easy. I’m trying to do this as an automation:

  trigger:
    - platform: zone
      entity_id: group.family
      zone: zone.mycity
      event: leave
      for: "00:30:00"

So, the idea is that once the last family member leaves the city for 30 minutes, the action will fire. The problem is, is that it seems that “for” isn’t supported for “zone” platforms, which is a real shame.

Does anyone have any suggestions for how else this could be accomplished?

(FWIW, the point of this is that the action will turn off my house heating, but I only want to do it if I’m pretty sure that we are away. If we’re just nipping out and back, I’d rather it didn’t - hence the “for” in the logic)

1 Like

First, as you noticed, the zone trigger does not support the for option. Second, groups of device_tracker and/or person entities do not contain GPS data (i.e., latitude and longitude), which is required for the zone trigger. So you really can’t use a group with the zone trigger anyway.

One way to do what you want is to define a Template Binary Sensor that indicates whether or not anyone is in zone.mycity. E.g.:

binary_sensor:
  - platform: template
    sensors:
      someone_in_mycity:
        value_template: >
          {{ expand('group.family')
             |selectattr('state','eq','My City Friendly Name')|list|length > 0 }}
        entity_id:
          - device_tracker.tracker1
          - person.person2

Unfortunately the Template Binary Sensor is not smart enough to monitor all the entities in the group for state changes so you have to manually list them (via the entity_id option.) Also you need to use the friendly_name of the zone.

So this entity will be 'on' when anyone is in that zone, and 'off' when nobody is.

Now your automation trigger can be:

  trigger:
    - platform: state
      entity_id: binary_sensor.someone_in_mycity
      to: 'off'
      for:
        minutes: 30

Alternatively you can add the following to the configuration of the binary sensor:

        delay_off:
          minutes: 30

This will cause the binary sensor to only turn off when nobody has been in the city for at least 30 minutes. Then you can remove the for option from the trigger.

1 Like

Thanks, that’s really useful indeed.

I’m already using this for alerting on the alarm status if noone is at home:

  trigger:
    - platform: state
      entity_id: binary_sensor.alarm_set
    - platform: state
      entity_id: group.family
  condition:
    - condition: state
      entity_id: group.family
      state: 'not_home'
    - condition: state
      entity_id: binary_sensor.alarm_set
      state: 'on'

(it’s worth noting that the alarm_set entity is reversed as the device_class it’s mapped to (lock - the closest one I could find) uses off for locked and on for unlocked. Hence, the condition above is testing for alarm_set==on which is “alarm unset”. I should probably refactor my variable names!)

I have to admit that I assumed (naively) that I would be able to do something similar with zones, but I see your point about the need for individual GPS locations at point of evaluation being needed.

I’m certain that your solution will work well and I’ll update my configuration with this later tonight.

Many thanks for your help!

So out of curiosity (and possibly to adjust my suggestion), how is zone.mycity defined, especially as related to zone.home? Is it centered around your home but just with a larger radius? (I.e., is zone.home inside zone.mycity?)

If zone.home is indeed inside zone.mycity, then my suggestion, as currently written, probably won’t work, because in this scenario when someone goes inside zone.home (after being in zone.mycity) the state of the corresponding entity will change from zone.mycity's friendly name to home.

So on the trigger/condition you just showed for alerting on the alarm status, you could “simplify” it by replacing both with a single template trigger:

  trigger:
    - platform: template
      value_template: >
        {{ is_state('binary_sensor.alarm_set', 'on') and
           is_state('group.family', 'not_home') }}

Is it centered around your home but just with a larger radius? (I.e., is zone.home inside zone.mycity ?)

Yes, it is indeed. I’d rather not use the larger (2km) radius “mycity” zone as “home”, as it’s too inaccurate, but likewise I’d like to maintain the larger radius zone for automating other tasks that I’d rather not happen close to home (if you’ll excuse the cliche).

If zone.home is indeed inside zone.mycity , then my suggestion, as currently written, probably won’t work, because in this scenario when someone goes inside zone.home (after being in zone.mycity ) the state of the corresponding entity will change from zone.mycity 's friendly name to home .

Hmm, ok. This does make sense. Is it fair to say that an entity can only be inside a single zone at any one time? i.e. that overlapping zones may lead to unpredictable results. Is it possible to enumerate multiple zones that an entity is within at a given time and is there a defined precedence in how zones and entities get related?

For my own education, when we talk about “home” in the context of device tracker (i.e. "group.family == "home"), is this actually mapping to my own defined “zone.home”, or is it using some other construct within HA?

Thanks for the hint on streamlining the logic. I’m quite new to HA and am discovering that there’s usually at least 3 ways to do anything…the trick is picking the best one :slight_smile:

Zones can overlap. But device tracker & person entities can only have one state, which is home if they’re in zone.home, not_home if they’re not in any zone, or the friendly name of the zone they’re in (for zones other than zone.home.) Hence they can’t indicate more than one zone at a time, even if they are in more than one zone at a time.

Basically, when you’re in more than one zone at the same time, the zone it chooses is the one whose center you are closest to. If there are more than one you’re closest to (i.e., they have the same center), then it chooses the smallest of those. So, if zone.home and zone.mycity have the same coordinates but different radii, and you’re in both, then it will choose the smaller of the two (which you said is zone.home.)

zone.home can be defined explicitly in your configuration, or it will be created automatically using HA’s location configuration. See Home Zone.

So given that these two zones overlap I think you’ll need to change the value_template in my suggestion to:

          {{ expand('group.family')
             |selectattr('state','in',('My City Friendly Name','home'))|list|length > 0 }}
2 Likes

Thanks Phil - great post. I’ll try this and will report back tomorrow with progress!

1 Like

Just a quick update to close this off. This is working fine now and I’m very happy with how it works. Thank you once again for your help!

I’ll share the final bits of config here in case anyone else wanting to do something similar trips over this thread and is interested:

binary_sensor:
  - platform: template
    sensors:
      someone_near_home:
        friendly_name: "Someone is near home"
        value_template: >
          {{ expand('group.family')|selectattr('state','in',('My Big City','home'))|list|length > 0 }}
        entity_id:
          - device_tracker.life360_user1
          - device_tracker.life360_user2
          - device_tracker.life360_user3

Automation:

- id: 'heating_off_away_from_home'
  alias: 'Turn heating off if noone home for 30 minutes'
  trigger:
    - platform: state
      entity_id: binary_sensor.someone_near_home
      to: 'off'
      for: "00:30:00"
  action:
    - service: ifttt.trigger
      data: { 'event' : 'heating_off' }
    - service: ifttt.trigger
      data: { 'event' : 'hot_water_off' }
    - service: notify.pushover
      data_template:
        title: 'Turning heating off'
        message: >
          This has been triggered because {{ states('trigger.to_state.name') }} has changed.
          
          This happened at: {{ now() }}
        data:
          sound: bike

- id: 'heating_on_near_home'
  alias: 'Turn heating back to automatic if near home'
  trigger:
    - platform: state
      entity_id: binary_sensor.someone_near_home
      to: 'on'
  action:
    - service: ifttt.trigger
      data: { 'event' : 'heating_on' } 
    - service: ifttt.trigger
      data: { 'event' : 'heating_boost' }
    - service: ifttt.trigger
      data: { 'event' : 'hot_water_on' }
    - service: notify.pushover
      data_template:
        title: 'Turning heating on'
        message: >
          This has been triggered because {{ states('trigger.to_state.name') }} has changed.
          
          This happened at: {{ now() }}
        data:
          sound: bike

In this case heating_on and hot_water_on both just return the system to automatic mode, from the manually controlled fixed temperature in the “off” trigger. The additional boost is used to give the system a kick so if you return in the middle of the night when the system is cold, it will always give you a bit of heat even out of schedule, before returning to the schedule.

(As a note, the tado control component is going through some updated at the moment and doesn’t yet control hot water. For now, I’m relaying this through the “official” integration in ifttt which works well, although means it’s a bit more complicated)

2 Likes

I just finished up my geofencing logic for my family’s devices last night to find the new release this morning:

I guess we’ll be able to simplify our code now.