Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
provision32
A configurable ESP32 WiFi captive-portal provisioning library in Rust.
- Brings up an open AP (customizable name) with DHCP + DNS hijack, so any device that joins is redirected to a provisioning page.
- Serves a captive-portal form (Chinese / English UI) listing nearby WiFi networks in a dropdown.
- Receives the chosen SSID + password, persists it to Flash (survives power loss) and verifies it by switching to STA mode.
- On the next boot, if valid credentials are stored, the device auto-connects in pure STA mode and never opens the AP again.
The UI strings are gated behind the i18n-zh / i18n-en cargo features, so
you only pay for the languages you actually ship (smaller .rodata).
Features
| Feature | Description |
|---|---|
| Configurable AP name | ProvisionConfig::with_ap_ssid("MyDevice-Setup") |
| Chinese / English UI | Lang::Chinese / Lang::English (feature-gated) |
| Custom gateway IP | default 192.168.4.1/24 |
| Custom storage address | Flash offset, default 0x9000 |
| Tunable timeouts / retries | connect timeout, retries, wait duration |
| Captive-portal compatible | works with Android / iOS / Windows / macOS probes |
| Credential persistence | written to Flash via esp_storage, auto-reconnect on boot |
Cargo features
| Feature | Default | Effect |
|---|---|---|
i18n-zh |
yes | Compile the Simplified-Chinese portal / pending pages |
i18n-en |
yes | Compile the English portal / pending pages |
Disable a language to drop its static strings from flash, e.g. ship English only:
[]
= { = "0.2", = false, = ["i18n-en"] }
Lang always exists as the public API; when only one language is compiled the
other variant is unavailable and the page is fixed at compile time (no runtime
branch, no wasted .rodata).
Quick start (see examples/basic.rs)
use ;
esp_app_desc!;
async !
Public API
Configuration: ProvisionConfig
let cfg = default
.with_ap_ssid // AP name (default "ESP32配网页面")
.with_gw_ip // gateway IP (default 192.168.4.1)
.with_store_addr // Flash storage offset
.with_lang // UI language
.with_wait_before_connect // seconds to wait after password received
.with_connect_timeout // per-attempt STA connect timeout (s)
.with_connect_retries // connect retry count
.with_http_workers; // HTTP worker task count
Convenience functions
| Function | Purpose |
|---|---|
start_wifi(wifi, &cfg) |
Start WiFi in AP+STA mode, returns (controller, interfaces) |
run(spawner, controller, interfaces, cfg) -> Stack |
Start the full provisioning stack (AP/DHCP/DNS/HTTP + auto-reconnect) and return the live Stack — main entry (does not block) |
load_credentials(&cfg) |
Read saved credentials (ssid, password), None if absent |
store_credentials(&cfg, ssid, password) |
Write credentials to Flash |
try_auto_connect(&mut controller, &cfg, ssid, password) |
Connect in STA-only mode, returns true on success |
connection_state() |
Async query of the current ConnectionState (provisioning / connecting / connected / failed) |
Lang::from_hint("en") |
Pick language from a hint string |
Connection state
The library tracks its progress in a shared ConnectionState, which you can
poll from your own task to drive an LED, a display, or logging:
match connection_state.await
Note: the internal channel (
CONNECT_CH), WiFi-list types, and a few parsing helpers are intentionally not public — only the items documented above form the stable API surface.
Internal helpers (for custom pages)
render_portal(&cfg, &wifi_list)— build the portal HTMLrender_pending(&cfg, ssid)— build the "password received" pageparse_form(body)/urldecode(s)— parse the formwifi_list_options(&list)— build<option>entriesmk_static!(T, val)— convenience macro for astaticcell
Workflow
- First boot (no credentials): open AP
ESP32配网页面; once a phone joins, any URL is DNS-hijacked tohttp://192.168.4.1/. - User action: pick WiFi from the dropdown and enter the password, submit.
- Verify: after submit the "password received" page shows (~25s), and the ESP32 verifies the password in STA mode in the background.
- Success: credentials are saved to Flash, software reset → next boot auto-connects in pure STA mode, AP never appears again.
- Failure: the AP re-opens so the user can retry.
Build & flash
Requires the esp toolchain (nightly) and target xtensa-esp32-none-elf, with
xtensa-esp-elf-gcc on your PATH:
$env:PATH = 'f:\Arduino\xtensa-esp-elf\xtensa-esp-elf\bin;' + $env:PATH
cargo build --release
cargo espflash flash --release
To shrink flash by dropping a language:
cargo build --release --no-default-features --features i18n-en
Configuration is already included in .cargo/config.toml (build-std +
linkall.x) and rust-toolchain.toml (channel = "esp").
Examples
examples/basic.rs— minimal firmware wiring the library to a real ESP32.
Dependencies
esp-hal/esp-radio(WiFi) /esp-storage(Flash persistence)embassy-net,embassy-executor,embassy-syncedge-dhcp,edge-nal,edge-nal-embassy(DHCP server)static_cell,heapless,embedded-io-async