UP | HOME

ESP 32 WROOM - Bluetooth

Table of Contents

Differenza tra BLE e BluetoothSerial

La differenza principale tra Bluetooth Low Energy (BLE) e Bluetooth Serial riguarda il tipo di comunicazione e le loro caratteristiche.

Bluetooth Low Energy (BLE) è una versione ottimizzata del protocollo Bluetooth classico progettata per l'Internet delle cose (IoT) e dispositivi a basso consumo energetico. BLE è progettato per trasmettere piccoli pacchetti di dati a intervalli regolari, riducendo così il consumo energetico. È ideale per dispositivi come sensori, indossabili e dispositivi IoT, dove l'efficienza energetica è un fattore cruciale. BLE supporta un'ampia gamma di profili e servizi che consentono la comunicazione e lo scambio di dati tra dispositivi.

Bluetooth Serial, d'altra parte, fa riferimento alla comunicazione seriale tramite il protocollo Bluetooth. È un modo per trasmettere dati in modalità seriale (come i dati inviati tramite la porta seriale UART) tra dispositivi abilitati Bluetooth. Questo tipo di comunicazione è comune in applicazioni come l'interfacciamento con dispositivi come microcontrollori, Arduino o altri dispositivi che supportano la comunicazione seriale. Bluetooth Serial viene spesso utilizzato per inviare e ricevere dati in tempo reale tra dispositivi come computer, smartphone o tablet e dispositivi embedded.

In breve, Bluetooth Low Energy (BLE) è progettato per la comunicazione a basso consumo energetico tra dispositivi IoT e a bassa potenza, mentre Bluetooth Serial è utilizzato per la comunicazione seriale tra dispositivi abilitati Bluetooth, consentendo la trasmissione di dati in modalità seriale tra dispositivi.

Esempio con BLE

Questo esempio crea un server BLE sull'ESP32 che trasmette periodicamente la stringa "Hello, Bluetooth!" come valore di una caratteristica BLE notificabile. Puoi personalizzare il valore e le caratteristiche in base alle tue esigenze specifiche.

Ricorda che questo è solo un esempio di base per illustrare il funzionamento del BLE sull'ESP32 utilizzando la libreria Arduino. Puoi ulteriormente estendere e personalizzare il codice per adattarlo al tuo progetto specifico.

/*  Include le librerie per l'utilizzo del bluetooth */
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer;
BLECharacteristic *pCharacteristic;

void setup() {
  Serial.begin(115200);

  /* imposta il nome del seriale BT */
  BLEDevice::init("ESP32");

  /* Viene creato un oggetto BLEServer che gestirà il server BLE. */
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  /* Viene creato un oggetto BLEService che rappresenta un servizio BLE all'interno del server.*/
  BLEService *pService = pServer->createService(SERVICE_UUID);


  /*
     Viene creato un oggetto BLECharacteristic che rappresenta una caratteristica BLE
     all'interno del servizio. La caratteristica è configurata per essere leggibile,
     scrivibile e notificabile.
  */
  pCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID,
      BLECharacteristic::PROPERTY_READ |
          BLECharacteristic::PROPERTY_WRITE |
          BLECharacteristic::PROPERTY_NOTIFY);

  /* Viene aggiunto un descrittore BLE2902 alla caratteristica per abilitare le notifiche */
  pCharacteristic->addDescriptor(new BLE2902());

  /* Il servizio viene avviato */
  pService->start();

  /* Viene ottenuto un oggetto BLEAdvertising dal server e avviata la pubblicità BLE */
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {

  // Aggiorna qui il valore del carattere da trasmettere
  String value = "Hello, Bluetooth!";

  pCharacteristic->setValue(value.c_str());
  pCharacteristic->notify();

  delay(1000);
}

pServer->setCallbacks()

