From 2a74db3a599705a7f3957b271bb8fd345a869431 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 1 May 2026 15:28:02 -0400 Subject: [PATCH] fix(wifi): restore safe AP-enable trigger; decouple internet check from AP logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit introduced _check_internet_connectivity() into check_and_manage_ap_mode(), which shared the same _disconnected_checks counter that triggers AP enable. This created a false-positive risk: 90 seconds of packet loss on working WiFi would enable AP mode and kick off the connection. Fix: restore nmcli association state as the sole AP-enable trigger (original, safe behaviour). The internet connectivity check is now used only in the daemon watchdog for the NM-restart escalation — matching how adsb-feeder-image actually structures the two concerns (initial setup detection vs. ongoing monitoring). Also clarify daemon comment: the connectivity check runs once per cycle in the watchdog block, not inside check_and_manage_ap_mode, so there is no double-call. Co-Authored-By: Claude Sonnet 4.6 --- scripts/utils/wifi_monitor_daemon.py | 9 +++++---- src/wifi_manager.py | 29 ++++++++++------------------ 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/scripts/utils/wifi_monitor_daemon.py b/scripts/utils/wifi_monitor_daemon.py index 00730d45..30962acc 100755 --- a/scripts/utils/wifi_monitor_daemon.py +++ b/scripts/utils/wifi_monitor_daemon.py @@ -126,10 +126,11 @@ class WiFiMonitorDaemon: else: logger.debug(f"Status check: WiFi=disconnected, Ethernet={updated_ethernet}, AP={updated_status.ap_mode_active}") - # Escalating recovery: if nmcli reports connected but internet is - # unreachable for several consecutive checks, restart NetworkManager. - # check_and_manage_ap_mode() already calls _check_internet_connectivity() - # internally; we track the failure count here from the observed state. + # Escalating recovery: if nmcli reports connected but actual internet + # is unreachable for several consecutive checks, restart NetworkManager. + # This is done HERE (not inside check_and_manage_ap_mode) to keep the + # AP-enable trigger clean and avoid false-positive AP enables from + # transient packet loss on otherwise working WiFi. if updated_status.connected and not updated_status.ap_mode_active: if not self.wifi_manager._check_internet_connectivity(): self._consecutive_internet_failures += 1 diff --git a/src/wifi_manager.py b/src/wifi_manager.py index 995c601d..6521d6df 100644 --- a/src/wifi_manager.py +++ b/src/wifi_manager.py @@ -2396,29 +2396,20 @@ address=/detectportal.firefox.com/192.168.4.1 f"auto_enable={auto_enable}, disconnected_checks={self._disconnected_checks}") # Determine if we should have AP mode active. - # "Disconnected" means either: - # (a) nmcli reports no WiFi/Ethernet association, OR - # (b) nmcli reports connected but there is no actual internet reachability. - # Case (b) catches the common scenario where the Pi is associated with a - # router whose WAN link is down (e.g. ISP outage, user moved home). - has_association = status.connected or ethernet_connected - if has_association: - has_internet = self._check_internet_connectivity() - else: - has_internet = False - - is_disconnected = not has_association or not has_internet + # AP-enable uses only the nmcli association state (fast, no network calls). + # This keeps the same reliable behaviour as before: momentary packet loss + # while on working WiFi does NOT trigger AP mode. The internet-reachability + # check is performed separately in the daemon watchdog for NM recovery. + is_disconnected = not status.connected and not ethernet_connected if is_disconnected: # Increment disconnected check counter self._disconnected_checks += 1 - reason = "no association" if not has_association else "no internet reachability" - logger.debug(f"Network effectively disconnected ({reason}) " - f"(check {self._disconnected_checks}/{self._disconnected_checks_required})") + logger.debug(f"Network disconnected (check {self._disconnected_checks}/{self._disconnected_checks_required})") else: - # Reset counter if we're genuinely connected with internet + # Reset counter if we're associated if self._disconnected_checks > 0: - logger.debug("Network connected with internet reachability, resetting counter") + logger.debug("Network connected, resetting disconnected check counter") self._disconnected_checks = 0 # Only enable AP if we've had enough consecutive disconnected checks @@ -2448,11 +2439,11 @@ address=/detectportal.firefox.com/192.168.4.1 elif not should_have_ap and ap_active: # Should not have AP but do - disable AP mode # Always disable if WiFi or Ethernet connects, regardless of auto_enable setting - if not is_disconnected: + if status.connected or ethernet_connected: success, message = self.disable_ap_mode() if success: if status.connected: - logger.info("Auto-disabled AP mode (WiFi connected with internet)") + logger.info("Auto-disabled AP mode (WiFi connected)") elif ethernet_connected: logger.info("Auto-disabled AP mode (Ethernet connected)") self._disconnected_checks = 0 # Reset counter