Goal: increase reliability of home
and not_home
state of your family members by looking if their phones are connected to your house WiFi or not.
With a properly deployed WiFi system, the MAC addresses of the devices which are connected to the network are present in the ARP tables of the AP, switch and router through which the data generated by these devices is flowing. Since pfSense is usually the central part of the network, it’s a good place to look for this information.
To have a very simple device tracker in Home Assistant, based on the ARP table in pfSense, you don’t necessarily need any custom components or third party packages installed on either side. With just a simple script triggered by a cron job on pfSense side every minute you can filter for the desired MAC addresses and simply push this information over to Home Assistant through a webhook.
Since no extra components are required, no further ports and user credentials are opened on either side, you’re not increasing your cybersecurity risks in any way.
On pfSense side, put this script, named arp_presence_to_homeassistant.sh
in the /cf/conf/
directory:
#!/bin/sh -f
sleep 30 #let's check at the middle of each minute
ARPTABLE=$(arp -a)
echo $ARPTABLE | grep -q 'aa:bb:cc:dd:ee:ff' && USER1='"home"' || USER1='"not_home"'
echo $ARPTABLE | grep -q 'ff:ee:dd:cc:bb:aa' && USER2='"home"' || USER2='"not_home"'
JSONTOHA="{ \"User1\": ${USER1}, \"User2\": ${USER2} }"
curl -X POST http://ha.lan.ip.address:8123/api/webhook/-pres-kMSTJyKRQUl4ra -m 15 --json "${JSONTOHA}"
Add to your crontab (you can use the Cron official package) in pfSense:
*/1 * * * * root /bin/sh /cf/conf/arp_presence_to_homeassistant.sh
(the command is /bin/sh /cf/conf/arp_presence_to_homeassistant.sh
)
On Home Assistant side, add an automation:
- alias: pfsense-router-arp-presence
description: "pfSense presence based on ARP"
mode: single
triggers:
- trigger: webhook
allowed_methods:
- POST
local_only: true
webhook_id: "-pres-kMSTJyKRQUl4ra"
actions:
- action: device_tracker.see
data:
source_type: router
dev_id: user1
location_name: '{{ trigger.json.User1 }}'
- action: device_tracker.see
data:
source_type: router
dev_id: user2
location_name: '{{ trigger.json.User2 }}'
and of course the device trackers to the known_devices.yaml
:
user1:
name: User 1 on WiFi
mac:
icon: mdi:cellphone-wireless
picture:
track: true
user2:
name: User 2 on WiFi
mac:
icon: mdi:cellphone-wireless
picture:
track: true
and restart Home Assistant.
You can then assign the device_tracker.user1
and device_tracker.user2
through the UI to the respective persons, in addition to other trackers you may have (like HA companion app).
Don’t forget to adjust in each device to use the device’s real MAC address when connecting to your network instead of the randomized one.
Tip: when disconnected from the network (leaving from home), the device’s MAC address stays cached in pfSense’s ARP table for 1200 seconds before being cleared out, thus this much time has to pass to switch state to not_home
. If you think this is too much, you can decrease this by adding a system tunable in pfSense, namely net.link.ether.inet.max_age
with a lower value. I have this set to 300
since a couple of years and it works flawlessly, has no negative impact otherwise.