ESP32 Bluetooth Low Energy Tutorial with ESP-IDF: Menuconfig and Code Implementation Explained

ESP32 Bluetooth Low Energy Tutorial with ESP-IDF

Bluetooth Low Energy (BLE) technology has revolutionized the world of IoT by enabling efficient wireless communication between devices while conserving power. In this tutorial, we’ll delve into the fascinating realm of ESP32 and BLE data exchange using the ESP-IDF (Espressif IoT Development Framework). Whether you’re a beginner or an experienced developer, this guide will equip you with the knowledge and tools to create impressive IoT projects.

Introduction to ESP32 and BLE(Bluetooth Low Energy)

ESP32: The ESP32 is a powerful microcontroller that’s well-suited for a wide range of IoT applications. With built-in Wi-Fi and BLE capabilities, it’s a favorite among developers for its versatility and cost-effectiveness.

Bluetooth Low Energy (BLE): Bluetooth Low Energy is a wireless communication protocol designed for energy-efficient data transmission. It’s ideal for IoT devices, wearables, and applications where power consumption is critical.

Getting Started


Before we dive into the tutorial, make sure you have the following:

  1. An ESP32 development board.
  2. ESP-IDF installed on your computer. You can download it here.

Setting up Menuconfig

Menuconfig is a powerful configuration tool in ESP-IDF that allows you to customize your project settings. To access Menuconfig, navigate to your project directory in the terminal and run: menuconfig

Here, you can configure various aspects of your project, including Wi-Fi and BLE settings. Let’s explore a few critical settings:

  • Wi-Fi and BLE Configuration: Under “Component config,” you can enable both Wi-Fi and BLE(Bluetooth Low Energy) support. Ensure that “ESP32 Bluetooth Enable” is selected.
  • Bluetooth Configuration: Customize BLE parameters like the device name and appearance here. These settings will affect how your ESP32 device appears to other BLE devices.
  • GATT Server Configuration: GATT (Generic Attribute Profile) is essential for BLE(Bluetooth Low Energy) communication. Configure services and characteristics as needed for your application.
ESP32 Bluetooth Low Energy Nimble configuration

Once you’ve configured Menuconfig to your requirements, save the settings and exit.

Code Implementation

Now comes the exciting part: writing the code to enable BLE(Bluetooth Low Energy) data exchange. Below is a simplified example to get you started. We’ll create a simple BLE(Bluetooth Low Energy) server that broadcasts a “Hello, BLE!” message.

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "sdkconfig.h"

char *TAG = "BLE-Server";
uint8_t ble_addr_type;
void ble_app_advertise(void);

// Write data to ESP32 defined as server
static int device_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
    // printf("Data from the client: %.*s\n", ctxt->om->om_len, ctxt->om->om_data);

    char * data = (char *)ctxt->om->om_data;
    printf("%d\n",strcmp(data, (char *)"LIGHT ON")==0);
    if (strcmp(data, (char *)"LIGHT ON\0")==0)
       printf("LIGHT ON\n");
    else if (strcmp(data, (char *)"LIGHT OFF\0")==0)
        printf("LIGHT OFF\n");
    else if (strcmp(data, (char *)"FAN ON\0")==0)
        printf("FAN ON\n");
    else if (strcmp(data, (char *)"FAN OFF\0")==0)
        printf("FAN OFF\n");
        printf("Data from the client: %.*s\n", ctxt->om->om_len, ctxt->om->om_data);
    return 0;

