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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user