ESP32 Part 3 - Advanced

E13. Bluetooth Low Energy Essentials

Make the ESP32 appear on your phone over Bluetooth LE, then switch an LED by writing 1 or 0 from the phone.

Estimated time 3-4 hours

Learning outcomes

  • Say when Bluetooth LE is a better fit than Wi-Fi
  • Explain advertising, service and characteristic in plain words
  • Make the ESP32 show up in a phone's Bluetooth scanner
  • Switch an LED when the phone writes a value

Parts and preparation

ESP32 board with Bluetooth LE (classic ESP32 or C3/C5/C6 - not P4 without a companion radio). USB data cable, LED + resistor on GPIO 2 (or the on-board LED). Phone with the free nRF Connect app.

Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.

Libraries for this lesson

In Arduino IDE 2 open Tools → Manage Libraries…. Search by the Library Manager name and install the package by the exact author below. Similar names from other authors can use different APIs and will break the example.

IncludeLibrary Manager nameAuthorInstall note
BLEDevice.hESP32 BLE ArduinoEspressifBuilt into the esp32 Arduino core (BLEDevice, BLEServer). No Library Manager install required.

What you will do

Bluetooth Low Energy (BLE) lets a phone talk to a gadget a few metres away, with no router and no internet.

Sketch 1 makes the ESP32 appear in your phone's Bluetooth scanner. Sketch 2 lets the phone switch the LED by writing 1 or 0.

Phone as BLE client writing a characteristic on ESP32 GATT server to toggle LED
The phone writes a value; the ESP32 switches the LED.
You needBetter fit
Control from a browser, or data from the internetWi-Fi (ESP32 Lesson 08 to ESP32 Lesson 12)
A phone next to the gadget, no routerBluetooth LE

Advertising

A BLE gadget advertises: it sends out its name a few times a second so phones nearby can find it. When a phone connects, it can look inside.

Services and characteristics

Inside, values are grouped. A characteristic is one value the phone can read or write - here, the LED setting. A service is a group of characteristics. Each has a long ID called a UUID, so the phone can tell them apart. The IDs in sketch 2 are examples from Espressif - copy them as they are.

WordIn this lesson
AdvertisingThe ESP32 announcing ESP32-yourname
ServiceThe group that holds the LED value
CharacteristicThe LED value: 1 = on, 0 = off
UUIDThe long ID of the service or characteristic

Using nRF Connect

1) Upload the sketch and open nRF Connect on your phone. 2) Press Scan and find ESP32-yourname. Press Connect. 3) Sketch 2: open the Unknown Service, find the characteristic and press its up-arrow (write). 4) Choose Text (UTF-8), type 1 and press Send. The LED comes on. Send 0 to switch it off.

Code you copy as it is

Bluetooth needs some set-up lines that use C++ features beyond this course: the * after a type name, -> instead of a dot, and a class block. Every one of those lines has a comment saying what it does - you only need to change the name, the pin and what happens inside onWrite.

Wiring and safe build sequence

  1. GPIO 2 -> 220-330 ohm -> LED long leg; LED short leg -> GND (or use the on-board LED)
  2. USB power; a Bluetooth LE ESP32 board
  3. Phone within a few metres, with Bluetooth on
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.

Worked sketch 1: Appear on the phone

Download .ino

What this sketch is for: Change yourname, upload, then scan with nRF Connect. ESP32-yourname should be in the list.

#include <BLEDevice.h>                         // the Bluetooth LE commands

void setup() {                                 // runs once
  Serial.begin(115200);                        // start Serial at the ESP32 speed
  BLEDevice::init("ESP32-yourname");           // switch on Bluetooth LE with this name
  BLEServer* server = BLEDevice::createServer(); // something a phone can connect to (copy as it is)
  server->advertiseOnDisconnect(true);         // let the next phone connect after one leaves
  BLEDevice::startAdvertising();               // start telling nearby phones we are here
  Serial.println("Advertising - scan for ESP32-yourname"); // tell the user
}

void loop() {                                  // nothing to repeat in this sketch
}

How the code works

  1. The name in BLEDevice::init() is what the phone shows - make it yours so you find your own board.
  2. Advertising carries on by itself after setup(), so loop() can stay empty.

Worked sketch 2: Switch the LED from the phone

Download .ino

What this sketch is for: Connect with nRF Connect and write the text 1 or 0 to the characteristic. Match the breadboard layout below before upload, or use the on-board LED.

Breadboard layout for ESP32 BLE LED: LED with series resistor on GPIO 2
Breadboard for sketch 2: LED with series resistor on GPIO 2 to GND. Click to enlarge.
#include <BLEDevice.h>                         // the Bluetooth LE commands

const int ledPin = 2;                          // the LED is on GPIO 2

// the library runs onWrite when the phone writes a value (copy the block as it is)
class LedCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* characteristic) {
    String value = characteristic->getValue(); // the text the phone wrote
    if (value == "1") {                        // phone wrote 1?
      digitalWrite(ledPin, HIGH);              // LED on
    }
    if (value == "0") {                        // phone wrote 0?
      digitalWrite(ledPin, LOW);               // LED off
    }
  }
};

void setup() {                                 // runs once
  pinMode(ledPin, OUTPUT);                     // the LED pin is an output
  BLEDevice::init("ESP32-yourname");           // switch on Bluetooth LE with this name
  BLEServer* server = BLEDevice::createServer(); // something a phone can connect to
  server->advertiseOnDisconnect(true);         // let the next phone connect after one leaves

  // a service (a group of values) with its ID
  BLEService* service = server->createService("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
  // one value inside it, with its own ID, that the phone is allowed to write
  BLECharacteristic* ledValue = service->createCharacteristic(
    "beb5483e-36e1-4688-b7f5-ea07361b26a8", BLECharacteristic::PROPERTY_WRITE);
  ledValue->setCallbacks(new LedCallbacks());  // run LedCallbacks when it is written
  service->start();                            // switch the service on

  BLEDevice::startAdvertising();               // start telling nearby phones we are here
}

void loop() {                                  // nothing to repeat - onWrite does the work
}

How the code works

  1. The only part you would normally change is inside onWrite: what to do with the value.
  2. value == "1" compares the whole text, so send exactly 1 - no spaces.
  3. Build from the breadboard photo: LED on GPIO 2.

Test and record evidence

Expected result: Sketch 1: ESP32-yourname appears in the nRF Connect scan list. Sketch 2: after connecting, writing 1 turns the LED on and writing 0 turns it off.

Practical evidence checklist

Common faults and checks
  • Board not in the scan list: check the board has Bluetooth LE (not a P4), and the phone's Bluetooth and location are on.
  • Too many devices in the list: use the scanner's name filter and type your name.
  • LED does not react: choose Text (UTF-8) when writing, and send just 1 or 0.
  • Compile error about getValue: update the esp32 board package to version 3 or newer.
Challenge (extension - optional): In sketch 2, add a third value: writing 2 makes the LED blink three times.

Check your understanding

Q1. When is Bluetooth LE a better fit than Wi-Fi?

Show answer

When a phone is close to the gadget and there is no router or internet.

Q2. What does advertising do?

Show answer

Sends out the gadget's name so nearby phones can find it.

Q3. What is a characteristic?

Show answer

One value the phone can read or write, such as the LED setting.

Q4. What is a service?

Show answer

A group of characteristics.

Q5. What is a UUID?

Show answer

A long ID that tells services and characteristics apart.

Q6. What text turns the LED on in sketch 2?

Show answer

1.

Q7. Which part of sketch 2 runs when the phone writes?

Show answer

onWrite inside LedCallbacks.