// Read data from ESP32 defined as server
static int device_read(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
    os_mbuf_append(ctxt->om, "Data from the server", strlen("Data from the server"));
    return 0;

// Array of pointers to other service definitions
// UUID - Universal Unique Identifier
static const struct ble_gatt_svc_def gatt_svcs[] = {
     .uuid = BLE_UUID16_DECLARE(0x180),                 // Define UUID for device type
     .characteristics = (struct ble_gatt_chr_def[]){
         {.uuid = BLE_UUID16_DECLARE(0xFEF4),           // Define UUID for reading
          .flags = BLE_GATT_CHR_F_READ,
          .access_cb = device_read},
         {.uuid = BLE_UUID16_DECLARE(0xDEAD),           // Define UUID for writing
          .flags = BLE_GATT_CHR_F_WRITE,
          .access_cb = device_write},

// BLE event handling
static int ble_gap_event(struct ble_gap_event *event, void *arg)
    switch (event->type)
    // Advertise if connected
        ESP_LOGI("GAP", "BLE GAP EVENT CONNECT %s", event->connect.status == 0 ? "OK!" : "FAILED!");
        if (event->connect.status != 0)
    // Advertise again after completion of the event
    return 0;

// Define the BLE connection
void ble_app_advertise(void)
    // GAP - device name definition
    struct ble_hs_adv_fields fields;
    const char *device_name;
    memset(&fields, 0, sizeof(fields));
    device_name = ble_svc_gap_device_name(); // Read the BLE device name = (uint8_t *)device_name;
    fields.name_len = strlen(device_name);
    fields.name_is_complete = 1;

    // GAP - device connectivity definition
    struct ble_gap_adv_params adv_params;
    memset(&adv_params, 0, sizeof(adv_params));
    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; // connectable or non-connectable
    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // discoverable or non-discoverable
    ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_gap_event, NULL);

// The application
void ble_app_on_sync(void)
    ble_hs_id_infer_auto(0, &ble_addr_type); // Determines the best address type automatically
    ble_app_advertise();                     // Define the BLE connection

// The infinite task
void host_task(void *param)
    nimble_port_run(); // This function will return only when nimble_port_stop() is executed

void app_main()
    nvs_flash_init();                          // 1 - Initialize NVS flash using
    // esp_nimble_hci_and_controller_init();      // 2 - Initialize ESP controller
    nimble_port_init();                        // 3 - Initialize the host stack
    ble_svc_gap_device_name_set("BLE-Server"); // 4 - Initialize NimBLE configuration - server name
    ble_svc_gap_init();                        // 4 - Initialize NimBLE configuration - gap service
    ble_svc_gatt_init();                       // 4 - Initialize NimBLE configuration - gatt service
    ble_gatts_count_cfg(gatt_svcs);            // 4 - Initialize NimBLE configuration - config gatt services
    ble_gatts_add_svcs(gatt_svcs);             // 4 - Initialize NimBLE configuration - queues gatt services.
    ble_hs_cfg.sync_cb = ble_app_on_sync;      // 5 - Initialize application
    nimble_port_freertos_init(host_task);      // 6 - Run the thread

This code initializes the ESP32, sets up Bluetooth, registers callback functions for GAP and GATT events, and starts advertising as a BLE server. You can modify this code to suit your project’s requirements.

Uploading the Code

To build and flash the program of BLE(Bluetooth Low Energy) to ESP32 use the following commands: build flash monitor

BLE Data Exchange

Once your ESP32 is set up as a BLE server, other BLE devices can connect to it and exchange data. This data can include sensor readings, commands, or any information relevant to your application.

In the real world, data exchange involves creating services and characteristics, which act as containers for your data. The ESP-IDF provides tools and APIs to define and manage these services and characteristics.

Troubleshooting Tips

BLE development can sometimes be challenging, but don’t worry; it’s part of the learning process. Here are some common issues and tips to resolve them:

  1. Ensure Correct UUIDs: UUIDs (Universally Unique Identifiers) are crucial for identifying services and characteristics. Double-check that your UUIDs match on both the server and client sides.
  2. Proper Callback Handling: Make sure you handle GAP and GATT events correctly in your callback functions. Incorrect event handling can lead to communication issues.
  3. Power and Signal Strength: BLE devices are sensitive to power levels and signal strength. Ensure your ESP32 has sufficient power and that there are no physical obstructions blocking the signal.
Bluetooth Low Energy GitHub full code esp idf

Download Full Code

Use Cases of BLE in IoT Projects

Bluetooth Low Energy (BLE) has gained immense popularity in the realm of Internet of Things (IoT) due to its energy efficiency and versatility. It offers various use cases that make it an ideal choice for connecting IoT devices. Let’s explore some of the most common applications:

1. Sensor Readings and Monitoring

One of the primary use cases of BLE in IoT is for sensor readings and monitoring. IoT devices equipped with BLE can gather data from various sensors such as temperature, humidity, pressure, light, and motion sensors. Here’s how it works:

  • Smart Home: BLE-enabled sensors can monitor environmental conditions within a smart home. For example, a BLE-connected thermostat can collect temperature and humidity data, allowing homeowners to maintain optimal indoor conditions and save energy.
  • Healthcare: Wearable devices with BLE can track vital signs like heart rate, blood pressure, and oxygen levels. This data can be transmitted to smartphones or cloud platforms for real-time health monitoring.
  • Agriculture: BLE sensors can be placed in fields to monitor soil moisture levels, helping farmers optimize irrigation and crop health.

2. Device Control and Automation

BLE enables seamless device control and automation in IoT applications. Devices can communicate with each other or with a central hub, allowing for remote control and automation of various processes:

  • Smart Lighting: BLE-connected light bulbs and switches can be controlled using a smartphone app or voice commands. Users can adjust lighting levels, colors, and schedules effortlessly.
  • Industrial Automation: BLE-equipped sensors and actuators are used in industrial settings to control machinery, monitor equipment health, and automate processes. This improves efficiency and reduces downtime.
  • Asset Tracking: BLE beacons attached to assets or products can provide real-time location data. This is valuable for tracking shipments, inventory management, and security.

3. Data Synchronization and Sharing

BLE can facilitate data synchronization and sharing between devices, making it a valuable tool for IoT applications that require collaborative data processing:

  • Wearable Fitness Devices: BLE enables fitness trackers and smartwatches to sync data with smartphones or cloud services. This allows users to view their exercise and health data on multiple devices seamlessly.
  • Smart Grids: In smart grid systems, BLE(Bluetooth Low Energy) can connect meters, appliances, and renewable energy sources to coordinate energy consumption, monitor grid health, and optimize energy distribution.
  • Collaborative IoT Ecosystems: In scenarios where multiple IoT devices work together, BLE(Bluetooth Low Energy) can serve as a communication bridge, ensuring devices are in sync and sharing data efficiently.

4. Proximity-Based Services

BLE’s ability to detect nearby devices accurately makes it suitable for proximity-based services and marketing applications:

  • Retail: BLE(Bluetooth Low Energy) beacons placed in stores can send notifications, discounts, and product information to shoppers’ smartphones as they browse, enhancing the retail experience.
  • Museums and Exhibitions: BLE-powered audio guides can provide visitors with detailed information about exhibits as they approach them.
  • Indoor Navigation: BLE(Bluetooth Low Energy) beacons can help users navigate large indoor spaces, such as airports or shopping malls, by providing turn-by-turn directions on smartphones.

These use cases highlight the flexibility and potential of BLE in various IoT applications. By leveraging the power of BLE, IoT developers can create innovative solutions that enhance user experiences, improve efficiency, and transform industries. Whether it’s monitoring sensor data, controlling devices remotely, synchronizing data, or enabling proximity-based services, BLE continues to play a pivotal role in shaping the future of IoT.


Congratulations! You’ve now embarked on a journey to master BLE data exchange with ESP32 and ESP-IDF. We’ve covered the basics of ESP32 and BLE(Bluetooth Low Energy), setting up Menuconfig, and implementing BLE communication in code. Remember that this is just the beginning; BLE(Bluetooth Low Energy) opens up a world of possibilities for your IoT projects.

Stay curious, keep experimenting, and watch your IoT projects come to life with the power of ESP32 and BLE(Bluetooth Low Energy). Happy coding!

For more in-depth tutorials and exciting IoT projects, be sure to subscribe to INNOVATE YOURSELF. We’re here to help you on your tech journey.

Also, check out our other playlist Rasa ChatbotInternet of thingsDockerPython ProgrammingMQTTTech NewsESP-IDF etc.
Become a member of our social family on youtube here.
Stay tuned and Happy Learning. ✌🏻😃
Happy tinkering! ❤️🔥

Leave a Reply