Skip to content

web: add WiFi SSID/password entry (+ scan dropdown) to the dashboard - #35

Open
meelyn-pandit wants to merge 12 commits into
lts_26_07.isofrom
web-wifi-manual-entry
Open

web: add WiFi SSID/password entry (+ scan dropdown) to the dashboard#35
meelyn-pandit wants to merge 12 commits into
lts_26_07.isofrom
web-wifi-manual-entry

Conversation

@meelyn-pandit

Copy link
Copy Markdown
Contributor

What

Adds manual WiFi setup to the dashboard's Network Control → WiFi section, so an operator can join a network from the browser instead of only via a USB credentials file (/usb/wifi).

New controls:

  • Scan for networks button → scanned-SSID dropdown (dedup, sorted by signal; picking one fills the SSID field)
  • SSID text input + Password input (type=password)
  • Connect button

How

  • controls/wifi-connect.js (POST /wifi/connect) joins via execFile('nmcli', [...]) — an argv array, not the shell-based RunCommand (src/command.js uses exec()). The operator-supplied SSID/password are passed as literal args, so a name/password with spaces or shell metacharacters can't inject a command. Runs nmcli dev wifi connect <ssid> [password <psk>] then ipv4.method auto — the same join /usb/wifi does, param-driven.
  • controls/wifi-networks.js (GET /wifi/networks) proxies a new hardware-server route GET /internet/wifi-scanWifi.GetNetworks() (the full visible list; /wifi-networks only returned the connected one).
  • Frontend: interface.js scan handler + Connect handler; main.pug inputs.

Verified (v3r3 station)

  • Page renders the scan button, dropdown, SSID/password inputs, Connect.
  • POST /wifi/connect no SSID → 400 {"error":"ssid required"}.
  • POST /wifi/connect bogus SSID → 500 {"detail":"No network with SSID '…' found."} — nmcli ran with the SSID as a literal arg (no shell), error surfaced.
  • /wifi/networks → 200; /internet/wifi-scan → the network array.
  • A real join needs WiFi enabled + an AP in range (same nmcli path the USB flow already uses).

Note

