• EUR€
  • £GBP
  • $USD

ESP32 Arduino Bluetooth classic: Getting started

DFRobot Mar 15 2018 454

In this article, we will check how to get started using Bluetooth classic on the Arduino core, running on the ESP32. The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.



In this article, we will check how to get started using Bluetooth classic on the Arduino core, running on the ESP32.

At the time of writing, there aren’t yet higher level abstractions available on the Arduino core to use the Bluetooth classic functionality provided by the IDF (official ESP32 development framework) lower level APIs. Thus, we are going to use those lower level APIs to get started with Bluetooth.

As mentioned before, we are going to use the Arduino environment to program the ESP32. This is possible since we can call IDF APIs from the Arduino core, pretty much like we do to use FreeRTOS in this environment.

Note however that higher level and simpler to use functions should be arriving to the Arduino core soon. For example, at the time of writing, there’s this pull request open from Copercini that implements a UART to Bluetooth classic bridge for the ESP32, which provides a very high level API much similar to the Serial interface that’s available in the Arduino libraries.

Nonetheless, knowing how to use the lower level APIs is always an advantage because it not only allows us to better understand what happens under the hood but also because these APIs tend to be much more flexible.

The code we are going to analyze in this tutorial is going to be based on the previously mentioned Pull Request, which also uses the IDF API under the hood.

In this example, we will simply start the Bluetooth interface and make the ESP32 discoverable from other Bluetooth enabled devices.

The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


IDF’s Bluetooth architecture

Before we start with the code, it is important to understand a bit more about how Bluetooth works on The ESP32. This will help us understand why we are calling some of the functions in our code. A very good document to get started is this Espressif’s Bluetooth architecture description.

In general, the Bluetooth protocol has two main stacks, one on top of the other [1][2]. The lower level stack is called the controller stack and the higher level is called the host stack [1][3].

These two stacks are implemented independently because the communication interface between them is well defined [4].
The controller stack is responsible for handling the exchange of Bluetooth packets between devices and to manage the radio interface [5]. The host stack deals with higher level data [5].

One interesting thing to mention is that the host stack can be implemented on the same device of the controller stack or in a different one, and both scenarios are supported by the ESP32 [1].

In IDF, the available host stack is Bluedroid, for both Bluetooth classic and Bluetooth low energy [1].

In our application, we will have both the controller and the host stack running on the ESP32.


Getting the binary of the Bluetooth library

In order to be able to use the full Bluetooth functionality, we need to have the core compiled with some additional configurations, as indicated in the Pull Request mentioned on the introductory section.

At the time of writing, this was not available on the Arduino core yet, which is why the PR included a new version of the compiled BT lib.

When the PR is merged, the procedure from this section should no longer be needed. Nonetheless, for those who are following the tutorial before that, this will explain how to get that binary and where to place it

So, go to the files changed section of the mentioned PR and look for the libbt.a file. It should have a “Binary file not shown” message instead of displaying any content. On the right side, click the “view” button, as highlighted in figure 1.


Figure 1 – Viewing the binary file.

On the new page, simply click the “download” button (highlighted in figure 2), and the file should get transferred to your computer.


Figure 2 – Downloading the binary file.

To finalize, go to your ESP32 installation (where you have installed the Arduino core for the ESP32) and place the file in the following directory:
It will ask you to replace the existing file. You can make a copy of the old one before proceeding with the replace, so you can revert the changes if needed.

As mentioned, this is only needed if the version of the Arduino core you are working with still doesn’t have the latest binary (which is the case at the time of writing this article). If you can compile the code below without getting any error, then you shouldn’t need to do the procedure from this section.

Also, make sure you are using the latest version of the Arduino core, since the Bluetooth classic functionality has arrived very recently.

The code

We will start by including the libraries needed to access the Bluetooth functionality. 

This library will make available the functions we need to initialize the Bluedroid stack.

#include "esp_bt_main.h"

Additionally, we will need the esp_gap_bt_api.h library. This library will expose the API needed to use the functionalities of the Generic Access Profile (GAP), which defines how devices find each other and how they establish a connection  using the Bluetooth protocol [6].

Without configuring this, even if we initialized the Bluedroid stack, the device would not be discoverable, since that part of the Bluetooth protocol is handled by this profile.

#include "esp_gap_bt_api.h"

Next we will handle the initialization of the two Bluetooth stacks (controller and host). Since, as mentioned, this code is based on the existing Pull Request for the Arduino core, we will be keeping the same name of the initializing function used there. We will latter call it from the Arduino setup function.

static bool _init_bt(){ ... }

Inside this function, the first thing we need to do is initialize the controller stack. We can do it using the btStart function defined here.

This function takes no arguments and returns true if the the controller was correctly initialized and false otherwise.

if(!btStart()){    Serial.println("Failed to initialize controller");    return false; }

Next we will initialize the Bluedroid stack. This is done with a call to the esp_bluedroid_init function.

This function takes no arguments and returns a value of type esp_err_t (defined here). In case of success, it will return ESP_OK.

if (esp_bluedroid_init()!= ESP_OK) {    Serial.println("Failed to initialize bluedroid");    return false; }


After the initialization, we need to enable the Bluedroid stack. We do it with a call to the esp_bluedroid_enable function. This function also takes no arguments and returns ESP_OK in case of success.

if (esp_bluedroid_enable()!= ESP_OK) {    Serial.println("Failed to enable bluedroid");    return false; }

Now that we have initialized and enabled both stacks, we need to set our ESP32 as discoverable. Otherwise, we will not be able to find it from other devices.

We do this by calling the esp_bt_gap_set_scan_mode function. This function receives as input the scan mode, which is an enum of type esp_bt_scan_mode_t.

We will use the value ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE, which means the device is set to be both discoverable and connectable.


This completes the code for the Bluetooth initialization. Now we simply need to call it from the Arduino setup function and our device should become discoverable. You can check the final source code below.

#include "esp_bt_main.h" #include "esp_gap_bt_api.h" static bool _init_bt() {  if (!btStart()) {    Serial.println("Failed to initialize controller");    return false;  }  if (esp_bluedroid_init()!= ESP_OK) {    Serial.println("Failed to initialize bluedroid");    return false;  }  if (esp_bluedroid_enable()!= ESP_OK) {    Serial.println("Failed to enable bluedroid");    return false;  }  esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); } void setup() {  _init_bt(); } void loop() {}

Testing the code

To test the code, simply compile it and upload it to your ESP32 using the arduino IDE. Once the procedure finishes, the ESP32 should be visible from other Bluetooth enabled devices, as shown in figure 3.

Figure 3 – ESP32 discoverable from an Android smartphone.

Note that what appears in the image is the address of the device, since we didn’t configure a name for the device. Depending on the device from where you are doing the search, it may display the Bluetooth address of the ESP32 or other generic name.

Please note that this is a  very simple getting started example, so it only makes the device discoverable. Don’t try to pair it since it won’t work.