Goal
Create a device tracker for specific WiFi clients on my Unifi APs using only HA’s MQTT integration; replace unifi_direct
for device tracking and presence detection.
Background
I use a WiFi client tracker for presence detection for household members, who almost always have their mobile phones when they leave the house. This allows for automations like turning down the heat when nobody is home. I had previously used HA’s Ubiquiti Unifi AP (unifi_direct
) platform to track devices on my WiFi.
I had a few issues with unifi_direct
though and noticed there is an open issue related to the requirement to move Unifi specific parsing to PyPI. It seems improvements are stuck there. I decided to create my own device tracker with the following goals:
- MQTT integration is the only required HA dependency.
- Use SSH key auth instead of password to connect to Unifi AP to retrieve clients.
- Improve error handling;
unifi_direct
was causing noise in HA logs. - One less HA component dependency to keep my HA installation simple and minimal.
- Have fun with another DIY project!
Here is the PyPI link:
unifi-tracker · PyPI
Here is the Github link:
idatum/unifi_tracker: Track Unifi AP WiFi client comings and goings (github.com)
I run the follow service under docker, along with HA and Mosquitto (and other services):
It’s a simple service using the unifi_tracker
module:
- Periodically return client info from all APs.
- Union all client MACs from all APs.
- Do a diff between the previous and current set of MAC addresses.
- Publish diff to MQTT (Mosquitto) for processing in HA using the MQTT service.
A few key notes:
MQTT messages are retained so HA can restart and pick up current presence state. The topic has the MAC address, and the payload is “home”. Here is an example HA device_tracker.yaml (included in configuration.yaml):
- platform: mqtt
consider_home: 60
devices:
tracked_phone: "device_tracker/unifi_tracker/xx:xx:xx:xx:xx:xx"
qos: 1
source_type: router
Note consider_home
: to have HA correctly honor that setting, deleting the retained message is required instead of publishing “not_home” in the payload. To delete a retained MQTT message, you publish a retained topic with no payload. Here’s the code in device_tracker.py
:
last_clients, added, deleted = unifiTracker.scan_aps(ap_hosts=AP_hosts, last_mac_clients=last_clients)
for mac in added:
publish_state(topic=f'{Topic_base}/{mac}', state='home', retain=True)
for mac in deleted:
# Empty payload
publish_state(topic=f'{Topic_base}/{mac}', state=None, retain=True)
Notice the empty (None) state payload for a deleted device. In HA for this example, the presence for the associated Person will change to away after about a minute.
If any AP fails to return output from mca-dump
, the entire diff will fail. Note that clients can roam, switching from one AP to another. I only have a couple APs, but if you have many, the probability of failing to do a diff increases. I get 1 or 2 failures per hour from any of the my APs (it simply doesn’t return any results – no clue why).
I use multiprocessing.Pool to retrieve output in parallel from the APs.
There are 2 environment variables for MQTT credentials:
MQTT_USERNAME
MQTT_PASSWORD
The Unifi AP SSH username (using SSH key auth) is also an environment variable:
UNIFI_SSH_USERNAME
In summary: device_tracker.py
drives the main processing and handles MQTT, unifi_tracker.py
handles SSH and client diff with APs.
Summary
Works fine generally, basically like the existing HA unifi_direct
, but allows me to more freely innovate and be less dependent on another component for running HA for my home automation.