La funzione viene utilizzata per impostare i callback (chiamate di ritorno) per gestire gli eventi del server BLE. I callback consentono di gestire determinati eventi o azioni che si verificano nel server BLE. Di seguito un elenco degli eventi che possono essere personalizzati :

  1. onConnect: Chiamato quando un dispositivo si connette al server BLE.
  2. onDisconnect: Chiamato quando un dispositivo si disconnette dal server BLE.
  3. onWrite: Chiamato quando una caratteristica viene scritta da un dispositivo connesso al server BLE.
  4. onRead: Chiamato quando una caratteristica viene letta da un dispositivo connesso al server BLE.
  5. onSubscribe: Chiamato quando un dispositivo si abbona alle notifiche o indicazioni di una caratteristica.
  6. onUnsubscribe: Chiamato quando un dispositivo si disiscrive dalle notifiche o indicazioni di una caratteristica.
  7. onNotify: Chiamato quando viene inviata una notifica o indicazione a un dispositivo connesso.

Di seguito un esempio funzionante

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

BLEServer *pServer;
BLECharacteristic *pCharacteristic;

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    Serial.println("Device connected");
  }

  void onDisconnect(BLEServer* pServer) {
    Serial.println("Device disconnected");
  }

  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string value = pCharacteristic->getValue();
    Serial.print("Received data: ");
    Serial.println(value.c_str());
  }
};

void setup() {
  Serial.begin(115200);

  BLEDevice::init("ESP32");
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(BLEUUID((uint16_t)0x180D));

  pCharacteristic = pService->createCharacteristic(
      BLEUUID((uint16_t)0x2A37),
      BLECharacteristic::PROPERTY_READ |
          BLECharacteristic::PROPERTY_WRITE);

  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  // Do nothing in the loop
}

La classe MyServerCallbacks eredita dalla classe BLEServerCallbacks e definisce i callback personalizzati per gli eventi del server BLE. Nel nostro esempio, abbiamo implementato onConnect, onDisconnect e onWrite.

Nella funzione setup(), inizializziamo la comunicazione seriale, inizializziamo il dispositivo BLE, creiamo il server BLE e impostiamo i callback utilizzando pServer->setCallbacks(new MyServerCallbacks()).

Creiamo un servizio BLE e una caratteristica BLE all'interno del server. La caratteristica è impostata come leggibile e scrivibile. Infine, avviamo il servizio e l'annuncio BLE.

Nel callback onConnect, stampiamo un messaggio sulla console seriale quando un dispositivo si connette al server BLE.

Nel callback onDisconnect, stampiamo un messaggio sulla console seriale quando un dispositivo si disconnette dal server BLE.

Nel callback onWrite, recuperiamo il valore scritto nella caratteristica BLE e lo stampiamo sulla console seriale.

All'interno della funzione loop(), non è presente alcun codice poiché non è necessario fare nulla di specifico nel loop principale per gestire gli eventi BLE.

Cos'e' una caratteristica - pCharacteristic->addDescriptor(new BLE2902())

Una caratteristica (characteristic) nel contesto del Bluetooth Low Energy (BLE) è un'entità di dati che rappresenta una proprietà o una funzionalità specifica di un dispositivo BLE. Le caratteristiche sono organizzate all'interno di servizi (services) e consentono la trasmissione di dati tra dispositivi BLE.

Ogni caratteristica ha una UUID (Universally Unique Identifier) che ne identifica in modo univoco il tipo e le proprietà. Le proprietà di una caratteristica definiscono il suo comportamento e includono:

  1. Proprietà di lettura (Read): Consente a un dispositivo centrale di leggere il valore corrente della caratteristica dal dispositivo periferico.
  2. Proprietà di scrittura (Write): Consente a un dispositivo centrale di scrivere un valore nella caratteristica del dispositivo periferico.
  3. Proprietà di notifica (Notify): Consente a un dispositivo periferico di inviare notifiche ai dispositivi centrali quando il valore della caratteristica cambia.

Proprietà di indicazione (Indicate): Simile alle notifiche, consente a un dispositivo periferico di inviare indicazioni periodiche ai dispositivi centrali con il valore aggiornato della caratteristica.

