Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home IoT & Smart Home

ESP32 Bluetooth Low Energy Tutorial: BLE GATT Server

ESP32 Bluetooth Low Energy Tutorial: BLE GATT Server

March 11, 2026 /Posted byJayesh Jain / 0

The ESP32 BLE GATT server tutorial you’ve been searching for is here — a deep, hands-on guide that goes beyond blinking an LED over Bluetooth and teaches you the architectural concepts behind Bluetooth Low Energy. The ESP32’s built-in BLE stack (based on NimBLE or Bluedroid) makes it one of the most capable and affordable platforms for building BLE-enabled IoT devices — smart sensors, wearables, home automation bridges, and industrial monitoring nodes. This guide covers the complete GATT protocol stack, building a working BLE server with custom services and characteristics, implementing notifications, and connecting from an Android or iOS app.

Table of Contents

  1. BLE Fundamentals: GAP, GATT, Services and Characteristics
  2. ESP32 BLE Stack: NimBLE vs Bluedroid
  3. Building a BLE GATT Server with Arduino Framework
  4. Understanding Characteristic Properties: Read, Write, Notify
  5. Real Project: BLE Temperature Sensor with Notifications
  6. BLE Security: Pairing and Bonding on ESP32
  7. NimBLE with ESP-IDF for Production Firmware
  8. Frequently Asked Questions

BLE Fundamentals: GAP, GATT, Services and Characteristics

Before writing a single line of code, understanding the BLE protocol architecture is essential. BLE is not the same as classic Bluetooth (BR/EDR) — it’s a completely different protocol optimised for low power, short data bursts, and simple one-to-one or one-to-many device communication. BLE operates on 40 RF channels in the 2.4 GHz band and uses FHSS (Frequency Hopping Spread Spectrum) to avoid interference with WiFi on the same ESP32.

GAP: Generic Access Profile

GAP controls how BLE devices advertise themselves and how connections are established. Two key roles:

  • Peripheral (Server): Broadcasts advertising packets at defined intervals (typically 100–500 ms). Your ESP32 GATT server runs in this role — it advertises its presence and accepts connections from central devices.
  • Central (Client): Scans for advertising packets and initiates connections. Your smartphone app runs in this role.

Advertising packets contain the device name, UUID of advertised services, and optionally manufacturer-specific data — all within 31 bytes (extended advertising in BLE 5.0 allows up to 255 bytes).

GATT: Generic Attribute Profile

Once a BLE connection is established, communication happens via GATT. GATT organises data into a hierarchical structure:

  • Profile: A collection of services (e.g., Heart Rate Profile, Environmental Sensing Profile).
  • Service: Groups related characteristics. Identified by a 16-bit UUID (standardised by Bluetooth SIG) or 128-bit UUID (custom). Example: Battery Service = 0x180F.
  • Characteristic: The actual data container. Each characteristic has a UUID, a value (up to 512 bytes), and properties that define allowed operations (Read, Write, Notify, Indicate).
  • Descriptor: Metadata attached to a characteristic. The most important is CCCD (Client Characteristic Configuration Descriptor, UUID 0x2902), which the client writes to enable/disable notifications.

UUID Reference Table

Service/Characteristic 16-bit UUID Properties
Generic Access Service 0x1800 –
Battery Service 0x180F –
Battery Level 0x2A19 Read, Notify
Environmental Sensing 0x181A –
Temperature 0x2A6E Read, Notify
Humidity 0x2A6F Read, Notify
Device Information 0x180A –

ESP32 BLE Stack: NimBLE vs Bluedroid

ESP32 supports two Bluetooth stacks:

Bluedroid (Classic + BLE)

Bluedroid is Espressif’s port of the Android Bluetooth stack. It supports both Classic Bluetooth (for A2DP audio, SPP serial profile) and BLE. However, it consumes about 100 KB more RAM than NimBLE and is slower to initialise. Bluedroid is the default in the Arduino ESP32 core’s BLEDevice.h library.

NimBLE (BLE Only)

NimBLE is Apache’s open-source BLE-only stack ported to ESP-IDF. It uses approximately 50 KB less RAM than Bluedroid, initialises in ~100 ms instead of ~500 ms, and achieves better throughput. The Arduino NimBLE-Arduino library provides a nearly API-compatible replacement for Bluedroid’s BLEDevice.h. For new projects that don’t need Classic Bluetooth, always choose NimBLE.

