BLE Mesh Network with ESP32 using ESP-IDF – A Complete Tutorial

2
0

Introduction

Bluetooth Low Energy (BLE) Mesh is revolutionizing how devices communicate in large-scale IoT deployments. By extending BLE’s many‑to‑one model into a true many‑to‑many mesh, devices can relay messages across multiple hops—greatly expanding coverage and reliability. In this guide, you’ll learn how to build a BLE Mesh network using the ESP32 and ESP-IDF, controlling three LEDs wired to GPIO2, GPIO4, and GPIO5. We’ll use Espressif’s OnOff Server example as our firmware base, and the nRF Mesh mobile app for provisioning and control.

Whether you’re building a smart‑lighting system, sensor grid, or just exploring mesh topologies, this step‑by‑step tutorial has you covered. By the end, you’ll have a working mesh of ESP32 nodes that turn LEDs on/off via smartphone commands.


Table of Contents

  1. Understanding BLE Mesh Networking
  2. Components Required
  3. Setting Up the Development Environment
  4. Exploring the ESP-IDF OnOff Server Example
  5. Hardware Setup and Circuit Design
  6. Configuring the Firmware
  7. Building and Flashing the Firmware
  8. Provisioning and Controlling the Nodes
  9. Troubleshooting Common Issues
  10. Advanced Concepts and Further Reading
  11. Conclusion

1. Understanding BLE Mesh Networking

What Is BLE Mesh?

BLE Mesh extends Bluetooth Low Energy from simple point‑to‑point links into a true many‑to‑many network. In a BLE Mesh:

  • Nodes communicate with each other directly or via relays.
  • Messages can hop across multiple nodes, extending range.
  • The network is self‑healing: if one node fails, messages reroute automatically.

This architecture makes BLE Mesh ideal for applications such as smart lighting, building automation, industrial sensor networks, and asset tracking. Unlike classic BLE (central/peripheral), BLE Mesh doesn’t require a central coordinator; any node can act as a relay or proxy, making the system highly scalable and robust.

Core Concepts

  • Provisioning: Securely adding a node to the mesh, assigning it addresses and keys.
  • Elements & Models: Each node can have one or more elements (logical units). Each element supports models—standardized interfaces (e.g., Generic OnOff) that define behavior.
  • Configuration Server & Client Models: Used during setup to configure nodes (e.g., set publication addresses).
  • Generic OnOff Model: A foundation model that turns an output (like an LED) on/off.

By mastering these concepts, you’ll be able to build flexible, large‑scale BLE Mesh deployments.


2. Components Required

ComponentDescriptionBuy Link
ESP32 Dev BoardDual‑core MCU with Wi‑Fi & BLEESP32‑WROOM‑32 (38‑Pin)
5 mm Red LEDs (×3)Visual indicators for On/Off commands5 mm Red LEDs
BreadboardSolderless prototyping board400‑Tie‑Points Mini Breadboard
330 Ω Resistors (×3)Current‑limiting resistors for LEDs330 Ohm Resistors
Jumper WiresFor connections between ESP32 and breadboard
USB CableFor programming and powering the ESP32Micro USB Cable
Android SmartphoneTo run the nRF Mesh mobile app for provisioning/controlnRF Mesh app (Google Play)

Gather these parts before proceeding. The total cost is modest, and all items can be purchased via the provided ElecSynergy links.


3. Setting Up the Development Environment

Before writing any code, ensure your machine is ready for ESP32 development.

3.1 Install ESP-IDF

  1. Clone the ESP-IDF repo (with submodules): git clone --recursive https://github.com/espressif/esp-idf.git
  2. Run the installer (Linux/macOS): cd esp-idf ./install.sh
  3. Export environment variables: . ./export.sh This sets IDF_PATH and updates your PATH.
  4. Verify by running: idf.py --version

3.2 Required Tools

  • Python 3.6+ (used by ESP-IDF scripts)
  • CMake & Ninja (build system)
  • Serial Terminal (e.g., miniterm, PuTTY) for idf.py monitor output

Once these are installed, you’re ready to build BLE Mesh examples.


4. Exploring the ESP-IDF OnOff Server Example

Espressif provides a ready‑made BLE Mesh example: OnOff Server, which you’ll adapt to control three LEDs.

4.1 Locating the Example

cd $IDF_PATH/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server

