Those using WiFi for presence detection are well aware of the issue where smartphones “sleep” to save power when not used for a period of time. To resolve this, the device tracker component uses “consider home” to allow a delay before marking the device as away. I’ve combined a few components to improve this. It requires a few things:
A shell script running on your router (I already had this running on my DD-WRT access points to publish a MQTT topic with device signal strengths for crude room presence detection)
Some sort of indicator sensor that typically fires when someone leaves (I have a z-wave lock that has a unique alarm code for when the deadbolt is unlocked using the inside handle, but there are many options for this…door sensor, garage door, car, etc.)
By combining these two sensors, I now set “consider home” to a fairly high number (20 minutes). Long enough that no device will sleep longer than this interval (and also useful in preventing devices from being marked “away” when powered off or out of battery briefly). Then I use an automation to mark devices away when aren’t seen by the router if and only if the lock has been opened recently from the inside. So essentially the lock status tells HASS “someone left” and my access points tell me “who left”. Below is the automation used for this. It would be cool to build an “auxiliary” sensor into router based device trackers to streamline this.
- alias: Update Device Tracker upon Departure
trigger:
- platform: numeric_state
entity_id: sensor.signal_east_person1
below: -89 #my ddwrt script sets the signal to -90 if the mac address isn't connected
for:
seconds: 10
- platform: numeric_state
entity_id: sensor.signal_east_person2
below: -89
for:
seconds: 10
condition:
- condition: state #this is the sensor I setup for when the door/lock was opened from the inside
entity_id: binary_sensor.someone_left_home
state: 'on'
action:
- delay: 00:01:00 #I have two access points that publish signal strengths every minute, so I wait 1 minute then make sure the device isn't connected to any of them
- condition: template
value_template: '{{ is_state( trigger.entity_id | replace("east", "west"), "-90") }}'
- condition: template
value_template: '{{ is_state( trigger.entity_id | replace("west", "east"), "-90") }}'
- service: device_tracker.see
data_template:
dev_id: "{{ trigger.entity_id.split('signal_east_')[1] }}"
location_name: 'not_home'
Sure thing, but note that it was quick/dirty and likely not very versatile. It works for my setup with an mqtt client installed on the router. It should work with most standard DD-WRT versions built in the past 3 years or so using HTTP. Older builds may experience issues with curl (and possibly other packages). Not sure how the DD-WRT component is built in python, but this would probably make more sense to build into HASS and populate in something similar to the “GPS Accuracy” attribute. The RSSI signal strength is published on the DD-WRT frontend, but I imagine our existing component isn’t scraping connected clients from this table.
# Runs on DDWRT router. Place in jffs or opt partition and initiate the script at boot. May require some optware packages, depending on your version.
# ONLY MONITORS 5ghz FREQUENCY (eth2 in the "wl" command). FIXED.
iter="1 2 3"
mac1=00:00:00:00:00:00 # PERSON1
mac2=00:00:00:00:00:00 # PERSON2
mac3=00:00:00:00:00:00 # PERSON3
mac4=00:00:00:00:00:00 # PERSON4
#hass_host="" #hardcoded for now
#hass_pass="" #hardcoded. for now
while true; do
tot1=0
tot2=0
tot3=0
tot4=0
for i in $iter;
do
sleep 10
rssi1=$(wl -i eth1 rssi $mac1)
rssi2=$(wl -i eth1 rssi $mac2)
rssi3=$(wl -i eth1 rssi $mac3)
rssi4=$(wl -i eth1 rssi $mac4)
## SEARCH ALL CHANNELs/SSIDs/VLANs - depends on your specific hardware
if [ "$rssi1" == "" ]; then rssi1=$(wl -i eth2 rssi $mac1); fi
if [ "$rssi2" == "" ]; then rssi2=$(wl -i eth2 rssi $mac2); fi
if [ "$rssi3" == "" ]; then rssi3=$(wl -i eth2 rssi $mac3); fi
if [ "$rssi4" == "" ]; then rssi4=$(wl -i eth2 rssi $mac4); fi
# TEST THAT INTEGERS RETURNED, OTHERWISE DEFAULT TO -90
if expr "$rssi1" : '-[0-9]\+$' >/dev/null
then
tot1=$((tot1 + rssi1))
else
tot1=$((tot1 - 90))
fi
if expr "$rssi2" : '-[0-9]\+$' >/dev/null
then
tot2=$((tot2 + rssi2))
else
tot2=$((tot2 - 90))
fi
if expr "$rssi3" : '-[0-9]\+$' >/dev/null
then
tot3=$((tot3 + rssi3))
else
tot3=$((tot3 - 90 ))
fi
if expr "$rssi4" : '-[0-9]\+$' >/dev/null
then
tot4=$((tot4 + $rssi4))
else
tot4=$((tot4 - 90))
fi
sleep 10;
done
#FIND AVERAGE RSSI OVER TIME PERIOD
tot1=$((tot1 / 3))
tot2=$((tot2 / 3))
tot3=$((tot3 / 3))
tot4=$((tot4 / 3))
#SEND TO HASS via Mosquitto Client Optware/Entware package on ddwrt
/opt/bin/mosquitto_pub -h 000.000.00.0 -u USERNAME -P PASSWORD -t WAP/1/rssi/PERSON1 -m "$tot1"
/opt/bin/mosquitto_pub -h 000.000.00.0 -u USERNAME -P PASSWORD -t WAP/1/rssi/PERSON2 -m "$tot2"
/opt/bin/mosquitto_pub -h 000.000.00.0 -u USERNAME -P PASSWORD -t WAP/1/rssi/PERSON3 -m "$tot3"
/opt/bin/mosquitto_pub -h 000.000.00.0 -u USERNAME -P PASSOWRD -t WAP/1/rssi/PERSON4 -m "$tot4"
##Old Method Using HTTP rather than MQTT
#curl -X POST --insecure --retry-delay 180 -s -H "x-ha-access: PASSWORD" -H "Content-Type: application/json" -d '{"state":"'$tot1'", "attributes": {"unit_of_measurement": "rssi", "friendly_name": "PERSON1 West Signal"}}' "https://000.000.00.0:8123/api/states/sensor.signal_west_PERSON1"
#curl -X POST --insecure --retry-delay 180 -s -H "x-ha-access: PASSWORD" -H "Content-Type: application/json" -d '{"state":"'$tot2'", "attributes": {"unit_of_measurement": "rssi", "friendly_name": "PERSON2 West Signal"}}' "https://000.000.00.0:8123/api/states/sensor.signal_west_PERSON2"
#curl -X POST --insecure --retry-delay 180 -s -H "x-ha-access: PASSWORD" -H "Content-Type: application/json" -d '{"state":"'$tot3'", "attributes": {"unit_of_measurement": "rssi", "friendly_name": "PERSON3 West Signal"}}' "https://000.000.00.0:8123/api/states/sensor.signal_west_PERSON3"
#curl -X POST --insecure --retry-delay 180 -s -H "x-ha-access: PASSWORD" -H "Content-Type: application/json" -d '{"state":"'$tot4'", "attributes": {"unit_of_measurement": "rssi", "friendly_name": "PERSON4 West Signal"}}' "https://000.000.00.0:8123/api/states/sensor.signal_west_PERSON4"
done