Serwisy partnerskie:
Close icon
Serwisy partnerskie

Korzystanie z funkcjonalności BLE układu ESP32

Jedną z najpiękniejszych cech ESP32 w stosunku do ESP-12e jest fakt, że oprócz Wi-Fi, posiada on na pokładzie dwa inne moduły komunikacyjne. ESP32 posiada wbudowane moduły Classic Bluetooth oraz Bluetooth Low Energy. W tym projekcie zbadamy, jak moduł Bluetooth Low Energy znajdujący się na pokładzie ESP-32 może być wykorzystany w projektach.
Article Image

Wprowadzenie do Bluetooth Low Energy - BLE

Protokół Bluetooth można podzielić na dwa rodzaje: klasyczny Bluetooth oraz nowszy protokół Bluetooth Low Energy, który jest również określany jako Bluetooth 4.0. Te dwa protokoły działają w paśmie ISM 2.4GHz, ale oba mają różną szybkość transmisji danych, różne zużycie energii i są zoptymalizowane dla różnych rodzajów aplikacji. Bluetooth Low Energy (BLE) został stworzony, aby przezwyciężyć wady klasycznego Bluetooth, które sprawiają, że trochę nie nadaje się do stosowania w IoT i zasilanych z baterii inteligentnych urządzeń, które muszą wysyłać tylko krótkie serie danych w określonych odstępach czasu. BLE został zaprojektowany tak, aby zużywał tylko ułamek energii, którą klasyczne urządzenia Bluetooth zużywają podczas transmisji danych i pozostawał w trybie uśpienia, gdy nie transmituje danych, w przeciwieństwie do ciągłego strumienia danych klasycznego Bluetooth. To sprawia, że urządzenia BLE są bardziej wydajne energetycznie i odpowiednie dla produktów IoT oraz innych inteligentnych urządzeń zasilanych bateriami, które zazwyczaj powinny działać tak długo, jak to możliwe na jednym ładowaniu baterii.

Szczegółowe porównanie pomiędzy tymi dwoma typami Bluetooth jest pokazane na poniższym obrazku.

BLE vs Klasyczny Bluetooth

Jednym z minusów dynamiki działania urządzeń BLE jest złożoność lub solidność (w zależności od tego, jak na to spojrzeć) systemu przesyłania wiadomości. W klasycznym Bluetooth, protokół portu szeregowego (SPP) jest zwykle używany do przesyłania danych pomiędzy urządzeniami, ponieważ komunikacja odbywa się bez większego narzutu, ale w przypadku BLE, dane podczas komunikacji są organizowane przy użyciu profilu określanego jako GATT (Generic Attributes).

Istnieją zasadniczo dwa protokoły, które są ważne w komunikacji pomiędzy dwoma urządzeniami BLE; GAP i GATT. Zrozumienie działania tych dwóch protokołów jest niezwykle ważne przy programowaniu urządzeń do komunikacji za pomocą protokołu BLE.

Protokół GAP

GAP jest akronimem dla Generic Access Profile, i kontroluje połączenia i reklamę (Uczynienie urządzenia widocznym i otwartym na połączenie) w Bluetooth. Definiuje on role, jakie urządzenia odgrywają w komunikacji, a także określa, w jaki sposób nadawany jest ładunek reklamowy (lub skanujący, w zależności od roli urządzenia).

Istnieją zasadniczo dwie role, które urządzenia BLE mogą pełnić w oparciu o GAP: Central Device i Peripheral Device. Te dwa urządzenia są reprezentacją BLE dla bardziej popularnych słów: "Klient" i "Serwer" odpowiednio. Urządzenia peryferyjne są zazwyczaj małymi urządzeniami zasilanymi bateryjnie, które rozgłaszają dane reklamowe, oczekując na połączenie z urządzeniem centralnym gotowym do odebrania ładunku danych. W rozwiązaniach opartych o IoT, urządzenia peryferyjne to zazwyczaj czujniki, itp., natomiast urządzenia centralne to zazwyczaj bramy, smartfony, itp. Przed nawiązaniem połączenia, profil Generic Access będzie nadawał ładunek reklamowy, dopóki nie pojawi się pasująca odpowiedź skanowania. Po nawiązaniu połączenia pomiędzy urządzeniem peryferyjnym a centralnym, proces reklamowy zostanie zatrzymany i zazwyczaj nie będzie już można wysyłać pakietów reklamowych w tym momencie usługi i właściwości GATT zostają uruchomione, aby ułatwić komunikację w obu kierunkach.

Protokół GATT

