PR-07: WiFi provisioning & station management#13
Merged
Conversation
Spec-kit artifacts for PR-07 (WiFi station management + first-boot SoftAP provisioning), approved at Checkpoint 2. Records the pre-made FR9 decision (custom SoftAP portal), parity reconnect timing, and the host-testable IWifiDriver seam. No implementation yet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…vent-loop init Phase 1+2 of PR-07 (WiFi provisioning). Adds: - network component (linux-guarded CMake; header-only for now) - IWifiDriver pure interface (interfaces/) + WifiState types + MockWifiDriver - Kconfig: WS_PROV_AP_SSID/PASSWORD + WS_WIFI_* reconnect constants (parity defaults) - app_main: esp_netif_init() + esp_event_loop_create_default() after NVS, pumps_force_off() preserved as first action; no WiFi objects constructed yet - host wifi test suite registered (run_wifi_tests stub) Verified: host tests 164/0, both board targets build + board-config verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lidation Phase 3 / User Story 1 of PR-07: - WifiCredentialValidation (pure): SSID 1-32, password empty-or-8..64, typed reasons - decideBootMode (pure): button-held or no-credentials => Provisioning - ProvisioningPortal (target-only): standalone esp_http_server, GET / setup page, POST /wifi/config -> validate -> IConfigStore::setWifiCredentials -> 200 + deferred esp_restart (~3s, injectable RestartHook); never logs credential values - app_main: boot-mode decision + portal start in Provisioning mode (SoftAP radio bring-up left as TODO(US2/T018); config-button read TODO(US3/T024)) Verified: host tests 168/0 (+4 wifi cases), both board targets build + verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 4 / US2 (host-testable core): - WifiManager (pure, no IDF): STA connect + fixed-interval reconnect (10s retry, +60s pause after 5 fails, 5s rssi monitor), Connecting/Connected/Reconnecting/ ReconnectPaused; GotIp=connected. Constructor injects only IWifiDriver/ IConfigStore/ITimeProvider/ReconnectPolicy (FR-014: no watering dependency). Overflow-guarded failure counter; never reboots (FR-013 no boot loop). - 6 host tests (MockWifiDriver + FakeTimeProvider): happy path, 10s retry boundary, 60s pause after 5 fails, disconnect->reconnect, AP-mode suspends, no-block isolation. Hardware wiring (EspWifiDriver, wifi_task, app_main STA, LED) is the next mission. Verified: host tests 174/0, both board targets build + verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing-up Phase 4 / US2 hardware layer (target-only): - EspWifiDriver: esp_wifi/esp_netif/esp_event; WIFI_EVENT/IP_EVENT handlers push WifiEvents onto a FreeRTOS queue (lock-free task hand-off, no watering coupling); non-blocking staConnect/staStop/apStart/apStop/pollEvent/rssi; STA/AP exclusive; WIFI_STORAGE_RAM (real creds stay in wscfg NVS) - wifi_task: own FreeRTOS task (mirrors sensor_task) ticking WifiManager @250ms; drives BOARD_PIN_STATUS_LED (steady=connected, 500ms toggle=connecting/reconnecting) - app_main: builds ReconnectPolicy from CONFIG_WS_WIFI_*; provisioning branch apStart + portal; station branch WifiManager.begin(Station) + wifi_task_start; resolves the US1 apStart and US2 station TODOs. Reuses existing EspTimeProvider. - diag console: 'wifi' status line from snapshot (no credential values) Verified: host tests 174/0, both board targets build + verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…boot-loop Phase 5 / US3 + polish docs: - app_main: read BOARD_PIN_BTN_CONFIG (GPIO18, active-LOW/pull-up) at boot; held >=5s forces provisioning with 100ms status-LED blink; clears WiFi credentials first on an already-configured device (emergency reset). pumps_force_off() still first; hold loop bounded and only entered when pressed at boot. - WifiBootMode: pure shouldClearCredentialsOnBoot(credsPresent, buttonHeld) - host tests: no-boot-loop under permanent failure (800 rounds, bounded counters, never Connected/Provisioning), emergency-reset decision -> 176/0 - firmware/CLAUDE.md: reference the FR9 SoftAP-portal decision (specs/007-*) - HIL checklist specs/007-wifi-provisioning/checklists/hil.md for the rev1 rig Verified: host 176/0; rev1 1011536B (36% slot free) + rev2 1013920B (35% free), both board-config verified; dependencies.lock + esp-modbus pins unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…agnostics Addresses CP3 review findings (all verified, host 178/0, both boards green): - F1: WifiManager routes synchronous staConnect() failure through handleFailure so the reconnect cadence advances instead of wedging in Connecting forever - F4: handleFailure ignores stray failure events while ReconnectPaused (counter stays <= failuresBeforePause; 60s deadline not re-armed) - F3: EspWifiDriver::init() unwinds cleanly on event-handler registration failure (unregister handler, esp_wifi_deinit, delete queue) — no leak/dangling handler - F2: app_main gates provisioning AND station bring-up on WiFi-init success; wifi_manager stays null on failure (console reports 'not available') - F5: correct the WifiConnectionSnapshot concurrency comment (no mutex exists; single-writer + benign cross-task diagnostic read); TODO(PR-09) LockedWifiManager - F6: qualify credential-never-logged citations to (PR-06 FR-004) - M1: count + WARN dropped WiFi events (queue full drops the newest, corrected) - M2: log a terminal 'provisioning unavailable' line if AP/portal start fails - M3: distinct 400 for a missing ssid form field (vs length error) - host tests: synchronous-staConnect-failure cadence + paused-ignores-stray-disconnect Known minor (out of scope, pre-existing, bounded): STA/AP netifs are not destroyed on the init failure paths (idempotent once-called static; WiFi-unavailable outcome). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
PR-07 — WiFi provisioning & station management
Implements FR9 (provisioning) + the WiFi reliability NFR from the master PRD. Spec-kit
artifacts in
specs/007-wifi-provisioning/.What it does
device (empty SSID) boots into a WPA2 AP at 192.168.4.1 serving a minimal setup page on a
standalone
esp_http_server; valid SSID/password is persisted to NVS and the device restarts(~3 s) to apply.
wifi_provisioningis the documented re-escalation fallback (research R1).(10 s retry, +60 s pause after 5 consecutive failures, 5 s health monitor). Never reboots
(FR-013 — no boot loop).
credentials; a wrong password keeps retrying and stays provisionable.
WifiManager's constructor takes onlyIWifiDriver/IConfigStore/ITimeProvider/ReconnectPolicy— no watering reference — andruns on its own FreeRTOS task with no shared mutex; WiFi outages never touch watering.
Architecture
New
networkcomponent, split at theIWifiDriverseam (same pattern as the sensor drivers):WifiManagerstate machine,validateWifiCredentials,decideBootMode.EspWifiDriver(
esp_wifi/esp_netif/esp_event→WifiEventqueue) andProvisioningPortal.IConfigStorefor credentials (empty SSID = unconfigured; values never logged).app_mainaddsesp_netif_init()+esp_event_loop_create_default()after NVS;pumps_force_off()stays the first action.diag_consolegains awifistatus command.Verification
boot-mode truth table, credential validation, no-boot-loop (800 rounds), FR-014 isolation,
synchronous-staConnect-failure cadence, paused-ignores-stray-disconnect.
1.5 MB OTA slot).
dependencies.lockand bothesp-modbuspins unchanged. No frozen-legacy edits.Review (CP3)
Five specialist agents reviewed; all core invariants PASS. Findings F1–F6 + M1/M2/M3 fixed and
re-verified (see
docs/checkpoints/cp3-007-wifi-provisioning.md).Deferred (by design)
LockedWifiManager(cross-task snapshot) and type nice-to-haves → PR-09 (with the HTTPstatus reader).
specs/007-wifi-provisioning/checklists/hil.md) runs on the rev1 rig —includes config-button polarity (active-LOW, bench-verify) and the brownout watch (QUIRK 4).
🤖 Generated with Claude Code