Wi-Fi provisioning over BLE

Browse source code on GitHub

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 gatt_svc.h)

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

  1. Install nRF Connect for Mobile on Android or iOS.

  2. Open the app, tap Scan, and connect to the advertised device.

  3. Expand the custom service (base UUID 8b840001-f6fa-4e33-9a0c-e14d9f35f201).

  4. Write the SSID as UTF-8 bytes to the 0002 characteristic.

  5. Write the password to the 0003 characteristic.

  6. (Optional) Write the Security byte to the 0004 characteristic.

  7. (Optional) Enable notifications on the Status 0006 characteristic.

  8. Write 0x01 to the Control 0005 characteristic to request a Wi-Fi connect.

  9. Watch the serial console and the Status notifications transitioning through CONNECTING (2) and CONNECTED (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

See also

Bluetooth APIs
Wi-Fi Management
Wi-Fi credentials library