Skip to content

WiFi scan, optimistic disconnect, and cursor-restore fixes#202

Merged
sastraxi merged 6 commits into
mainfrom
fix/wifi-woes
Jul 18, 2026
Merged

WiFi scan, optimistic disconnect, and cursor-restore fixes#202
sastraxi merged 6 commits into
mainfrom
fix/wifi-woes

Conversation

@sastraxi

@sastraxi sastraxi commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Problems

  1. Stale/empty scan results. nmcli dev wifi list --rescan yes without sudo silently exits 0 with a stale cache. While connected, NM runs no periodic scan; wpa_supplicant's 30s bgscan only probes the configured SSID, so everything else ages out of the cache permanently.
  2. Disconnect lagged up to 5s. The UI waited for the polling thread's next 5s tick before reflecting a disconnect. The ✔ stayed painted from stale status.
  3. Cursor reset on every scan re-render. Menu.default_item compared a str against rich rows' list[Segment], which never matched — cursor restore was silently broken for every network row. The 2s tick's blind pop/push reset scroll position under the user.
  4. Nearby submenu lied. It showed "Scanning..." forever even after a scan completed with no unsaved networks in range.

Fixes

Scanning (ops.py, wifi_menu.py). scan_networks now uses sudo nmcli dev wifi list --rescan yes — a single blocking call that triggers a real scan and returns fresh results. The menu paces this at 10s (NM rate-limits scans to one per 8s while connected); the CommandQueue dedupes if one is already in flight. The earlier split into request_rescan (trigger) + scan_networks (cache read) was collapsed — it existed only to work around the polkit denial, which sudo fixes.

Optimistic disconnect (manager.py, wifi_menu.py, commands.py). WifiManager.set_status() publishes a predicted status through on_status_change immediately, on the calling thread, then request_refresh() wakes the polling thread to confirm. The poller's _force_publish flag ensures the result is published even if unchanged (a failed op leaves status identical but the UI may have painted optimistically). The flag is claimed at the top of each poll pass so a refresh requested mid-poll survives into the next. CommandQueue nudges request_refresh() after every write op (not scans), guarded so a failure can't kill the worker.

Cursor restore (uilib/menu.py, mode_selector.py). label_key() reduces rich labels (segment lists) to their text for default_item comparison. mode_selector.py drops the ✔ prefix it was compensating with. The signature-based rerender guard (_rows_sig) in wifi_menu.py skips re-renders when row contents haven't meaningfully changed (signal bucketed to 1–4 bars), so the 10s scan tick no longer resets the cursor.

Nearby empty state (wifi_menu.py). _scan_completed flag distinguishes "still scanning" from "scan done, nothing to list". The nearby submenu shows "No other networks found" once a scan has completed with no unsaved networks.

WPA3 transition compat (ops.py). connect_scanned adds wifi-sec.pmf optional on the wpa-psk path, covering WPA3-transition APs that require PMF. The join-dialog flow uses "WPA2" (wpa-psk covers WPA2 + WPA3-transition; WPA3-only needs the scan flow, which detects SAE from the AP's SECURITY field).

Tests. _open() now uses the LCD's own WifiMenu instance (the handler's status callback re-renders lcd.wifi_menu, so a private instance never saw repaints). New tests cover the optimistic publish path, the mid-poll force-publish survival, the scan-pacing interval, the write-op refresh nudge, and worker survival on refresh failure.

@sastraxi sastraxi changed the title Wifi scan, connect, and disconnect fixes WiFi scan, optimistic disconnect, and cursor-restore fixes Jul 11, 2026
@sastraxi
sastraxi requested a review from rreichenbach July 11, 2026 18:24
@sastraxi

Copy link
Copy Markdown
Collaborator Author

@rreichenbach good to merge this one?

@sastraxi
sastraxi merged commit 6b436b1 into main Jul 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants