Serial API Over BLE

This demo lets you use a web page as a wireless serial terminal to your ESP32—no USB cable needed. Under the hood it uses:

• An Arduino-style sketch on the ESP32 implementing the Nordic UART Service (NUS) over Bluetooth Low Energy (BLE).
• A HTML page with Web-Bluetooth JavaScript that:
– Opens the standard BLE device picker in your browser.
– Connects to the ESP32’s GATT server.
– Subscribes to the “TX” characteristic so incoming ESP32 serial prints appear in the page.
– Writes to the “RX” characteristic so anything you type in the page is sent to the ESP32’s Serial Monitor.

Key Benefits:

• Wireless serial terminal: monitor and control the ESP32 from your phone or desktop browser.
• No native app required—runs in Chrome (desktop or Android) with just a web page.
• Works on Android Chrome Beta/Dev/Canary (enable Web Bluetooth flags + grant “Nearby devices” permission) and on desktop Chrome without extra setup.
• Simple, bidirectional, line-oriented console: type a line in the page → it appears on Serial; Serial.println() on the ESP32 → it appears in the page log.

Load this on your ESP32 (Wemos LOLIN32, DevKitC, etc.):

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

// UART Service UUIDs  for own use https://www.uuidgenerator.net/
#define NUS_SERVICE_UUID "6e28c1e1-29f7-4e0c-9ac1-69c4930153ab"
#define NUS_RX_CHAR_UUID "6e28c1e1-29f7-4e0c-9ac1-69c4930153ab"
#define NUS_TX_CHAR_UUID "6e28c1e1-29f7-4e0c-9ac1-69c4930153ab"

BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;

// Track connect/disconnect to restart advertising
class ServerCallbacks : public BLEServerCallbacks {
    void onConnect(BLEServer* server) override {
      deviceConnected = true;
    }
    void onDisconnect(BLEServer* server) override {
      deviceConnected = false;
      server->getAdvertising()->start();
    }
};

// Handle data written by the web page (RX characteristic)
class RXCallbacks : public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic* characteristic) override {
      String rx = characteristic->getValue();
      if (rx.length()) {
        // 1) Print to Serial Monitor
        Serial.print("From HTML → ESP32: ");
        Serial.println(rx);

        // 2) Echo back over BLE (TX characteristic)
        pTxCharacteristic->setValue(rx);
        pTxCharacteristic->notify();
      }
    }
};

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  while (!Serial) {
    delay(10);
  }

  // 1) Create BLE device
  BLEDevice::init("ESP32-BLE-UART");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new ServerCallbacks());

  // 2) Create NUS service
  BLEService *pService = pServer->createService(NUS_SERVICE_UUID);

  // 3) Create TX characteristic (ESP32 → client notifications)
  pTxCharacteristic = pService->createCharacteristic(
                        NUS_TX_CHAR_UUID,
                        BLECharacteristic::PROPERTY_NOTIFY
                      );
  pTxCharacteristic->addDescriptor(new BLE2902()); // enable notifications

  // 4) Create RX characteristic (client → ESP32 writes)
  BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
      NUS_RX_CHAR_UUID,
      BLECharacteristic::PROPERTY_WRITE
                                         );
  pRxCharacteristic->setCallbacks(new RXCallbacks());

  // 5) Start service and begin advertising
  pService->start();
  pServer->getAdvertising()->start();
  Serial.println(">> BLE UART started. Waiting for HTML client to connect...");
}

void loop() {
  // Forward anything printed to Serial while connected back to the page
  while (Serial.available()) {
    String line = Serial.readStringUntil('\n');
    if (line.length() && deviceConnected) {
      pTxCharacteristic->setValue(line);
      pTxCharacteristic->notify();
    }
  }
  delay(20);
}


HTML + JS PAGE

Save as index.html locally, then open in your browser:


BROWSER SETTINGS & PERMISSIONS

On Android Chrome (Beta/Dev/Canary):

  1. chrome://flags → Enable
    • “Web Bluetooth” (#enable-web-bluetooth)
    • “Web Bluetooth Scanning” (#enable-web-bluetooth-scanning)
  2. Relaunch browser.
  3. Android Settings → Apps → Chrome → Permissions → Nearby devices (or Location) → Allow.


HOW TO USE

Power on your ESP32 with the BLE-UART sketch.

  1. Save HTML page locally.
  2. Open the page in Chrome (Android or Desktop).
  3. Tap Connect to ESP32, select “ESP32-BLE-UART” in the picker.
  4. Once “Connected!” appears, type a message and click Send (or press Enter).
  5. Watch messages echo in both the page’s log and the ESP32’s Serial Monitor.

Leave a Reply