Presence detection, the final countdown?

2 minute read

The last time I said that I didn’t think there was more I could do. I was wrong. My use of monitor hasn’t changed, and I’ll leave the config for that below.

Changed behaviour

Now I’ve changed the automations so that the majority wins for departure, rather than requiring everything to show not_home. This makes for faster departures, and avoids problems when something goes wrong with one of the device trackers - one of the monitor nodes sometimes freezes.

These work by the magic of a wonderful template somebody else wrote on the Discord server:

{{ dict((states|selectattr('entity_id', 'in', state_attr('group.person_person1', 'entity_id'))|list)|groupby('state'))['home']|count }}

This returns the number of entities in that group that are in the state home.

I’m now using the individual devices in the triggers, so that the automation is run for the change of state on each device, rather than only when the group changes state. This has made things more responsive.

The MQTT device tracker is used purely for the person integration. It serves no other purpose.

As always, these can be found on my GitHub.

Automations and scripts

Departure automation

alias: 'person1 away'  
initial_state: 'on'  
trigger:  
  - platform: state  
    entity_id:   
      - device_tracker.person1_phone_wifi  
      - device_tracker.person1_bt_mobile  
      - device_tracker.person1_bt_front_mobile  
    to: 'not_home'  
  - platform: homeassistant  
    event: start  
condition:  
  # As long as at least two trackers mark as away, they're away  
  - condition: numeric_state  
    entity_id: group.person_person1  
    below: 2  
    value_template: "{{ dict((states|selectattr('entity_id', 'in', state_attr('group.person_person1', 'entity_id'))|list)|groupby('state'))['home']|count }}"  
  # An exit door recently opened or closed - I can likely drop this to 300 (5 minutes)  
  - condition: template  
    value_template: "{{ (as_timestamp(now()) - as_timestamp(states.binary_sensor.pi3_front_door_sensor.last_updated)) | int < 600 }}"  
action:  
  - service: script.person1_away

Departure script

alias: person1 away  
sequence:  
  - service: input_boolean.turn_off  
    entity_id: input_boolean.person1_home  
  - service: mqtt.publish  
    data:  
      topic: location/person1  
      payload: 'not_home'  

Arrival automation

initial_state: 'on'  
alias: 'person1 home'  
trigger:  
  - platform: state  
    entity_id:   
      - device_tracker.person1_phone_wifi  
      - device_tracker.person1_bt_mobile  
      - device_tracker.person1_bt_front_mobile  
    to: 'home'  
  - platform: homeassistant  
    event: start  
condition:  
  - condition: numeric_state  
    entity_id: group.person_person1  
    above: 0  
    value_template: "{{ dict((states|selectattr('entity_id', 'in', state_attr('group.person_person1', 'entity_id'))|list)|groupby('state'))['home']|count }}"  
action:  
  - service: script.person1_home

Arrival script

alias: person1 home  
sequence:  
  - service: input_boolean.turn_on  
    entity_id: input_boolean.person1_home  
  - service: mqtt.publish  
    data:  
      topic: location/person1  
      payload: 'home'

Monitor

Behaviour preferences

#MAX RETRY ATTEMPTS FOR ARRIVAL  
PREF_ARRIVAL_SCAN_ATTEMPTS=2  
  
#MAX RETRY ATTEMPTS FOR DEPART  
PREF_DEPART_SCAN_ATTEMPTS=2  
  
#SECONDS UNTIL A BEACON IS CONSIDERED EXPIRED  
PREF_BEACON_EXPIRATION=240  
  
#MINIMUM TIME BEWTEEN THE SAME TYPE OF SCAN (ARRIVE SCAN, DEPART SCAN)  
PREF_MINIMUM_TIME_BETWEEN_SCANS=15  
  
#ARRIVE TRIGGER FILTER(S)  
PREF_PASS_FILTER_ADV_FLAGS_ARRIVE=".*"  
PREF_PASS_FILTER_MANUFACTURER_ARRIVE="Google|HTC Corporation|LG Electronics|Chipolo"  
  
PREF_FAIL_FILTER_ADV_FLAGS_ARRIVE="NONE"  
PREF_FAIL_FILTER_MANUFACTURER_ARRIVE="NONE"  
  
PREF_RSSI_IGNORE_BELOW=-95  
PREF_DEVICE_TRACKER_REPORT=true  

Command line flags

I’m using -x -b -tdr as the flags, and these mean:

  • -x - retain mqtt status messages
  • -b - report bluetooth beacons
  • -tdr - only performs a departure scan when a message is published to the MQTT topic, and notifies other instances when it does a scan