Sperando di fare cosa gradita, volevo mettere a disposizione uno sketch di test per ESP32 ed un progetto MIT App Inventor da usare insieme allo sketch.
Troppo spesso infatti si vede che il BLE di questa MCU viene usato (secondo me) in modo improprio cercando di replicare il funzionamento dei moduli tipo HC-05 ovvero emulando una comunicazione di tipo seriale.
Come già detto altrove, trovo che sia assurdo usare un sistema di trasmissione (Bluetooth) per emularne un altro (Seriale) e poi dover fare via software il parsing dei dati ricevuti per ottenere quello che il primo sistema ti consente di fare in modo nativo (lettura/scrittura/notifica di valori da e verso la MCU).
Questo è il progetto MIT App Inventor (con pochi passaggi si può convertire anche per usarlo in Kodular)
ESP32_Test.zip (227.7 KB)
E questo invece è il progetto per ESP32
esp32-ble-peripheral-mitAI.zip (9.1 KB)
Ovviamente si tratta di uno sketch fatto a scopo di test con dei valori random ed è quindi buono solo come un'eventuale base da sviluppare e/o migliorare integrando le funzionalità necessarie.
Visto che molti non amano scaricare dei file, aggiungo il sorgente anche alla vecchia maniera
#include <WiFi.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
// Puntatori alle caratteristiche che vogliamo leggere/scrivere/notificare
BLECharacteristic* pTempCh = nullptr;
BLECharacteristic* pHumCh = nullptr;
BLECharacteristic* pLedCh = nullptr;
BLECharacteristic* pPWMCh = nullptr;
// The service to be exposed
static BLEUUID serviceUUID ("0000181a-0000-1000-8000-00805f9b34fb");
// The characteristic of the remote service we are interested in.
static BLEUUID temperatureCharUUID ("0000181a-0001-1000-8000-00805f9b34fb");
static BLEUUID humidityCharUUID ("0000181a-0002-1000-8000-00805f9b34fb");
static BLEUUID builtinledCharUUID ("0000181a-0003-1000-8000-00805f9b34fb");
static BLEUUID pwmvalueCharUUID ("0000181a-0004-1000-8000-00805f9b34fb");
// Definiamo un po' di scorciatoie da usare nelle definizioni delle proprietà delle carattestische
#define READ_WRITE (BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE)
#define READ_NOTIFY (BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY)
uint8_t ledPin = LED_BUILTIN;
bool connected = false;
// Valori che saranno letti/aggiornati usando l'APP
// (il led viene acceso/spento senza usare variabili di appoggio)
///////////////////////////////////////////////////////////////////////
float temp = 25.50;
float hum = 45.0;
uint16_t pwmValue = 1023;
///////////////////////////////////////////////////////////////////////
// Server connect/disconnect callback class
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
connected = true;
Serial.println("BLE central connected");
};
void onDisconnect(BLEServer* pServer) {
connected = false;
Serial.println("Restart advertising");
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
}
};
// Write Characteristic callback class (called when central writes)
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
// La libreria BLE non fornisce dei metodi specializzati per tipo di dati (int, float, etc etc)
// Dobbiamo quindi recuperare il puntatore ai dati passati e fare le necessarie conversioni
// Se si tratta del LED abbiamo uno "short", quindi un solo byte di lunghezza
if (pCharacteristic->getUUID().equals(builtinledCharUUID)) {
uint8_t* dataPtr = pCharacteristic->getData();
// N.B. dataPtr è un puntatore, quindi va deferenziato
if (*dataPtr == 1) {
Serial.println("LED ON");
analogWrite(ledPin, pwmValue);
}
else {
Serial.println("LED OFF");
analogWrite(ledPin, 0);
}
}
// Se si tratta del PWM sono 2 byte (PWM impostato a 10 bit nel setup)
if (pCharacteristic->getUUID().equals(pwmvalueCharUUID)) {
uint8_t* dataPtr = pCharacteristic->getData();
// N.B. dataPtr è un puntatore, quindi va deferenziato
uint16_t value = *(dataPtr + 1) << 8 | *dataPtr;
Serial.print("PWM value: ");
Serial.println(value);
pwmValue = value;
}
}
};
void setup() {
pinMode(ledPin, OUTPUT);
analogWriteResolution(10);
Serial.begin(115200);
Serial.println("\n\n\n\nStarting ESP32 BLE peripheral...");
// Create the BLE Device
BLEDevice::init("ESP32");
// Create the BLE Server
BLEServer* pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(serviceUUID);
// Create BLE Characteristics
pTempCh = pService->createCharacteristic(temperatureCharUUID, READ_NOTIFY);
pTempCh->addDescriptor(new BLE2902());
pHumCh = pService->createCharacteristic(humidityCharUUID, READ_NOTIFY);
pHumCh->addDescriptor(new BLE2902());
pLedCh = pService->createCharacteristic(builtinledCharUUID, READ_WRITE);
pLedCh->addDescriptor(new BLE2902());
pLedCh->setCallbacks(new MyCallbacks()); // Registro l'oggetto da richiamare quando la caratteristica viene scritta
pPWMCh = pService->createCharacteristic(pwmvalueCharUUID, READ_WRITE);
pPWMCh->addDescriptor(new BLE2902());
pPWMCh->setCallbacks(new MyCallbacks()); // Registro l'oggetto da richiamare quando la caratteristica viene scritta
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(serviceUUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
BLEDevice::startAdvertising();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
// Usiamo un semplice timer oer inviare i valori aggiornati
static uint32_t updateTime;
if (millis() - updateTime >= 1000) {
updateTime = millis();
temp = (float)random(200, 250) / 10.0;
pTempCh->setValue(temp); // A differenza di getValue, setValue ha metodi tipizzati
pTempCh->notify();
// Serial.print("Temperatura: ");
// Serial.println(temp, 1);
hum = (float)random(400, 600) / 10.0;
pHumCh->setValue(hum); // A differenza di getValue, setValue ha metodi tipizzati
pHumCh->notify();
// Serial.print("Umidità: ");
// Serial.println(hum, 1);
}
}
P.S.
Scusate i commenti mezzo in Inglese e mezzo in Italiano, ma ovviamente sono partito dagli esempi inclusi nel core ESP32.