
Основы ESP32: Bluetooth Low Energy (BLE)
Bluetooth Low Energy (BLE) сегодня повсюду. Если вы включите сканер на своём телефоне и прогуляетесь по окрестностям, вы, без сомнения, найдёте десятки, если не сотни, BLE-устройств.
Если вам интересно и вы хотите начать работать с BLE, это руководство станет отличной отправной точкой. Оно даст вам краткий обзор BLE (в частности, как организованы данные в BLE, как два BLE-устройства обмениваются данными друг с другом) и как использовать BLE на ESP32.
Основы Bluetooth Low Energy
Bluetooth Low Energy (BLE), иногда называемый «Bluetooth Smart», — это облегчённое подмножество классического Bluetooth, представленное как часть спецификации Bluetooth 4.0.
BLE предназначен для устройств, которые отправляют небольшие объёмы данных нечасто и работают от небольших батарей. Он использует тот же частотный диапазон, что и классический Bluetooth — диапазон 2,4 ГГц ISM (industrial, scientific, and medical), который не требует лицензии для использования. Диапазон ISM разделён на 40 каналов, и BLE-устройства переключаются между ними, чтобы избежать помех.
Для экономии энергии BLE имеет меньшую мощность передачи (от 0,01 до 10 мВт) по сравнению с классическим Bluetooth (до 100 мВт для класса 1 и 1 мВт для устройств класса 3). Данные передаются тем же способом (с использованием гауссовой частотной манипуляции — Gaussian Frequency Shift Keying), но скорость передачи данных ниже — максимум 1 Мбит/с по сравнению с максимумом 24 Мбит/с классического Bluetooth. BLE-устройства также могут переключаться между режимами ожидания и активным режимом гораздо быстрее, чем устройства с классическим Bluetooth, что позволяет экономить ещё больше энергии.
Если кратко, BLE разработан для предоставления многих тех же возможностей, что и классический Bluetooth, но с упором на низкое энергопотребление. В результате он стал стандартной технологией для широкого спектра применений, включая умное освещение, умные дома, маячки (beacons), фитнес-трекеры, инсулиновые помпы, слуховые аппараты и другие энергочувствительные приложения.
Профили Bluetooth
Профили Bluetooth — это дополнительные протоколы, которые строятся поверх базового стандарта Bluetooth. Они помогают определить тип данных, которые передаёт модуль Bluetooth. В то время как спецификации Bluetooth определяют, как работает технология, профили определяют, как она используется.
Профили, которые поддерживает устройство Bluetooth, определяют приложения, для которых оно предназначено. Например, Bluetooth-гарнитура для режима «свободные руки» использует профиль гарнитуры (HSP), тогда как беспроводная клавиатура использует профиль устройства с человеко-машинным интерфейсом (HID). Эти профили разрабатываются либо Bluetooth SIG (Bluetooth Special Interest Group), либо разработчиками периферийных устройств. Полный список официально принятых профилей можно посмотреть здесь.
Профили, с которыми вам следует ознакомиться, — это GAP и GATT, поскольку все стандартные профили BLE основаны на них. Итак, давайте познакомимся с ними поближе.
GAP (Generic Access Profile)
GAP управляет подключениями и рекламными объявлениями (advertising) в Bluetooth. GAP делает ваше устройство видимым для внешнего мира и определяет, как два устройства обнаруживают друг друга и устанавливают соединение.
GAP определяет различные роли для устройств, но два ключевых понятия, которые следует запомнить, — это центральные устройства (Central) и периферийные устройства (Peripheral).
Периферийные устройства — это обычно небольшие, маломощные устройства с ограниченными ресурсами, такие как мониторы сердечного ритма или метки приближения, которые могут подключаться к гораздо более мощному центральному устройству.
Центральные устройства — это обычно устройства с гораздо большей вычислительной мощностью и памятью, такие как мобильные телефоны или планшеты, к которым вы подключаетесь.
Периферийное устройство передаёт рекламные пакеты (advertising packets) через заданные интервалы, чтобы информировать ближайшие центральные устройства о своём присутствии. Как только соединение между периферийным и центральным устройством установлено, процесс рекламирования прекращается, и в игру вступает GATT, обеспечивая двунаправленный обмен данными.
GATT (Generic ATTribute Profile)
GATT определяет, как данные должны быть организованы и как два BLE-устройства должны обмениваться данными. В отличие от GAP, который определяет низкоуровневые взаимодействия с устройствами, GATT работает только с фактическими процедурами и форматами передачи данных.
Данные организованы иерархически в разделы, называемые сервисами (services), которые группируют концептуально связанные фрагменты пользовательских данных, называемые характеристиками (characteristics), как показано на иллюстрации ниже:
Сервисы (Services)
Сервис GATT — это набор концептуально связанных данных, называемых характеристиками. Каждый сервис может иметь одну или несколько характеристик и имеет собственный уникальный числовой идентификатор — UUID, который может быть 16-битным (для официально принятых BLE-сервисов) или 128-битным (для пользовательских сервисов). Подробнее об этом далее.
Например, рассмотрим сервис Heart Rate Service. Этот официально принятый сервис имеет 16-битный UUID 0x180D и содержит до 3 характеристик: Heart Rate Measurement, Body Sensor Location и Heart Rate Control Point. Больше сервисов, определённых Bluetooth SIG, можно найти здесь.
Характеристики (Characteristics)
Характеристика GATT — это группа информации, называемая атрибутами (Attributes). Атрибуты — это фактическая информация, передаваемая между BLE-устройствами. Типичная характеристика состоит из следующих атрибутов:
Значение (Value): это фактические данные, хранящиеся в характеристике. Значение может быть любым типом данных, например числом, строкой или массивом байтов.
Дескриптор (Descriptor): предоставляет дополнительную информацию или параметры конфигурации для характеристики.
Помимо значения, с каждой характеристикой связаны следующие свойства:
Дескриптор (Handle): 16-битное число, используемое для доступа к характеристике на серверном устройстве.
UUID: 128-битный универсально уникальный идентификатор, указывающий, что представляет собой характеристика.
Разрешения (Permissions): определяют, какие операции над характеристикой разрешены, например чтение, запись или уведомление.
UUID (Universally Unique Identifier)
UUID обеспечивают уникальную идентификацию сервисов и характеристик. Они играют важную роль в определении и доступе к данным на BLE-устройстве. В BLE существует два типа UUID:
16-битный UUID: используется для официальных профилей, сервисов и характеристик BLE. Они стандартизированы Bluetooth SIG. Например, «Heart Rate Service» имеет стандартизированный 16-битный UUID 0x180D, а характеристика «Heart Rate Measurement» в рамках Heart Rate Service использует UUID 0x2A37.
128-битный UUID: используется для пользовательских (vendor-specific) сервисов и характеристик. Если компания разрабатывает собственный сервис, не охваченный официальными BLE-сервисами, она использует уникальный 128-битный UUID. 128-битный UUID выглядит так: 4fafc201-1fb5-459e-8fcc-c5c9c331914b.
GATT-сервер и GATT-клиент
С точки зрения GATT, когда два устройства соединены, каждое из них находится в одной из двух ролей.
GATT-сервер — это устройство, которое содержит базу данных характеристик.
GATT-клиент — это устройство, которое считывает данные с GATT-сервера или записывает данные на него.
На следующем рисунке показана эта взаимосвязь в примере BLE-соединения, где периферийное устройство (ESP32) является GATT-сервером, а центральное устройство (смартфон) — GATT-клиентом.
Важно отметить, что роли GATT — клиент и сервер — не зависят от ролей GAP — периферийное и центральное устройство. Периферийное устройство может быть как GATT-клиентом, так и GATT-сервером, или и тем и другим, и аналогично центральное устройство может быть как GATT-клиентом, так и GATT-сервером.
Использование BLE на ESP32
Теперь, когда вы узнали о протоколе беспроводной связи Bluetooth Low Energy (BLE), включая его возможности, профили и способы обмена данными с устройствами, пришло время попробовать его в действии.
Для ESP32 в библиотеке ESP32 BLE доступно несколько примеров скетчей. Эта библиотека устанавливается автоматически при установке ядра ESP32 в Arduino IDE.
Чтобы получить доступ к примерам скетчей, перейдите в File > Examples > ESP32 BLE Arduino.
Вы увидите набор примеров скетчей. Вы можете выбрать любой из них, чтобы загрузить скетч в вашу IDE. Давайте начнём с примера BLE_server.
Этот пример настраивает ESP32 как BLE-сервер с определённым сервисом и характеристикой. Затем он рекламирует этот сервис, делая его обнаруживаемым и доступным для BLE-клиентов, таких как ваш смартфон.
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
// See the following for generating UUIDs:
// 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("MyESP32"); // set the device name
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!");
pService->start();
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
Serial.println("Characteristic defined! Now you can read it in your phone!");
}
void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
Разбор кода
Давайте подробно разберём код BLE_server. Он начинается с подключения необходимых библиотек для работы с BLE на ESP32.
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
Далее определяются UUID для сервиса и характеристики. UUID (Universally Unique Identifiers) уникально идентифицируют сервисы и характеристики в BLE.
Вы можете использовать UUID по умолчанию или перейти на uuidgenerator.net для генерации случайных UUID.
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
В функции setup() инициализируется последовательная связь со скоростью 115200 бод.
Serial.begin(115200);
Затем создаётся BLE-устройство с именем MyESP32. Вы можете изменить имя на любое другое по своему желанию.
// Create the BLE Device
BLEDevice::init("MyESP32");
После этого наше BLE-устройство настраивается как сервер.
BLEServer *pServer = BLEDevice::createServer();
Далее создаётся новый сервис для нашего сервера с ранее определённым UUID.
BLEService *pService = pServer->createService(SERVICE_UUID);
Затем для сервиса создаётся новая характеристика. Как вы можете видеть, свойства характеристики, в данном случае READ и WRITE, передаются в качестве аргументов вместе с CHARACTERISTIC_UUID.
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
После создания характеристики используйте метод setValue() для установки её значения. В данном случае значение установлено как текст «Hello World!». Вы можете изменить этот текст на что угодно; это могут быть показания датчика, состояние кнопки или что-либо ещё.
pCharacteristic->setValue("Hello World!");
Далее сервис запускается, чтобы он мог отвечать на входящие запросы.
pService->start();
Наконец, настраиваются параметры рекламирования, и затем сервис начинает рекламироваться. Рекламирование делает ESP32 обнаруживаемым другими BLE-устройствами.
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
Это простой пример настройки BLE-сервера, поэтому в loop() ничего не выполняется. Однако в зависимости от приложения вы можете добавить действия при подключении нового клиента (обратитесь к примеру BLE_notify для руководства).
void loop() {
delay(2000);
}
Использование nRF Connect для тестирования
Для тестирования BLE-соединения вам нужно сопрячь ESP32 с вашим смартфоном. Вам также потребуется приложение для отладки Bluetooth, установленное на нём. Есть несколько доступных вариантов; одно из наших любимых — Nordic nRF Connect, которое доступно как для iOS, так и для Android-устройств. Это мощный инструмент, который позволяет сканировать и исследовать ваши BLE-устройства и обмениваться с ними данными.
Перейдите в Google Play Store или Apple App Store и найдите «nRF Connect for Mobile». Установите приложение и откройте его.
Убедитесь, что Bluetooth на вашем телефоне включён.
В приложении нажмите на кнопку «SCAN». Приложение начнёт сканирование ближайших BLE-устройств.
Появится список доступных устройств с их уровнями сигнала и другими деталями. Найдите «MyESP32» и нажмите кнопку «Connect» рядом с ним.
Вы перейдёте в представление «Services». Там вы увидите список доступных сервисов. Нажмите «Unknown Service» — строка UUID должна совпадать с
SERVICE_UUIDв вашем примере кода.
Нажмите на сервис, чтобы увидеть связанные с ним характеристики. Рядом с каждой характеристикой будут два значка. Стрелка вниз позволяет прочитать характеристику, а стрелка вверх — записать в неё.
Нажмите на стрелку вниз, чтобы прочитать характеристику. Вы увидите UUID характеристики, свойства READ и WRITE, а также значение «Hello World!» — точно так, как указано в нашем коде.