Wi-Fi provisioning over BLE
Overview
On first boot, the device advertises a custom GATT service that lets
a BLE central write the Wi-Fi SSID and pre-shared key. On a control
command the credentials are stored via the
Wi-Fi credentials Library library and the device joins the Wi-Fi
network using
NET_REQUEST_WIFI_CONNECT_STORED. On subsequent boots, the
stored credentials are used to reconnect automatically.
State machine
IDLE --(SSID + PSK + CONNECT)--> CONNECTING --> CONNECTED
\
--> FAILED
The control command ERASE clears stored credentials and returns
to IDLE.
GATT service
All characteristics share the custom 128-bit base UUID
8b84xxxx-f6fa-4e33-9a0c-e14d9f35f201 where the short identifier
replaces xxxx:
Char |
UUID |
Properties |
Payload |
|---|---|---|---|
SSID |
0002 |
write |
UTF-8, up to 32 bytes |
Password |
0003 |
write |
UTF-8, up to 64 bytes |
Security |
0004 |
write |
1 byte (optional, see table below) |
Control |
0005 |
write |
1 byte: 0x01 = CONNECT, 0x02 = ERASE |
Status |
0006 |
read, notify |
1 byte enum (see |
Security type values match wifi_security_type:
Byte |
Meaning |
|---|---|
0 |
Open (no password) |
1 |
WPA2-PSK |
2 |
WPA2-PSK-SHA256 |
3 |
WPA3-SAE |
6 |
WPA-Auto-Personal (WPA2/WPA3 transition) |
0xFF |
Auto-detect: open if PSK empty, otherwise WPA2-PSK (default) |
If the Security characteristic is not written, the device falls back
to 0xFF (auto-detect).
Requirements
A board with both Wi-Fi and Bluetooth LE support.
Building and Running
west build -b esp32c6_devkitc/esp32c6/hpcore samples/net/wifi/ble_provisioning
west flash
After flashing, the device starts advertising as
Zephyr Wi-Fi Provisioning (configurable through
CONFIG_BT_DEVICE_NAME).
Testing with nRF Connect Mobile
Install nRF Connect for Mobile on Android or iOS.
Open the app, tap Scan, and connect to the advertised device.
Expand the custom service (base UUID
8b840001-f6fa-4e33-9a0c-e14d9f35f201).Write the SSID as UTF-8 bytes to the
0002characteristic.Write the password to the
0003characteristic.(Optional) Write the Security byte to the
0004characteristic.(Optional) Enable notifications on the Status
0006characteristic.Write
0x01to the Control0005characteristic to request a Wi-Fi connect.Watch the serial console and the Status notifications transitioning through
CONNECTING(2) andCONNECTED(3).
To erase stored credentials, write 0x02 to the Control
characteristic.
Security
Three BLE security modes are selectable via a Kconfig choice:
- None (
CONFIG_WIFI_BLE_PROV_SECURITY_NONE, default) No pairing. Credentials travel in plaintext. Evaluation only.
- Encrypted link (
CONFIG_WIFI_BLE_PROV_SECURITY_ENCRYPT) Writes require an encrypted link. Pairing happens without user interaction; a passive eavesdropper cannot recover the credentials.
- Authenticated pairing (
CONFIG_WIFI_BLE_PROV_SECURITY_AUTH) Writes require authenticated LESC pairing with encryption. The device prints a 6-digit passkey on the console that the central must enter.
Stored credentials remain plaintext in NVS. For credential-at-rest
protection, switch the backend to
CONFIG_WIFI_CREDENTIALS_BACKEND_PSA or use vendor
NVS encryption.
Note
Switching security modes reuses the same NVS partition. Stored BLE
bonds from a previous build may log set-value failure warnings
on boot; erase flash (west flash --erase) when switching.
Sample Kconfig options
CONFIG_BT_DEVICE_NAME– Advertised device name.CONFIG_WIFI_BLE_PROV_KEEP_BLE_AFTER_CONNECT– Keep advertising after Wi-Fi is connected.CONFIG_WIFI_BLE_PROV_SECURITY_NONE/CONFIG_WIFI_BLE_PROV_SECURITY_ENCRYPT/CONFIG_WIFI_BLE_PROV_SECURITY_AUTH– BLE security mode for provisioning writes.
Sample output
*** Booting Zephyr OS build v4.4.0 ***
<inf> wifi_ble_prov: Wi-Fi BLE provisioning starting
<inf> wifi_ble_prov: security: none (plaintext)
<inf> gatt_svc: status -> 0
<inf> wifi_ble_prov: no stored credentials; waiting for provisioning over BLE
<inf> gatt_svc: advertising as 'Zephyr Wi-Fi Provisioning'
<inf> wifi_ble_prov: connected: 4F:0D:14:E8:76:98 (random)
<inf> wifi_prov: connecting using stored credentials
<inf> gatt_svc: status -> 2
<inf> wifi_prov: Wi-Fi connected
<inf> gatt_svc: status -> 3