uploaded 1 hour ago
WiFi Manager component with multi-network support, auto-reconnect, SoftAP captive portal, and REST API configuration

readme

# ESP WiFi Manager

[![Component Registry](https://components.espressif.com/components/tuanpmt/esp_wifi_manager/badge.svg)](https://components.espressif.com/components/tuanpmt/esp_wifi_manager)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

WiFi Manager component for ESP-IDF with multi-network support, auto-reconnect, SoftAP captive portal, Web UI, CLI, and REST API.

## Features

- **Multi-network support**: Save multiple WiFi networks with priority-based auto-connect
- **Auto-reconnect**: Automatic retry with exponential backoff and failover between saved networks
- **SoftAP mode**: Captive portal for initial configuration (triggers OS popup)
- **Web UI**: Embedded responsive web interface (Preact-based, ~10KB gzipped)
- **CLI interface**: Serial console commands for configuration
- **REST API**: HTTP endpoints for remote configuration with CORS support
- **Basic Auth**: Optional authentication for HTTP endpoints
- **mDNS**: Access device via hostname (e.g., `esp32-abc123.local`)
- **Custom variables**: Key-value storage for application settings
- **NVS persistence**: Networks, variables, and AP config stored in flash
- **esp_bus integration**: Event-driven architecture with actions and events

## Architecture

```
┌──────────────────────────────────────────────────────────────────────┐
│                        ESP_WIFI_MANAGER                              │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  WiFi Core                    │  NVS Storage                   │  │
│  │  ─────────                    │  ───────────                   │  │
│  │  • Multi-network              │  • Saved networks              │  │
│  │  • Auto retry + backoff       │  • AP configuration            │  │
│  │  • Reconnect logic            │  • Custom variables            │  │
│  │  • Captive portal + DNS       │                                │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                                                      │
│  ┌─────────────── Configuration Interfaces ───────────────────────┐  │
│  │                                                                │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐       │  │
│  │  │  Web UI  │  │   HTTP   │  │   CLI    │  │   mDNS   │       │  │
│  │  │ (Preact) │  │   API    │  │ (Console)│  │          │       │  │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────┘       │  │
│  │       │              │             │             │            │  │
│  │       └──────────────┴─────────────┴─────────────┘            │  │
│  │                              │                                │  │
│  │                              ▼                                │  │
│  │                 ┌─────────────────────────┐                   │  │
│  │                 │  WiFi Manager Core API  │                   │  │
│  │                 └─────────────────────────┘                   │  │
│  └────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────┘
         │                              │
         │ events                       │ requests
         ▼                              ▼
┌──────────────────────────────────────────────────────────────────────┐
│                             ESP_BUS                                  │
└──────────────────────────────────────────────────────────────────────┘
```

## Installation

### Using ESP-IDF Component Manager (Recommended)

Add to your project's `idf_component.yml`:

```yaml
dependencies:
  tuanpmt/esp_wifi_manager: "*"
```

### Manual Installation

Clone into your project's `components/` directory:

```bash
cd components
git clone https://github.com/tuanpmt/esp_wifi_manager.git
```

## Quick Start

```c
#include "esp_wifi_manager.h"
#include "esp_bus.h"
#include "nvs_flash.h"

void app_main(void)
{
    // Initialize NVS (required)
    nvs_flash_init();

    // Initialize esp_bus (required before wifi_manager_init)
    esp_bus_init();

    // Subscribe to WiFi events (optional)
    esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_CONNECTED), on_connected_cb, NULL);
    esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_GOT_IP), on_got_ip_cb, NULL);

    // Initialize WiFi Manager
    wifi_manager_init(&(wifi_manager_config_t){
        .default_networks = (wifi_network_t[]){
            {"HomeWifi", "password123", 10},   // priority 10 (highest)
            {"OfficeWifi", "office456", 5},    // priority 5 (fallback)
        },
        .default_network_count = 2,

        // Enable HTTP REST API
        .http = {
            .enable = true,
            .api_base_path = "/api/wifi",
        },

        // Enable captive portal if no networks available
        .enable_captive_portal = true,
    });

    // Wait for connection (30 second timeout)
    if (wifi_manager_wait_connected(30000) == ESP_OK) {
        ESP_LOGI(TAG, "WiFi connected!");
    }
}
```

## Examples

| Example | Description |
|---------|-------------|
| [basic](examples/basic/) | Minimal setup with default configuration |
| [with_cli](examples/with_cli/) | CLI interface with ESP Console REPL |
| [with_webui](examples/with_webui/) | Embedded Web UI (no external files needed) |
| [with_webui_customize](examples/with_webui_customize/) | Custom frontend from LittleFS |

## Configuration

### Kconfig Options

Configure via `idf.py menuconfig` → WiFi Manager:

| Option | Default | Description |
|--------|---------|-------------|
| `WIFI_MGR_MAX_NETWORKS` | 5 | Maximum saved networks |
| `WIFI_MGR_MAX_VARS` | 10 | Maximum custom variables |
| `WIFI_MGR_DEFAULT_RETRY` | 3 | Retries per network |
| `WIFI_MGR_RETRY_INTERVAL_MS` | 5000 | Base retry interval (ms) |
| `WIFI_MGR_AP_SSID` | "ESP32-Config" | Default AP SSID |
| `WIFI_MGR_AP_PASSWORD` | "" | Default AP password |
| `WIFI_MGR_AP_IP` | "192.168.4.1" | Default AP IP |
| `WIFI_MGR_MDNS_HOSTNAME` | "esp32-{id}" | mDNS hostname template |
| `WIFI_MGR_ENABLE_CLI` | n | Enable CLI interface |
| `WIFI_MGR_ENABLE_WEBUI` | n | Enable embedded Web UI |
| `WIFI_MGR_WEBUI_CUSTOM_PATH` | "" | Custom Web UI path (LittleFS/SPIFFS) |

### Runtime Configuration

```c
wifi_manager_config_t config = {
    // Default networks (fallback if NVS empty)
    .default_networks = networks,
    .default_network_count = 2,

    // Default variables
    .default_vars = (wifi_var_t[]){
        {"server_url", "https://api.example.com"},
        {"device_name", "my-device"},
    },
    .default_var_count = 2,

    // Retry config with exponential backoff
    .max_retry_per_network = 3,
    .retry_interval_ms = 5000,      // Base interval
    .retry_max_interval_ms = 60000, // Max backoff
    .auto_reconnect = true,

    // SoftAP config (supports {id} placeholder for MAC suffix)
    .default_ap = {
        .ssid = "MyDevice-{id}",
        .password = "",
        .ip = "192.168.4.1",
    },
    .enable_captive_portal = true,
    .stop_ap_on_connect = true,

    // HTTP interface
    .http = {
        .enable = true,
        .api_base_path = "/api/wifi",
        .enable_auth = true,
        .auth_username = "admin",
        .auth_password = "secret",
    },

    // mDNS (supports {id} placeholder)
    .mdns = {
        .enable = true,
        .hostname = "esp32-{id}",
    },
};

wifi_manager_init(&config);
```

## C API Reference

```c
// Initialization
esp_err_t wifi_manager_init(const wifi_manager_config_t *config);
esp_err_t wifi_manager_deinit(void);

// Status
bool wifi_manager_is_connected(void);
wifi_state_t wifi_manager_get_state(void);
esp_err_t wifi_manager_get_status(wifi_status_t *status);
esp_err_t wifi_manager_wait_connected(uint32_t timeout_ms);

// Connection
esp_err_t wifi_manager_connect(const char *ssid);  // NULL for auto-connect
esp_err_t wifi_manager_disconnect(void);
esp_err_t wifi_manager_scan(wifi_scan_result_t *results, size_t max, size_t *count);

// Network management
esp_err_t wifi_manager_add_network(const wifi_network_t *network);
esp_err_t wifi_manager_update_network(const wifi_network_t *network);
esp_err_t wifi_manager_remove_network(const char *ssid);
esp_err_t wifi_manager_list_networks(wifi_network_t *networks, size_t max, size_t *count);

// SoftAP
esp_err_t wifi_manager_start_ap(const wifi_mgr_ap_config_t *config);
esp_err_t wifi_manager_stop_ap(void);
esp_err_t wifi_manager_get_ap_status(wifi_ap_status_t *status);

// Custom variables
esp_err_t wifi_manager_set_var(const char *key, const char *value);
esp_err_t wifi_manager_get_var(const char *key, char *value, size_t max_len);
esp_err_t wifi_manager_del_var(const char *key);

// Factory reset
esp_err_t wifi_manager_factory_reset(void);

// Shared HTTP server (for adding custom endpoints)
httpd_handle_t wifi_manager_get_httpd(void);
```

## esp_bus Integration

**Events (pub/sub):**

```c
void on_connected(const char *event, const void *data, size_t len, void *ctx) {
    wifi_connected_t *info = (wifi_connected_t *)data;
    ESP_LOGI(TAG, "Connected to %s, RSSI: %d", info->ssid, info->rssi);
}

esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_CONNECTED), on_connected, NULL);
esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_DISCONNECTED), on_disconnected, NULL);
esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_GOT_IP), on_got_ip, NULL);
esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_SCAN_DONE), on_scan_done, NULL);
esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_NETWORK_ADDED), on_network_added, NULL);
esp_bus_sub(WIFI_EVT(WIFI_MGR_EVT_VAR_CHANGED), on_var_changed, NULL);
```

## CLI Commands

Enable with `CONFIG_WIFI_MGR_ENABLE_CLI=y`:

| Command | Description |
|---------|-------------|
| `wifi status` | Show connection status |
| `wifi scan` | Scan available networks |
| `wifi list` | List saved networks |
| `wifi add <ssid> [password] [priority]` | Add network |
| `wifi del <ssid>` | Remove network |
| `wifi connect [ssid]` | Connect (auto or specific) |
| `wifi disconnect` | Disconnect |
| `wifi ap start` | Start SoftAP |
| `wifi ap stop` | Stop SoftAP |
| `wifi reset` | Factory reset |
| `wifi var get <key>` | Get variable |
| `wifi var set <key> <value>` | Set variable |

## REST API Reference

Base URL: `http://<device-ip>/api/wifi` (configurable via `api_base_path`)

### Authentication

If `enable_auth = true`, all endpoints require Basic Auth:

```bash
curl -u admin:password http://192.168.4.1/api/wifi/status
```

### Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/status` | Get connection status |
| GET | `/scan` | Scan available networks |
| GET | `/networks` | List saved networks |
| POST | `/networks` | Add new network |
| PUT | `/networks/:ssid` | Update network |
| DELETE | `/networks/:ssid` | Remove network |
| POST | `/connect` | Connect (auto or specific SSID) |
| POST | `/disconnect` | Disconnect |
| GET | `/ap/status` | Get AP status |
| GET | `/ap/config` | Get AP configuration |
| PUT | `/ap/config` | Update AP configuration |
| POST | `/ap/start` | Start SoftAP |
| POST | `/ap/stop` | Stop SoftAP |
| GET | `/vars` | List custom variables |
| PUT | `/vars/:key` | Set variable |
| DELETE | `/vars/:key` | Delete variable |
| POST | `/factory_reset` | Factory reset |

### Example Requests

```bash
# Get status
curl http://192.168.4.1/api/wifi/status

# Scan networks
curl http://192.168.4.1/api/wifi/scan

# Add network
curl -X POST http://192.168.4.1/api/wifi/networks \
  -H "Content-Type: application/json" \
  -d '{"ssid": "MyWiFi", "password": "secret123", "priority": 10}'

# Connect to specific network
curl -X POST http://192.168.4.1/api/wifi/connect \
  -H "Content-Type: application/json" \
  -d '{"ssid": "MyWiFi"}'

# Auto-connect (highest priority)
curl -X POST http://192.168.4.1/api/wifi/connect

# Delete network
curl -X DELETE http://192.168.4.1/api/wifi/networks/MyWiFi

# Set custom variable
curl -X PUT http://192.168.4.1/api/wifi/vars/device_name \
  -H "Content-Type: application/json" \
  -d '{"value": "Living Room"}'
```

### Response Examples

**GET /status**
```json
{
  "state": "connected",
  "ssid": "MyWiFi",
  "ip": "192.168.1.100",
  "gateway": "192.168.1.1",
  "netmask": "255.255.255.0",
  "dns": "192.168.1.1",
  "rssi": -65,
  "quality": 70,
  "channel": 6,
  "mac": "AA:BB:CC:DD:EE:FF",
  "hostname": "esp32-aabbcc",
  "uptime_ms": 123456,
  "ap_active": false
}
```

**GET /scan**
```json
{
  "networks": [
    {"ssid": "MyWiFi", "rssi": -65, "auth": "WPA2"},
    {"ssid": "Neighbor", "rssi": -80, "auth": "WPA/WPA2"},
    {"ssid": "OpenNet", "rssi": -70, "auth": "OPEN"}
  ]
}
```

**GET /ap/status**
```json
{
  "active": true,
  "ssid": "ESP32-AABBCC",
  "ip": "192.168.4.1",
  "channel": 1,
  "sta_count": 2,
  "clients": [
    {"mac": "AA:BB:CC:DD:EE:01", "ip": "192.168.4.2"},
    {"mac": "AA:BB:CC:DD:EE:02", "ip": "192.168.4.3"}
  ]
}
```

### Error Responses

```json
{"error": "Error message"}
```

| HTTP Code | Description |
|-----------|-------------|
| 400 | Bad Request - Invalid JSON, missing field |
| 401 | Unauthorized - Auth required |
| 404 | Not Found - Network/Variable does not exist |
| 500 | Internal Error - Operation failed |

## Connection Flow

```
boot → load saved networks → try connect →
  ├── success → emit CONNECTED event → emit GOT_IP event
  └── fail all → start captive portal (if enabled)

Auto-connect logic:
1. Load saved networks from NVS (sorted by priority DESC)
2. For each network:
   a. Try connect (max_retry_per_network times)
   b. Exponential backoff between retries
   c. If success → done
   d. If fail → try next network
3. If all fail and captive_portal enabled → start AP
4. If connected and disconnected → auto-reconnect if enabled
```

## Captive Portal

When no networks are configured or all connections fail, the device starts a SoftAP with captive portal:

1. Connect to AP (e.g., "ESP32-AABBCC")
2. OS automatically opens captive portal popup
3. Configure WiFi via Web UI or REST API
4. Device connects and AP stops (if `stop_ap_on_connect = true`)

Supported captive portal detection:
- Android: `/generate_204`, `/gen_204`
- iOS/macOS: `/hotspot-detect.html`
- Windows: `/ncsi.txt`, `/connecttest.txt`
- Firefox: `/success.txt`, `/canonical.html`

## Dependencies

- ESP-IDF >= 5.0.0
- [esp_bus](https://components.espressif.com/components/tuanpmt/esp_bus) - Event bus component
- cJSON - JSON parsing (included in ESP-IDF)
- mbedTLS - Base64 for Basic Auth (included in ESP-IDF)

## License

MIT License - see [LICENSE](LICENSE) file.

Links

Maintainer

  • tuanpmt

License: MIT

To add this component to your project, run:

idf.py add-dependency "tuanpmt/esp_wifi_manager^1.0.0"

download archive

Stats

  • Archive size
    Archive size ~ 20.74 MB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

tuanpmt/esp_wifi_manager version: 1.0.0
|