From d801cebb2e6e9a1d0931522cb2e86ba9d481b8a7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 5 Mar 2026 01:23:29 -0800 Subject: [PATCH] mici setup: guard continue button when forgetting/connecting (#37568) * test * fix * test * too much * simple to ship * revert * bug free * simpler * fix * even safer guard --- .../mici/layouts/settings/network/wifi_ui.py | 9 ++++++ system/ui/mici_setup.py | 31 +++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/mici/layouts/settings/network/wifi_ui.py b/selfdrive/ui/mici/layouts/settings/network/wifi_ui.py index 9cd4db7bf..02b561d81 100644 --- a/selfdrive/ui/mici/layouts/settings/network/wifi_ui.py +++ b/selfdrive/ui/mici/layouts/settings/network/wifi_ui.py @@ -110,6 +110,10 @@ class WifiButton(BigButton): if self._is_connected or self._is_connecting: self._wrong_password = False + @property + def network_forgetting(self) -> bool: + return self._network_forgetting + def _forget_network(self): if self._network_forgetting: return @@ -286,6 +290,11 @@ class WifiUIMici(NavScroller): networks_updated=self._on_network_updated, ) + @property + def any_network_forgetting(self) -> bool: + # TODO: deactivate before forget and add DISCONNECTING state + return any(btn.network_forgetting for btn in self._scroller.items if isinstance(btn, WifiButton)) + def show_event(self): # Clear scroller items and update from latest scan results super().show_event() diff --git a/system/ui/mici_setup.py b/system/ui/mici_setup.py index 5a0b751d3..270228770 100755 --- a/system/ui/mici_setup.py +++ b/system/ui/mici_setup.py @@ -20,7 +20,7 @@ from openpilot.common.swaglog import cloudlog from openpilot.common.time_helpers import system_time_valid from openpilot.common.utils import run_cmd from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.wifi_manager import WifiManager +from openpilot.system.ui.lib.wifi_manager import WifiManager, ConnectStatus from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets.nav_widget import NavWidget from openpilot.system.ui.widgets.label import UnifiedLabel @@ -55,6 +55,7 @@ class NetworkConnectivityMonitor: def __init__(self, should_check: Callable[[], bool] | None = None): self.network_connected = threading.Event() self.wifi_connected = threading.Event() + self.recheck_event = threading.Event() self._should_check = should_check or (lambda: True) self._stop_event = threading.Event() self._last_timesyncd_restart = 0.0 @@ -76,12 +77,21 @@ class NetworkConnectivityMonitor: self.network_connected.clear() self.wifi_connected.clear() + def invalidate(self): + self.recheck_event.set() + def _run(self): while not self._stop_event.is_set(): if self._should_check(): try: request = urllib.request.Request(OPENPILOT_URL, method="HEAD") urllib.request.urlopen(request, timeout=2.0) + + # Discard stale result if invalidated during request + if self.recheck_event.is_set(): + self.recheck_event.clear() + continue + self.network_connected.set() if HARDWARE.get_network_type() == NetworkType.wifi: self.wifi_connected.set() @@ -392,7 +402,17 @@ class NetworkSetupPageBase(Scroller): def _nav_stack_tick(self): self._wifi_manager.process_callbacks() - has_internet = self._network_monitor.network_connected.is_set() + # Discard stale poll results while network state is changing + network_changing = self._wifi_ui.any_network_forgetting or self._wifi_manager.wifi_state.status == ConnectStatus.CONNECTING + if network_changing: + self._network_monitor.invalidate() + + has_internet = (self._network_monitor.network_connected.is_set() and + not network_changing and + not self._network_monitor.recheck_event.is_set()) + self._continue_button.set_visible(has_internet) + self._waiting_button.set_visible(not has_internet) + if has_internet and not self._prev_has_internet: self._pending_has_internet_scroll = True self._prev_has_internet = has_internet @@ -432,13 +452,6 @@ class NetworkSetupPageBase(Scroller): self._pending_wifi_grow_animation = False self._wifi_button.trigger_grow_animation() - if self._network_monitor.network_connected.is_set(): - self._continue_button.set_visible(True) - self._waiting_button.set_visible(False) - else: - self._continue_button.set_visible(False) - self._waiting_button.set_visible(True) - class NetworkSetupPage(NetworkSetupPageBase, NavScroller): def __init__(self, network_monitor: NetworkConnectivityMonitor, continue_callback: Callable[[bool], None],