← До всіх проєктів
Бездротовий зв’язок Середній

Bluetooth LE: керуємо ESP32 з телефона без Wi-Fi

Робимо з ESP32 BLE-пристрій із сервісом UART: надсилаємо команди з телефона та отримуємо відповіді. Працює там, де немає роутера — у машині, на велосипеді, в гаражі.

Складність
Середній
Час
1 h
Категорія
Бездротовий зв’язок

Навіщо BLE

Wi-Fi потребує роутера, а Bluetooth Low Energy — лише телефона поруч. ESP32 має BLE «на борту», тож додаткові модулі не потрібні. Ми реалізуємо популярний сервіс Nordic UART Service (NUS) — для нього вже є готові застосунки-термінали, тож писати свій застосунок не доведеться.

Як це працює:

  • телефон пише текст у характеристику RX → ESP32 виконує команду;
  • ESP32 надсилає відповідь через характеристику TX зі сповіщенням (notify).

Що знадобиться

  • ESP32 DevKit (вбудований світлодіод на GPIO 2 або свій LED + 330 Ом)
  • Смартфон із застосунком:
    • Android — Serial Bluetooth Terminal або nRF Connect;
    • iOS — nRF Toolbox (режим UART) або Bluefruit Connect.

Бібліотека BLE входить до ядра arduino-esp32 — нічого встановлювати не треба.

Код

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

// Стандартні UUID Nordic UART Service
#define SERVICE_UUID "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
#define RX_UUID      "6e400002-b5a3-f393-e0a9-e50e24dcca9e"  // телефон → ESP32
#define TX_UUID      "6e400003-b5a3-f393-e0a9-e50e24dcca9e"  // ESP32 → телефон

const int LED_PIN = 2;
BLECharacteristic *txChar;
bool connected = false;
unsigned long lastNotify = 0;

void sendText(const String &text) {
  txChar->setValue((uint8_t *)text.c_str(), text.length());
  txChar->notify();
}

class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *server) override {
    connected = true;
  }
  void onDisconnect(BLEServer *server) override {
    connected = false;
    BLEDevice::startAdvertising();   // дозволяємо підключитися знову
  }
};

class RxCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *c) override {
    String cmd = String(c->getValue().c_str());
    cmd.trim();
    cmd.toLowerCase();

    if (cmd == "on") {
      digitalWrite(LED_PIN, HIGH);
    } else if (cmd == "off") {
      digitalWrite(LED_PIN, LOW);
    } else if (cmd != "status") {
      sendText("Commands: on, off, status\n");
      return;
    }
    sendText("LED " + String(digitalRead(LED_PIN) ? "ON" : "OFF") + "\n");
  }
};

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);

  BLEDevice::init("ESP32-LED");
  BLEServer *server = BLEDevice::createServer();
  server->setCallbacks(new ServerCallbacks());

  BLEService *service = server->createService(SERVICE_UUID);

  txChar = service->createCharacteristic(TX_UUID, BLECharacteristic::PROPERTY_NOTIFY);
  txChar->addDescriptor(new BLE2902());

  BLECharacteristic *rxChar = service->createCharacteristic(
      RX_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
  rxChar->setCallbacks(new RxCallbacks());

  service->start();

  BLEAdvertising *adv = BLEDevice::getAdvertising();
  adv->addServiceUUID(SERVICE_UUID);
  adv->setScanResponse(true);
  BLEDevice::startAdvertising();
  Serial.println("Advertising as ESP32-LED");
}

void loop() {
  // Раз на 5 с надсилаємо телефону «пульс» з часом роботи
  if (connected && millis() - lastNotify > 5000) {
    lastNotify = millis();
    sendText("uptime " + String(millis() / 1000) + " s\n");
  }
}

Перевірка

  1. Прошийте плату. У Serial Monitor з'явиться Advertising as ESP32-LED.
  2. Відкрийте застосунок-термінал → Devices → Bluetooth LE → оберіть ESP32-LED.
  3. Надішліть on — світлодіод засвітиться, у відповідь прийде LED ON.
  4. Кожні 5 секунд у терміналі з'являтиметься uptime ….

Створювати пару з пристроєм у системних налаштуваннях Bluetooth не потрібно — підключення відбувається прямо із застосунку.

Нюанси

  • Ядро 2.x vs 3.x. getValue() повертає std::string у 2.x і String у 3.x. Виклик .c_str() робить код сумісним з обома версіями.
  • Розмір пакета. За замовчуванням в одне повідомлення вміщується 20 байт; довші рядки розбивайте або збільшуйте MTU.
  • Безпека. Будь-хто поруч може підключитися. Для реальних пристроїв увімкніть шифрування з PIN (BLESecurity) або перевіряйте «пароль» першою командою.
  • BLE і Wi-Fi можуть працювати одночасно, але це займає багато пам'яті — для великих проєктів подивіться бібліотеку NimBLE-Arduino.

Ідеї

  • Керування реле у гаражі чи в машині без інтернету.
  • Веб-сторінка з Web Bluetooth API (Chrome), яка підключається до ESP32 напряму з браузера.
  • Налаштування Wi-Fi через BLE замість порталу — так роблять комерційні пристрої.