Oltre alle proprietà, una caratteristica può anche avere dei descrittori (descriptors) associati. I descrittori forniscono ulteriori informazioni o configurazioni sulla caratteristica stessa, come metadati, unità di misura o limiti di valori consentiti.

Le caratteristiche vengono organizzate all'interno dei servizi BLE, che possono rappresentare una raccolta logica di caratteristiche correlate. Ad esempio, un servizio potrebbe rappresentare il servizio di misurazione di un sensore, con caratteristiche per la temperatura, l'umidità, la pressione, ecc.

La comunicazione e lo scambio di dati tra dispositivi BLE avviene attraverso la lettura o scrittura delle caratteristiche dei servizi. I dispositivi centrali possono leggere il valore delle caratteristiche dei dispositivi periferici, scrivere nuovi valori nelle caratteristiche o sottoscriversi per ricevere notifiche o indicazioni quando il valore di una caratteristica cambia.

Le caratteristiche e i servizi BLE sono definiti utilizzando un'appropriato profilo BLE o personalizzati per soddisfare le specifiche esigenze del tuo progetto. La definizione delle caratteristiche, dei servizi e dei descrittori avviene mediante l'assegnazione delle relative UUID e la configurazione delle proprietà e delle funzionalità desiderate.

Di seguito un esempio di uso delle caratteristiche in cui una volta creato un oggetto BLECharacteristic chiamato pCharacteristic con un UUID specifico. La caratteristica viene configurata come notificabile (BLENotify) e scrivibile (BLEWrite).

Successivamente, utilizziamo il metodo addDescriptor() per aggiungere un nuovo descrittore alla caratteristica. In questo caso, stiamo aggiungendo un descrittore BLE2902, che è comunemente usato per abilitare o disabilitare le notifiche o gli indirizzi di raccolta dati.

#include <BLE2902.h>

// Creazione della caratteristica
BLECharacteristic pCharacteristic("characteristicUUID", BLENotify | BLEWrite);

// Aggiunta del descrittore BLE2902
pCharacteristic.addDescriptor(new BLE2902());

BluetoothSerial

Nell'esempio sotto, stiamo utilizzando la libreria BluetoothSerial per creare una connessione Bluetooth tra l'Arduino e un dispositivo remoto, come uno smartphone.

All'interno della funzione setup(), inizializziamo la comunicazione seriale di debug tramite Serial.begin() e successivamente avviamo la comunicazione Bluetooth tramite SerialBT.begin("NomeDelDispositivo"). Assicurati di sostituire "NomeDelDispositivo" con il nome che desideri assegnare al tuo dispositivo Bluetooth.

Controlliamo anche se la connessione Bluetooth è stata stabilita correttamente utilizzando l'if statement if (!SerialBT.begin("NomeDelDispositivo")). In caso di errore di connessione, stampiamo un messaggio di errore sulla porta seriale di debug e il programma entra in un ciclo infinito.

All'interno della funzione loop(), controlliamo se ci sono dati disponibili sulla porta seriale di debug utilizzando Serial.available(). Se ci sono dati, li leggiamo con Serial.read() e li inviamo al modulo Bluetooth tramite SerialBT.write().

Successivamente, controlliamo se ci sono dati disponibili sul modulo Bluetooth utilizzando SerialBT.available(). Se ci sono dati, li leggiamo con SerialBT.read() e li stampiamo sulla porta seriale di debug utilizzando Serial.println().

#include <BluetoothSerial.h>

BluetoothSerial SerialBT; // Crea un'istanza di BluetoothSerial

void setup() {
  Serial.begin(115200); // Inizializza la comunicazione seriale di debug
  SerialBT.begin("NomeDelDispositivo"); // Inizia la comunicazione Bluetooth con il nome del dispositivo specificato

  // Verifica se il modulo Bluetooth è connesso correttamente
  if (!SerialBT.begin("NomeDelDispositivo")) {
    Serial.println("Errore di connessione al modulo Bluetooth!");
    while (1); // Attendi in un ciclo infinito
  }

  Serial.println("Modulo Bluetooth connesso correttamente!");
}

