Know when was the time the phone app has reported successfully?

For anyone coming after me, it turns out there’s now a last_reported attribute on State objects. You can see this with the following template:

{% set dev = device_id('device_tracker.my_iphone') %}
{% set dev_states = expand(device_entities(dev)) %}
{% set last_reported = dev_states | map(attribute='last_reported') | max %}
Last report: {{ last_reported }}
Report age: {{ (now() - last_reported).total_seconds() }} ({{last_reported | relative_time }})
{% set last_reported_entities = dev_states | selectattr('last_reported', 'eq', last_reported) | map(attribute="entity_id") | join(",") %}
Last reporting entities: {{ last_reported_entities }}

which outputs something like:

Last report: 2024-12-16 21:38:43.162378+00:00
Report age: 257.063042 (4 minutes)

Last reporting entities: sensor.my_iphone_location_permission

It does seem to be the same entity reporting last each time on iPhone, but varies on Android. The overhead for checking all of them is too small to measure so I’m doing that.

I’ve set up an automation that checks every minute how long ago a device last checked in, and if it’s offline for a while, updates an input_select to show it’s Probably Away. This fits in with other automations that set the state to Away, Home, Bed, etc based on actual updates.

alias: Phone probably away detection
triggers:
  - trigger: time_pattern
    minutes: "*"
conditions:
  - condition: not
    conditions:
      - condition: state
        entity_id: input_select.my_phone
        state: Away
    - condition: state
      entity_id: input_select.my_phone
      state: Probably Away
  - alias: Phone has been offline for 25 minutes
    condition: template
    value_template: |-
      {% set dev = device_id('device_tracker.my_iphone') %}
      {% set dev_states = expand(device_entities(dev)) %}
      {% set last_reported = dev_states | map(attribute='last_reported') | max %}
      {{ now() - last_reported > timedelta(minutes=25) }}
actions:
  - action: input_select.select_option
    data:
      option: Probably Away
    target:
      entity_id: input_select.my_phone

You probably also need a “returned” automation to treat updates as evidence that the phone is back at the location it claims it is. The device tracker doesn’t update its reported time, so we look at all of them again:

triggers:
  - trigger: time_pattern
    minutes: "*"
conditions:
  - condition: state
    entity_id: input_select.my_phone
    state: Probably Away
  - condition: state
    entity_id: device_tracker.my_iphone
    state: Home
  - alias: Phone has been online in the last 2 minutes
    condition: template
    value_template: |-
      {% set dev = device_id('device_tracker.my_iphone') %}
      {% set dev_states = expand(device_entities(dev)) %}
      {% set last_reported = dev_states | map(attribute='last_reported') | max %}
      {{ now() - last_reported < timedelta(minutes=2) }}
actions:
  - action: input_select.select_option
    data:
      option: Probably Home
    target:
      entity_id: input_select.my_phone

If instead you want to use a template sensor, make sure you don’t associate it with the same device, or it’ll trigger an update on itself (thanks to expand).

Mark