Fix departure detection for AP ARP-proxy networks (passive-only)

ARP proxy on WiFi APs causes the kernel neighbor table to show devices
as REACHABLE even after they disconnect. This made last_seen refresh
continuously from on_arrival() (netlink path), preventing the watchdog
from ever detecting departure.

Two fixes:
1. Remove _update_last_seen() from on_arrival() — netlink events are
   not reliable as a genuine-traffic source on ARP-proxy networks.
   last_seen is now only updated by the raw packet capture path (ARP
   requests, mDNS, DHCP) where src_mac must be the device itself.

2. Watchdog now covers all is_personal_device() entries in known_devices,
   not just the personal_devices enrollment set. device_labels entries
   (like named phones) were previously unmonitored by the watchdog.
This commit is contained in:
Cobra
2026-04-14 15:52:26 -04:00
parent 52fc12b97a
commit 88bc36af61
+3 -6
View File
@@ -953,9 +953,6 @@ def update_occupancy_state() -> None:
def on_arrival(mac: str, ip: str, hostname: str = "") -> None: def on_arrival(mac: str, ip: str, hostname: str = "") -> None:
"""Handle device arrival.""" """Handle device arrival."""
# Update passive observation tracking
_update_last_seen(mac)
# Infrastructure IPs never trigger alerts # Infrastructure IPs never trigger alerts
if ip in infrastructure_ips: if ip in infrastructure_ips:
logging.debug(f"Ignoring infrastructure IP {ip} (MAC:{mac})") logging.debug(f"Ignoring infrastructure IP {ip} (MAC:{mac})")
@@ -1758,9 +1755,9 @@ def personal_watchdog() -> None:
time.sleep(60) # Check every minute time.sleep(60) # Check every minute
now = time.time() now = time.time()
# Get current set of personal devices without holding lock for long # Track all personal devices currently in known_devices (not just enrolled set)
with personal_lock: with known_lock:
tracked = set(personal_devices) tracked = {mac for mac in known_devices if is_personal_device(mac)}
for mac in tracked: for mac in tracked:
# Get last_seen timestamp # Get last_seen timestamp