This directory contains:

  • main/ – application source
  • CMakeLists.txt – build configuration
  • Kconfig.projbuild – menuconfig settings

4.2 How It Works

The OnOff Server example implements:

  • Generic OnOff Server model: Responds to on/off messages.
  • Provisioning logic: Handles mesh provisioning via callbacks.
  • LED control stub: A placeholder function toggles a single LED.

We’ll extend this stub to manage three LEDs on GPIO2, GPIO4, and GPIO5.

Refer to Espressif’s BLE Mesh guide for more details on models and provisioning citeturn0search8.


5. Hardware Setup and Circuit Design

With the code base in place, let’s wire up the ESP32 and LEDs.

Interfacing ESP32 with LEDs for BLE Mesh Networking

5.1 Pin Assignments

LEDESP32 GPIOResistorBreadboard Connection
LED 1GPIO2330 ΩRow A (Anode) → GPIO2; Row B (Cathode) → GND
LED 2GPIO4330 ΩRow C (Anode) → GPIO4; Row D (Cathode) → GND
LED 3GPIO5330 ΩRow E (Anode) → GPIO5; Row F (Cathode) → GND
  1. Insert the breadboard and ESP32 so their rails align.
  2. Place each LED in its own row.
  3. Connect a 330 Ω resistor in series with each LED anode.
  4. Use jumper wires to connect resistors to GPIO2, GPIO4, GPIO5.
  5. Tie all LED cathodes to a common GND rail.

Visually verify no shorts exist. Power the ESP32 via USB; all LEDs should be off initially.


6. Configuring the Firmware

Now modify the OnOff Server example to:

  1. Initialize three GPIOs.
  2. Control each LED based on incoming mesh messages.

6.1 Define GPIOs

In main/board.h, at the top:

#define LED1_GPIO 2
#define LED2_GPIO 4
#define LED3_GPIO 5

6.2 Initialize GPIOs

Replace the single‑LED init with:

struct _led_state led_state[3] = {
    { LED_OFF, LED_OFF, LED_R, "red"   },
    { LED_OFF, LED_OFF, LED_G, "green" },
    { LED_OFF, LED_OFF, LED_B, "blue"  },
};

static void board_led_init(void)
{
    for (int i = 0; i < 3; i++) {
        gpio_reset_pin(led_state[i].pin);
        gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
        gpio_set_level(led_state[i].pin, LED_OFF);
        led_state[i].previous = LED_OFF;
    }
}

6.3 Extend the OnOff Handler

The example’s Generic OnOff Server callback receives a message with:

  • element index (which LED)
  • onoff value (0 = off, 1 = on)

Locate the example_handle_gen_onoff_msg() function and update:

static void example_handle_gen_onoff_msg(esp_ble_mesh_model_t *model,
                                         esp_ble_mesh_msg_ctx_t *ctx,
                                         esp_ble_mesh_server_recv_gen_onoff_set_t *set)
{
    esp_ble_mesh_gen_onoff_srv_t *srv = (esp_ble_mesh_gen_onoff_srv_t *)model->user_data;

    switch (ctx->recv_op) {
    case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
        esp_ble_mesh_server_model_send_msg(model, ctx,
            ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff);
        break;
    case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
    case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK:
        if (set->op_en == false) {
            srv->state.onoff = set->onoff;
        } else {
            /* TODO: Delay and state transition */
            srv->state.onoff = set->onoff;
        }
        if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
            esp_ble_mesh_server_model_send_msg(model, ctx,
                ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff);
        }
        esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
            sizeof(srv->state.onoff), &srv->state.onoff, ROLE_NODE);
        example_change_led_state(model, ctx, srv->state.onoff);
        break;
    default:
        break;
    }
}

Download the full code here.

6.4 Update CMakeLists.txt

No changes needed if you’re still in the same folder; just ensure main/onoff_server.c includes your modifications.


7. Building and Flashing the Firmware

With code updated, it’s time to build and flash.

  1. Set target (if not already): idf.py set-target esp32
  2. Menuconfig (optional): idf.py menuconfig
    • Under Component config → Bluetooth Mesh, set Number of Elements to 3.
    • Configure other mesh parameters as needed (TTL, relay, proxy).
  3. Build: idf.py build
  4. Flash & Monitor: idf.py -p /dev/ttyUSB0 flash monitor

You should see log output for mesh initialization:

I (1234) BLE_MESH: [BLE Mesh Initialized]
I (2345) BLE_MESH: Provisioning started

