ESP32

ESP32 Bluetooth Basics: BLE Notify Sensor

DIY Daily Updated July 27, 2026 5 min read

Wi-Fi is great for dashboards, but when your phone should talk directly to a sensor — no router, no internet — Bluetooth Low Energy is the right tool. The ESP32 has BLE built in, and its most useful pattern is notify: the board pushes new values to your phone automatically the moment they change. In this tutorial you will build a BLE temperature sensor that notifies a phone app every two seconds, and learn the GATT concepts — services, characteristics, UUIDs — that every BLE device on the planet shares.

BLE in Four Ideas

BLE organizes data as a GATT server on the sensor: a service (like “Environmental Sensing”) contains characteristics (like “Temperature”), and each characteristic has properties — read, write, or notify. Your phone is the client: it scans for devices advertising a name, connects, discovers the services, and subscribes to a notifying characteristic. From then on the ESP32 calls notify() and the phone gets the new value instantly — no polling, which is exactly why BLE sensors run for months on coin cells. Services and characteristics are identified by UUIDs; standard ones are 16-bit (temperature is 0x2A6E), custom ones are 128-bit random numbers you can generate once and hard-code.

Parts Needed

  • ESP32 dev board with USB cable
  • 1× DHT11 or DHT22 sensor (or just use the built-in hall sensor for a parts-free demo)
  • 10 kΩ pull-up resistor for bare DHT sensors
  • An Android or iOS phone with the free nRF Connect app installed

Wiring the Sensor

Identical to our weather station build — BLE does not change the hardware at all.

DHT Sensor Pin ESP32 Notes
VCC 3V3 3.3 V keeps the data line GPIO-safe
DATA GPIO 4 10 kΩ pull-up to 3V3 if bare sensor
GND GND

The BLE Notify Sketch

Install the “DHT sensor library” by Adafruit; the BLE library ships with the ESP32 Arduino core. Upload this sketch:

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

#define SERVICE_UUID  "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define TEMP_CHAR_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

const int DHT_PIN = 4;
DHT dht(DHT_PIN, DHT22);

BLECharacteristic* tempChar = nullptr;
bool phoneConnected = false;

class ServerCB : public BLEServerCallbacks {
  void onConnect(BLEServer* s)    { phoneConnected = true; }
  void onDisconnect(BLEServer* s) { phoneConnected = false; s->startAdvertising(); }
};

void setup() {
  Serial.begin(115200);
  dht.begin();

  BLEDevice::init("DIYDAILY-Temp");
  BLEServer* server = BLEDevice::createServer();
  server->setCallbacks(new ServerCB());

  BLEService* service = server->createService(SERVICE_UUID);
  tempChar = service->createCharacteristic(
    TEMP_CHAR_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  service->start();
  BLEDevice::startAdvertising();
  Serial.println("Advertising as DIYDAILY-Temp");
}

void loop() {
  float t = dht.readTemperature();
  if (!isnan(t)) {
    String payload = String(t, 1);
    tempChar->setValue(payload.c_str());
    if (phoneConnected) tempChar->notify();
    Serial.println(payload);
  }
  delay(2000);
}

Walkthrough

The setup chain is always the same: init the radio with a device name, create a server, create a service, add a characteristic with PROPERTY_NOTIFY, start advertising. The callback restarts advertising when the phone disconnects — without it the board vanishes forever after the first session. In the loop we push a plain string (“23.4”) into the characteristic and notify. In nRF Connect: scan, connect to DIYDAILY-Temp, open the service, tap the three-arrow subscribe icon on the characteristic, and watch values arrive every two seconds.

Where to Go Next

Add a second characteristic for humidity, or a writeable one so the phone can set a sample interval. Replace the string payload with the standard 16-bit temperature format (hundredths of a degree) and use UUID 0x2A6E inside service 0x181A — suddenly generic fitness-style apps understand your sensor. The same notify pattern drives heart-rate straps, bike power meters and smart thermometers, so everything you practiced here transfers directly.

Designing Your Own GATT Profile

When you outgrow one value, think in profile terms: one service per logical device function, one characteristic per value or control point. A plant monitor might expose a “Plant” service with moisture (notify), battery level (read) and sample interval (read/write). Generate fresh 128-bit UUIDs for custom items — never reuse the reserved 16-bit range for non-standard meanings — and paste each UUID into your sketch as a constant with a comment saying what it is. Keep notify payloads small (under 20 bytes fits the default BLE packet); pack multiple readings into one short string or a compact byte array rather than notifying five characteristics back to back. Your phone battery and your connection stability will both thank you.

Troubleshooting

  • Device not found when scanning: check the board actually booted (open Serial at 115200) and that advertising restarted after a previous connection.
  • Connects, then drops instantly: weak USB power — BLE TX bursts brown out cheap cables; use a short, thick cable.
  • Subscribed but no values: you forgot PROPERTY_NOTIFY at creation, or notify() only runs when phoneConnected is true.
  • Old value shows after reconnect: nRF Connect caches services; refresh from the app menu.
  • Pairing prompts: this sketch uses open “Just Works” connections; if an app demands bonding, add security callbacks or choose “pair” and accept the default.

Safety Notes

  • BLE is radio: anyone in range can read an unsecured characteristic — never put sensitive data on an open notify channel.
  • Keep the antenna area of the board clear of metal; detuning the antenna wastes battery and range.
  • As with Wi-Fi projects, power from a supply that can deliver 500 mA peaks cleanly.

Conclusion

You now speak the language of billions of devices: services, characteristics, notify. The complete loop — sense on the ESP32, push over BLE, display on a phone — took no router, no account and under eighty lines of code. Next, combine BLE notify with deep sleep and you have a commercial-grade wireless sensor built on your kitchen table.

#ble #bluetooth #esp32

DIY Daily

Electronics tinkerer and tutorial writer at DIY Daily.

Leave a Comment

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