yahboom
HomeLearn
Solution
Blog
Online Store
About Us
EN/中文
ESP32 Core Board📖
1. ESP32 Introduction
  • 1. ESP32S3 Overview
  • 2. Environment Setup Introduction
  • 3. Dev Board Introduction
2. ESP-IDF Development Tutorial
1. Before Development
  • 1. Environment Setup (Windows)
  • 2. Environment Setup (Linux)
  • 3. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. DMA
  • 8. ADC
  • 9. PWM Breathing LED
  • 10. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. PSRAM External Memory Experiment
  • 5. Flash Read and Write Experiment
  • 6. USB Emulated Mass Storage Experiment
4. FreeRTOS operating system
  • 1.FreeRTOS Core Concepts Theory
  • 2.Task Creation and Management
  • 3.Queue
  • 4.Binary Semaphore
  • 5.Mutex
  • 6.Event Groups
  • 7.Software Timer
  • 8.Task Scheduler
  • 9.Low Power Mode
  • 10.Deadlock
  • 11.Priority Inversion
5. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. Socket Programming Basics
  • 9. HTTP Client Experiment
  • 10. HTTP Server Experiment
  • 11. MQTT IoT Communication Protocol
  • 12. WIFI OTA Upgrade
  • 13. Bluetooth Fundamentals
  • 14. Bluetooth Slave Mode
  • 15. Bluetooth Master Mode
6. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
7. Xiaozhi AI Voice
  • 1. Burn Xiaozhi Firmware
  • 2. Network and Configuration
  • 3. AI Agent Settings
  • 4. Program Analysis
  • 5. Free Chat
3. Arduino Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. ADC
  • 8. PWM Breathing LED
  • 9. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication
  • 2. I2C OLED Display
  • 3. SPI Bus Communication
  • 4. Flash Read and Write
  • 5. USB Emulated Mass Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Server Experiment
  • 5. UDP Client Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT IoT Communication Protocol
  • 11. WIFI OTA Upgrade
  • 12. Bluetooth Fundamentals
  • 13. Bluetooth Slave Mode
  • 14. Bluetooth Master Mode
5. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
4. MicroPython Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
  • 3. Thonny IDE
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. TIMER_IT
  • 5. Watchdog Timer
  • 6. ADC
  • 7. PWM Breathing LED
  • 8. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. Flash Read and Write Experiment
  • 5. Print Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT
  • 11. Bluetooth Fundamentals
  • 12. Bluetooth Slave Mode
  • 13. Bluetooth Master Mode
5. Audio Applications
  • 1. I2S Audio Playback Experiment
  • 2. Repeater Experiment
Download
  • Code
  • Hardware_Info
  • 3D_Model_File
  • Software_Tools
  • VMware
  • VM_File
Download ZIP

Welcome to ESP32 Core Board repository

13. Bluetooth Slave Mode

Bluetooth Slave Mode

Bluetooth Slave Mode


Bluetooth Slave Mode1. Bluetooth Slave Overview2. Core Concepts2.1 GAP — Generic Access Profile2.2 GATT — Generic Attribute Profile2.3 Notify vs Write2.4 NimBLE-Arduino Library Architecture2.5 Notify vs Indicate Implementation Differences in Arduino3. Hardware Dependencies3.1 ESP32-S3 BLE Hardware Specifications3.2 Required Libraries4. Project Architecture and Flow5. Source Code Analysis5.1 Header Files and Global Variables5.2 Receiving Master Data — WriteCallbacks5.3 Connect/Disconnect Event Callbacks — ServerCallbacks5.4 FreeRTOS Push Task — sendTask5.5 setup() — Initialize BLE Slave5.6 loop() — Empty Loop6. Operation Procedures6.1 Build and Flash6.2 Method 1: Phone Bluetooth Debug6.3 Method 2: Dual-Board Communication Test (Requires Two Boards)6.4 Expected Output — Phone Debug6.5 Expected Output — Dual-Board Communication6.6 Log Field Description6.7 Edge Cases7. FAQ