void loop() {
  if (Serial.available()) { // Controlla se ci sono dati disponibili sulla porta seriale di debug
    char data = Serial.read(); // Legge i dati dalla porta seriale di debug
    SerialBT.write(data); // Invia i dati al modulo Bluetooth
  }

  if (SerialBT.available()) { // Controlla se ci sono dati disponibili sul modulo Bluetooth
    char data = SerialBT.read(); // Legge i dati dal modulo Bluetooth
    Serial.print("Dati ricevuti tramite Bluetooth: ");
    Serial.println(data); // Stampa i dati ricevuti sulla porta seriale di debug
  }
}

Invio dei dei dati

Nella classe BluetoothSerial, i metodi println() e write() hanno due scopi diversi per l'invio dei dati tramite Bluetooth:

  • SerialBT.println(): Questo metodo invia una stringa ( oggetto String di Arduino/ESP32 ) o un valore seguito da un carattere di nuova riga ("\r\n"). Ad esempio, se utilizzi SerialBT.println("Hello"), invierà la stringa "Hello" seguita da un carattere di nuova riga. Questo è utile quando desideri inviare dati con una nuova riga alla fine, il che può essere utile per distinguere i messaggi o per interpretare correttamente i dati ricevuti.
  • SerialBT.write(): Questo metodo invia un singolo byte di dati. Puoi utilizzarlo per inviare un carattere, un valore numerico o qualsiasi dato rappresentato da un singolo byte. Ad esempio, se utilizzi SerialBT.write('A'), invierà il carattere "A" come byte. Questo metodo è utile quando desideri inviare dati byte per byte senza aggiungere caratteri di formattazione o di controllo.

Elenco dei metodi della classe BluetoothSerial

L'elenco completo dei metodi disponibili nella classe BluetoothSerial:

  • begin(deviceName): Avvia la comunicazione Bluetooth e imposta il nome del dispositivo Bluetooth come specificato da deviceName.
  • end(): Termina la comunicazione Bluetooth e libera le risorse associate al modulo Bluetooth.
  • available(): Restituisce il numero di byte disponibili per la lettura dal modulo Bluetooth.
  • read(): Legge il prossimo byte disponibile dal modulo Bluetooth e lo restituisce come un valore di tipo int.
  • peek(): Restituisce il prossimo byte disponibile dal modulo Bluetooth senza rimuoverlo dalla coda di lettura.
  • flush(): Svuota il buffer di trasmissione del modulo Bluetooth e assicura che tutti i dati siano stati inviati.
  • write(data): Invia un singolo byte (data) al dispositivo remoto connesso attraverso il modulo Bluetooth.
  • print(data): Stampa i dati specificati (di tipo int, float, char, ecc.) sulla porta seriale di debug.
  • println(data): Stampa i dati specificati seguiti da un carattere di nuova riga sulla porta seriale di debug.
  • printf(format, args…): Stampa i dati specificati formattati secondo il formato specificato.
  • setTransmitPower(powerLevel): Imposta il livello di potenza di trasmissione per il modulo Bluetooth (disponibile solo su alcune schede).
  • setPin(pin): Imposta il pin di connessione per il modulo Bluetooth (disponibile solo su alcune schede).
  • connected(): Restituisce true se c'è una connessione Bluetooth attiva, altrimenti restituisce false.
  • operator bool(): Restituisce true se il modulo Bluetooth è stato inizializzato correttamente, altrimenti restituisce false.

Link Utili

BLOG Sezione ARI Montecatini Terme

ARI ( Associazione Radioamatori Italiani)

PTLUG ( Linux User Group Pistoia )

ARAL ( Associazione Radiamatori Monte Amiata / Monte Labbro )

Author: ARI people

Created: 2023-06-29 gio 18:53

Validate