fix(wifi): restore safe AP-enable trigger; decouple internet check from AP logic

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 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-05-01 15:28:02 -04:00
parent 4b39fbcfd1
commit 2a74db3a59
2 changed files with 15 additions and 23 deletions

View File

@@ -126,10 +126,11 @@ class WiFiMonitorDaemon:
else: else:
logger.debug(f"Status check: WiFi=disconnected, Ethernet={updated_ethernet}, AP={updated_status.ap_mode_active}") 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 # Escalating recovery: if nmcli reports connected but actual internet
# unreachable for several consecutive checks, restart NetworkManager. # is unreachable for several consecutive checks, restart NetworkManager.
# check_and_manage_ap_mode() already calls _check_internet_connectivity() # This is done HERE (not inside check_and_manage_ap_mode) to keep the
# internally; we track the failure count here from the observed state. # 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 updated_status.connected and not updated_status.ap_mode_active:
if not self.wifi_manager._check_internet_connectivity(): if not self.wifi_manager._check_internet_connectivity():
self._consecutive_internet_failures += 1 self._consecutive_internet_failures += 1

View File

@@ -2396,29 +2396,20 @@ address=/detectportal.firefox.com/192.168.4.1
f"auto_enable={auto_enable}, disconnected_checks={self._disconnected_checks}") f"auto_enable={auto_enable}, disconnected_checks={self._disconnected_checks}")
# Determine if we should have AP mode active. # Determine if we should have AP mode active.
# "Disconnected" means either: # AP-enable uses only the nmcli association state (fast, no network calls).
# (a) nmcli reports no WiFi/Ethernet association, OR # This keeps the same reliable behaviour as before: momentary packet loss
# (b) nmcli reports connected but there is no actual internet reachability. # while on working WiFi does NOT trigger AP mode. The internet-reachability
# Case (b) catches the common scenario where the Pi is associated with a # check is performed separately in the daemon watchdog for NM recovery.
# router whose WAN link is down (e.g. ISP outage, user moved home). is_disconnected = not status.connected and not ethernet_connected
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
if is_disconnected: if is_disconnected:
# Increment disconnected check counter # Increment disconnected check counter
self._disconnected_checks += 1 self._disconnected_checks += 1
reason = "no association" if not has_association else "no internet reachability" logger.debug(f"Network disconnected (check {self._disconnected_checks}/{self._disconnected_checks_required})")
logger.debug(f"Network effectively disconnected ({reason}) "
f"(check {self._disconnected_checks}/{self._disconnected_checks_required})")
else: else:
# Reset counter if we're genuinely connected with internet # Reset counter if we're associated
if self._disconnected_checks > 0: 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 self._disconnected_checks = 0
# Only enable AP if we've had enough consecutive disconnected checks # 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: elif not should_have_ap and ap_active:
# Should not have AP but do - disable AP mode # Should not have AP but do - disable AP mode
# Always disable if WiFi or Ethernet connects, regardless of auto_enable setting # 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() success, message = self.disable_ap_mode()
if success: if success:
if status.connected: if status.connected:
logger.info("Auto-disabled AP mode (WiFi connected with internet)") logger.info("Auto-disabled AP mode (WiFi connected)")
elif ethernet_connected: elif ethernet_connected:
logger.info("Auto-disabled AP mode (Ethernet connected)") logger.info("Auto-disabled AP mode (Ethernet connected)")
self._disconnected_checks = 0 # Reset counter self._disconnected_checks = 0 # Reset counter