ESP32 Wi-Fi Provisioning via BLE (Bluetooth Low Energy) – Arduino IDE

In this tutorial, you’ll learn how to set up Wi-Fi provisioning via BLE on the ESP32. The Wi-Fi provisioning service allows you to configure Wi-Fi credentials over Bluetooth Low Energy. This is a great option for IoT projects that require Wi-Fi credentials to connect to the internet, without the need to hard-code them on the Arduino sketch while developing.

ESP32 Wi-Fi Provisioning via BLE Arduino IDE

Table of Contents:

Wi-Fi Provisioning

Wi-Fi provisioning is the process of connecting a new Wi-Fi device (station) to a Wi-Fi network (access point). In this case, we want to connect an ESP32 to a Wi-Fi network. The provisioning process involves loading the ESP32 with the name of the network (SSID) and password that we want to connect to.

The ESP32 supports Wi-Fi provisioning over SoftAP (access point) or via Bluetooth Low Energy. In this tutorial, we’ll cover Wi-Fi provisioning via Bluetooth.

Provisioning over BLE

To provision the ESP32 via BLE, we need to use another BLE-enabled device, usually a smartphone to connect to the ESP32 via BLE and send the Wi-Fi credentials. We can use an Android or iOS app or a Web Bluetooth app.

Espressif developed Android and iOS apps that support Wi-Fi provisioning for its devices like the ESP32 boards. Alternatively, you can create your own BLE app.

After the provisioning process, the ESP32 can connect to the desired Wi-Fi network with the provided network credentials.

ESP32 Wi-Fi Provisioning over BLE
ESP32 Wi-Fi Provisioning over BLE

Here’s a quick summary of how it works:

  1. You have a new device that you want to connect to a known network. In our case, an ESP32.
  2. You connect to the ESP32 via BLE. On the Wi-Fi provisioning app, you enter and send the SSID and password of the network you want your ESP32 to connect to.
  3. Finally, the ESP32 connects to the network using the provided credentials. From this moment, it can do any other Wi-Fi-related tasks it needs.

Wi-Fi Provisioning App

To connect and send the credentials to the ESP32 via BLE, we’ll use the Wi-Fi Provisioning App developed by Espressif (alternatively, you can create your own BLE app).

Installing the Wi-Fi Provisioning App

Before proceeding, make sure you install the Wi-Fi provisioning app on your smartphone:

Wi-Fi provisioning App - espressif

ESP32 WiFi Provisioning via BLE – Code

The following code will prepare the ESP32 for Wi-Fi provisioning via BLE. This is the minimal code required to do that. We adapted this code slightly from the official example that also supports WiFi provisioning via an access point.

Copy the following code to the Arduino IDE.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-wi-fi-provisioning-ble-arduino/

  Please read README.md file in this folder, or on the web: https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFiProv/examples/WiFiProv
  Note: This sketch takes up a lot of space for the app and may not be able to flash with default setting on some chips.
  If you see Error like this: "Sketch too big"
  In Arduino IDE go to: Tools > Partition scheme > chose anything that has more than 1.4MB APP
   - for example "No OTA (2MB APP/2MB SPIFFS)"
*********/

#include "WiFiProv.h"
#include "WiFi.h"

const char * pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by the user in the phone app
const char * service_name = "PROV_123"; // Name of your device (the Espressif apps expects by default device name starting with "Prov_")
const char * service_key = NULL; // Password used for SofAP method (NULL = no password needed)
bool reset_provisioned = true; // When true the library will automatically delete previously provisioned data.

