Neste tutorial, vamos aprender a ativar e gerir o Bluetooth Low Energy (BLE) num ESP32 utilizando a linguagem de programação Arduino.
O Bluetooth Low Energy é uma versão de baixo consumo de energia do Bluetooth que permite o envio de pequenos pacotes de dados a intervalos regulares.
Equipamento
- Um módulo ESP32 (Bluetooth+Wifi integrados)
- Um computador com Python instalado ou um smartphone
- Cabo USB para ligação ao computador ESP32
Configuração do ambiente e do IDE
Para programar o seu ESP32 com o IDE Arduino, pode seguir este tutorial anterior.
Communication Série via BLE
A comunicação BLE deve ser configurada com um determinado número de endereços (UIID), que são como registos de memória nos quais podemos ler e escrever.
//https://github.com/espressif/arduino-esp32/tree/master/libraries/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" class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() > 0) { Serial.println("*********"); Serial.print("New value: "); for (int i = 0; i < value.length(); i++) Serial.print(value[i]); Serial.println(); Serial.println("*********"); } } }; void setup() { Serial.begin(115200); Serial.println("1- Download and install an BLE Terminal FREE"); Serial.println("2- Scan for BLE devices in the app"); Serial.println("3- Connect to ESP32BLE"); Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); BLEDevice::init("ESP32BLE"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(SERVICE_UUID); BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setCallbacks(new MyCallbacks()); pCharacteristic->setValue("Hello World"); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); Serial.print("Server address:"); Serial.println(BLEDevice::getAddress().toString().c_str()); } void loop() { // put your main code here, to run repeatedly: delay(2000); }
Nota: é possível obter o endereço MAC do ESP32 utilizando a função BLEDevice::getAddress().toString().c_str().
Emparelhamento
Uma vez configurado o módulo, pode emparelhar o ESP32 com o sistema da sua escolha, como qualquer outro dispositivo Bluetooth. Seleccione o nome na lista dos dispositivos detectados (nome ESP32BLE)
Teste da comunicação BLE utilizando o terminal BLE
Vamos testar a comunicação BLE utilizando a aplicação Terminal BLE.
A mensagem é trocada entre o telemóvel e o ESP32 através de Bluetooth LE
Comunicação bidirecional entre o dispositivo e o ESP32BLE
Este é o código utilizado para modificar o valor da caraterística através do monitor serial. O dispositivo conectado e o monitor serial modificam o valor da caraterística.
#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" BLECharacteristic *pCharacteristic = NULL; std::string msg; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() > 0) { Serial.println("*********"); Serial.print("New value: "); for (int i = 0; i < value.length(); i++) Serial.print(value[i]); Serial.println(); Serial.println("*********"); } } }; void setup() { Serial.begin(115200); Serial.println("1- Download and install an BLE Terminal Free"); Serial.println("2- Scan for BLE devices in the app"); Serial.println("3- Connect to ESP32BLE"); Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); BLEDevice::init("ESP32BLE"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setCallbacks(new MyCallbacks()); pCharacteristic->setValue("Hello World"); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue pAdvertising->setMinPreferred(0x12); pAdvertising->start(); Serial.print("Server address:"); Serial.println(BLEDevice::getAddress().toString().c_str()); } void loop() { readSerialPort(); //Send data to slave if(msg!=""){ pCharacteristic->setValue(msg); msg=""; } delay(2000); } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //add to String } } Serial.flush(); //clean buffer }
Na prática, será certamente preferível utilizar um serviço para a escrita e outro para a leitura.
Comunicação entre o ESP32 e o Python via BLE
Pode gerir a comunicação Bluetooth Low Energy a partir do seu PC.
Para isso, instale o pacote Bleak
python -m pip install bleak
Detetar dispositivos bluetooth
import asyncio from bleak import BleakScanner async def main(): target_name = "ESP32BLE" target_address = None devices = await BleakScanner.discover() for d in devices: print(d) if target_name == d.name: target_address = d.address print("found target {} bluetooth device with address {} ".format(target_name,target_address)) break asyncio.run(main())
Saída
C1:2E:C6:8E:47:E8: None 3C:61:05:31:5F:12: ESP32BLE found target ESP32BLE bluetooth device with address 3C:61:05:31:5F:12
Ligação e comunicação com o ESP32
Eis um script Python para ligar automaticamente o dispositivo ESP32 BLE a partir de um PC. Para comunicar com o dispositivo BLE, é importante conhecer o uiid dos diferentes serviços. Definimos os UUIDs como os definidos no código do ESP32
import asyncio from bleak import BleakScanner from bleak import BleakClient async def main(): target_name = "ESP32BLE" target_address = None SERVICE_UUID= "4fafc201-1fb5-459e-8fcc-c5c9c331914b" CHARACTERISTIC_UUID= "beb5483e-36e1-4688-b7f5-ea07361b26a8" devices = await BleakScanner.discover() for d in devices: print(d) if target_name == d.name: target_address = d.address print("found target {} bluetooth device with address {} ".format(target_name,target_address)) break if target_address is not None: async with BleakClient(target_address) as client: print(f"Connected: {client.is_connected}") while 1: text = input() if text == "quit": break await client.write_gatt_char(CHARACTERISTIC_UUID, bytes(text, 'UTF-8'), response=True) try: data = await client.read_gatt_char(CHARACTERISTIC_UUID) data = data.decode('utf-8') #convert byte to str print("data: {}".format(data)) except Exception: pass else: print("could not find target bluetooth device nearby") asyncio.run(main())
Aplicação
- Criar um sensor IoT ligado que envia dados através de BLE
- Criar um terminal BLE com o React Native