WiFi scan, optimistic disconnect, and cursor-restore fixes#202
Merged
Conversation
Collaborator
Author
|
@rreichenbach good to merge this one? |
rreichenbach
approved these changes
Jul 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problems
nmcli dev wifi list --rescan yeswithout 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.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.