Fix arrival/departure gates dropping LAA MACs; halve ARP scan interval

The phone/wearable gate used a manual OUI check that missed privately-addressed
MACs (iOS 14+/Android 10+ randomize per network). Any phone not pre-configured
in device_labels was silently enrolled with no alert, causing ARRIVED/OCCUPIED
to never fire. Replacing the gate with is_personal_device() catches OUI, labels,
and LAA bit uniformly.

ARP scan interval drops from 30s to 15s so worst-case arrival detection is 15s.
This commit is contained in:
Cobra
2026-04-15 15:25:32 -04:00
parent d8c742cea6
commit 047635c304
+7 -11
View File
@@ -32,7 +32,7 @@ OUI_DB_PATH = "/opt/net_alerter/oui.db"
ENV_PATH = Path(os.getenv("NET_ALERTER_ENV", "/opt/net_alerter/.env"))
BLE_NAMES_FILE = Path("/opt/net_alerter/ble_names.json")
BLE_CORRELATION_WINDOW = 60 # seconds — how far back to look for nearby BLE devices
ARP_SCAN_INTERVAL = int(os.getenv("NET_ALERTER_ARP_SCAN_INTERVAL", "30"))
ARP_SCAN_INTERVAL = int(os.getenv("NET_ALERTER_ARP_SCAN_INTERVAL", "15"))
known_devices = {} # {mac: {ip, hostname, vendor, first_seen, last_seen, infrastructure (opt)}}
known_lock = threading.Lock()
@@ -1111,12 +1111,9 @@ def on_arrival(mac: str, ip: str, hostname: str = "") -> None:
'last_seen': now
}
# Only alert for phones/wearables (MOBILE_DEVICE_OUIS) or explicitly labeled devices.
# Everything else is enrolled silently.
oui = mac.replace(":", "").upper()[:6]
normalized = _normalize_mac(mac)
if oui not in MOBILE_DEVICE_OUIS and normalized not in device_labels:
logging.debug(f"Silent enroll {mac} — not a phone/wearable OUI and no label")
# Only alert for phones/wearables. Everything else is enrolled silently.
if not is_personal_device(mac):
logging.debug(f"Silent enroll {mac} — not a phone/wearable")
update_occupancy_state()
return
@@ -1156,11 +1153,10 @@ def on_departure(mac: str) -> None:
logging.debug(f"Ignoring departure for infrastructure IP {dev['ip']} (MAC:{mac})")
return
# Only alert departure for phones/wearables or labeled devices
oui = mac.replace(":", "").upper()[:6]
if oui not in MOBILE_DEVICE_OUIS and _normalize_mac(mac) not in device_labels:
# Only alert departure for phones/wearables
if not is_personal_device(mac):
known_devices.pop(mac, None)
logging.debug(f"Silent depart {mac} — not a phone/wearable OUI and no label")
logging.debug(f"Silent depart {mac} — not a phone/wearable")
return
# Check if this is part of an interface flap (suppress simultaneous mass-departure)