1. Bluetooth Slave Overview

BLE (Bluetooth Low Energy) is a short-range wireless communication protocol designed for low power consumption and low bandwidth scenarios. Compared to Classic Bluetooth, BLE connections are faster (millisecond-level) and consume less power (coin batteries can run for months).

Importance of BLE Slave Tutorial: BLE Slave (Peripheral) is the most common role for IoT devices — sensor nodes, wearable devices, smart home peripherals, etc. Most scenarios run as slaves. Mastering slave programming means you can build smart devices that can be discovered and connected by phones, tablets, or gateways. This is a core skill for embedded BLE development.

This experiment uses the NimBLE protocol stack (saves ~50% RAM compared to Arduino's default Bluedroid), creating a FreeRTOS task that pushes data to the master every 2 seconds, while also receiving data written by the master.

After completing this tutorial, you will have: An ESP32-S3 development board broadcasting with device name ESP-IDF. Phones or another ESP32-S3 can scan, connect, receive pushed data every 2 seconds, and send arbitrary text commands to the slave — a complete bidirectional BLE communication slave.

Typical Application Scenarios:

Application TypeExample
Sensor SlaveThermometer broadcasts and pushes readings
Wearable DeviceFitness band pushes heart rate data to phone
BeaconiBeacon location broadcast

BLE Role System:

RoleGAP NameResponsibility
SlavePeripheralBroadcasts presence, accepts connections, provides GATT services for master access
MasterCentralActively scans nearby devices, initiates connections, discovers services and characteristics, reads/writes data

2. Core Concepts

2.1 GAP — Generic Access Profile

GAP (Generic Access Profile) defines how BLE devices are scanned and connected.

GAP operations for this slave:

OperationArduino APIDescription
AdvertisingNimBLEDevice::getAdvertising()->start()Periodically sends advertising packets containing device name and service UUID
Connection ResponseServerCallbacks::onConnect()Accepts master connection request, updates connection status
Re-advertising on DisconnectServerCallbacks::onDisconnect() → NimBLEDevice::startAdvertising()Automatically restarts advertising after disconnection

Advertising Packet Structure

Advertising Packet
  ├─ Flags: General discoverable + BR/EDR not supported
  ├─ Name: "ESP-IDF" (Complete)
  │         Complete device name; central matches on this
  └─ Service UUID: 0xFFF0 (Complete List of 16-bit Service UUIDs)
            Custom service UUID; central can determine available services during scan

2.2 GATT — Generic Attribute Profile

GATT (Generic Attribute Profile) defines the data organization structure of BLE devices.

GATT Custom Service Architecture for This Project

xxxxxxxxxx
Service: 0xFFF0 (Custom Primary Service)
  ├─ Characteristic: 0xFFF1
  │     Properties: READ | NOTIFY (Readable + Slave notifies master actively)
  │     Direction: Slave → Master
  │     Purpose: Slave pushes data to central via Notify every 2 seconds
  │
  └─ Characteristic: 0xFFF2
        Properties: WRITE | WRITE_NR (Supports both acknowledged and unacknowledged writes)
        Direction: Master → Slave
        Purpose: Receives data from central, processed in onWrite() callback

2.3 Notify vs Write

OperationInitiatorTargetAcknowledgmentTypical Scenario
NotifySlave → Master0xFFF1No ACKSensor data reporting, heartbeat counting
WriteMaster → Slave0xFFF2WRITE: Requires link layer ACK; WRITE_NR: No ACKControl command delivery, parameter configuration
IndicateSlave → Master(Not used)Requires master ACKCritical data reporting, guaranteed delivery

In this project, the slave sends a fixed message via Notify on 0xFFF1 every 2 seconds; the master can write arbitrary data to 0xFFF2 at any time, and the slave receives and prints it immediately in onWrite(). Both operations are asynchronous and independent, non-blocking.

2.4 NimBLE-Arduino Library Architecture

ESP32-S3 uses Apache NimBLE as the BLE Host protocol stack.

Core Class Hierarchy

xxxxxxxxxx
NimBLEDevice               ← Static class, stack initialization + global control
  ├─ NimBLEServer          ← GATT server, manages service list
  │    ├─ NimBLEService    ← GATT service, contains multiple characteristics
  │    │    └─ NimBLECharacteristic  ← GATT characteristic, data carrier + callback binding
  │    └─ NimBLEServerCallbacks     ← User overrides onConnect/onDisconnect
  ├─ NimBLEAdvertising     ← Advertising parameter config and control
  └─ NimBLECharacteristicCallbacks  ← User overrides onWrite/onRead

Compared to ESP-IDF native NimBLE's callback-style API (gap_event_cb, gatt_svr_access_cb), the Arduino wrapper maps each event type to independent C++ virtual methods implemented through class inheritance. This makes code logic more focused and eliminates the need for switch/case dispatching in a single callback function.

2.5 Notify vs Indicate Implementation Differences in Arduino

In Arduino NimBLEDevice library, the difference between notify and indicate is determined by characteristic properties and send methods together.

OperationProperty DeclarationSend MethodMaster Acknowledgment
NotifyNIMBLE_PROPERTY::NOTIFYpChar->notify()No
IndicateNIMBLE_PROPERTY::INDICATEpChar->indicate()Yes
​x
// Notify — No ACK, suitable for high-frequency sensor data
pCharNotify = pService->createCharacteristic(
    CHAR_NOTIFY_UUID,
    NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY  // Declare NOTIFY property
);
pCharNotify->setValue("Hello");
pCharNotify->notify();   // Send ATT Handle Value Notification

// Indicate — Requires ACK, suitable for critical control commands
// pChar->indicate();    // Send ATT Handle Value Indication

3. Hardware Dependencies

3.1 ESP32-S3 BLE Hardware Specifications

SpecificationParameter
Wireless StandardBLE 5.0
Max TX Power+20 dBm
Receiver Sensitivity-97 dBm (1Mbps mode)
Max MTU251 bytes (Auto-negotiated by NimBLE-Arduino)
AntennaOn-board PCB antenna
Advertising IntervalProtocol stack default (~100ms)
Protocol StackNimBLE (Apache open source) via NimBLE-Arduino
Arduino TX Power SettingNimBLEDevice::setPower(ESP_PWR_LVL_P3) — Set to +3dBm in this tutorial

BLE and Wi-Fi share the 2.4GHz RF front-end and can coexist through time-division multiplexing.

3.2 Required Libraries

LibraryPurposeInclude Method
NimBLEDevice.hNimBLE BLE protocol stack Arduino wrapper#include <NimBLEDevice.h>

NimBLEDevice library needs to be installed via Arduino IDE library manager: Tools → Manage Libraries → Search "NimBLE" → Install "NimBLE-Arduino" (Author: h2zero). Do not confuse with ESP32's built-in "BLE" library (based on Bluedroid).


4. Project Architecture and Flow

File Structure ([BLE_Slave.ino](../../../Arduino/3.Network%20Communication/BLE_Slave/BLE_Slave.ino), ~90 lines total):

xxxxxxxxxx
BLE_Slave.ino
├─ #include + Macros (DEVICE_NAME, SERVICE_UUID, CHAR_*_UUID)
├─ Global variables (pServer, pCharNotify, g_connected)
├─ class WriteCallbacks         ← Receives master writes (5.2)
├─ class ServerCallbacks        ← Connect/disconnect events (5.3)
├─ void sendTask()              ← FreeRTOS periodic push (5.4)
├─ void setup()                 ← BLE slave initialization six-step method (5.5)
└─ void loop()                  ← Empty loop (5.6)

Program Flow:

xxxxxxxxxx
setup()
  ├─ NimBLEDevice::init("ESP-IDF")                       // Initialize stack
  ├─ createServer() + setCallbacks(serverCb)              // Create GATT server
  ├─ createService(0xFFF0)
  │    ├─ createCharacteristic(0xFFF1, READ|NOTIFY)      // Notify characteristic
  │    └─ createCharacteristic(0xFFF2, WRITE|WRITE_NR)   // Write characteristic + bind callback
  ├─ service.start()
  └─ startAdvertising()                                   // Start advertising

sendTask (FreeRTOS):
  └─ Every 2s: setValue + notify                             // Push data

WriteCallbacks::onWrite():
  └─ Print data received from master

5. Source Code Analysis

Source code: Source code → Arduino → 3.Network Communication → BLE_Slave → BLE_Slave.ino

5.1 Header Files and Global Variables

The top of the file contains #include, macro definitions, and global variables. NimBLEDevice.h is the only header file, which internally aggregates all C++ wrapper classes for the NimBLE protocol stack. Macros use NimBLEUUID((uint16_t)0x...) to wrap 16-bit UUIDs into BLE standard 128-bit UUIDs. Three global variables — server pointer, Notify characteristic pointer, and connection status flag — persist throughout the program lifecycle.

xxxxxxxxxx
// NimBLE BLE stack
#include <NimBLEDevice.h>

// Advertising device name
#define DEVICE_NAME          "ESP-IDF"
// Primary service UUID
#define SERVICE_UUID         NimBLEUUID((uint16_t)0xFFF0)
// Notify char — slave→central
#define CHAR_NOTIFY_UUID     NimBLEUUID((uint16_t)0xFFF1)
// Write char — central→slave
#define CHAR_WRITE_UUID      NimBLEUUID((uint16_t)0xFFF2)

// BLE GATT server pointer
NimBLEServer*        pServer      = nullptr;
// Notify char pointer
NimBLECharacteristic* pCharNotify = nullptr;
// BLE connection status flag
bool                  g_connected  = false;

5.2 Receiving Master Data — WriteCallbacks

WriteCallbacks is responsible for receiving data sent by the master through the Write characteristic (0xFFF2). It inherits from NimBLECharacteristicCallbacks and overrides onWrite(), which NimBLE protocol stack automatically calls each time a master write completes. getValue() returns complete data (std::string), no manual mbuf operation or packet aggregation timer needed.

xxxxxxxxxx
// Callback class for receiving central write data
class WriteCallbacks : public NimBLECharacteristicCallbacks {
  void onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connInfo) override {
    // Get data central just wrote
    std::string recvData = pChar->getValue();
    Serial.println("==================================");
    Serial.printf("Host Message: %s\n", recvData.c_str());
    Serial.println("==================================");
  }
} writeCb;  // Global instance, bound when creating characteristic

