šŸ’” Electron Parade
← Back to Academy

Look, I get it. You’ve finally mastered making an LED blink over Wi-Fi, and now I’m asking you to learn Bluetooth Low Energy (BLE). I know what you’re thinking: ā€œIsn’t Bluetooth just that thing that mysteriously refuses to pair with my car stereo every morning?ā€ Yes. Yes it is.

But here’s the reality: if you want to build battery-powered wearables, smart home sensors, or literally anything that needs to talk to a smartphone without obliterating its own battery in 45 minutes, you have to learn BLE.

Is the documentation a labyrinth of acronyms like GATT, GAP, UUIDs, and Characteristics? Absolutely. Does it feel like trying to read spaghetti code written by a caffeinated spider? You bet. But fear not. Today, we’re going to strip away the magic blue smoke of confusion and build a BLE GATT Server on an ESP32. We’ll make your board broadcast its feelings (or at least some sensor data) directly to your phone. Let’s dive in.

The Hardware You Need

To follow along, you just need a microcontroller with built-in BLE capabilities. The ESP32 is the undisputed king here.

Understanding the Alphabet Soup: GAP and GATT

Before we write code, we need to understand the two main roles in BLE.

1. GAP (Generic Access Profile)

This is how devices find each other. GAP controls advertising and connections.

2. GATT (Generic Attribute Profile)

Once connected, GATT takes over. This is how data is actually organized and exchanged. Think of GATT like a highly structured spreadsheet.

The Code: Setting Up a Basic GATT Server

We’re going to write an Arduino sketch that turns our ESP32 into a BLE server. It will host one Service and one Characteristic. You can read the characteristic from your phone using an app like nRF Connect.

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  // 1. Initialize the BLE Device
  BLEDevice::init("ESP32_ElectronParade");

  // 2. Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();

  // 3. Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // 4. Create a BLE Characteristic
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setValue("Hello from the Magic Blue Smoke!");

  // 5. Start the service
  pService->start();

  // 6. Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  
  Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop() {
  // We aren't doing anything in the loop for this basic example.
  delay(2000);
}

How to Test It

  1. Upload the code to your ESP32.
  2. Open the Serial Monitor (115200 baud). You should see ā€œStarting BLE work!ā€
  3. Download nRF Connect for Mobile on your iOS or Android device.
  4. Open the app and scan for devices. You should see a device named ESP32_ElectronParade.
  5. Connect to it!
  6. Expand the Unknown Service (which corresponds to your SERVICE_UUID).
  7. Tap the read arrow next to the Characteristic (CHARACTERISTIC_UUID). You’ll see the text ā€œHello from the Magic Blue Smoke!ā€ pop up.

Wrapping Up

You just created your first BLE server. You’ve bypassed the cloud entirely and passed data straight to your phone like a true hardware wizard.

In our next lesson, we’ll look at sending live sensor data and updating the characteristic continuously. But for now, go take a break. You earned it.