Last active
March 13, 2026 12:18
-
-
Save erkr/6dbe8c9ec6feaef8102afff3786a5bd0 to your computer and use it in GitHub Desktop.
Compose one device tracker for a person in Home Assistant by composing multiple stationary and gps trackers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: Composite person device tracker | |
| description: compose one tracker for a person by composing multiple stationary (BLE/Router) | |
| and GPS trackers | |
| domain: automation | |
| input: | |
| composite_name: | |
| name: composite name | |
| description: The name for the composite tracker. Be carefull when changing the | |
| name afterwards, as the automation will create a composite tracker when it | |
| doesn't exist yet! (Trackers can be deleted by removing them from known_devices.yaml) | |
| selector: | |
| text: | |
| multiline: false | |
| multiple: false | |
| trigger_at_startup: | |
| name: Trigger at Home Assistant startup | |
| description: Initialize the composite tracker at startup, based on the stationary trackers. | |
| default: true | |
| selector: | |
| boolean: {} | |
| input_trackers: | |
| name: input trackers | |
| description: Select (bluetooth, router or GPS) device_trackers and/or (connectivity or presence) binary sensors | |
| selector: | |
| entity: | |
| filter: | |
| - domain: device_tracker | |
| - domain: binary_sensor | |
| device_class: | |
| - connectivity | |
| - presence | |
| multiple: true | |
| reorder: false | |
| source_url: https://gist.github.com/erkr/6dbe8c9ec6feaef8102afff3786a5bd0#file-composite_device_tracker-yaml | |
| triggers: | |
| - trigger: state | |
| entity_id: !input input_trackers | |
| id: 'tracker' | |
| variables: | |
| latitude: '{{ trigger.to_state.attributes.latitude | default(0) }}' | |
| longitude: '{{ trigger.to_state.attributes.longitude| default(0) }}' | |
| gps_accuracy: '{{ trigger.to_state.attributes.gps_accuracy | default(10) }}' | |
| gps_update: "{{ latitude!=0 and longitude!=0 }}" | |
| enabled: true | |
| - trigger: homeassistant | |
| event: start | |
| id: 'startup' | |
| conditions: | |
| - alias: Filter non-relevant stationary triggers | |
| or: | |
| - condition: template | |
| value_template: "{{ trigger.id=='startup' or gps_update|default(false) }}" | |
| - condition: template | |
| value_template: > | |
| {% set old_state=states(composite_tracker) %} | |
| {% set home=['home','on'] %} | |
| {{ trigger.to_state.state not in home | |
| if old_state=='home' else | |
| trigger.to_state.state in home}} | |
| actions: | |
| - choose: | |
| - conditions: | |
| - alias: special activations | |
| or: | |
| - condition: template | |
| value_template: '{{ trigger is not defined or trigger.id is not defined }}' | |
| alias: manual execution of automation | |
| - condition: template | |
| value_template: "{{ trigger.id=='startup' and trigger_at_startup }}" | |
| alias: Initialize at startup | |
| sequence: | |
| - variables: | |
| on_premises: > | |
| {{ expand(input_trackers) | |
| |rejectattr('attributes.latitude','defined') | |
| |rejectattr('attributes.longitude','defined') | |
| |selectattr('state','in',['home','on'])|list|count> 0 }} | |
| new_state: '{{ ''home'' if on_premises else ''not_home'' }}' | |
| - action: device_tracker.see | |
| data: | |
| dev_id: '{{composite_name}}' | |
| location_name: '{{ new_state }}' | |
| alias: Publish startup location name | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ trigger.id=='tracker' and gps_update|default(false) }}" | |
| alias: If GPS coordinates known | |
| sequence: | |
| - action: device_tracker.see | |
| data: | |
| gps: | |
| - '{{latitude}}' | |
| - '{{longitude}}' | |
| dev_id: '{{composite_name}}' | |
| gps_accuracy: '{{gps_accuracy}}' | |
| alias: Publish GPS | |
| - conditions: | |
| - condition: template | |
| value_template: "{{ trigger.id=='tracker' and not gps_update|default(false) }}" | |
| alias: If triggered by a stationary tracker | |
| sequence: | |
| - alias: If the stationary tracker reports home, or all report away | |
| if: | |
| - condition: template | |
| value_template: "{{ trigger.to_state.state in ['home','on'] }}" | |
| alias: Home comming trigger | |
| then: | |
| - action: device_tracker.see | |
| data: | |
| dev_id: '{{composite_name}}' | |
| location_name: home | |
| alias: Publish home | |
| else: | |
| - alias: If Leaving was reported by the last stationary tracker | |
| if: | |
| - condition: template | |
| value_template: > | |
| {{ expand(input_trackers) | |
| |rejectattr('attributes.latitude','defined') | |
| |rejectattr('attributes.longitude','defined') | |
| |selectattr('state','in',['home','on'])|list|count == 0 }} | |
| alias: Away was triggered by the last stationary tracker | |
| then: | |
| - variables: | |
| old_state: '{{ states(composite_tracker) }}' | |
| away_state: > | |
| {{ old_state if (old_state not in ['home','unknown','unavailable']) | |
| else 'not_home' }} | |
| - action: device_tracker.see | |
| data: | |
| dev_id: '{{composite_name}}' | |
| location_name: '{{ away_state }}' | |
| alias: Publish away | |
| trigger_variables: | |
| nice_name: !input composite_name | |
| composite_name: '{{ nice_name|slugify }}' | |
| composite_tracker: "{{ 'device_tracker.'~composite_name }}" | |
| input_trackers: !input input_trackers | |
| trigger_at_startup: !input trigger_at_startup | |
| mode: queued | |
| trace: | |
| stored_traces: 20 | |
| max: 10 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment