ESP32 BLE Development with ESP-IDF
Building BLE applications on ESP32 using ESP-IDF
ESP32 BLE Development
The ESP32 family (ESP32, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2) integrates BLE with a dual-core processor and optional Wi-Fi on a single SoC. ESP-IDF 5.x uses NimBLE as the default BLE host stack, running on top of FreeRTOS.
ESP-IDF Setup
git clone --recursive https://github.com/espressif/esp-idf.git -b v5.3
cd esp-idf && ./install.sh esp32,esp32s3,esp32c3
. ./export.sh
idf.py create-project-from-example "nvs_flash:nvs_flash" myproject
cd myproject && idf.py set-target esp32s3
NimBLE vs Bluedroid
| Feature | NimBLE | Bluedroid (legacy) |
|---|---|---|
| RAM footprint | ~50 KB | ~110 KB |
| BLE 5.0 support | Yes | Partial |
| Classic BT | No | Yes (ESP32 only) |
| Mesh networking | Yes | No |
| Maintenance | Active | Legacy |
GATT Server Example
GATT services are declared as static tables in NimBLE:
static const struct ble_gatt_svc_def gatt_svcs[] = {
{
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x180F), /* Battery Service */
.characteristics = (struct ble_gatt_chr_def[]) {
{
.uuid = BLE_UUID16_DECLARE(0x2A19),
.access_cb = battery_level_cb,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
},
{ 0 }
},
},
{ 0 }
};
Use the GATT Profile Browser to look up standard service and characteristic UUIDs before defining custom ones.
Wi-Fi + BLE Coexistence
ESP32 shares the 2.4 GHz radio between Wi-Fi and BLE using a time-division arbiter.
| Scenario | Recommendation |
|---|---|
| BLE advertising + Wi-Fi connected | Default coex handles well |
| BLE connection + Wi-Fi data burst | Increase connection interval to 100 ms+ |
| BLE throughput-critical | Disable Wi-Fi during transfer |
esp_coex_preference_set(ESP_COEX_PREFER_BALANCE);
For a comparison of ESP32 variants and radio capabilities, use the BLE Chip Selector.
Frequently Asked Questions
The original ESP32 supports Classic Bluetooth + BLE 4.2. The ESP32-S3 adds BLE 5.0 with extended advertising and 2M PHY but drops Classic Bluetooth. The ESP32-C3 and ESP32-C6 are BLE 5.0-only RISC-V chips optimised for low power. The ESP32-H2 adds IEEE 802.15.4 alongside BLE 5.2, targeting Matter deployments.
ESP-IDF provides direct access to Bluedroid (the Android-derived BLE stack) and NimBLE (lightweight open-source stack), full Kconfig control, and production-grade power management. Arduino wraps ESP-IDF via the ESP32 Arduino core, offering simpler APIs at the cost of less control over stack configuration, memory, and power profiles.
NimBLE is strongly recommended for new projects. It consumes roughly half the RAM and flash of Bluedroid (around 50 KB vs 100 KB RAM), supports BLE 5.0 features, and has an active upstream community. Bluedroid remains the default for backward compatibility but is effectively in maintenance mode on ESP-IDF.
Enable modem sleep (CONFIG_PM_ENABLE + CONFIG_BT_CTRL_MODEM_SLEEP) so the radio powers down between advertising events and connection intervals. Increase the advertising interval to 500 ms or greater during idle periods. Use light sleep mode between sensor readings and configure the BLE connection interval to at least 500 ms when low-latency data exchange is not required.
Yes, our guides range from beginner introductions to advanced topics. Each guide indicates its difficulty level and prerequisites so you can find the right starting point.