Device tracker changes in 2027.5... what to do?

Good remark @Mariusthvdb
I tried that first, it was working better than the default prioritisation done in person but was still not really satisfied.
Especially for two use cases if I recall correctly:

  • when hovering around the zone perimeter gave many state alterations. I recently added even some hysteresis for that
  • When GPS is stucked to home (as described above). I ignore GPS state, only GPS triggers matter ( stationary, states are reliable though )

The custom integration has complex configuration options, but I simply couldn’t figure out the intent to get it working better.

Edit: Just for the fun, leaving and enter examples (first line is the composite):


Was triggered not home by first GPS way outside the zone, even while NMAP didn't timeout yet:
image

Same for entering, triggered by BLE (just before GPS):

Note: I can really advice to add BLE trackers using EspHome BLE scanners and the Prive BLE integration to be able to recognize you phones. Most phone loose the network quite often for several minutes while not used, but BLE tends to work both way faster (detecting in seconds) and more reliable (almost 24/7 stable)

Just use this.state in your templates. It's not possible, nor will it ever be possible, to have this in the triggers or conditions in the main section. The coordinator that handles triggers, the action section, and the condition section, is built well before the entities are built. It's a chicken/egg scenario that cannot be overcome without an entire rewrite. Secondly, the likelihood of template blueprints remaining single entity is low. I'll likely remove this restriction in the future when i start reworking the blueprints.

@petro Thanks for the crisp answer!!
Can you maybe reflect if my last (3rd) option is viable (do the update, but use previous settings to only update last recorded)

regards
Eric

Can you explain what you mean? Updates are purely handled by core. Meaning they determine when to update those properties based on the update they receive from the integration. I.e. This is typically handled by the user and their template with template entities.

I mean that if I don't want to update the state of the device tracker (without this above entity_level that is to be determined at entity level), I hope to pass exacly the previous values, in order not to send a new value to the recorder (so only last reported changed).
It that works I know how to proceed. Understanding the forums it seems this would do the job:

template:
 …
 device_tracker:
   - name: test
     variables:
        no_update: “{{ true if ... }}”
     in_zones: “{{ this.attributes.in_zones if no_update else … }}”
     latitude: "{{ this.attributes.latitude if no_update else … }}"
     longitude: "{{ this.attributes.longitude if no_update else … }}"
     location_accuracy: "{{ this.attributes.gps_accuracy if no_update else … }}"

thanks Eric

If you pass the exact values from before that's not a state change

Thanks, I will proceed with that approach :smile:

@petro

I got stuck with the trigger based device_tracker template
I expected to have this available at entity level, but it isn't for variables inside the entity:

  device_tracker:
  - name: Car
    variables:
      old_state: "{ this.state }}"

I get:

2026-06-08 15:25:06.192 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: 'this' is undefined when rendering '{{ this.state }}'

Is that a bug?
I really need the old state at this point

Best Eric

variables at the entity level do not allow this at this time, but it's possible to add it in the future.

Thanks, I for now have to replicate part of the logic in all parameters of device tracer . Hope to cleanup when this is possible :grinning_face:

@petro

I have the device tracker working, except for preventing state changes, even with identical data
The trace of a simple automation (triggered by any state or attribute changes) demonstrates:

trigger:
  id: '0'
  idx: '0'
  alias: null
  platform: state
  entity_id: device_tracker.car
  from_state:
    entity_id: device_tracker.car
    state: home
    attributes:
      in_zones:
        - zone.home
      source_type: gps
      latitude: 51.430669051424694
      longitude: 5.539841840042397
      gps_accuracy: 7.295014
      friendly_name: Car
    last_changed: '2026-06-08T14:35:08.286559+00:00'
    last_reported: '2026-06-08T14:35:08.286559+00:00'
    last_updated: '2026-06-08T14:35:08.286559+00:00'
    context:
      id: 01KTKTH9KNGX36DCZGGQG7XV08
      parent_id: null
      user_id: null
  to_state:
    entity_id: device_tracker.car
    state: home
    attributes:
      in_zones:
        - zone.home
      source_type: gps
      latitude: 51.430669051424694
      longitude: 5.539841840042397
      gps_accuracy: 7.295014
      friendly_name: Car
    last_changed: '2026-06-08T14:36:10.799278+00:00'
    last_reported: '2026-06-08T14:36:10.799278+00:00'
    last_updated: '2026-06-08T14:36:10.799278+00:00'
    context:
      id: 01KTKTK6N625T3N6YX5QAR95F6
      parent_id: null
      user_id: null
  for: null
  attribute: null
  description: state of device_tracker.car

AFIKT the to and from states are identical, except for last_changed, reported and updated
They have changed, even with identical state. I expected only reported to be updates?!