// WARNING: SysProvEvent is called from a separate FreeRTOS task (thread)!
void SysProvEvent(arduino_event_t *sys_event){
    switch (sys_event->event_id) {
    case ARDUINO_EVENT_WIFI_STA_GOT_IP:
        Serial.print("\nConnected IP address : ");
        Serial.println(IPAddress(sys_event->event_info.got_ip.ip_info.ip.addr));
        break;
    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
        Serial.println("\nDisconnected. Connecting to the AP again... ");
        break;
    case ARDUINO_EVENT_PROV_START:
        Serial.println("\nProvisioning started\nGive Credentials of your access point using smartphone app");
        break;
    case ARDUINO_EVENT_PROV_CRED_RECV: {
        Serial.println("\nReceived Wi-Fi credentials");
        Serial.print("\tSSID : ");
        Serial.println((const char *) sys_event->event_info.prov_cred_recv.ssid);
        Serial.print("\tPassword : ");
        Serial.println((char const *) sys_event->event_info.prov_cred_recv.password);
        break;
    }
    case ARDUINO_EVENT_PROV_CRED_FAIL: {
        Serial.println("\nProvisioning failed!\nPlease reset to factory and retry provisioning\n");
        if(sys_event->event_info.prov_fail_reason == WIFI_PROV_STA_AUTH_ERROR)
            Serial.println("\nWi-Fi AP password incorrect");
        else
            Serial.println("\nWi-Fi AP not found....Add API \" nvs_flash_erase() \" before beginProvision()");
        break;
    }
    case ARDUINO_EVENT_PROV_CRED_SUCCESS:
        Serial.println("\nProvisioning Successful");
        break;
    case ARDUINO_EVENT_PROV_END:
        Serial.println("\nProvisioning Ends");
        break;
    default:
        break;
    }
}

void setup() {
  Serial.begin(115200);
  WiFi.onEvent(SysProvEvent);

  Serial.println("Begin Provisioning using BLE");
  // Sample uuid that user can pass during provisioning using BLE
  uint8_t uuid[16] = {0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,
                      0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02 };
  WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name, service_key, uuid, reset_provisioned);
  log_d("ble qr");
  WiFiProv.printQR(service_name, pop, "ble");
}

void loop() {
  
}

View raw code

How the Code Works

Let’s take a quick look at how the code works (or skip to the next section).

Including Libraries

First, you include the required libraries, the WiFiProv.h for Wi-Fi provisioning and the WiFi.h for Wi-Fi related functions.

#include "WiFiProv.h"
#include "WiFi.h"

Provisioning Details

Then, we declare some variables to hold details for the provisioning service.

The pop variable is the proof of possession, it’s like a password so that you can connect the smartphone to this specific device. For testing, we’ll use the default value.

const char * pop = "abcd1234"; // Proof of possession - otherwise called a PIN - string provided by the device, entered by the user in the phone app

The service_name is the name of our BLE device. If you’re using the Espressif app, like we’ll do in this tutorial, the service name must start with the prefix PROV_.

const char * service_name = "PROV_123"; // Name of your device (the Espressif apps expects by default device name starting with "Prov_")

The service_key is used when using Wi-Fi Provisioning via Access Point (not included in this guide). Set it to NULL because it’s not needed.

const char * service_key = NULL; // Password used for SofAP method (NULL = no password needed)

The reset_provisioned is a boolean variable indicating whether the library should delete previously provisioned data.

bool reset_provisioned = true; // When true the library will automatically delete previously provisioned data.

Wi-Fi Event Callback Function

In the setup(), set a function that will run when a Wi-Fi event occurs. In this case, it will call the SysProvEvent() function when any Wi-Fi event occurs. Then, on the SysProvEvent() function we’ll decide what happens according to the Wi-Fi event detected.

WiFi.onEvent(SysProvEvent);

You may also like: ESP32 Useful Wi-Fi Library Functions (Arduino IDE)

Starting WiFi Provisioning

Starting the Wi-Fi provisioning process is as easy as using WiFiProv.beginProvision() with the proper arguments.

WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name, service_key, uuid, reset_provisioned);

Print QR Code

We also print the BLE provision details in a QR code that can be detected by the Wi-Fi Provisioning app.

log_d("ble qr");
WiFiProv.printQR(service_name, pop, "ble");

Detecting WiFi Events

The different Wi-Fi events will be passed to the SysProvEenvent().

ARDUINO_EVENT_WIFI_STA_GOT_IP

When the ESP32 connects to a network and is assigned an IP address, it detects the ARDUINO_EVENT_WIFI_STA_GOT_IP event. When this happens, we print the ESP32 IP address (you can run other tasks as needed, or add a flag variable to indicate that the ESP32 is connected to WiFi and that we can run wifi-related tasks in the loop()).

case ARDUINO_EVENT_WIFI_STA_GOT_IP:
    Serial.print("\nConnected IP address : ");
    Serial.println(IPAddress(sys_event->event_info.got_ip.ip_info.ip.addr));
    break;
ARDUINO_EVENT_PROV_START

The ARDUINO_EVENT_PROV_START event happens when the provisioning process starts. This happens when we call the WiFiProv.beginProvision() function in the setup().

case ARDUINO_EVENT_PROV_START:
    Serial.println("\nProvisioning started\nGive Credentials of your access point using smartphone app");
    break;
