ESP32 Bluetooth Low Energy (BLE): Sensordaten aufs Smartphone senden – Komplettes Tutorial

Du willst Sensorwerte aufs Handy holen, aber kein WLAN einrichten und schon gar keine eigene App programmieren? Bluetooth Low Energy (BLE) ist die Antwort. Der ESP32 wird zum BLE-Server, dein Smartphone verbindet sich mit einer kostenlosen App – und die Temperatur- und Luftfeuchtewerte deines DHT22 erscheinen live auf dem Display. In diesem Tutorial lernst du die BLE-Grundbegriffe, richtest Services und Characteristics ein und sendest Werte per Notify in Echtzeit.

Warum BLE statt WLAN?

WLAN ist super, wenn du ins Internet willst – aber es braucht einen Router, Zugangsdaten und mehr Strom. Für eine schnelle Punkt-zu-Punkt-Verbindung zwischen ESP32 und Handy ist Bluetooth Low Energy oft die bessere Wahl: Es funktioniert überall (auch draußen ohne Netz), verbraucht sehr wenig Energie und ist ideal für kleine Datenmengen wie Sensorwerte. Genau dafür wurde BLE entworfen. Und das Beste: Du brauchst keine eigene App – fertige BLE-Scanner-Apps zeigen deine Werte sofort an.

💡 BLE vs. klassisches Bluetooth: Der ESP32 beherrscht beides. Das ältere „Bluetooth Classic“ (SPP) verhält sich wie eine serielle Schnittstelle, verbraucht aber mehr Strom. BLE ist moderner, sparsamer und der Standard für Sensorik – deshalb nutzen wir hier BLE.

BLE-Grundbegriffe in 2 Minuten

BLE organisiert Daten in einer festen Hierarchie. Das klingt zuerst abstrakt, ist aber schnell verstanden:

Begriff Bedeutung Analogie
Server Gerät, das Daten bereitstellt (der ESP32) ein Gebäude
Service Gruppe zusammengehöriger Daten ein Stockwerk
Characteristic ein einzelner Wert (z. B. Temperatur) ein Zimmer
UUID eindeutige Kennung für Service/Characteristic die Adresse
Notify Server schickt neue Werte automatisch eine Benachrichtigung

Merke dir vor allem den Unterschied zwischen Read (das Handy fragt aktiv einen Wert ab) und Notify (der ESP32 schickt neue Werte von selbst, sobald sie sich ändern). Für Live-Sensordaten willst du Notify.

Das brauchst du

DHT22 (AM2302) Sensor – misst Temperatur & Luftfeuchte
1,3 Zoll OLED-Display (I2C) – optionale lokale Anzeige

Auf dem Smartphone brauchst du eine kostenlose BLE-App wie nRF Connect (Android & iOS) oder LightBlue. Damit scannst du nach dem ESP32, verbindest dich und siehst die Werte.

1Verkabelung

Der DHT22 hängt mit drei Leitungen am ESP32. Das OLED ist optional und teilt sich den I2C-Bus.

Bauteil / Pin ESP32 Hinweis
DHT22 VCC (+) 3V3 Versorgung
DHT22 DATA GPIO4 Datenleitung
DHT22 GND (−) GND Masse
OLED SDA / SCL GPIO21 / GPIO22 I2C (optional)
OLED VCC / GND 3V3 / GND Versorgung

ℹ️ Fertiges DHT22-Modul? Viele DHT22 kommen als Modul mit bereits verbautem Pull-up-Widerstand – dann kannst du DATA direkt anschließen. Beim nackten Sensor gehört ein 10-kΩ-Widerstand zwischen DATA und VCC. Details im ESP32-Wetterstation-Tutorial.

2Der erste BLE-Server

Die BLE-Bibliothek ist bereits im ESP32-Core der Arduino IDE enthalten – du musst nichts extra installieren. Dieser Sketch startet einen BLE-Server, der einen festen Text bereitstellt. So lernst du die Struktur kennen, bevor echte Sensordaten dazukommen:

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

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

void setup() {
  Serial.begin(115200);
  BLEDevice::init("MAKEROO-ESP32");           // so heisst das Geraet beim Scan
  BLEServer *server = BLEDevice::createServer();
  BLEService *service = server->createService(SERVICE_UUID);

  BLECharacteristic *ch = service->createCharacteristic(
      CHAR_UUID, BLECharacteristic::PROPERTY_READ);
  ch->setValue("Hallo vom ESP32!");

  service->start();
  BLEAdvertising *adv = BLEDevice::getAdvertising();
  adv->addServiceUUID(SERVICE_UUID);
  adv->start();
  Serial.println("BLE-Server laeuft, jetzt scannen...");
}

void loop() { delay(1000); }

💡 Jetzt testen: Öffne nRF Connect auf dem Handy, starte einen Scan und such nach MAKEROO-ESP32. Verbinde dich, öffne den Service und tippe auf das Read-Symbol – du siehst „Hallo vom ESP32!“. Die UUIDs kannst du frei wählen; nutze am besten zufällige, damit sie eindeutig sind.

3Sensordaten per Notify senden

Jetzt kommt der spannende Teil: Wir lesen den DHT22 aus und schicken die Werte automatisch, sobald sich der Client verbindet. Dafür aktivieren wir die Notify-Eigenschaft und einen Descriptor. Installiere über den Bibliotheksverwalter die DHT sensor library von Adafruit.

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

#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

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

BLECharacteristic *ch;
bool verbunden = false;