Like the existing /wifi/enable and /modem/* control POSTs, these endpoints aren't behind the dashboard's page-login middleware (LAN-trusted). Unchanged here, but flagged since this one now carries a password — worth a follow-up if the control plane should require auth.

🤖 Generated with Claude Code

The dashboard's Network Control only had Enable/Disable WiFi buttons; joining a
network required a USB credentials file (/usb/wifi). Add manual entry from the
web UI:

- main.pug: a "Scan for networks" button, a scanned-SSID dropdown, an SSID text
  input, a password input, and a Connect button in the WiFi section.
- interface.js: Scan populates the dropdown (dedup + sort by signal; selecting an
  entry fills the SSID field); Connect POSTs {ssid, psk} to /wifi/connect.
- controls/wifi-connect.js (new): joins via execFile('nmcli', [...]) — an argv
  array, NOT the shell-based RunCommand, so the operator-supplied SSID/password
  can't inject a shell command. Runs `nmcli dev wifi connect <ssid> [password
  <psk>]` then sets ipv4.method auto (same join /usb/wifi does, param-driven).
- controls/wifi-networks.js (new): proxies the hardware-server scan for the
  dropdown.
- hardware-server internet.js: new GET /internet/wifi-scan returning
  Wifi.GetNetworks() (the full visible-network list).
- app.js + controls/index.js: wire POST /wifi/connect and GET /wifi/networks.

Verified on a v3r3 station: page renders the inputs; POST /wifi/connect with no
SSID -> 400; with a bogus SSID -> 500 surfacing nmcli's "No network with SSID
'...' found" (proves nmcli ran with the SSID as a literal arg, no shell); scan
endpoints return 200 / the network array. A real join needs WiFi enabled + an AP
in range (same nmcli path the USB flow already uses).

Note: like the existing /wifi/enable and /modem/* control POSTs, these endpoints
are not behind the dashboard's page-login middleware (LAN-trusted); unchanged
here, but this one now carries a password.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@meelyn-pandit

Copy link
Copy Markdown
Contributor Author

Closing per request; removing this PR and its branch.

@meelyn-pandit
meelyn-pandit deleted the web-wifi-manual-entry branch July 7, 2026 18:49
@meelyn-pandit
meelyn-pandit restored the web-wifi-manual-entry branch July 7, 2026 19:34
meelyn-pandit and others added 2 commits July 7, 2026 16:10
- hardware wifi module: add GetCurrentIp() (nmcli, finds the connected
  wifi device rather than hardcoding wlan0)
- /internet/wifi-networks now returns the current IP (null-safe)
- dashboard WiFi section: new "WiFi IP Address" row; SSID input prefills
  once with the connected network (never clobbers user edits)
- the SSID dropdown is now the scan control: opening it triggers a scan
  and repopulates itself; the separate "Scan for networks" button is gone

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SSID dropdown: add a 15s freshness guard so re-opening the dropdown to
  pick a network no longer re-scans and wipes the options mid-click (the
  selection now reliably fills the SSID input); a stale/empty list still
  rescans on open
- WiFi password: add a "Show password" checkbox that toggles the input
  between password and text

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@meelyn-pandit meelyn-pandit reopened this Jul 9, 2026
meelyn-pandit and others added 9 commits July 15, 2026 15:50
…; lcd 0.4.1

- enable-wifi.sh: after modprobe recreates wlan0, restart wpa_supplicant and
  NetworkManager so they re-attach to the new interface. Fixes WiFi scans
  returning nothing (and needing a reboot) right after enabling WiFi.
- ctt-lcd: bump 0.4.0 -> 0.4.1 (boot splash "Booting up...").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…board

Add numeric read-outs next to the WiFi and cellular-modem signal icons on
the web interface, plus the cellular network provider.

- wifi.js: read real WiFi dBm from /proc/net/wireless (iw/iwconfig aren't
  installed on the station image); GetCurrentNetwork now returns `dbm`
  alongside the nmcli signal percent. Factor out GetConnectedWifiDevice().
- interface.js: render `NN% / -NN dBm` beside both icons and populate the
  provider field. Modem dBm prefers real RSRP (mmcli --signal-get), falling
  back to percent-derived RSSI; WiFi uses the /proc dBm, falling back to a
  ~percent-derived estimate when unavailable.
- main.pug: add #wifi-signal-text / #modem-signal-text spans and a new
  "Cellular Network Provider" row (#modem-carrier).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dBm to RSSI

- menu-manager.js: autoRefresh_ dereferenced this.focus.view without a null
  check. When a refresh cycle resolved/rejected after the user navigated to a
  view-less menu node (or popped the stack), it threw, clearing the refresh
  timer without re-arming it and freezing the LCD on its last frame. Guard on
  this.focus && this.focus.view before reading autoRefresh.
- interface.js: show the modem dBm from RSSI (percent-derived) instead of RSRP
  so the web dashboard and the LCD (station-stats.js) report the same value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The WiFi section now shows just the nmcli signal percent next to the icon.
Remove the /proc/net/wireless dBm plumbing added for it (GetSignalDbm and the
GetCurrentNetwork `dbm` augmentation); GetConnectedWifiDevice stays since the
IP lookup uses it. The modem read-out keeps its % + dBm (RSSI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the queue

The uploader used a flat 20s request timeout and aborted the entire run on the
first file that failed. A single oversized rotated log (observed: a 42MB .gz on
a ~0.5MB/s uplink needs ~80s) could never finish within 20s, and because the
queue is processed in sorted() order it sat at the front and blocked every file
behind it on every hourly run — the backlog just grew.

- Scale the per-request timeout to file size (BASE_TIMEOUT + size/floor-rate)
  instead of a fixed 20s.
- On a failed file, re-check connectivity: a real outage stops the run (retry
  everything next run); if still online the file itself is the problem, so move
  it to /data/rotated-failed and continue draining the rest. Applied to both the
  CTT and SG loops.
- Reset the per-file attempt counter in uploadFile (was only reset on success).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant