Интро
Уже сравнительно давно микроконтроллер ESP32 стал неким стандартом для множества DIY проектов. И действительно, возможность работы с Wi-Fi, Bluetooth, встроенная энергонезависимая память, а так же большое число выводов позволяют сделать массу интересных проектов.
В этой статье, мы поговорим про управление конроллером с помощью BLE используя доступные в AppStore приложения. А в следующей,
На основе непосредственно контроллера, существует множество плат, с различными интегрируемыми модулями: экраном, модулем для карт памяти и тд. Одной из самых удобных для новичков, которым интересно именно программирование, а не возня с кучей проводков — платформа M5Stack.
Это устройство, в базовой комплектации, включает в себя LCD-дисплей, кардридер, аккумулятор, и три кнопки. Кроме этого, к нему существует множество модулей, подключаемых по принципу «бутерброда».
Не смотря на то, что в данной статье программирование микроконтроллера будет в Arduino IDE, его так же можно программировать с помощью MicroPython, а так же собственной блоковой среды разработки — UiFlow.
Инструкцию по настройке ArduinoIDE, для работы с M5Stack можно найти здесь.
Немного про то, что же такое BLE
BLE — Bluetooth Low Energy, это протокол, который, в отличии от обычного Bluetooth, постоянно находится в спящем режиме, кроме тех случаев, когда идёт непосредственная передача данных. За счёт этого, тратится примерно в 100 раз меньше энергии, что очень важно при использовании встраиваемых устройств с аккумуляторами.
Когда мы используем протокол BLE, мы работаем с сервисами и характеристиками. Это очень напоминает протокол MQTT, где есть топики. У каждого сервиса, есть как минимум одна характеристика. Каждый сервис это просто объем информации: например состояние датчика. Характеристика включает в себя описание себя (что она умеет: читать, писать, является Broadcast-ом) и непосредственно значение.
Каждый элемент, с которым мы работаем: сервис, характеристика должен иметь свой UUID (Universally unique identifier).
Подробнее про BLE можно почитать тут.
В Ардуино, система работа с BLE примерно такая: есть сервер — это само устройство, у сервера есть сервис, а у сервиса уже есть характеристики, в которые и поступают данные. У каждого из них могут быть Callback функции.
Выводим сообщение на экран
Чтобы работать с BLE и M5Stack из Arduino IDE необходимо подключить библиотеки.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <M5Stack.h>
Затем сгенерировать как минимум два UUID: один для сервиса, а один для характеристики. Для генерации можно использовать UUID generator.
#define SERVICE_UUID "9a8ca9ef-e43f-4157-9fee-c37a3d7dc12d" // ID сервиса
#define ELEM_UUID "cc46b944-003e-42b6-b836-c4246b8f19a0" // ID характеристики
#define DEVINFO_UUID (uint16_t)0x180a
#define DEVINFO_MANUFACTURER_UUID (uint16_t)0x2a29
#define DEVINFO_NAME_UUID (uint16_t)0x2a24
#define DEVINFO_SERIAL_UUID (uint16_t)0x2a25
#define DEVICE_MANUFACTURER "M5Stack" // Имя "Производителя"
#define DEVICE_NAME "M5Stack_BLE" // Имя устройства
Создадим сервер и сервис.
// Создание Callback функции для сервера.
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
// Обработка подключения телефона к устройству
M5.Lcd.println("Connected");
};
void onDisconnect(BLEServer* pServer) {
// Обработка отключения
M5.Lcd.println("Disconnected");
}
};
// Код размещённый ниже - помещается в функцию setup()
String devName = DEVICE_NAME;
String chipId = String((uint32_t)(ESP.getEfuseMac() >> 24), HEX);
devName += '_';
devName += chipId;
BLEDevice::init(devName.c_str()); // Инициализация девайса
BLEServer *pServer = BLEDevice::createServer(); // Создание сервера
pServer->setCallbacks(new MyServerCallbacks()); // Подключение Callback-а
BLEService *pService = pServer->createService(SERVICE_UUID); // Cоздание сервиса
Для создания какой-либо характеристики необходимо сделать следующее:
- Объявить характеристику.
BLECharacteristic *pElem;
- Объявить класс Callback Функция onWrite вызывается, когда в данную характеристику поступает информация. В нашем случае, информация просто выводится на экран.
class ElemCallbacs : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value1 = pCharacteristic->getValue(); M5.Lcd.clear(BLACK); M5.Lcd.setCursor(3, 35); M5.Lcd.print("Get value: "); M5.Lcd.println(value1.c_str()); } };
- И добавить новую характеристику к уже существующему сервису, с указанием свойств. Это тоже делается внутри функции setup()
pElem = pService->createCharacteristic(ELEM_UUID,BLECharacteristic::PROPERTY_READ| BLECharacteristic::PROPERTY_WRITE); pElem->setCallbacks(new ElemCallbacs());
После добавления всех характеристик, важно не забыть запустить сервис, а после этого запустить Advertising.
pService->start();
// ----- Advertising
BLEAdvertising *pAdvertising = pServer->getAdvertising();
BLEAdvertisementData adv;
adv.setName(devName.c_str());
pAdvertising->setAdvertisementData(adv);
BLEAdvertisementData adv2;
adv2.setCompleteServices(BLEUUID(SERVICE_UUID));
pAdvertising->setScanResponseData(adv2);
pAdvertising->start();
Полностью исходный код представлен на гитхабе.
Тестируем
Для тестирования была использована программа BLE scanner. В ней можно выбрать устройство, выбрать характеристику и отправить на неё данные в текстовом или байтовом формате.
При запуске необходимо выбрать наше устройство, затем выбрать ту характеристику, с которой мы хотим работать и отправить в неё информацию.
А что же происходит на устройстве? При загрузке на нём отображается такие сообщения:
После подключения телефона — добавляется соответствующая строка:
А когда отправляется сообщение — экран выглядит так:
Заключение
Используя предложенный пример, можно достаточно легко сделать собственный функционал. А с учётом возможностей M5Stack, часть проектов не потребует никакого дополнительного оборудования.
P.S. Пользователи Android, не обижайтесь, что я не сказал про вас ни слова. У вас тоже есть возможность работы с BLE и даже приложение BLE Scanner доступно в PlayMarket.