Do you think this is a bug in the core classed used?!

post the template entity

Sorry, its big (don’ see how to upload as a file). Stationary updates nicely preserve the last zone and GPS information, but state is reported,updated and changed:

- trigger:
  - platform: state
    entity_id:
      - device_tracker.iphone_eric
      - device_tracker.iphone_eric_nmap
      - device_tracker.ble_iphone_eric_bermuda_tracker
    variables:
      latitude: "{{ trigger.to_state.attributes.latitude | default(None) }}"
      longitude: "{{ trigger.to_state.attributes.longitude| default(None) }}"
      gps_accuracy: "{{ trigger.to_state.attributes.gps_accuracy | default(20) }}"
      gps_update: "{{ latitude!=None and longitude!=None }}"
    enabled: true
  - platform: homeassistant
    event: start
    variables:
      latitude: "{{None }}"
      longitude: "{{None }}"
      gps_accuracy: "{{ None }}"
      gps_update: false
  
  variables:
    input_trackers:
        - device_tracker.iphone_eric
        - device_tracker.iphone_eric_nmap
        - device_tracker.ble_iphone_eric_bermuda_tracker
    trigger_at_startup: true
    gps_home_filter:
        - bluetooth_le
        - bluetooth
      
  
  conditions:
  - condition: template 
    value_template: "{{ trigger.platform!='homeassistant' or trigger_at_startup }}"

  device_tracker:
  - name: Car
    variables:
#      old_state: |
#        {{ this.state if this.state else 'unknown' }}
      new_state: |
        {% if gps_update %}
          {% if trigger.to_state.state!='home' 
             and 
              (expand(input_trackers)
              | selectattr('attributes.source_type','in',gps_home_filter)
              | selectattr('entity_id', 'is_state', 'home')
              | list | count > 0
              ) 
             and 
              (distance(trigger.entity_id)*1000 <
               (gps_accuracy+state_attr("zone.home", "radius")|float(30)) 
              )
          %}
            {#- overrule GPS reporting not home in case a
                selected stationary tracker still report
                home and the distance to home is close enough 
             -#}
            {{ 'home' }}
          {% else %}
            {{ trigger.to_state.state }}
          {% endif %}
        {% else %}
          {#- 
            home, if any stationary tracker report home.
            Preserve other zones by using old_state when not home
           -#}
          {{ 'home' if (expand(input_trackers) 
             |rejectattr('attributes.latitude','defined') 
             |rejectattr('attributes.longitude','defined') 
             |selectattr('state','in',['home','on'])|list|count>0)
            else 'not_home' }} 
        {% endif %}
#            else old_state if 
#             (old_state not in ['home','unknown','unavailable'])
    in_zones: |
      {# use old state to preserve other zones when a stationary tracker reports not_nome #}
      {% set old_state=  this.state if this is defined and this.state is defined else 'unknown' %}
      {% if gps_update or old_state in ['home','unknown','unavailable'] or new_state!='not_home' %}
        {{ ['zone.'~new_state] if (states.zone[new_state]) else [] }}
      {% else %}
        {{ ['zone.'~old_state] if (states.zone[old_state]) else [] }}
      {% endif %}
    latitude: |
      {% set old_state=  this.state if this is defined and this.state is defined else 'unknown' %}
      {{ latitude if gps_update else None if old_state!=new_state else this.attributes.latitude|default(None) }}
    longitude:  | 
      {% set old_state=  this.state if this is defined and this.state is defined else 'unknown' %}
      {{ longitude if gps_update else None if old_state!=new_state else this.attributes.longitude|default(None) }}
    location_accuracy: | 
      {% set old_state=  this.state if this is defined and this.state is defined else 'unknown' %}
      {{ gps_accuracy if gps_update else None if old_state!=new_state else this.attributes.gps_accuracy|default(None)}}
      
    

Not sure, it shouldn't have a state change. Device trackers may behave differently than other platforms.

Thanks for looking onto this ,Do you agree this is a bug of the core platform? I will then raise an issue.
(This is why I originally wanted to filter unwanted updates in the condition section. Cleaner code and more certain :frowning: ).

I don't necessarily agree if it's a bug or not. The device_tracker platform is different from all other platforms, this may be something that is intentional.

I will raise it as an question then :slight_smile:

@petro

I'm going to stop for today, but I noticed two other issues:

  • trigger based templates should persist, right?! It seems device_tracker doens't. even when I reload the templates, the initial state becomes unknown
  • less an issue. Can't add attributes. Would be nice while testing to see intermediate results

That's not built yet. Restore state is only available on a few platforms.

Also not available on that platform yet

Ok, thanks, the persistence is really what I took for granted. I hope it is fixed before device_tracker.see phase out. Thanks