GATT jest akronimem dla Generic Attribute Profile, i definiuje jak dwa urządzenia Bluetooth Low Energy przesyłają  dane  między sobą, przy użyciu koncepcji zwanych Usługi i Charakterystyki. Wykorzystuje on ogólny protokół danych o nazwie Attribute Protocol (ATT) do przechowywania usług, charakterystyk i powiązanych danych w prostej tabeli wyszukiwania, wykorzystującej 16-bitowe identyfikatory dla każdego wpisu w tabeli. Hierarchiczna struktura danych GATT składa się z trzech głównych elementów: profili, usług i charakterystyk.

 GATT - Generic Attribute Profile

Profil jest predefiniowanym zbiorem usług, który został opracowany przez Bluetooth SIG lub przez projektantów urządzeń peryferyjnych. Na przykład, w przypadku monitora pracy serca, Profil Tętna może zawierać Usługę Tętna, Usługę Żywotności Baterii oraz Usługę Informacji o Urządzeniu. Lista oficjalnie przyjętych GATT jest dostępna tutaj.

Usługi są używane do grupowania danych w logiczne jednostki i zawierają określone porcje danych zwane charakterystykami. Usługa może mieć jedną lub więcej charakterystyk, a każda usługa odróżnia się od innych usług za pomocą unikalnego identyfikatora numerycznego zwanego UUID, który może być 16-bitowy (dla oficjalnie przyjętych usług BLE) lub 128-bitowy (dla usług niestandardowych). Pełną listę oficjalnie przyjętych usług BLE można zobaczyć na stronie Usługi w Bluetooth Developer Portal. Aby lepiej zrozumieć jak działają usługi, rozważmy ponownie przykład tętna, może ono zawierać do 3 cech, które w oficjalnie przyjętej usłudze, na przykład, obejmują: pomiar tętna, lokalizację czujnika ciała i punkt kontrolny tętna. Tak więc usługa zasadniczo grupuje powiązane dane.

Charakterystyka stanowi pojęcie najniższego poziomu w strukturze GATT. Obejmuje ona pojedynczy punkt danych i podobnie jak usługi, odróżnia się od innych charakterystyk za pomocą unikalnego identyfikatora numerycznego - UUID. Charakterystyki są głównymi kontenerami, które przenoszą dane pomiędzy dwoma urządzeniami.

W związku z powyższym w tym projekcie pokażemy, jak skonfigurować ESP32 jako klienta (urządzenie centralne) i jako serwer (urządzenie peryferyjne). W celu poprawnej demonstracji użyjemy dwóch płytek ESP32. Jedna z płytek zostanie zaprogramowana do działania jako serwer, z charakterystyką do wysyłania losowych danych, podczas gdy druga płytka ESP32 zostanie zaprogramowana do działania jako skaner BLE w celu znalezienia serwera.

Wykaz elementów
Ilość
Symbol
Nazwa/opis/gdzie kupić

Jak wspomniano we wstępie, potrzebujemy tylko modułu ESP32, ponieważ ma on już na pokładzie wszystko, co jest potrzebne do realizacji projektu. Zasilacz pomaga w łatwy sposób zasilać zestaw Devkit w trybie autonomicznym.  Projekt można łatwo zmodyfikować, dodając czujniki wysyłające dane na żywo do urządzenia centralnego.

My użyjemy tylko płytki ESP32, więc bez schematów, przejdziemy od razu do kodu projektu.

Kod

Jak wspomniałem we wstępie, ESP32 skonfigurujemy jako klienta i jako serwer. Oznacza to, że potrzebujemy dwóch różnych szkiców i zajmiemy się nimi jeden po drugim.

Ważne jest, aby pamiętać, że kod dla tego projektu będzie napisany przy użyciu Arduino IDE i nie będzie możliwe załadowanie kodu, jeśli twoje IDE nie ma zainstalowanego pakietu ESP 32 Arduino Board.

Po zainstalowaniu plików płytki, automatycznie załaduje ona kilka bibliotek ESP 32 do Arduino IDE. Oba szkice do tego projektu będą w dużym stopniu zależne od jednej z tych bibliotek - ESP32 BLE Arduino Library. Biblioteka ta składa się z funkcji i deklaracji, które ułatwiają wysyłanie danych przez skomplikowany protokół (przynajmniej bardziej skomplikowany w porównaniu do szeregowego) jakim jest BLE.

Szkic serwera BLE

Omówię pokrótce oba szkice, zaczynając od BLE Servera. Algorytm działania serwera BLE jest zgodny z wyjaśnieniem zawartym we wstępie powyżej. Zaczynamy od stworzenia usługi BLE, następnie tworzymy charakterystykę BLE pod tą usługą oraz deskryptor BLE pod charakterystyką. Następnie uruchamiamy usługę i uruchamiamy reklamę, aby urządzenie było widoczne dla skanujących urządzeń BLE.

Szkic rozpoczynamy od zaimportowania bibliotek w ramach biblioteki BLE Arduino, które są wymagane do wykonania kodu.

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

