В плату ESP32 вшит не только модуль Wi-Fi, но и Bluetooth Low Energy (BLE). В данном руководстве кратко рассмотрим применение этой технологии на платах ESP32. Для начала рассмотрим саму технологию и ее использование, а затем покажем пару примеров в среде Arduino.
Что такое Bluetooth Low Energy?
На самом деле все просто – это версия спецификации ядра технологии Bluetooth с низким энергопотреблением. Ее, в основном, применяют для передач небольших объемов данных на малые расстояния. BLE находится в спящем режиме до установления соединения, в отличие от Bluetooth, который всегда включен.
Так и достигается низкое энергопотребление (примерно в 100 раз меньшее, чем у Bluetooth).
К тому же, BLE поддерживает не только передачу в сети «точка-точка», но также может работать в широковещательном режиме и в ячеистой топологии.
Приведем сравнительную таблицу характеристик BLE и Bluetooth:
Bluetooth Low Energy (BLE) | Bluetooth | |
---|---|---|
Оптимизирован для... | Периодических передач небольших данных | Постоянных передач данных |
Частота | 2,4 ГГц | 2,4 ГГц |
Канальность | 40 каналов шириной 2 Мгц | 79 каналов шириной 1 МГЦ |
Надёжность | Адаптивная быстрая перестройка частоты | Адаптивная быстрая перестройка частоты |
Модуляция | GFSK | GFSK, 8PDSK, π/4 DQPSK |
Потребление электроэнергии | 0.01x - 0.5x (относительно Bluetooth, зависит от режима использования) | 1 (относительная величина) |
Скорость передачи данных | LE 2M PHY: 2 Мб/с LE 1M PHY: 1 Мб/с LE Coded PHY (S=2): 500 Кб/с LE Coded PHY (S=8): 125 Кб/с | EDR PHY (8PDSK): 3 Мб/с EDR PHY (π/4 DQPSK): 2 Мб/с BR PHY (GFSK): 1 Мб/с |
Мощность передатчика | Класс 1: 100 мВ (+20 дБм) Класс 1,5: 10 мВ (+10 дБм) Класс 2: 2,5 мВ (+4 дБм) Класс 3: 1 мВ (0 дБм) | Класс 1: 100 мВ (+20 дБм) Класс 2: 2,5 мВ (+4 дБм) Класс 3: 1 мВ (0 дБм) |
Топологии сети | точка-точка широковещание mesh-сети | точка-точка |
Благодаря своим характеристикам, BLE подходит для проектов, в которых есть потребность в обмене небольшими данными и питанием от миниатюрных батарей. Примером могут служить девайсы для фитнеса, маячки, сигнализации и т.д.
Сервер для BLE
В документации к BLE описываются два режима устройств – клиент и сервер. Впрочем, ESP32 может работать в обоих режимах.
На сервере хранятся данные, с которыми клиент может взаимодействовать. Для этого клиент ищет устройства поблизости, затем при обнаружении сервера подключается к нему и ищет требуемые данные. Такая сеть называется «точка-точка».
Но BLE также поддерживает и другие виды сетей.
- Широковещательный режим: сервер передает данные нескольким устройствам;
- Ячеистая топология: все устройства подключены между собой.
GATT
Аббревиатура расшифровывается как Generic Attributes и обозначает иерархическую структуру данных, отображаемую для устройств, использующих BLE. То есть, GATT определяет порядок отправки и приема сообщений в сети. Понимание этой иерархии важно для написания приложений и взаимодействия с технология BLE.
На верхнем уровне иерархии находится профиль, состоящий из одной или нескольких уровней или протоколов. Тем не менее, обычно уровней больше, чем один.
Каждый сервис содержит как минимум один параметр или устанавливает связи с другими уровнями. Такая структура удобная для делегирования конкретных задач определенным уровням.
Также есть предопределенные уровни для нескольких типов данных, например: сервис заряда батареи, кровяное давление, частота сердечных сокращений и т.д. Здесь вы можете найти их все.
Характеристики уровня BLE
Они всегда описывают только один сервис. Характеристики всегда имеют два параметра: объявление характеристики и ее значение.
Также, после значений характеристик могут быть размещены дескрипторы для уточнения данных в объявлении характеристик.
Свойства описывают способы взаимодействия со значениями характеристик. Обычно свойства содержат пул операций и процедур, которые можно использовать с характеристиками:
- Broadcast
- Read
- Write without response
- Write
- Notify
- Indicate
- Authenticated Signed Writes
- Extended Properties
UUID
Каждый сервис, характеристика и дескриптор имеют UUID (универсальный уникальный идентификатор) – 128-битное (16-байт) число. Например: 55072829-bc9e-4c53-938a-74a6d4c78776.
Для всех типов, уровней и профилей в широкораспространенном промышленном стандарте протоколов (Bluetooth SIG) есть сокращенные UUID.
Однако, если ваше приложение требует собственные UUID, вы можете их создать здесь.
В общем, UUID используется для индивидуальной информации, например для определенного уровня или службы, предоставляемой устройством.
BLE на ESP32
Как уже говорилось, ESP32 может выступать в роли как клиента, так и сервера. В библиотеке BLE для Arduino IDE есть несколько примеров. Сама библиотека устанавливается при установке пакета платы ESP32.
Примечание: Для дальнейшей работы требуется, чтобы плата ESP32 была установлена в среде разработки.
Вы также можете перейти Файл>Примеры>ESP32 BLE Arduino и ознакомиться с этими примерами:
Для краткого ознакомления с BLE создадим сервер, а затем найдем его. Будем использовать данные примеры и также немного их поясним.
Нам потребуются две платы ESP32, мы используем эти платы.
ESP32 в режиме сервера BLE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/* Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp Ported to Arduino ESP32 by Evandro Copercini updates by chegewara */ #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> // Cгенерировать UUID можно здесь: // https://www.uuidgenerator.net/ #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" void setup() { Serial.begin(115200); Serial.println("Starting BLE work!"); BLEDevice::init("Long name works now"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(SERVICE_UUID); BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setValue("Hello World says Neil"); pService->start(); // BLEAdvertising *pAdvertising = pServer->getAdvertising(); BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); pAdvertising->setMinPreferred(0x12); BLEDevice::startAdvertising(); Serial.println("Characteristic defined! Now you can read it in your phone!"); } void loop() { // здесь пишем основной код delay(2000); |
Для работы в режиме сервера нам нужно выполнить следующие пункты:
- Создаем сервер;
- Создаем сервис BLE;
- Создаем характеристики;
- Создаем дескриптор для характеристики;
- Запускаем сервис;
- Включаем обнаружение устройства.
Как работает код?
Давайте быстро рассмотрим основные моменты:
Импортируем необходимые библиотеки:
1 2 3 4 5 |
#include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> |
Далее, необходимо определить UUID для сервиса и характеристики.
1 2 3 |
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
Вы можете оставить UUID по умолчанию, или создать свои.
В setup() запускаем монитор порта на скорости 115200 бод.
1 |
Serial.begin(115200); |
Затем создаем устройство “MyESP32”. Название, конечно же, можно изменить.
1 |
BLEDevice::init("MyESP32"); |
В следующей строке выставляем режим работы платы.
1 |
BLEServer *pServer = BLEDevice::createServer(); |
И присваиваем серверу ранее определенный UUID.
1 |
BLEService *pService = pServer->createService(SERVICE_UUID); |
Далее, указываем характеристики устройства. Здесь мы также используем UUID для характеристики и указываем свойства характеристики (в данном случаем READ и WRITE)
1 2 3 4 5 6 7 8 9 |
BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); |
После создания характеристики устанавливаем ее значение методом setValue():
1 |
pCharacteristic->setValue("Hello World says Neil"); |
В данном случаем мы присваиваем ей текстовое значение (его, конечно, можно изменить). В будущих ваших проектах это значение может быть, например, показаниями датчика, состоянием диода и др.
Наконец, запускаем сервис и обнаружение устройства.
1 2 3 |
BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); |
В данном скетче в loop() ничего не делается, но вы можете добавить действия, например, при подключении к сети нового устройства (есть в примере BLE_notify).
Поиск сервера ESP32 BLE
Создание скетча для поиска сервера BLE элементарно. Возьмем за основу другой пример из Файл>Примеры>ESP32 BLE Arduino>BLE_scan. Загрузится следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
/* Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp Ported to Arduino ESP32 by Evandro Copercini */ #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEScan.h> #include <BLEAdvertisedDevice.h> int scanTime = 5; //в секундах BLEScan* pBLEScan; class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void onResult(BLEAdvertisedDevice advertisedDevice) { Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); } }; void setup() { Serial.begin(115200); Serial.println("Scanning..."); BLEDevice::init(""); pBLEScan = BLEDevice::getScan(); //ищем устройства pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setActiveScan(true); //active scan работает быстрее, но тратит больше энергии pBLEScan->setInterval(100); pBLEScan->setWindow(99); // должен быть меньшим или равным значению setInterval } void loop() { // здесь пишем основной код BLEScanResults foundDevices = pBLEScan->start(scanTime, false); Serial.print("Devices found: "); Serial.println(foundDevices.getCount()); Serial.println("Scan done!"); pBLEScan->clearResults(); // освобождаем память буфера delay(2000); } |
Этот код устанавливает режим клиента ESP32 и ищет устройства поблизости. Загрузите код на плату.
Откройте монитор порта платы-клиента, нажмите кнопку ENABLE на плате и подождите несколько секунд.
В нашем случае, плата нашла два устройства: плату –сервер и часы MiBand2:
Тестируем сервер с помощью смартфона
Большинство современных смартфонов поддерживают технологию BLE. Вы можете включить поиск устройств на телефоне и посмотреть сервисы и характеристики. Для этого будем использовать приложение nRF Connect for Mobile (Play Store, App store)
Устанавливаем приложение, включаем Bluetooth на смартфоне, также включаем обнаружение.
Запустите плату-сервер и запустите поиск на телефоне, сервер должен обнаружиться.
Подключаемся к серверу. Также можно увидеть, что у сервера есть характеристика с заданными нами свойствами. При нажатии на сервис выпадает меню с характеристикой и UUID.
Заключение
В данном руководстве мы рассмотрели базовые принципы работы технологии Bluetooth с малым энергопотреблением и показали вам парочку примеров с ее использованием.
Данную технологию можно применять для обмена небольшими данными на малых расстояниях, например для передачи показаний датчиков, индикации состояния светодиодов и др.
Вопросы по прошивке и работе с кодом лучше писать напрямую автору в комментариях к статье (на англ. языке)