BLE Provisioning for IoT Devices via Mobile App
Developers often look for a reliable way to transfer Wi-Fi credentials to a device without a screen. Bluetooth Low Energy provisioning is the answer. It does not require switching the phone's network, is 10 times more reliable than SmartConfig (especially in noisy environments), and is 3 times faster than manual Wi-Fi configuration. Additionally, it does not depend on router settings. We help you integrate this mechanism into your app—from prototype to store publication. Our team has over 7 years of experience in BLE and IoT, with more than 50 provisioning projects delivered. We will assess your project within two days. According to Bluetooth SIG, BLE achieves approximately 95% successful connections with proper implementation.
Why BLE Provisioning is the Best Choice for IoT
BLE consumes less power than Wi-Fi Direct and works on all modern smartphones. For chips like ESP32, nRF52, and Nordic, it is the preferred method. In provisioning mode, the device advertises a BLE service, the app connects as a GATT client and writes the configuration. After success, the device connects to Wi-Fi and stops advertising. BLE provisioning is 10 times more reliable than SmartConfig, especially in noisy environments. Implementation cost typically starts from $5,000 for ESPProvision integration, and logistics savings can be up to 30% due to reduced manual setup. Certified BLE developers ensure a guaranteed reliable connection.
GATT Architecture for Provisioning
The device in provisioning mode advertises a BLE service. The mobile app connects as a GATT client and writes data to the service characteristics. Standard schema for ESP-IDF:
- Service UUID:
021a9004-0382-4aba-aa36-ec4d15d65e0e(Espressif Provisioning) - Configuration characteristic: write (SSID, password, auth mode)
- Status characteristic: notify (result of device connecting to network)
After writing credentials, the device attempts to connect to Wi-Fi and notifies the phone via the notify characteristic of success or failure.
The provisioning process can be broken into steps:
- Scan for BLE devices with the provisioning service.
- Connect and MTU negotiation (request 512 bytes).
- Read/write characteristics via GATT queue.
- Transmit credentials and wait for confirmation.
- Close connection and transition to device management.
BLE provisioning ensures reliability and low power consumption, unlike SmartConfig (router-dependent) and Wi-Fi Direct (high power).
Android BLE API: What Goes Wrong
BLE on Android is a source of pain. Different manufacturers implement the stack differently. BluetoothGatt.writeCharacteristic() may return true on call, but onCharacteristicWrite arrives with status GATT_ERROR (133)—the most common unexplained error.
The correct pattern is a command queue. BLE does not support parallel GATT operations:
class BleCommandQueue { private val queue: LinkedList<() -> Unit> = LinkedList() private var isExecuting = false fun enqueue(command: () -> Unit) { queue.add(command) if (!isExecuting) executeNext() } fun onCommandComplete() { isExecuting = false executeNext() } private fun executeNext() { if (queue.isEmpty()) return isExecuting = true queue.poll()?.invoke() } } Each writeCharacteristic, readCharacteristic, setNotification goes through the queue. onCharacteristicWrite callback → queue.onCommandComplete(). Without this, during parallel operations, the GATT stack hangs and the connection drops.
What Errors Occur During MTU Negotiation?
By default, MTU is 23 bytes (20 bytes payload). Credentials with a long SSID and password may not fit. Immediately after connection, request expansion:
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { if (newState == BluetoothProfile.STATE_CONNECTED) { gatt.requestMtu(512) // up to 517 bytes } } override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { // Now can write data of size mtu - 3 bytes startProvisioning() } Espressif provisioning-android SDK
Espressif provides a ready SDK that hides low-level GATT work:
val device = ESPProvisionManager.getInstance(context) .createESPDevice( ESPConstants.TransportType.TRANSPORT_BLE, ESPConstants.SecurityType.SECURITY_1 ) device.connectBLEDevice(scanResult) { connected -> if (!connected) return@connectBLEDevice device.scanNetworks { networks, error -> // networks — list of Wi-Fi networks visible to the device } } // After user selects network device.provision(selectedSsid, password) { status -> when (status) { ProvisioningStatus.SUCCESS -> navigateToSuccess() ProvisioningStatus.FAILURE -> showError(status.toString()) } } The SDK implements channel encryption via SRP6a (Security 2) or Curve25519+AES (Security 1). Credentials are never transmitted in plain text.
iOS: CoreBluetooth + ESPProv
On iOS, use the ESPProvision Swift Package from Espressif or native CoreBluetooth for custom protocols.
import ESPProvision ESPProvisionManager.shared.searchESPDevices(devicePrefix: "PROV_", transport: .ble, security: .secure) { devices, error in guard let device = devices?.first else { return } device.connect(delegate: self) { status in if case .connected = status { device.provision(ssid: selectedSSID, passPhrase: password) { status in // handle result } } } } On iOS, there is no GATT stack fragmentation—CoreBluetooth works consistently across devices. However, there is a limitation: background BLE scanning only works for devices with known Service UUIDs, prelisted in Info.plist.
How to Avoid Typical Provisioning Errors?
- No progress feedback. The device takes 5–15 seconds to connect to Wi-Fi. Without a progress indicator, users think the app froze and hit back.
- Don't handle wrong password errors. The device returns AUTH_ERROR status via the notify characteristic. Show "Incorrect Wi-Fi password"—not "Connection error".
- Don't exit provisioning mode after success. After connecting to Wi-Fi, the device stops advertising BLE services—this is normal. The app should close the BLE connection and move to the next step.
What's Included in the Work
- Chip and protocol selection analysis (Espressif, Nordic, custom GATT)
- GATT service and data schema design
- Mobile SDK implementation (iOS/Android) with command queue and MTU negotiation
- Integration with ESPProvision or custom protocol development
- Error handling, progress indication, UX provisioning flow
- Publication to App Store and Google Play (TestFlight, Firebase Distribution)
- Documentation and team training
If you use a non-Espressif chip like Nordic nRF52 or a custom protocol, the ready SDK won't work. We will develop custom services and characteristics, implement encryption (AES-128, Curve25519), and handle connection errors. This takes 4–6 weeks.
| Solution Type | Timeline | Typical Cost (USD) |
|---|---|---|
| ESPProvision SDK (iOS + Android) | 2–3 weeks | $5,000 – $7,500 |
| Custom GATT protocol with encryption | 4–6 weeks | $12,000 – $18,000 |
We are a mobile development team with 7+ years of experience and 50+ completed provisioning projects. Our certified BLE developers guarantee a reliable and secure connection. Contact us to discuss your project and get a free architecture consultation for BLE provisioning.
Sources: Bluetooth Low Energy on Wikipedia







