A Flutter plugin that simplifies provisioning ESP32 modules over Bluetooth Low Energy (BLE).
It is transport-agnostic: you implement a thin ProvTransport with the BLE package of your choice (the example uses flutter_blue_plus), and the plugin handles the secure handshake, Wi-Fi scanning, credential delivery and status reporting on top of Espressif's protocomm protocol.
- Secure session establishment with Security 1 (Curve25519 key exchange + AES-CTR) using a Proof-of-Possession (PoP).
- Scan the Wi-Fi networks visible to the device, with SSID, RSSI, BSSID and whether the network is secured.
- Send Wi-Fi credentials and apply them, optionally targeting a specific access point by BSSID.
- Query the provisioning status, including the assigned device IP and the failure reason.
- Exchange arbitrary custom data over the encrypted session.
- Transport-agnostic: bring your own BLE stack by implementing
ProvTransport.
| Platform | Support |
|---|---|
| Android | ✅ |
| iOS | ✅ |
The plugin logic is pure Dart on top of your ProvTransport, so the platform reach is ultimately bounded by the BLE package you plug in.
- Features
- Supported platforms
- Installation
- Getting started
- Security
- Protocol communication overview
- Comparison
- Changelog
- Contributing
- Credits
- License
Add the package with:
flutter pub add esp_provisioning_bleOr add it to your pubspec.yaml manually and run flutter pub get:
dependencies:
esp_provisioning_ble: ^1.0.0The package exposes an abstract ProvTransport class that you implement with your preferred Bluetooth package. The example provides a TransportBLE implementation built on flutter_blue_plus. A legacy example using flutter_ble_lib_ios_15 is available in example_legacy.
The snippets below are plain Dart, so they fit any state-management approach.
EspProv takes a transport (any ProvTransport) and a security (any ProvSecurity; the package ships Security1, which carries the Proof-of-Possession).
final prov = EspProv(
transport: TransportBLE(peripheral),
security: Security1(pop: pop),
);Call establishSession to run the secure handshake. It returns an EstablishSessionStatus:
connected: the session was established successfully.disconnected: the connection to the device dropped.keymismatch: the Proof-of-Possession (PoP) is incorrect.
final status = await prov.establishSession();
switch (status) {
case EstablishSessionStatus.connected:
// Ready to scan and send Wi-Fi credentials.
break;
case EstablishSessionStatus.disconnected:
// Handle the dropped connection.
break;
case EstablishSessionStatus.keymismatch:
// Wrong Proof-of-Possession.
break;
}Once the session is established establishSession is idempotent, so you can call it defensively without repeating the handshake.
startScanWiFi returns a list of WifiAP objects, each with:
String ssidint rssibool activebool private: whether the network is secured.String? bssid: MAC-style address (aa:bb:cc:dd:ee:ff) when known.
final networks = await prov.startScanWiFi();
for (final ap in networks) {
print('${ap.ssid} (${ap.rssi} dBm)');
}sendWifiConfig delivers the credentials and returns whether the device accepted them; applyWifiConfig then tells the device to connect. Pass an optional bssid to target a specific access point.
await prov.sendWifiConfig(ssid: ssid, password: password);
// Or target a specific access point:
// await prov.sendWifiConfig(ssid: ssid, password: password, bssid: 'aa:bb:cc:dd:ee:ff');
await prov.applyWifiConfig();getStatus returns a ConnectionStatus with:
WifiConnectionState state:Connecting,Connected,DisconnectedorConnectionFailed.String? deviceIp: the device IP once connected.WifiConnectFailedReason? failedReason:AuthError(wrong password) orNetworkNotFound(wrong SSID), set when the state isConnectionFailed.
final status = await prov.getStatus();
switch (status.state) {
case WifiConnectionState.Connecting:
// Still connecting.
break;
case WifiConnectionState.Connected:
print('Device IP: ${status.deviceIp}');
break;
case WifiConnectionState.Disconnected:
// Not connected.
break;
case WifiConnectionState.ConnectionFailed:
// Inspect status.failedReason.
break;
}sendReceiveCustomData sends a payload over the encrypted session and returns the device's response.
final answerBytes = await prov.sendReceiveCustomData(
Uint8List.fromList(utf8.encode(message)),
);
final answer = utf8.decode(answerBytes);See the example (flutter_blue_plus) or example_legacy (flutter_ble_lib_ios_15) for complete applications.
This package currently implements Security 1 through the Security1 class: a Curve25519 key exchange with AES-CTR encryption, authenticated with a Proof-of-Possession (PoP). This maps to Espressif's protocomm_security1.
- Security 0 (no security) is in progress.
- Security 2 (SRP6a key exchange + AES-GCM) is not yet available.
To use a different scheme, provide your own ProvSecurity implementation.
To report a security vulnerability, please follow the security policy.
The protocomm component from ESP-IDF manages secure sessions and provides the framework for multiple transports. Applications can also use the protocomm layer directly for application-specific extensions.
It defines three security schemes:
protocomm_security0: no security.protocomm_security1: Curve25519 key exchange + AES-CTR (implemented here asSecurity1).protocomm_security2: SRP6a key exchange + AES-GCM.
Proof-of-Possession is supported with security 1; salt and verifier with security 2. Protocomm uses protobuf for session establishment and provides the framework for transports such as Bluetooth LE, Wi-Fi (SoftAP + HTTPD) and console.
For security 1 and security 2 the client still needs to establish a session by performing the two-way handshake. See Unified Provisioning for more details on the handshake logic.
esp_provisioning_ble is the Bluetooth LE counterpart to esp_provisioning_softap: this package provisions the device over Bluetooth LE, while esp_provisioning_softap provisions it over Wi-Fi SoftAP. Both build on the protocomm security schemes and protobuf.
See the CHANGELOG for the release history.
Contributions are welcome. Please read the contributing guide to get set up and learn the workflow. This project follows a Code of Conduct, and security issues are handled through our security policy.
- Based on esp_provisioning.
- Also references esp_provisioning_softap, a Dart 3.0-compatible version of esp_softap_provisioning.
Released under the MIT License.