thorrak/esp_wifi_config

0.3.1~1

Latest
uploaded 43 minutes ago
WiFi Config component with multi-network support, auto-reconnect, SoftAP captive portal, REST API, and ESP-IDF Network Provisioning over BLE

Readme

# ESP WiFi Config

[![Component Registry](https://components.espressif.com/components/thorrak/esp_wifi_config/badge.svg)](https://components.espressif.com/components/thorrak/esp_wifi_config)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Docs](https://img.shields.io/badge/docs-wificonfig.com-blue)](https://wificonfig.com)

WiFi configuration library for ESP-IDF and native Arduino-ESP32 with multi-network support, auto-reconnect, and multiple provisioning interfaces. The library supports four provisioning methods with an optional Serial CLI for debugging:

* Bluetooth (BLE) Provisionining
* SoftAP Provisioning
* Improv WiFi Serial
* Improv WiFi Bluetooth

These are provided "batteries included" with additional features such as:
* Multi-network store (optionally configure multiple networks at once)
* Auto-reconnect with exponential backoff
* Configurable logic when the chip is unable to connect to a saved network or is unexpectedly disconnected
* Configurable state machine that decides when each interface activates and shuts down

It's a one-stop shop: enable the channels you want at build time, fill in a `wifi_cfg_init()` struct, and the rest — captive portal popup, BLE pairing, credential storage, retries, reconnects, and teardown — is handled for you.

## Arduino

Native Arduino support is included in version **0.3.1**. Use the stock
Arduino-ESP32 3.3.11 board package
and open `examples/arduino/Basic`. See the [Arduino guide](website/docs/arduino.md)
for installation, build options, partition selection, and compatibility limits.
Optional NimBLE-Arduino support is available for both Espressif provisioning and
Improv BLE; see `NimBLEProvisioning` and `NimBLEImprov` in the Arduino examples.
On classic ESP32, matched hardware tests measured about 51–58 KiB more free RAM
while advertising and 429–434 KiB smaller firmware. S3 already uses SDK NimBLE
and showed no resource benefit from switching. See the
[measurements and test coverage](website/docs/arduino.md#nimble-arduino-measurements).

## Features

- **Four provisioning channels** plus a serial CLI, all sharing one config struct and one network store (see [Provisioning Methods](#provisioning-methods))
- **Multi-network storage** in NVS with priority-based connect order
- **Auto-reconnect** with exponential backoff and failover between saved networks
- **Provisioning lifecycle** — `ON_FAILURE` / `WHEN_UNPROVISIONED` / `MANUAL` start modes, configurable post-connect teardown delay, and three post-provisioning HTTP behaviours
- **Reboot on successful BLE provisioning** (default on) — sidesteps `wifi_prov_mgr`'s lack of a clean BLE-stack tear-down/rebuild path; opt out via `prov_ble.disable_reboot_on_provisioning_success`
- **Reconnect-exhaustion policy** — reboot after N failed reconnects, or retry indefinitely
- **Embedded Web UI** — responsive Preact frontend (~10 KB gzipped) served on the captive portal, or [bring your own](https://wificonfig.com/docs/guides/custom-webui)
- **REST API** with optional HTTP Basic Auth
- **Custom variable store** — application key/value settings flow through every provisioning interface
- **Event-driven** on ESP-IDF's default event loop under `WIFI_CFG_EVENT` (connected, disconnected, got IP, provisioning started/stopped)

**Targets:** ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2

## Provisioning Methods

All channels share the same multi-network store and lifecycle policy — enable any compatible combination you want at build time.

| Channel | How a user sets up the device | Typical client |
|---|---|---|
| **SoftAP + Captive Portal** | Phone or laptop joins the device's WiFi AP; the OS pops the configuration page automatically | Any web browser |
| **BLE** | Mobile app or CLI pairs over Bluetooth and pushes credentials | iOS/Android App (see below), `esp_prov` Python tool |
| **Improv WiFi** (BLE and Serial transports) | Open ESPHome standard over Web Bluetooth or Web Serial | [improv-wifi.com](https://www.improv-wifi.com/) in Chrome/Edge, ESPHome companion app |
| **Serial CLI** *(optional)* | Console commands (`wifi scan`, `wifi connect`, …) over UART | Any serial monitor |

The SoftAP + captive portal, Improv WiFi (both transports), Serial CLI, and REST API are implemented **inside this library** — they don't depend on any Espressif provisioning component. The **BLE** channel is built on top of Espressif's official `wifi_provisioning` component (`network_provisioning` on IDF 6.x) as its transport; see the next section for what that means in practice.

The two BLE channels (this library's BLE and Improv WiFi BLE) are mutually exclusive at compile time — they each want to own the BLE GAP advertising slot. Improv Serial is independent of BLE and can be combined with either - but is mutually exclusive with the Serial CLI. Soft AP can be enabled alongside any of the other options. 

## Compatibility with Espressif's Network Provisioning

Because the BLE channel uses **Espressif's `wifi_provisioning` component** as its transport, the on-the-wire protocol is the standard Espressif one:

- **Espressif-compatible clients work out of the box.** "ESP BLE Provisioning" mobile apps, the `esp_prov` Python tool in any ESP-IDF checkout, and the `esp-idf-provisioning-android` / `-ios` SDKs all pair with devices running this library.
- **Security 1 (PoP)** and **Security 2 (SRP6a)** handshakes are both supported. Set `prov_ble.pop` (Security 1) or `prov_ble.security2_salt` / `prov_ble.security2_verifier` (Security 2) in your `wifi_cfg_init()` call — the example uses `"abcd1234"` so Espressif's apps pair out of the box.
- The standard `prov-config` / `prov-scan` endpoints behave exactly as Espressif's clients expect.

See the [BLE Protocol Reference](website/docs/api/ble-protocol.md) for the five
library JSON extensions, and [BLE Wire Protocol](website/docs/api/ble-wire-protocol.md)
for transport, protobuf, and security implementation details.

What `wifi_provisioning` does on its own is hand a single set of credentials to `esp_wifi` once, over BLE (or SoftAP). It has no opinion about what happens before, after, or alongside that handoff. This library wraps `wifi_provisioning` for the BLE handshake and adds everything else:

| | Espressif `wifi_provisioning` alone | This library |
|---|---|---|
| BLE handshake + single credential transfer | ✅ | uses Espressif's |
| Multi-network store with priority and failover | — | ✅ |
| Auto-reconnect with exponential backoff | — | ✅ |
| Provisioning lifecycle state machine (when to start, when to tear down) | — | ✅ |
| Reconnect-exhaustion behaviour (reboot or indefinite retry) | — | ✅ |
| Automatic reboot after a successful BLE provisioning flow | — | ✅ |
| SoftAP + captive portal + embedded Web UI | — | ✅ |
| Improv WiFi (BLE + Serial) | — | ✅ |
| Serial CLI | — | ✅ |
| REST API with optional Basic Auth | — | ✅ |
| Custom application key/value store | — | ✅ (exposed via every interface, plus a custom protocomm endpoint over BLE) |
| Event-driven integration via `esp_event` | — | ✅ |

In short: if all you need is to hand off WiFi credentials once over BLE, Espressif's component on its own is enough. If you want a device that remembers multiple networks, decides on its own when to reopen provisioning, exposes the same configuration over a captive portal and serial console, and emits events your application can react to — that's the rest of this library.

### iOS "ESP BLE Provisioning" app — "Encrypted Communication" toggle

Espressif's iOS "ESP BLE Provisioning" app hides a setting that is **not auto-negotiated** with the device. From the device-list screen, tap the gear icon in the upper-left to reach Settings. The **"Encrypted Communication"** toggle has two states:

- **Off ("Unsecured")** — the app speaks plaintext protocomm. This is the mode required by devices built with `.prov_ble.security = WIFI_CFG_PROV_SECURITY_0`.
- **On ("Secured")** — the app uses Security 2 (SRP6a) and prompts for a username when it connects. The device must advertise `sec_ver=2` (i.e. be built with `WIFI_CFG_PROV_SECURITY_2` and a valid salt/verifier pair).

The toggle does not adjust itself based on what the device advertises, and the app gives no in-app hint that it exists. A Security 0 device opened from the app while the toggle is in "Secured" mode will simply hang after the device is tapped — no PoP prompt appears and no progress is shown. Set the toggle to match your firmware's `.prov_ble.security` value before pairing.

The interaction between this toggle and Security 1 (PoP) has not been confirmed; see [BLE Provisioning docs](https://wificonfig.com/docs/provisioning/ble-gatt#ios-esp-ble-provisioning-app-encrypted-communication-toggle) for details as they become available.

### NimBLE reconnect workaround

ESP-IDF 5.5.3's NimBLE host has a bug where only the **first** BLE client to connect after boot can complete a provisioning session — subsequent reconnects accept at the link layer but then time out at supervision, and the wedged state only clears on a full reboot. The bug reproduces deterministically with both the Espressif iOS app and `esp_prov`.

This library works around the issue by tearing down and re-initialising the provisioning manager whenever a BLE client disconnects before credentials have been delivered. Most of the time this is invisible — clients reconnect successfully on retry. There is a sub-second window during the restart where a fresh connect attempt can still fail; clients that auto-retry (or the Espressif apps' user-driven retry) work through it.

Set `wifi_cfg_prov_config_t.disable_disconnect_restart = true` to opt out (intended for debugging the underlying IDF bug or for apps that need to drive the stop/restart sequence themselves).

### ESP-IDF 5.5.3 — Wi-Fi scan drops the BLE link on classic ESP32

ESP-IDF **5.5.3** shipped a NimBLE **host flow-control** regression ([IDFGH-17350](https://github.com/espressif/esp-idf/issues/18323)) that can cause connection loss on the **classic ESP32**. The relevant option, `CONFIG_BT_NIMBLE_HS_FLOW_CTRL`, is `default y if IDF_TARGET_ESP32` (and `default n` on the ESP32-C3/S3, which is why those targets are unaffected). The bug stalls the host's BLE data path under load (e.g. during the scan of Wi-Fi networks during provisioning) and drops the link.

Fix, in order of preference:

1. **Build against ESP-IDF 5.5.4 or newer.** The 5.5.4 release notes list it fixed: *"Fixed the issue of potential NimBLE host connection loss in ESP-IDF v5.5.3 release on ESP32 / ESP32C3 / ESP32S3."* No project changes needed.
2. **If you must stay on 5.5.3**, disable host flow control in your project's `sdkconfig.defaults`:

   ```
   CONFIG_BT_NIMBLE_HS_FLOW_CTRL=n
   ```

   The library **enforces** this at build time: compiling the BLE provisioning backend on ESP-IDF 5.5.3 with `CONFIG_BT_NIMBLE_HS_FLOW_CTRL` still enabled raises a `#error` pointing here.

### Reboot after successful BLE provisioning

The library enables automatic reboot by default to avoid BLE/Wi-Fi handoff
failures seen with Espressif's SDK provisioning stack. Native Arduino now has
tested provisioning and repeated `begin()` / `end()` without rebooting, including
NimBLE-Arduino; applications choosing that lifecycle can set
`prov_ble.disable_reboot_on_provisioning_success=true`. See the
[Arduino ownership and cleanup limits](website/docs/arduino.md#nimble-arduino).

The reboot fires on whichever happens first:

1. While the provisioning manager is active, the BLE client disconnecting after `WIFI_PROV_EVT_CRED_RECV`. Credentials have been received at this point; Wi-Fi connection is not necessarily confirmed.
2. A backstop timer set on `WIFI_PROV_EVT_CRED_SUCCESS` — default 15000 ms, configurable via `prov_ble.reboot_max_wait_ms`.

Defaults are designed so most apps need no extra configuration. The relevant fields on `wifi_cfg_prov_config_t`:

```c
.prov_ble = {
    // Default: reboot enabled (false → reboot on).
    // Set true ONLY if the app handles the BLE / Wi-Fi handoff itself.
    .disable_reboot_on_provisioning_success = false,
    .reboot_max_wait_ms = 15000,  // 0 → 15000 ms; ignored if reboot disabled
}
```

The backstop must comfortably exceed the client's status-poll interval
(Espressif's ESPProvision SDK polls every ~5 s) plus the time to associate and
get an IP, or the device can reboot in the gap between two polls and the client
reports a false failure.

If your application does significant work in the `WIFI_CFG_EVENT_PROV_CRED_SUCCESS` handler, finish that work before the callback returns (it runs before the reboot) — or extend `reboot_max_wait_ms`. Anything that must persist across the reboot needs to land in NVS first.

`prov_ble.stop_after_success` is bypassed while reboot-on-success is active.
The separate `stop_provisioning_on_connect` / `provisioning_teardown_delay_ms`
lifecycle still schedules interface shutdown after the station gets an IP,
including BLE, so the backstop does not guarantee 15 seconds of endpoint access.
If BLE drops before a client confirms Connected, the outcome is unconfirmed;
verify through an application-specific LAN/status check before reporting success.

## Quick Start

Add to `main/idf_component.yml`:

```yaml
dependencies:
  thorrak/esp_wifi_config: "*"
```

```c
#include "esp_wifi_config.h"
#include "nvs_flash.h"

void app_main(void)
{
    nvs_flash_init();

    // Always start from WIFI_CFG_DEFAULTS. wifi_cfg_init() does not patch
    // fields you leave at zero, so a config built without it is rejected
    // (zero retry interval) or silently never reconnects.
    wifi_cfg_init(&(wifi_cfg_config_t){
        WIFI_CFG_DEFAULTS,
        .default_networks = (wifi_network_t[]){
            {"MyWiFi", "password", 10},
        },
        .default_network_count = 1,
        .stop_provisioning_on_connect = true,
        .enable_ap = true,
    });

    wifi_cfg_wait_connected(30000);
}
```

`provisioning_mode` defaults to `WIFI_PROV_ON_FAILURE`, so the AP and HTTP
server come up when no networks are saved or every saved network fails.
`wifi_cfg_init(NULL)` uses the defaults unmodified.

## Examples

| Example | Description |
|---------|-------------|
| [basic](examples/basic/) | Minimal setup with REST API and captive portal |
| [with_cli](examples/with_cli/) | Serial console CLI interface |
| [with_webui](examples/with_webui/) | Embedded Web UI |
| [with_webui_customize](examples/with_webui_customize/) | Custom frontend from LittleFS |
| [with_ble](examples/with_ble/) | BLE provisioning (on top of Espressif's `wifi_prov_mgr`) |
| [with_ble_deinit](examples/with_ble_deinit/) | Improv BLE host-stack handoff to the application |
| [with_improv](examples/with_improv/) | Improv WiFi (Web Bluetooth / Web Serial) |

## Documentation

Full documentation is available at **[wificonfig.com](https://wificonfig.com)**:

- [esp_bus Migration](ESP_BUS_MIGRATION.md) — quick reference for apps upgrading off the event bus
- [Getting Started](https://wificonfig.com/docs/getting-started) — Installation and first project
- [Provisioning Modes](https://wificonfig.com/docs/provisioning/modes) — Control when AP/BLE/Improv activate
- [API Reference](https://wificonfig.com/docs/api/c-api) — C API, REST API, BLE protocol, CLI
- [Examples](https://wificonfig.com/docs/examples) — Complete example walkthroughs

### AI-Friendly Docs

Point your AI coding assistant at [`wificonfig.com/llms.txt`](https://wificonfig.com/llms.txt) for machine-readable documentation, or see the [AI Integration Guide](https://wificonfig.com/docs/ai-integration-guide) for scenario-based recipes.

## Dependencies

- ESP-IDF >= 5.4
  ESP-IDF 6.x is supported via `idf_component.yml`'s automatic switch to
  `espressif/network_provisioning`.

## Acknowledgments

Based on the original [esp_wifi_manager](https://github.com/tuanpmt/esp_wifi_manager) by [tuanpmt](https://github.com/tuanpmt).

## License

MIT License — see [LICENSE](LICENSE).

Links

Maintainer

  • thorrak
To add this component to your project, run:

idf.py add-dependency "thorrak/esp_wifi_config^0.3.1~1"

download archive

Stats

  • Archive size
    Archive size ~ 636.76 KB
  • Downloaded in total
    Downloaded in total 80 times
  • Weekly Downloads Weekly Downloads (All Versions)
  • Downloaded this version
    This version: 0 times

Badge

thorrak/esp_wifi_config version: 0.3.1~1
|