In PlatformIO, add to your platformio.ini:

lib_deps = h2zero/NimBLE-Arduino@^1.4.1
ESP32-C3-01M Wi-Fi + BLE Module

Ai Thinker ESP32-C3-01M Wi-Fi + BLE Module

The ESP32-C3 natively supports Bluetooth 5.0 LE with improved range — perfect for BLE GATT server projects where the module will be mounted inside an enclosure away from the phone.

View on Zbotic

Building a BLE GATT Server with Arduino Framework

Here is a complete, working BLE GATT server for ESP32 using the NimBLE-Arduino library. This server exposes a custom service with two characteristics: one readable and one notifiable.

#include <NimBLEDevice.h>

// Custom 128-bit service and characteristic UUIDs
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHAR_READ_UUID      "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define CHAR_NOTIFY_UUID    "1c95d5e3-d8f7-413a-bf3d-7a2e5d7be87e"

NimBLEServer* pServer = nullptr;
NimBLECharacteristic* pReadChar = nullptr;
NimBLECharacteristic* pNotifyChar = nullptr;
bool deviceConnected = false;
uint32_t counter = 0;

class ServerCallbacks : public NimBLEServerCallbacks {
    void onConnect(NimBLEServer* pSrv, NimBLEConnInfo& connInfo) {
        deviceConnected = true;
        Serial.printf("Client connected: %sn", connInfo.getAddress().toString().c_str());
    }
    void onDisconnect(NimBLEServer* pSrv, NimBLEConnInfo& connInfo, int reason) {
        deviceConnected = false;
        NimBLEDevice::startAdvertising();
        Serial.println("Client disconnected, restarting advertising");
    }
};

void setup() {
    Serial.begin(115200);
    NimBLEDevice::init("ESP32-Zbotic-Sensor");
    NimBLEDevice::setPower(ESP_PWR_LVL_P9);  // Max TX power

    pServer = NimBLEDevice::createServer();
    pServer->setCallbacks(new ServerCallbacks());

    NimBLEService* pService = pServer->createService(SERVICE_UUID);

    // Read characteristic: client can poll this
    pReadChar = pService->createCharacteristic(
        CHAR_READ_UUID,
        NIMBLE_PROPERTY::READ
    );
    pReadChar->setValue("Hello from ESP32!");

    // Notify characteristic: ESP32 pushes updates
    pNotifyChar = pService->createCharacteristic(
        CHAR_NOTIFY_UUID,
        NIMBLE_PROPERTY::NOTIFY
    );

    pService->start();

    NimBLEAdvertising* pAdv = NimBLEDevice::getAdvertising();
    pAdv->addServiceUUID(SERVICE_UUID);
    pAdv->setScanResponse(true);
    pAdv->start();
    Serial.println("BLE GATT Server advertising...");
}

void loop() {
    if (deviceConnected) {
        // Send counter value as notification every second
        counter++;
        pNotifyChar->setValue(counter);
        pNotifyChar->notify();
        Serial.printf("Notified: %un", counter);
    }
    delay(1000);
}

Understanding Characteristic Properties: Read, Write, Notify

Each characteristic can have one or more properties that define what operations the GATT client (smartphone) can perform on it:

READ

The client can request the current value at any time. The server responds synchronously. Use for: device firmware version, configuration settings, last sensor reading. The server must update the characteristic’s value before the client reads it (or set it in a READ callback).

WRITE and WRITE_NR

The client sends data to the server. WRITE requires an acknowledgment (confirmed write); WRITE_NR (No Response) is fire-and-forget. Use for: sending commands, updating LED colour, changing sensor polling rate. Implement a NimBLECharacteristicCallbacks::onWrite() callback to process incoming data.

NOTIFY

The server pushes data to the client without the client needing to poll. Notifications are unconfirmed — they may be lost in a congested RF environment. Use for: sensor readings, counter values, status updates. The client must first write 0x0001 to the CCCD descriptor to enable notifications — this is handled automatically by most BLE apps.

INDICATE

