Super-simple device tracker for pfSense

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.

2 Likes

I’m sure that all works, but this gives you trackable devices with 0 work,

GitHub - travisghansen/hass-pfsense: pfSense integration with Home Assistant.

I made this just to escape from that one, which caused various stability problems on long term for me.

1 Like

Dear @robi ,

Thank you so much for posting this. It is exactly what I was looking for.
I only have Apple devices to track in our family so I have a quite reliable HomeKit tracking automation like this:

This also works if WiFi is switched off on the client device because the location part is handled by Apple.

However, we do have the occasional non-Apple devices and we have some very old (pre iOS 15) phones.

So your solution came at the exact right moment!

I am still beginner-ish at HA but I managed to get it working by substituting the HA IP, MAC addresses and user names.

Cheers, Pete

1 Like

@robi I am evaluating your ARP pfsense tracker solution. My iPhone 14 PM is tracked perfectly. However there are phone models that don’t play so well:
We had a visitor carrying a google pixel pro 7, which would stop responding to ARP requests upon screen lock. After the ARP timer elapses the lease is dropped. I don’t think we can fix this from the router side, maybe adjusting phone side settings could work.

So I suppose it will work fine as long as the phone models tracked behave as desired…

March 30 2025 update:
With the net.link.ether.inet.max_age system tunable set to 300 seconds, my iPhone 14 Pro Max lost its lease today. It was screen locked during that time. I set the time to 600 seconds and will see how this evolves.

April 3 2025 update:
The phone still disconnects now and then, even with the refresh tunable set to 600s, but it always reconnects 1 minute later so it’s not a problem, because in automations I set a trigger For duration anyway