I would like to fashion a single automation that fires a notification, with the name of the Zone, to keep track of when:
a Person leave home,
a Person enters a named Zone,
a Person exits a named Zone, and
a Person returns home.
This is proving surprisingly difficult.
It is extremely straightforward to fashion a notification that triggers when a Person enters or leaves the “Home” zone. What is proving difficult are the zone-to-zone notifications – when a Person is “away,” their state is changed to “not_home”, so it seems possible to trigger on that condition – however that is not working for me.
Has anyone had any luck creating an automation like this? Within similar topics, I see people hardcoding conditions for every single zone into their automation, which admittedly works, but is inelegant and difficult to scale. Ideally I think we’d all like something that took advantage of the multi-device capabilities of the Person, as well as scaled effectively over any number of Zones.
I think there are dozens of solutions available in this forum. The hard part is finding them!
Basically, don’t use zone triggers, use a state trigger, because a person entity’s state changes to the friendly name of a zone it has entered (or 'not_home' when not in any zone, or 'home' when in the Home zone.) It typically goes something like this:
- trigger:
- platform: state
entity_id:
- person.PERSON1
- person.PERSON2
...
condition:
- condition: template
value_template: >
{{ trigger.to_state is not none and
(trigger.from_state is none or
trigger.to_state.state != trigger.from_state.state) }}
action:
- service: notify.NOTIFIER
data_template:
message: >
{% set name = trigger.to_state.name %}
{% set zone_map = {'home': 'Home', 'not_home': 'Away'} %}
{% set from = trigger.from_state.state
if trigger.from_state is not none
else "unknown" %}
{% set from = zone_map.get(from, from) %}
{% set to = trigger.to_state.state %}
{% set to = zone_map.get(to, to) %}
{{ name }} moved from {{ from }} to {{ to }}
Phil, this is easily the most elegant way to accomplish this that I’ve seen yet. Thanks for taking the time to put this together.
Let me say back what this script does, to make sure I understand:
The automation is triggered on the state of the set of persons defined in entity_id.
The automation will continue as long as the state is not none, and as long as the to and from conditions are not identical. (why is this? to avoid errors when starting up?)
The automation then builds a message:
sets the name string from the Person who triggered the automation
builds a dict of zone_map to normalize the display of the Home and Away states (to avoid displaying “not_home”?)
sets the “from” string to be the state of the Person, before the script triggered. It then runs a get against the zone_map dict to capitalize “Home” and change not_home to “Away”. (What’s “unknown” for in this?)
sets the “to” string to be the state of the Person, as the script triggered. It then also runs a get against the zone_map dict to capitalize “Home” and change not_home to “Away”.
and then finally it assembles all the strings in a data_template.
It’s triggered whenever any of the listed person entities cause a state_changed event, which will happen whenever their state, or any of their attributes, change.
The test for none is to avoid running the actions when an entity is removed (which often happens with entities that can be “reloaded”.) This is just a “best practice” even if you pretty much know that won’t happen with a given type of entity (because you never know how HA might change in the future.)
The check that the old state and new state are different is to avoid running the actions if just an attribute (such as GPS location) changes.
Yes. Also works well for other languages (by, of course, adjusting the values in the dict.)
When the person entity is first created, old_state will be none. (This can also happen if the entity is “reloaded”. Before the reload new_state will be none, and after the reload old_state will be none.) This is just one way to handle that scenario.
Everything under message is part of a single template. The last line is just one part of it.
This helps so much. Thank you. Last dumb question: I’d like to place a map within the notification. Using this in the notification payload isn’t working, however:
Here’s what I have so far. It all works fine, until I add the code block with the map.
- id: supertracker
alias: Location Change
description: Track changes in location from zone to zone
trigger:
- platform: state
entity_id:
- person.PERSON1
- person.PERSON2
condition:
- condition: template
value_template: "{{ trigger.to_state is not none and (trigger.from_state is none or trigger.to_state.state != trigger.from_state.state) }}"
action:
- service: notify.NOTIFYPLATFORM
data_template:
title: "🌎 {{trigger.to_state.name}} Location"
message:>"{% set name = trigger.to_state.name %}
{% set zone_map = {'home': 'Home', 'not_home': 'Away'} %}
{% set from = trigger.from_state.state
if trigger.from_state is not none
else 'unknown' %}
{% set from = zone_map.get(from, from) %}
{% set to = trigger.to_state.state %}
{% set to = zone_map.get(to, to) %}
{{ name }} moved from {{ from }} to {{ to }}."
data:
push:
category: map
action_data:
latitude: "{{trigger.to_state.attributes.latitude}}"
longitude: "{{trigger.to_state.attributes.longitude}}"
shows_points_of_interest: true
apns_headers:
apns-collapse-id: location```
message:>"{% set name = trigger.to_state.name %}
{% set zone_map = {'home': 'Home', 'not_home': 'Away'} %}
{% set from = trigger.from_state.state
if trigger.from_state is not none
else 'unknown' %}
{% set from = zone_map.get(from, from) %}
{% set to = trigger.to_state.state %}
{% set to = zone_map.get(to, to) %}
{{ name }} moved from {{ from }} to {{ to }}."
Either use multi-line YAML or don’t. You can’t have it both ways.