Same as Notify but confirmed — the client must acknowledge each indication. This guarantees delivery but at the cost of throughput. Use for: critical alerts, commands that must not be missed (e.g., lock/unlock commands in a smart lock product).

Real Project: BLE Temperature Sensor with Notifications

Let’s build a practical BLE temperature sensor using the DHT11 sensor and ESP32. The ESP32 reads temperature and humidity every 2 seconds and sends them via BLE notifications to a connected smartphone.

DHT11 Temperature and Humidity Sensor with LED

DHT11 Temperature and Humidity Sensor Module with LED

The DHT11 with built-in LED indicator is the ideal beginner sensor for an ESP32 BLE GATT server project — connect to GPIO and broadcast temperature/humidity via Bluetooth to any smartphone app.

View on Zbotic

The DHT11 connects to GPIO 4. Add the DHT sensor library and NimBLE-Arduino to your project. In the firmware, use the BLE Environmental Sensing Service (0x181A) with standard Temperature Characteristic (0x2A6E) and Humidity Characteristic (0x2A6F) UUIDs — this makes the sensor compatible with any standard BLE health/environment app on Android or iOS without a custom app.

// Temperature value format: int16_t, unit 0.01 °C
// 25.00°C → 2500 (0x09C4)
int16_t temp_val = (int16_t)(temperature * 100);
pTempChar->setValue((uint8_t*)&temp_val, 2);
pTempChar->notify();

// Humidity value format: uint16_t, unit 0.01 %
uint16_t hum_val = (uint16_t)(humidity * 100);
pHumChar->setValue((uint8_t*)&hum_val, 2);
pHumChar->notify();

Open the nRF Connect app on your phone (Android or iOS), scan for “ESP32-Zbotic-Sensor”, connect, navigate to the Environmental Sensing service, and enable notifications on both characteristics. You’ll see live temperature and humidity updates on your phone without any custom app development.

BLE Security: Pairing and Bonding on ESP32

For IoT products deployed in real environments — smart locks, industrial sensors, medical devices — BLE security is non-negotiable. ESP32 NimBLE supports all BLE security modes:

Pairing Methods

  • Just Works: No user confirmation — easiest but vulnerable to man-in-the-middle attacks. Acceptable for low-security applications like a BLE LED controller.
  • Passkey Entry: A 6-digit PIN displayed on the peripheral (ESP32 serial output or display) is entered on the phone. Protects against passive eavesdropping.
  • Numeric Comparison (BLE 4.2+): A 6-digit number shown on both devices. User confirms they match. Protects against MITM attacks.
  • OOB (Out-of-Band): Uses NFC or QR code to exchange keys — highest security, requires additional hardware.
// Enable BLE security with passkey
NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_SC | BLE_SM_PAIR_AUTHREQ_BOND);
NimBLEDevice::setSecurityPasskey(123456);
NimBLEDevice::setSecurityIOCap(BLE_SM_IO_CAP_OUT_ONLY); // Display passkey

Bonding stores the long-term key (LTK) in ESP32 NVS flash, so subsequent connections are instant without re-pairing — critical for user experience in consumer IoT products.

NimBLE with ESP-IDF for Production Firmware

For production ESP-IDF projects, NimBLE is included in the IDF component registry. The architecture uses an event-driven callback model with a NimBLE host task running on a dedicated FreeRTOS task. Key advantages over the Arduino wrapper:

  • Full access to NimBLE’s L2CAP (Layer 2 Connection Oriented Channels) for custom protocols with 500+ byte MTU.
  • BLE 5.0 extended advertising with 255-byte payload (more device info, manufacturer data).
  • 2 Mbps PHY (BLE 5.0) support on ESP32-S3 for 2× the throughput at the same power level.
  • BLE mesh networking for multi-device smart home automation.
Ai-Thinker ESP32-C3-12F Module

Ai-Thinker ESP32-C3-12F Wi-Fi + BLE Module

The ESP32-C3-12F with 4MB flash and PCB antenna is an excellent production module for BLE GATT server products — RISC-V architecture, Bluetooth 5.0 LE, and a compact form factor for product integration.

View on Zbotic

Frequently Asked Questions

What is the maximum BLE range I can expect from an ESP32?