If you enabled proxy, you can connect via a standard BLE browser; otherwise use the provisioning flow.


8. Provisioning and Controlling the Nodes

8.1 Install nRF Mesh App

The nRF Mesh app allows you to provision, configure, and control nodes citeturn0search1.

8.2 Provisioning Steps

  1. Launch the nRF Mesh app and create a new network.
  2. Tap “+” to scan for unprovisioned devices. Your ESP32 nodes appear as “ESP_BLE_MESH”.
  3. Select a node (it will blink its LED to identify).
  4. Provision with No OOB or your chosen method.
  5. Repeat for all three nodes.

After provisioning, each node has:

  • A unicast address (e.g., 0x0001, 0x0002, 0x0003).
  • A network key and application key for secure messaging.

8.3 Binding and Publishing

For each node:

  1. Bind the Generic OnOff Server model to the App Key.
  2. Set Publication: Configure each server to publish its state changes to a group address (e.g., 0xC000).
  3. Subscribe: Optionally, have nodes subscribe to that group so they see each other’s messages.

8.4 Sending On/Off Commands

In the app’s Control tab:

  • Select Generic OnOff.
  • Choose Unicast to target a single node, or Group to broadcast.
  • Tap ON or OFF.

You should see the corresponding LED turn on/off in real time.


9. Troubleshooting Common Issues

9.1 No Devices Found During Provisioning

  • Ensure Bluetooth is enabled on your phone.
  • Confirm ESP32 logs show “Advertising”.
  • If using Proxy, ensure GATT Proxy is enabled in menuconfig.

9.2 LED Doesn’t Respond

  • Double‑check GPIO wiring and resistor placement.
  • Verify example_led_onoff_set() uses correct element_index.
  • Look for errors in the serial log (idf.py monitor).

9.3 Mesh Messages Not Relaying

  • Enable Relay in menuconfig under Mesh Feature.
  • Increase TTL (Time To Live) if nodes are far apart.
  • Ensure nodes subscribe/publish to correct addresses.

9.4 Provisioning Fails or Times Out

  • Power‑cycle the ESP32 to reset advertising state.
  • Use No OOB provisioning first; add security later.
  • Ensure your App Key is the same for all nodes.

10. Advanced Concepts and Further Reading

10.1 Proxy Support

Enable GATT Proxy to allow non‑mesh BLE devices (like phones) to interact with the mesh via a single node.

10.2 Fast Provisioning

ESP-IDF supports Fast Provisioning for batch‑adding multiple nodes quickly. Explore the fast_prov examples.

10.3 Vendor Models

Create custom models to carry proprietary data. The vendor_models example shows how to define your own model IDs and payloads.

10.4 Coexistence with Wi‑Fi

ESP32 can run BLE Mesh alongside Wi‑Fi. The wifi_coexist example demonstrates maintaining mesh performance while streaming data over Wi‑Fi.


11. Conclusion

In this tutorial, you’ve learned how to build a BLE Mesh network using ESP32 and ESP-IDF, leveraging the official OnOff Server example to control three LEDs on GPIO2, GPIO4, and GPIO5. You saw how to:

  • Set up your development environment
  • Modify and extend the mesh example for multiple elements
  • Wire hardware on a breadboard
  • Build, flash, and monitor firmware
  • Provision nodes and send on/off commands via the nRF Mesh app

BLE Mesh offers a powerful, scalable solution for IoT networks. With ESP32 and ESP-IDF, you have a cost‑effective platform to prototype and deploy robust mesh systems.

If you enjoyed this guide, don’t forget to subscribe to our YouTube channel for the full video demo and more projects. Visit our store to grab the components and start building today!


📽️ Watch the Full Demo

👉 BLE Mesh LED Control with ESP32 – YouTube Tutorial


🛒 Buy the Components


Ready to build your own BLE Mesh network?
Share your projects and questions in the comments below or reach out on our social channels. Happy building!

Also, check out our other playlist Rasa ChatbotInternet of thingsDockerPython ProgrammingMachine LearningNatural Language ProcessingMQTTTech NewsESP-IDF etc.
Become a member of our social family on youtube here.
Stay tuned and Happy Learning. ✌🏻😃
Happy coding, and may your NLP endeavors be both enlightening and rewarding! ❤️🔥🚀🛠️🏡💡

Leave a Reply