Skip to content

feat(wifi): SoftAP captive-portal Wi-Fi provisioning (Phase 7b) - #3

Merged
RndmCodeGuy20 merged 1 commit into
mainfrom
feat/phase7b-softap-provisioning
Aug 4, 2026
Merged

feat(wifi): SoftAP captive-portal Wi-Fi provisioning (Phase 7b)#3
RndmCodeGuy20 merged 1 commit into
mainfrom
feat/phase7b-softap-provisioning

Conversation

@RndmCodeGuy20

Copy link
Copy Markdown
Owner

Summary

  • Adds SoftAP captive-portal Wi-Fi provisioning: with no reachable network, the device comes up as its own open AP (edge-dns-setup), redirects any joined client to a scan-and-password form via a minimal captive DNS responder, and reboots into station mode once provisioned.
  • Wi-Fi config now lives in esp_wifi's own NVS storage (nvs.net80211) instead of the hardcoded wifi_credentials.h pair — that header is demoted to a first-boot seed only, mirroring the dns_records.h/DNS_RECORDS_DEFAULTS demotion from Phase 5.
  • A boot-time STA connect now times out after 30s (previously blocked forever) and falls back to the provisioning portal without erasing stored credentials, so a merely-rebooting router recovers on its own next cycle.
  • Factory reset: holding GPIO0 (BOOT) ~5s wipes stored Wi-Fi config and reboots into the portal — the recovery path for a wrong password with no cable handy.
  • Deliberately diverges from the original roadmap sketch on two points (documented in the design plan): credentials use esp_wifi's own NVS rather than a hand-rolled namespace, and the captive DNS responder is its own small loop rather than a mode flag threaded through dns_server.cpp's hot query path.

Test plan

  • idf.py build — firmware builds clean, signed mini_dns.bin produced
  • host_test — 47/47 Unity tests pass (24 dns_wire + 13 ota_version + 10 new provision_validate boundary cases)
  • Two-axis code review (Standards + Spec, parallel sub-agents) run against the diff; findings addressed — added a default: case to the ProvisionValidation switch, added an esp_wifi_stop() guard before reconfiguring an already-started Wi-Fi stack on the STA-timeout fallback path
  • Hardware verification — not done, no ESP32 board attached this session. Everything below the host-test line (DHCP DNS-offer behavior, real captive-portal OS probe redirection, GPIO0 factory-reset timing) needs a real device before merge is treated as field-verified.
idf.py -p <PORT> erase-flash flash monitor
# join "edge-dns-setup" from a phone -> portal should appear unprompted
curl http://192.168.4.1/scan
dig @192.168.4.1 anything.example            # expect 192.168.4.1
curl -X POST -H 'Content-Type: application/json' -d '{"ssid":"<net>","password":"<pw>"}' http://192.168.4.1/provision
# device reboots into STA; then hold BOOT 5s -> comes back as edge-dns-setup

- Add wifi_provision.cpp/.h: open AP edge-dns-setup, captive DNS
  responder, and /scan + /provision + wildcard portal httpd
- Add provision_validate.cpp/.h: pure SSID/password validation
  against 802.11/WPA2-PSK limits, host-tested
- Refactor wifi_connect() into wifi_connect_sta(): read/write Wi-Fi
  config via esp_wifi's own NVS storage instead of hardcoded
  credentials, seed from wifi_credentials.h only on first boot
- Add 30s connect timeout that falls back to the provisioning portal
  without erasing stored credentials
- Add factory_reset_watch_start(): GPIO0/BOOT hold (~5s) wipes stored
  Wi-Fi config and reboots into provisioning
- Wire the boot branch in main.cpp: provisioned+connected starts the
  DNS/HTTP/mDNS/OTA tasks as before, otherwise starts the portal
- Update ARCHITECTURE.md and README.md for the new boot flow,
  provisioning walkthrough, and no-auth-by-design portal routes
@RndmCodeGuy20
RndmCodeGuy20 merged commit d24761e into main Aug 4, 2026
3 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.

1 participant