ARDUINO_EVENT_PROV_CRED_RECV

This event is triggered when the board receives the credentials via Wi-Fi provisioning. In this case, we print the received SSID and password. Alternatively, you can save the credentials permanently to a file if that’s useful for your project.

case ARDUINO_EVENT_PROV_CRED_RECV: {
    Serial.println("\nReceived Wi-Fi credentials");
    Serial.print("\tSSID : ");
    Serial.println((const char *) sys_event->event_info.prov_cred_recv.ssid);
    Serial.print("\tPassword : ");
    Serial.println((char const *) sys_event->event_info.prov_cred_recv.password);
    break;
}
ARDUINO_EVENT_PROV_CRED_FAIL

This event will run if the credentials provided via Wi-Fi provisioning will fail to connect to the network.

case ARDUINO_EVENT_PROV_CRED_FAIL: {
    Serial.println("\nProvisioning failed!\nPlease reset to factory and retry provisioning\n");
    if(sys_event->event_info.prov_fail_reason == WIFI_PROV_STA_AUTH_ERROR)
        Serial.println("\nWi-Fi AP password incorrect");
    else
        Serial.println("\nWi-Fi AP not found....Add API \" nvs_flash_erase() \" before beginProvision()");
    break;
}
ARDUINO_EVENT_PROV_CRED_SUCCESS

The ARDUINO_EVEN_PROV_CRED_SUCCESS event will run if the ESP32 successfully connects to the network using the credentials provided via Wi-Fi provisioning.

case ARDUINO_EVENT_PROV_CRED_SUCCESS:
    Serial.println("\nProvisioning Successful");
    break;
ARDUINO_EVENT_PROV_END

Finally, when the provisioning process ends, the ARDUINO_EVENT_PROV_END is triggered.

case ARDUINO_EVENT_PROV_END:
    Serial.println("\nProvisioning Ends");
    break;

Instructions for Uploading the Code

This code takes up a lot of space and may not be able to flash with the default settings on some chips.