Następnie podajemy unikalne identyfikatory UUID dla usługi i charakterystyki. Te UUID mogą być wygenerowane za pomocą stron internetowych takich jak UUID Generator.

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

Następnie piszemy funkcję void setup(). Zaczynamy od zainicjalizowania komunikacji szeregowej, która będzie wykorzystywana do celów debugowania, po czym tworzymy obiekt klasy BLEDevice i ustawiamy go jako serwer.

void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");

BLEDevice::init("Long name works now");
BLEServer *pServer = BLEDevice::createServer();

Następnie tworzymy usługę dla serwera oraz właściwość dla usługi, podając w obu przypadkach identyfikator UUID. Określone zostały również charakterystyczne właściwości  (które w tym przypadku są READ i WRITE).

BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

Następnie ustawiamy wartość dla charakterystyki. Jak wspomniano wcześniej, w tym tutorialu użyjemy losowej wartości, ale może to być wartość czujnika lub jakakolwiek inna informacja, którą chcesz wysłać do klienta.

pCharacteristic->setValue("Hello World says Neil");

Na koniec uruchamiamy usługę, ustawiamy parametry dla reklamy i zaczynamy wysyłać ładunek reklamowy.

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();

Na potrzeby tego dema, pozostawimy sekcję pętli pustą, ale możesz zdecydować się na wykonanie dalszych zadań w jej obrębie. Możesz przejrzeć wszystkie przykłady w bibliotece BLE Arduino, aby lepiej zrozumieć.

void loop() {
  // put your main code here, to run repeatedly:
  
}

Kompletny kod serwera jest dostępny poniżej, a także jest załączony w sekcji download na końcu artykułu

/*
    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
*/

#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("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();  // 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);
}

Szkic skanera BLE

Szkic skanera, podobnie jak szkic serwera, jest dostępny jako przykład w ESP 32 BLE Arduino Library.

Jak zwykle zaczynamy od dołączenia wymaganych bibliotek.

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

Następnie określamy odstęp czasu pomiędzy kolejnymi transmisjami ładunku skanującego i tworzymy obiekt klasy BLEscan.

int scanTime = 5; //In seconds
BLEScan* pBLEScan;

Następnie piszemy funkcję void setup(). Zaczynamy od inicjalizacji monitora szeregowego, po czym inicjalizujemy BLE, co automatycznie aktywuje moduł BLE na ESP32. Argument ustawiamy jako pusty, ponieważ tak naprawdę nie potrzebujemy nazwy dla urządzenia.

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning...");

  BLEDevice::init("");

Aby zakończyć funkcję setup(), wywołujemy funkcję scan, ustawiając wszystkie parametry wymagane do skanowania.

pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

Następnie piszemy funkcję void loop(). Algorytm funkcji void loop() służy do prostego sprawdzenia czy zostało znalezione jakieś urządzenie i wypisania tych urządzeń wraz z ich numerem. Wyniki są kasowane, a pętla zaczyna się od nowa.

void loop() {
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

Kompletny kod skanera jest dostępny poniżej, a także dołączony w pliku zip w sekcji download.

/*
   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; //In seconds
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(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

Demo

Skopiuj kod i wklej do Arduino IDE (lub uruchom kod z pliku przykładowego), a następnie kolejno wgraj szkic serwera na płytkę oznaczoną jako serwer oraz kod skanera na płytkę oznaczoną jako skaner. Aby ta demonstracja działała, obie płytki muszą być "ON", ponieważ klient nie będzie w stanie zobaczyć serwera, jeśli jest on "OFF", więc możesz albo pozostawić obie z nich podłączone do komputera, albo podłączyć serwer do zasilacza lub innego źródła zasilania. Po wykonaniu tych czynności uruchom monitor szeregowy, upewniając się, że jest on ustawiony na port szeregowy, do którego podłączony jest klient. Po kilku sekundach powinieneś zobaczyć liczbę znalezionych urządzeń Bluetooth i ich nazwy wyświetlane na monitorze szeregowym.

To wszystko, jeśli chodzi o ten projekt. Można od razu rozszerzyć projekt podpinając czujnik do serwera BLE i uruchamiając przykład klienta BLE na drugiej płytce ESP32 lub jeszcze lepiej użyć aplikacji mobilnej obsługującej urządzenia BLE do interakcji z serwerem. BLE jest obecnie jedną z najczęściej używanych metod komunikacji dla inteligentnych urządzeń i mam nadzieję, że ten artykuł dostarczył Ci informacji potrzebnych do wykorzystania  w Twoim własnym projekcie.

Galeria
Do pobrania
Download icon Kod BLE

Artykuł USING THE BLE FUNCTIONALITY OF THE ESP32 opracowano w wersji polskiej na podstawie współpracy z portalem www.electronics-lab.com.

Tematyka materiału: ESP32, BLE
AUTOR
Źródło
www.electronics-lab.com
Udostępnij
UK Logo