BLE Provisioning of IoT Devices via Mobile App

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
BLE Provisioning of IoT Devices via Mobile App
Medium
~3-5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

BLE Provisioning for IoT Devices via Mobile Applications

BLE Provisioning — transmitting Wi-Fi credentials and configuration to an IoT device through Bluetooth Low Energy. This is the best method for user-friendly UX: no need to switch Wi-Fi networks on the phone, more reliable than SmartConfig, and doesn't depend on router settings. For ESP32, nRF52, Nordic chips — the preferred choice.

GATT Architecture for Provisioning

The device in provisioning mode advertises a BLE service. The mobile application connects as a GATT client and writes data to service characteristics. Standard scheme for ESP-IDF:

  • Service UUID: 021a9004-0382-4aba-aa36-ec4d15d65e0e (Espressif Provisioning)
  • Configuration characteristic: write (SSID, password, auth mode)
  • Status characteristic: notify (device Wi-Fi connection result)

After writing credentials, the device attempts to connect to Wi-Fi and notifies the phone via the notify characteristic of success or failure.

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 GATT_ERROR (133) status — the most common unexplained error.

The correct pattern is a command queue. BLE doesn't 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()
    }
}

Every writeCharacteristic, readCharacteristic, setNotification — goes through the queue. onCharacteristicWrite callback → queue.onCommandComplete(). Without this, parallel operations cause the GATT stack to hang and disconnect.

MTU negotiation. Default MTU = 23 bytes (20 bytes payload). Long credentials may not fit. Request expansion immediately after connection:

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 up to mtu - 3 bytes
    startProvisioning()
}

Espressif provisioning-android SDK

Espressif provides a ready-made 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 a 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 + ESPProvision

On iOS — 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's no GATT stack fragmentation — CoreBluetooth works identically across all devices. But there's a limitation: background BLE scanning only works for devices with known Service UUIDs predefined in Info.plist.

Typical Provisioning UX Mistakes

No progress feedback. Device connects to Wi-Fi in 5–15 seconds. Without a progress indicator, users think the app froze and press back.

Not handling wrong password error. Device returns AUTH_ERROR status via notify characteristic. Show "Incorrect Wi-Fi password" — not "Connection error".

Not exiting provisioning mode after success. Device stops advertising BLE services after connecting to Wi-Fi — normal behavior. App should close the BLE connection and move to the next step.

Implementing BLE Provisioning based on Espressif SDK: 2–3 weeks. Custom GATT protocol with encryption for another chip: 4–6 weeks.