Scanning BLE Devices Using ESP32 IDF


Introduction

The ESP32 is a low-cost, low-power microcontroller developed by Espressif Systems, featuring dual-mode capabilities for Wi-Fi and Bluetooth (including BLE, Bluetooth Low Energy). It is widely used in Internet of Things (IoT) projects, particularly suitable for applications involving wireless communication, smart homes, and automation systems. Its high performance and rich peripheral support make it very popular among developers.

Working Principle

BLE (Bluetooth Low Energy) is a Bluetooth technology designed for low-power devices and is mainly used for short-distance data transmission. On ESP32, BLE functionality can be used for device scanning, broadcasting, and data exchange.

1. BLE scanning principle
When ESP32 performs a BLE scan, it searches for surrounding BLE devices that are sending broadcast signals. These broadcast signals contain basic information about the device, such as MAC address (BDA, Bluetooth Device Address), device name, signal strength (RSSI), and other customized broadcast data.
There are two main modes of the scanning process:
Passive scanning: ESP32 will only receive broadcast signals and will not send scanning requests.
Active scanning: After receiving the broadcast signal, ESP32 will also send a scan request to obtain more device information.

2. ESP32 BLE scanning operation process
When we start the BLE scanning function of ESP32, ESP32 will perform the following steps
Set scan parameters: Set the scan interval, window time and scan mode (active or passive) through the esp_ble_scan_params_t structure.
Start scanning: Use the esp_ble_gap_start_scanning() function to start scanning, which will cause ESP32 to start scanning for nearby BLE devices.
Processing scan results: Whenever ESP32 scans a device, it will trigger a callback function and pass the scanned device data to the application in the form of an event. We can obtain the device name, MAC address, RSSI value, etc. from this data.

3. Name and BDA replacement
During the BLE scanning process, ESP32 usually identifies the device with a BDA (Bluetooth Device Address, MAC address). But if the device has a broadcast name (like the name advertised by a BLE peripheral), then we can replace the part that shows the BDA to display the device name in a more human-friendly way. In this way, when users view the scan results, they can not only see the address of the device, but also the name of the device, improving readability and recognition.

Installing VSCode & The ESP-IDF Extension

Make sure you have installed and configured the ESP-IDF development environment. You can also refer to the article the ESP32 Tutorial – ESP-IDF With VSCode.

Creating A New ESP32 Project

We can use VSCode's IDF plug-in to create a new ESP32 project. Please refer to ESP32 Tutorial – How To Create An ESP32 Project With VSCode.

Bluetooth Configuration In VSCode

1. Open your ESP-IDF project.
2. In VSCode, press Ctrl + Shift + P and select ESP-IDF: Configure Project.
3. In the pop-up SDK Configuration Editor, find the Bluetooth section.
4. Enable Bluetooth.
5. Save your configuration and recompile the project.

Initialize NVS & Bluetooth

The first step is to initialize the non-volatile storage (NVS) and Bluetooth functionality. NVS is required for BLE functionality as it is used to persistently store various configuration parameters.
Here we initialize the NVS storage using nvs_flash_init() and the Bluetooth controller using esp_bt_controller_init().

Set BLE Scanning Parameters

After the Bluetooth function is enabled, we can configure scanning parameters such as scan type, address type and filtering policy.
Scan type: We are using active scanning, which means the scanner sends a request to the BLE device to get more detailed information.
Scan filtering policy: Allow scanning of all devices.
Scan intervals and windows: These define how often and for how long scans occur. Adjusting these values ​​affects responsiveness and power consumption.

Process Scan Results

Next, we can register a callback function to handle the scan results. The esp_ble_gap_register_callback() function is used to register an event handler that will process the scan results and record the device name and RSSI.
We will use a helper function to extract the device name from the broadcast data. If the name is not found, we mark the device as "Unknown Device".
This function uses esp_ble_resolve_adv_data() to extract the name from the BLE advertisement packet.
Next, let's create the GAP event handler to manage the different BLE events, specifically the scan result events.
In the event handler:
ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: When the scanning parameters are set, ESP32 starts scanning.
ESP_GAP_BLE_SCAN_RESULT_EVT: Process the scan results and log the device name and RSSI.
ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: After the scan is completed, a completion message is logged.

Run BLE Scanner

Finally, combine all the code into the app_main() function...
This function initializes NVS, enables BLE, registers GAP callbacks, and sets scan parameters.

Compile, Flash & Monitor

Find the "ESP32-IDF: Build, Flash and Monitor" ICON in VSCode to execute and burn.

Results

Conclusion

With this code, you can now use the ESP32 to scan for BLE devices and log their names and signal strength (RSSI). BLE is a powerful tool in IoT projects, and scanning for devices is just the beginning. You can further extend this code to connect to specific devices, read sensor data, or even broadcast your own BLE information.

You can adjust the scan interval and window or modify the logging to filter for specific device names or RSSI values. The ESP32 offers great flexibility in BLE projects.