If you see an Error like this: “Sketch too big” during the uploading process, in Arduino IDE go to Tools > Partition scheme > choose anything that has more than 1.4MB APP, for example: “Huge APP (3MB No OTA/1MB SPIFFS“.

ESP32 Selecting Different Partition Scheme

If you don’t have the partition scheme option on your Tools menu, you need to select a different ESP32 board model—for example, the ESP32 Wrover Module.

Testing the Code

After uploading the code to the ESP32, open the Serial Monitor at a baud rate of 115200. Press the ESP32 RST button, so it starts running the code.

Note: you may get a PSRAM error. You can ignore it.

You’ll get something similar on your Serial Monitor.

Begin Provisioning using BLE

Provisioning started
Give Credentials of your access point using smartphone app
ESP32 Start Wi-Fi Provisioning via BLE Serial Monitor

Now, open the Espressif WiFi Provisioning App on your smartphone and click on Provision Device. It has the option to scan the QR code, but I couldn’t make it work. Click on “I don’t have a QR code“.

It will list all Bluetooth Devices within its range with the “PROV_” prefix. Our code sets the ESP32 as a BLE Device called “PROV_123“—click on that device.

Wifi Provisioning App - Provision Device
Wi-Fi provision via BLE - finding BLE devices

Then, you need to enter the proof of possession—it must be the same used in the code. We’re using the default values, so it will be abcd1234. After, it will list all Wi-Fi networks within its range (if it doesn’t list your network, you may need to enter it manually by clicking on “Join Other Network”).

Espressif Wi-Fi provisioning enter proof of possession
Wi-Fi provisioning app - listing Wi-Fi networks.

Finally, enter the password for your Wi-Fi network and click Connect. The Wi-Fi credentials should be sent to the ESP32 after a few seconds.

ESP32 WiFi Provisioning via BLE inserting SSID and password
WiFi Provisioning Sucessfull ESP32

On the Serial monitor, you can see that the ESP32 received the Wi-Fi credentials and connected successfully to the network (it printed its IP address on the network it connected to).

ESP32 WiFi Provisioning Successful Serial Monitor

That’s it. Wi-Fi provisioning was successfully implemented on the ESP32.

How to Apply the Wi-Fi Provisioning to Your Wi-Fi Projects

To add this feature to your projects that use Wi-Fi, I suggest creating a global variable that indicates whether the ESP32 is already connected to the internet. That variable will change to true when the ARDUINO_EVENT_WIFI_STA_GOT_IP is triggered.

Then, in the loop(), check the state of that variable. If it’s true, run your Wi-Fi-related tasks. If not, simply wait for the board to establish a connection.

We’ll create a web server example with this feature soon, so stay tuned.

Wrapping Up

In this tutorial, we’ve shown you how to add Wi-Fi Provisioning via BLE to your ESP32 devices. Using this feature is simple and easy thanks to the WiFiProv library and the Espressif Provisioning app.

This is a great option for IoT projects that require Wi-Fi credentials to connect to the internet, without the need to hard-code them while developing, which makes the project much more versatile.

We’ll create more tutorials about this subject soon, so stay tuned. You may also like reading:

We hope you’ve found this tutorial useful. Learn more about the ESP32 with our resources.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

16 thoughts on “ESP32 Wi-Fi Provisioning via BLE (Bluetooth Low Energy) – Arduino IDE”

    • Hi Hans,

      In the “Wrapping up” section there is mention of the “WiFiProv library” that was provided by Espressif. I have not tried this process yet so I can only work from the information I read above. Let us know how you went.

      Reply
      • Hi.
        It is included by default.
        You don’t need to install any library.
        Just make sure the ESP32 boards are updated in the Arduino IDE.
        Regards,
        Sara

        Reply
    • /*
      Please read README.md file in this folder, or on the web:
      https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFiProv/examples/WiFiProv

      Note: This sketch takes up a lot of space for the app and may not be able to flash with default setting on some chips.
      If you see Error like this: “Sketch too big”
      In Arduino IDE go to: Tools > Partition scheme > chose anything that has more than 1.4MB APP
      – for example “No OTA (2MB APP/2MB SPIFFS)”
      */

      Reply
    • Hi.
      You don’t need to install any library.
      Just make sure you have the ESP32 boards updated in your Arduino IDE.
      Regards,
      Sara

      Reply
  1. Good Morning, I have this errors messages …..
    C:\Users\Efrem\AppData\Local\Temp.arduinoIDE-unsaved2024311-8452-11tz2gj.7kaj\sketch_apr11a\sketch_apr11a.ino:21:19: error: ‘arduino_event_t’ was not declared in this scope
    C:\Users\Efrem\AppData\Local\Temp.arduinoIDE-unsaved2024311-8452-11tz2gj.7kaj\sketch_apr11a\sketch_apr11a.ino:21:36: error: ‘sys_event’ was not declared in this scope
    void SysProvEvent(arduino_event_t *sys_event){
    ^
    C:\Users\Efrem\AppData\Local\Temp.arduinoIDE-unsaved2024311-8452-11tz2gj.7kaj\sketch_apr11a\sketch_apr11a.ino:21:19: error: variable or field ‘SysProvEvent’ declared void
    void SysProvEvent(arduino_event_t *sys_event){
    ^
    C:\Users\Efrem\AppData\Local\Temp.arduinoIDE-unsaved2024311-8452-11tz2gj.7kaj\sketch_apr11a\sketch_apr11a.ino:21:19: error: ‘arduino_event_t’ was not declared in this scope
    C:\Users\Efrem\AppData\Local\Temp.arduinoIDE-unsaved2024311-8452-11tz2gj.7kaj\sketch_apr11a\sketch_apr11a.ino:21:36: error: ‘sys_event’ was not declared in this scope
    void SysProvEvent(arduino_event_t *sys_event){

    Reply
    • Hi.
      What version of the ESP32 do you have installed in the arduino IDE?
      Go to Tools > Boards > Boards Manager, search for ESP32 and check the version. You may need to update.
      Regards,
      Sara

      Reply
  2. Hi, the problem in using the Espressif app is that it only supports provisioning using a dynamic IP address. What can I do if I also want to set a static IP address during the provisioning process? If the app does not support this, you wrote that I can develop my own process/app. Are there any instructions on how to do that? Thanks!

    Reply
  3. Awesome tutorial. I like this idea over storing a boot config on sd card. Definitely will cut cost and boost realibity.

    Reply
  4. Very interesting but the memory use is a bit of a downer as it doesnt leave much for other, possibly more interesting stuff, like OTA or anything else a code could do. Long time ago I wrote a code to set WiFi credentials via Bluetooth Serial with a simple general phone Bluetooth app. I’ll see if I can dig that up again.

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.