class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *s) { verbunden = true; }
  void onDisconnect(BLEServer *s) {
    verbunden = false;
    s->startAdvertising();   // wieder sichtbar werden
  }
};

void setup() {
  Serial.begin(115200);
  dht.begin();
  BLEDevice::init("MAKEROO-ESP32");
  BLEServer *server = BLEDevice::createServer();
  server->setCallbacks(new ServerCallbacks());
  BLEService *service = server->createService(SERVICE_UUID);

  ch = service->createCharacteristic(CHAR_UUID,
      BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
  ch->addDescriptor(new BLE2902());   // noetig fuer Notify

  service->start();
  BLEDevice::getAdvertising()->addServiceUUID(SERVICE_UUID);
  BLEDevice::startAdvertising();
}

void loop() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (!isnan(t) && !isnan(h)) {
    char puffer[32];
    snprintf(puffer, sizeof(puffer), "%.1f C  %.1f %%", t, h);
    ch->setValue(puffer);
    if (verbunden) ch->notify();   // automatisch senden
    Serial.println(puffer);
  }
  delay(2000);   // DHT22 max. alle 2 s
}

ℹ️ Was macht der BLE2902-Descriptor? Er ist der Schalter, mit dem der Client Notifications ein- oder ausschaltet. Ohne ihn kann dein Handy keine automatischen Updates abonnieren. In nRF Connect tippst du dazu auf das Symbol mit den drei Pfeilen neben der Characteristic.

4Getrennte Werte für Temperatur und Feuchte

Für eine saubere Struktur legst du besser zwei getrennte Characteristics an – eine für Temperatur, eine für Luftfeuchte. So kann eine App jeden Wert einzeln abonnieren und anzeigen:

#define TEMP_UUID  "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define HUM_UUID   "c9af9c76-46de-11e5-ff01-000102030405"

BLECharacteristic *chTemp, *chHum;

// ... im setup() nach createService():
chTemp = service->createCharacteristic(TEMP_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
chTemp->addDescriptor(new BLE2902());
chHum = service->createCharacteristic(HUM_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
chHum->addDescriptor(new BLE2902());

// ... im loop():
char tBuf[8], hBuf[8];
dtostrf(t, 4, 1, tBuf);   // float in Text
dtostrf(h, 4, 1, hBuf);
chTemp->setValue(tBuf);
chHum->setValue(hBuf);
if (verbunden) { chTemp->notify(); chHum->notify(); }

💡 Tipp für echte Apps: Sendest du die Werte als reine Zahl (statt mit Einheit), kann eine App sie direkt in ein Diagramm zeichnen. Für Standard-Sensoren gibt es sogar offizielle 16-Bit-UUIDs (z. B. 0x2A6E für Temperatur), die manche Apps automatisch als „Temperatur“ erkennen.

Praxistipps & Ausbau

  • Lokale Anzeige: Ergänze ein OLED-Display, damit du die Werte auch ohne Handy siehst.
  • Strom sparen: Kombiniere BLE mit Deep Sleep, damit der Sensor monatelang mit Akku läuft.
  • Ins Smart Home: Willst du die Werte dauerhaft aufzeichnen und automatisieren, ist MQTT mit Home Assistant über WLAN die passende Ergänzung.
  • Reichweite: BLE schafft im Freien gut 10–30 m. Wände und Störquellen reduzieren das – halte Sender und Empfänger für stabile Verbindungen in Sichtweite.

Troubleshooting

⚠️ ESP32 taucht beim Scan nicht auf: Advertising nicht gestartet oder falsches Board gewählt. Prüfe, dass startAdvertising() aufgerufen wird und in der Arduino IDE ein ESP32-Board ausgewählt ist.

⚠️ Verbindung bricht sofort ab: Das ist normal, wenn der Client nach dem Lesen trennt. Wichtig ist, dass onDisconnect das Advertising neu startet – sonst wird der ESP32 nicht wieder gefunden.

⚠️ Keine automatischen Updates: Notifications nicht abonniert oder BLE2902-Descriptor vergessen. Aktiviere Notify in der App und ergänze den Descriptor im Code.

⚠️ DHT22 liefert nan: Verdrahtung prüfen, Pull-up vorhanden? Und nicht öfter als alle 2 Sekunden lesen – der DHT22 ist langsam.

⚠️ Sketch zu groß / Kompilierfehler: BLE braucht viel Flash. Wähle unter Tools → Partition Scheme ein Schema mit größerem App-Bereich (z. B. „Huge APP“).

🚀 Dein ESP32-BLE-Starterpaket

Alle Bauteile für dieses Projekt im Shop:

Fazit

Ohne Router, ohne App-Programmierung und mit minimalem Stromverbrauch hast du Sensordaten drahtlos aufs Handy gebracht. Du kennst jetzt die BLE-Hierarchie aus Server, Service und Characteristic, weißt, wann du Read und wann Notify nutzt, und sendest Temperatur und Luftfeuchte deines DHT22 in Echtzeit. Der BLE2902-Descriptor und das erneute Advertising nach dem Trennen sind die zwei Details, an denen die meisten scheitern – du kennst sie jetzt.

Von hier aus ist der Weg frei: getrennte Characteristics für saubere Apps, Deep Sleep für monatelange Akkulaufzeit oder der Umstieg auf MQTT, wenn es doch ins Internet gehen soll. BLE ist dein Werkzeug für alles, was schnell, sparsam und ohne Netz aufs Handy soll. Viel Spaß beim Funken!

Zurück zum Blog