5.3 Connect/Disconnect Event Callbacks — ServerCallbacks

Connect and disconnect are two critical events in the BLE slave lifecycle. Inherit from NimBLEServerCallbacks and override onConnect and onDisconnect: on connect, set the status flag for the send task; on disconnect, clear the flag first then call startAdvertising() to resume advertising — otherwise the device will be "silent" and the master can never scan it again.

xxxxxxxxxx
// BLE connect/disconnect callbacks class
class ServerCallbacks : public NimBLEServerCallbacks {
  void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
    // Set connection flag
    g_connected = true;
    Serial.println("Bluetooth connected");
  }

  void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
    // Clear connection flag
    g_connected = false;
    Serial.println("Bluetooth disconnected");
    // Key: restart advertisi
Bluetooth Fundamentals
Bluetooth Master Mode

COMPANY

  • About us
  • Team Style
  • Blog

LEARNING & EXPLORATION

  • Tutorials
  • Edge AI hardware
  • Educational robots
  • Embedded intelligent hardware

WHERE TO BUY

  • Yahboom Online Store
  • Amazon
  • Alibaba
  • AliExpress
  • Mercado

TECHNOLOGY SUPPORT

  • Email: support@yahboom.com

BE A DISTRIBUTOR

  • Email: sales@yahboom.com
QR Code

Copyright © 2017-2026 Yahboom. All Rights Reserved.

EN/中文