Fix arrival suppression when device returns during departure debounce

Watchdog-triggered departures set departing=True after 15 min of silence.
If the device returned during the 15-min debounce window, on_arrival()
treated it as a rapid flap and suppressed the ARRIVED alert — even though
the device had been genuinely absent for 15+ minutes.

Store depart_initiated timestamp when setting departing=True. On re-arrival,
check the gap: < 120s = true rapid flap (transient Netlink/DHCP event),
suppress as before. >= 120s = real absence confirmed by watchdog, pop the
device from known_devices and let it fall through to the new-device path
so the ARRIVED alert fires.

Also removes debug traceback instrumentation left in _update_last_seen
from the prior investigation session.
This commit is contained in:
Cobra
2026-04-14 19:49:33 -04:00
parent 57cf43eaea
commit 7d87f29a47
+17 -8
View File
@@ -985,15 +985,23 @@ def on_arrival(mac: str, ip: str, hostname: str = "") -> None:
with known_lock:
with departure_lock:
# Check if device marked departing (rapid flap recovery)
# Check if device marked departing
if mac in known_devices and known_devices[mac].get('departing'):
# Device returned during departure window — cancel timer, clear flag, no alert
known_devices[mac]['departing'] = False
with occupancy_lock:
_update_occupancy_state_unlocked()
last_departed_time.pop(mac, None)
logging.debug(f"Device {mac} re-arrived during departure window — suppressed alert")
return
depart_initiated = known_devices[mac].get('depart_initiated', now)
absence_secs = now - depart_initiated
if absence_secs < 120:
# True rapid flap (transient Netlink/DHCP event) — suppress
known_devices[mac]['departing'] = False
with occupancy_lock:
_update_occupancy_state_unlocked()
last_departed_time.pop(mac, None)
logging.debug(f"Device {mac} rapid-flap suppressed ({int(absence_secs)}s)")
return
else:
# Watchdog-confirmed absence — real re-arrival, let it alert
logging.debug(f"Device {mac} returning after {int(absence_secs)}s absence — treating as arrival")
known_devices.pop(mac)
last_departed_time.pop(mac, None)
# Log if we cancelled a timer
if timers_to_cancel:
@@ -1079,6 +1087,7 @@ def on_departure(mac: str) -> None:
dev_copy = dev.copy()
# Mark departing instead of popping — allows re-arrival to detect and cancel timer
known_devices[mac]['departing'] = True
known_devices[mac]['depart_initiated'] = time.time()
# Start 15-minute debounce timer
# Extract timer to cancel outside of lock to avoid deadlock