In open air with maximum TX power, ESP32 BLE reaches 50–100 metres. In an indoor home or office environment with walls and interference, expect 10–30 metres. The ESP32-C3 and ESP32-S3 have improved RF front-ends and can achieve better range than original ESP32 modules. For extended range, use an IPEX antenna connector with an external PCB antenna.

Can ESP32 be a BLE central (scanner) and peripheral (server) simultaneously?

Yes — ESP32 supports simultaneous BLE advertising (peripheral role) and scanning/connection (central role). This is called a BLE Multi-Role configuration. One practical use case: an ESP32 BLE gateway that scans for BLE sensor beacons (central role) and simultaneously advertises its own GATT service to a phone app (peripheral role). Enable multi-role in NimBLE by configuring both NimBLEScan and NimBLEServer.

Why do BLE notifications stop after a few seconds on Android?

Android aggressively manages BLE connections to save battery. If the ESP32’s connection interval is too short (< 15 ms) or the supervision timeout is too low, Android may terminate the connection. Set the preferred connection parameters in your ESP32 firmware: minimum interval 15 ms, maximum interval 30 ms, supervision timeout 500 ms. In NimBLE: pServer->updateConnParams(connInfo.getConnHandle(), 12, 24, 0, 500).

How do I send data larger than the MTU size over BLE?

Standard BLE MTU is 23 bytes (20 bytes payload). After connection, the GATT client and server negotiate a larger MTU (up to 512 bytes in BLE 4.2, up to 2048 bytes in BLE 5.0). NimBLE negotiates MTU automatically. For payloads larger than the negotiated MTU, implement a fragmentation protocol in your application layer: split data into chunks, add sequence numbers, reassemble on the client side. Alternatively, use BLE 5.0’s larger PDU size or switch to a different transport (BLE L2CAP CoC channels allow 64 KB+ throughput).

Is ESP32 BLE compatible with iPhone/iOS?

Yes, all standard Bluetooth SIG-defined GATT services work with iOS Core Bluetooth without any special approval. Custom 128-bit UUID services also work. The key iOS restriction is that background BLE scanning is rate-limited — apps that need continuous background updates must use the Core Bluetooth state restoration API. For the device side (ESP32 firmware), no special configuration is needed for iOS compatibility beyond standard BLE spec compliance.

Build Your BLE IoT Project with Components from Zbotic

Zbotic.in has everything you need for ESP32 BLE projects: ESP32 development boards, ESP32-C3 modules, DHT11/DHT20 sensors, BME280, and battery shields — all available with fast shipping across India.

Shop ESP32 and IoT Components at Zbotic

Tags: BLE IoT, Bluetooth Low Energy, ESP32 BLE, ESP32 Bluetooth, GATT server
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Time Series IoT Database: Infl...
blog time series iot database influxdb with esp32 and grafana 595529
blog esp32 gps tracker nmea parsing with neo 6m module 595538
ESP32 GPS Tracker: NMEA Parsin...

Related posts

Svg%3E
Read more

IoT Home Insurance Sensor Kit: Leak, Smoke, and Motion

April 1, 2026 0
Table of Contents IoT and Home Insurance Water Leak Detection Smoke and Fire Detection Motion and Intrusion Sensing Building the... Continue reading
Svg%3E
Read more

IoT Pet Tracker: GPS Collar with Geofencing Alerts

April 1, 2026 0
Table of Contents Introduction and Overview Hardware Components Required GPS Module Integration with ESP32 Cloud Platform Setup Real-Time Tracking Dashboard... Continue reading
Svg%3E
Read more

IoT Aquaponics Controller: Fish and Plant Automation

April 1, 2026 0
Table of Contents The Water Monitoring Challenge in India Sensor Technologies for Water Building the Sensor Node Data Transmission and... Continue reading
Svg%3E
Read more

IoT Composting Monitor: Temperature and Moisture Tracking

April 1, 2026 0
Table of Contents Why Temperature Monitoring Matters Sensor Selection Guide Hardware Assembly and Wiring Firmware Development Cloud Data Logging Alert... Continue reading
Svg%3E
Read more

IoT Beehive Monitor: Weight, Temperature, and Humidity

April 1, 2026 0
Table of Contents Why Monitor Beehives Weight Measurement System Temperature and Humidity Sensing Building the Monitor Data Analysis for Bee... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now