/blog/bluetooth_low_energy_esp32
2026-07-03 · 36 min · Embedded · Tutorial · Sicurezza · TAG · ESP32 · BLE · Bluetooth · IoT · Embedded · Sicurezza

Bluetooth Low Energy su ESP32: funzionamento, GATT, sicurezza, privacy e parametri reali

Il Bluetooth Low Energy, o più semplicemente BLE, è una tecnologia radio pensata per scambiare dati consumando poco. Lavora nella banda a 2,4 GHz ed è molto usata in sensori, dispositivi IoT, beacon, wearable, serrature smart, telecomandi, sistemi medicali, dispositivi configurabili da app e procedure di provisioning Wi-Fi.

Su ESP32 è particolarmente utile perché permette a un dispositivo embedded di parlare con smartphone, gateway o altri microcontrollori senza tenere una radio sempre attiva come in una connessione continua. Il punto non è solo "avere Bluetooth", ma poter progettare comunicazioni brevi, intermittenti e abbastanza efficienti da funzionare bene anche su dispositivi alimentati a batteria.

L'ESP32 classico supporta Bluetooth dual-mode 4.2, quindi sia Bluetooth Classic sia Bluetooth Low Energy. Va però chiarito subito un dettaglio importante: anche se alcune documentazioni parlano di certificazione Bluetooth LE 5.0, l'ESP32 classico non supporta le funzioni nuove di BLE 5 come 2M PHY, LE Long Range e advertising extensions. Per quelle servono chip più recenti della famiglia Espressif, come ESP32-S3, ESP32-C3, ESP32-C6 o altri modelli compatibili.

Questo articolo riassume il funzionamento di BLE su ESP32 dal punto di vista pratico: architettura dello stack, ruoli, advertising, scanning, connessione, GATT, ATT, MTU, Data Length Extension, notifiche, indicazioni, pairing, bonding, encryption, privacy, indirizzi BLE, parametri di configurazione e scelte di sicurezza.

1. BLE non è Bluetooth Classic

Bluetooth Classic e Bluetooth Low Energy condividono il nome Bluetooth, ma non vanno trattati come la stessa tecnologia.

Bluetooth Classic nasce per collegamenti più continui: audio, cuffie, speaker, tastiere, mouse, profili seriali classici e stream persistenti. È adatto a comunicazioni più stabili nel tempo, ma in genere consuma di più.

BLE, invece, nasce per comunicazioni brevi. Un dispositivo può dormire, svegliarsi, trasmettere pochi pacchetti, ricevere una risposta e tornare in sleep. È questo comportamento a renderlo adatto a sensori e dispositivi a batteria.

Su ESP32 la scelta dello stack dipende dal progetto.

EsigenzaScelta tipica
Solo BLENimBLE
BLE + Bluetooth ClassicBluedroid
Firmware leggeroNimBLE
Compatibilità con esempi ESP-IDF storiciBluedroid
Gateway BLE, sensori, provisioning, app mobiledi solito NimBLE
Profili Classic come SPP o A2DPBluedroid

In ESP-IDF, Bluedroid è lo stack Bluetooth storico. NimBLE è più leggero ed è spesso preferibile nei progetti BLE-only. ESP-IDF espone opzioni separate per ruoli e profili NimBLE, inclusi GATT Client, GATT Server e sicurezza SMP.

2. Architettura dello stack BLE su ESP32

BLE non è una seriale wireless. È uno stack multilivello.

Uno schema semplice è questo:

LivelloCosa fa
Applicationcodice applicativo: sensori, comandi, stato, logica prodotto
HostGAP, GATT, ATT, SMP, L2CAP
ControllerLink Layer, PHY, radio, canali, pacchetti

L'applicazione decide cosa deve succedere: leggere un sensore, accendere un LED, inviare una notifica, ricevere una configurazione. L'host organizza la comunicazione usando protocolli standard. Il controller gestisce radio, canali, sincronizzazione e pacchetti fisici.

I protocolli principali sono:

ProtocolloNomeRuolo
GAPGeneric Access Profileadvertising, scanning, connessione, ruoli, privacy
ATTAttribute Protocolaccesso agli attributi
GATTGeneric Attribute Profileservizi, caratteristiche, descrittori
SMPSecurity Manager Protocolpairing, bonding, chiavi, cifratura
L2CAPLogical Link Control and Adaptation Protocolmultiplexing e trasporto logico
HCIHost Controller Interfaceinterfaccia tra host e controller

ATT è il protocollo che permette a un client di leggere, scrivere, notificare o indicare attributi esposti da un server. GATT costruisce sopra ATT una struttura più leggibile: servizi, caratteristiche e descrittori.

Lo stack BLE su ESP32 è diviso tra logica applicativa, protocolli host, controller e attività radio.

3. Ruoli BLE: GAP e GATT sono due cose diverse

Uno degli errori più comuni è confondere i ruoli GAP con i ruoli GATT.

Ruoli GAP

GAP riguarda scoperta, advertising, scanning e connessione.

Ruolo GAPSignificato
Advertisertrasmette pacchetti advertising
Scannerascolta pacchetti advertising
Initiatoravvia una connessione
Peripheraldispositivo connesso che di solito espone dati
Centraldispositivo che avvia e gestisce la connessione
Broadcastertrasmette dati senza connessione
Observerascolta dati broadcast senza connettersi

Esempio tipico: un sensore ESP32 è peripheral, lo smartphone è central.

Ruoli GATT

GATT riguarda invece il modello dati.

Ruolo GATTSignificato
GATT Servercontiene servizi, caratteristiche e valori
GATT Clientscopre, legge, scrive e si iscrive ai dati del server

Nella maggior parte dei progetti un ESP32 è GAP peripheral e GATT server. Lo smartphone è GAP central e GATT client.

Non è però una regola obbligatoria. Un ESP32 può anche lavorare come central e client, per esempio quando deve leggere sensori BLE esterni. In alcuni casi può anche far convivere GATT server e GATT client.

4. Advertising: come un ESP32 si fa trovare

L'advertising è il meccanismo con cui un dispositivo BLE annuncia la propria presenza.

Un ESP32 può trasmettere pacchetti advertising per dire:

  • sono disponibile;
  • espongo questo servizio;
  • questo è il mio nome;
  • questi sono alcuni dati minimi;
  • posso accettare una connessione.

L'advertising può servire a due cose:

  • farsi trovare da un central che poi si connetterà;
  • trasmettere piccoli dati senza connessione, come fa un beacon.

Nel legacy advertising lo spazio è molto limitato. Advertising data e scan response possono contenere fino a 31 byte ciascuno. Questo significa che bisogna scegliere con attenzione cosa inserire nel payload.

Canali advertising

BLE usa tre canali principali per advertising: 37, 38 e 39.

Sono distribuiti nella banda a 2,4 GHz per ridurre la probabilità che vengano disturbati tutti insieme dal Wi-Fi.

Advertising interval

L'advertising interval indica ogni quanto il dispositivo invia un evento advertising.

IntervalloEffetto
20-100 msdiscovery molto rapida, consumo alto
100-500 msbuon compromesso
500 ms - 2 sadatto a molti dispositivi IoT
2-10 sbasso consumo, scoperta lenta

In ESP-IDF, adv_int_min e adv_int_max sono espressi in unità da 0,625 ms. Un valore 160 corrisponde quindi a 100 ms.

Tipi di advertising

TipoSignificato
Connectableil dispositivo accetta connessioni
Non-connectabletrasmette dati ma non accetta connessioni
Scannablepuò rispondere a scan request
Non-scannablenon invia scan response
Directedadvertising rivolto a un peer specifico
Undirectedadvertising generico

Per un sensore controllato da app si usa spesso advertising connectable undirected. Per un beacon si usa advertising non-connectable.

Advertising e privacy

L'advertising è visibile a chiunque sia nelle vicinanze. Va quindi trattato come pubblico.

Non mettere mai in advertising data o scan response:

  • password;
  • token;
  • dati sanitari;
  • seriali permanenti non necessari;
  • nome completo dell'utente;
  • identificativi facilmente tracciabili;
  • stato sensibile del dispositivo;
  • informazioni cloud o credenziali.

Usare indirizzi privati è utile, ma non basta se poi il payload advertising contiene sempre lo stesso identificativo. Un dispositivo con RPA ma con manufacturer data fisso resta comunque tracciabile.

5. Scanning: come ESP32 trova dispositivi BLE vicini

Lo scanning è la procedura con cui un dispositivo ascolta gli advertising packet trasmessi da altri dispositivi.

I parametri principali sono:

ParametroSignificato
Scan intervalogni quanto parte la scansione
Scan windowquanto tempo resta in ascolto
Scan typepassivo o attivo
Filter policyaccetta tutti o solo dispositivi filtrati

Se scan window è uguale a scan interval, lo scanner ascolta quasi continuamente. È rapido, ma consuma molto. Se la window è piccola rispetto all'interval, il consumo scende, ma aumenta il tempo necessario per trovare dispositivi.

In ESP-IDF si usano funzioni come esp_ble_gap_set_scan_params() e esp_ble_gap_start_scanning(). Una durata pari a 0 indica scanning continuo finché non viene fermato esplicitamente.

Passive scanning

Nel passive scanning, ESP32 ascolta soltanto. Riceve advertising packet, ma non chiede dati aggiuntivi.

Vantaggi:

  • consuma meno;
  • genera meno traffico radio;
  • è più discreto.

Limite:

  • vede solo quello che è contenuto nell'advertising packet.

Active scanning

Nell'active scanning, ESP32 invia una scan request a un advertiser scannable. Il dispositivo può rispondere con uno scan response.

Vantaggi:

  • permette di leggere dati aggiuntivi;
  • è utile per nome completo, UUID extra o manufacturer data più estesi.

Svantaggi:

  • consuma di più;
  • crea più traffico radio;
  • rivela la presenza dello scanner.

6. Connessione BLE: connection event, interval, latency e timeout

Quando un central si connette a un peripheral, la comunicazione non diventa continua. I due dispositivi si sincronizzano e comunicano in finestre periodiche chiamate connection event.

Connection interval

Il connection interval è il tempo tra due connection event.

Più è basso, più la comunicazione è reattiva. Però il consumo sale.

Caso d'usoConnection interval indicativo
telecomando o input rapido7,5-30 ms
sensore con aggiornamenti frequenti30-100 ms
configurazione via app30-200 ms
sensore a basso consumo250 ms - 1 s o più

Peripheral latency

La peripheral latency permette al peripheral di saltare alcuni connection event quando non ha dati da inviare.

Esempio:

  • connection interval: 30 ms;
  • latency: 9.

Il peripheral può saltare fino a 9 eventi. In pratica può svegliarsi circa ogni 300 ms se non ha dati, risparmiando energia senza perdere la connessione.

Supervision timeout

Il supervision timeout è il tempo massimo senza comunicazioni valide prima di considerare persa la connessione.

In ESP-IDF è espresso in unità da 10 ms. Deve essere coerente con connection interval e latency.

Regola pratica: non impostarlo troppo basso, altrimenti compaiono disconnessioni casuali. Non impostarlo nemmeno troppo alto, altrimenti il sistema impiega troppo tempo a capire che il peer è sparito.

7. GATT: servizi, caratteristiche, descrittori e attributi

GATT è il modello dati del BLE.

Non si inviano byte "a caso". Un dispositivo espone una tabella di attributi organizzata in servizi, caratteristiche e descrittori.

Attribute

Un attributo è l'unità base di ATT/GATT.

Ha questi elementi:

CampoSignificato
Handleidentificatore numerico dell'attributo
UUIDtipo dell'attributo
Permissionsregole di accesso
Valuevalore contenuto
Lengthdimensione del valore

L'handle permette al client di riferirsi in modo preciso a quell'attributo.

Service

Un servizio rappresenta una funzione logica.

Esempi:

ServizioUso
Battery Servicelivello batteria
Heart Rate Servicebattito cardiaco
Device Information Serviceinformazioni dispositivo
Environmental Sensingtemperatura, umidità, pressione
Servizio customfunzioni proprietarie

Un servizio può essere primary o secondary. I primary service sono quelli principali scoperti dal client. I secondary service sono ausiliari e vengono usati da altri servizi.

Characteristic

Una characteristic rappresenta un dato o un comando.

Esempi:

CharacteristicDirezione tipica
TemperaturaESP32 -> smartphone
Stato LEDESP32 -> smartphone
Comando LEDsmartphone -> ESP32
Configurazione Wi-Fismartphone -> ESP32
Livello batteriaESP32 -> smartphone
Stream dati sensoreESP32 -> gateway

Una characteristic non è solo un valore. In GATT è composta da più attributi:

  • Characteristic Declaration, con proprietà e handle del valore.
  • Characteristic Value, con UUID e valore vero.
  • eventuali descriptor, come il CCCD.

Descriptor

Un descrittore aggiunge metadati a una characteristic.

DescriptorUUIDUso
CCCD0x2902abilita notify/indicate
Characteristic User Description0x2901descrizione leggibile
Presentation Format0x2904formato e unità
Client Supported Featuresvariabilefunzioni supportate dal client

Il descrittore più importante è il CCCD, Client Characteristic Configuration Descriptor.

Quando una characteristic supporta notifiche o indicazioni, il client deve scrivere nel CCCD per abilitarle o disabilitarle. Senza CCCD configurato correttamente, notify e indicate spesso non funzionano come previsto.

8. Properties e permissions: una distinzione importante

In GATT ci sono due concetti diversi: properties e permissions.

Characteristic properties

Le properties dicono cosa una characteristic può fare.

PropertySignificato
Readpuò essere letta
Writepuò essere scritta
Write Without Responsepuò ricevere scritture senza risposta
Notifypuò inviare notifiche
Indicatepuò inviare indicazioni
Broadcastpuò essere usata in broadcast GATT
Extended Propertiesusa proprietà estese

Le properties sono visibili al client durante la discovery. Dicono: questa characteristic supporta queste operazioni.

Attribute permissions

Le permissions dicono invece chi può accedere e con quale livello di sicurezza.

PermissionSignificato
Readleggibile senza cifratura
Writescrivibile senza cifratura
Read Encryptedleggibile solo con link cifrato
Write Encryptedscrivibile solo con link cifrato
Read MITMleggibile solo con protezione MITM
Write MITMscrivibile solo con protezione MITM
Signed Writescrittura firmata

In Bluedroid, ESP-IDF usa flag come:

  • ESP_GATT_PERM_READ;
  • ESP_GATT_PERM_READ_ENCRYPTED;
  • ESP_GATT_PERM_READ_ENC_MITM;
  • ESP_GATT_PERM_WRITE;
  • ESP_GATT_PERM_WRITE_ENCRYPTED;
  • ESP_GATT_PERM_WRITE_ENC_MITM.

Questa distinzione è fondamentale.

Una characteristic può avere property WRITE, ma permission WRITE_ENC_MITM.

Significa che:

  • il client vede che la characteristic è scrivibile;
  • se prova a scrivere senza link cifrato e autenticato, lo stack rifiuta o richiede pairing;
  • la scrittura viene accettata solo dopo encryption e autenticazione adeguata.

9. Operazioni GATT: read, write, notify, indicate

Le operazioni principali sono cinque.

Read

Il client legge il valore di una characteristic.

Uso tipico:

  • temperatura;
  • livello batteria;
  • firmware version;
  • configurazione corrente.

Read è semplice, ma non è ideale per dati che cambiano spesso. In quel caso il client dovrebbe interrogare continuamente il server.

Write

Il client scrive un valore e il server risponde.

Uso tipico:

  • accendere o spegnere un LED;
  • impostare una soglia;
  • inviare una configurazione;
  • cambiare modalità del dispositivo.

Write è affidabile a livello GATT perché prevede una risposta.

Write Without Response

Il client scrive senza aspettare una risposta GATT.

Uso tipico:

  • stream di dati;
  • pacchetti rapidi;
  • protocolli applicativi che gestiscono l'ACK a un livello superiore.

È più veloce, ma bisogna gestire buffer, congestione e perdita se l'applicazione richiede affidabilità.

Notify

Il server invia dati al client senza conferma GATT.

Uso tipico:

  • aggiornamenti sensore;
  • log;
  • stream dati;
  • stato periodico.

Le notification evitano il polling continuo e sono molto usate quando il dato cambia nel tempo.

Indicate

Il server invia dati al client e il client deve confermare.

Uso tipico:

  • eventi importanti;
  • allarmi;
  • cambi di stato critici;
  • messaggi che non dovrebbero essere persi.

Le indication sono più sicure a livello GATT, ma più lente delle notification.

10. Service discovery e cache GATT

Quando un client si connette a un GATT server, deve scoprire quali servizi, caratteristiche e descrittori esistono. Questo processo si chiama service discovery.

Il client recupera:

  • handle iniziale e finale dei servizi;
  • UUID dei servizi;
  • characteristic disponibili;
  • properties;
  • descriptor;
  • handle dei valori.

Molti sistemi operativi, soprattutto smartphone, mettono in cache la tabella GATT. Questo può creare confusione durante lo sviluppo.

Se cambi UUID, handle o struttura del server, il telefono potrebbe continuare a vedere la vecchia struttura.

Buone pratiche:

  • non cambiare continuamente layout GATT;
  • mantieni stabili gli UUID;
  • mantieni stabili gli handle quando possibile;
  • usa Service Changed indication se il database cambia;
  • durante sviluppo, elimina bonding e cache dal telefono se i servizi sembrano vecchi.

ESP-IDF include API per inviare una service change indication dal GATT server.

11. MTU, payload utile e frammentazione

La MTU ATT definisce la dimensione massima di una singola operazione ATT/GATT.

Il valore minimo e spesso default è 23 byte. Con MTU 23, il payload utile tipico di una notification è circa 20 byte, perché 3 byte sono usati dall'header ATT.

Su ESP32 la MTU può essere configurata fino a 517 byte, ma la MTU effettiva è quella negoziata tra i due peer. Si usa sempre il valore più piccolo supportato da entrambi.

MTU non significa throughput automatico

Aumentare la MTU aiuta, ma non basta.

Il throughput dipende anche da:

  • connection interval;
  • Data Length Extension;
  • numero di pacchetti per connection event;
  • PHY;
  • qualità radio;
  • congestione;
  • stack BLE;
  • smartphone o peer usato;
  • logica applicativa.

MTU in ESP-IDF

Nel client Bluedroid, esp_ble_gattc_send_mtu_req() invia una richiesta MTU e genera ESP_GATTC_CFG_MTU_EVT.

Si può anche impostare la MTU locale con esp_ble_gatt_set_local_mtu(). Se non viene fatto, resta la MTU default di 23 byte.

Valori pratici

MTUPayload utile indicativoUso
23~20 bytecompatibilità massima
100~97 bytebuon compromesso
247~244 bytemolto usata per throughput
517~514 bytemassimo ESP32, se supportato dal peer

Non tutti gli smartphone accettano 517. In pratica valori come 185, 247 o simili sono spesso più realistici.

12. Data Length Extension, PHY e throughput

La Data Length Extension, o DLE, è diversa dalla MTU.

La MTU riguarda ATT/GATT. La DLE riguarda la dimensione del pacchetto dati a livello Link Layer.

ESP32 supporta Bluetooth 4.2 DLE e permette di impostare la dimensione massima del pacchetto dati LE con API come esp_ble_gap_set_pkt_data_len().

ConcettoLivelloCosa controlla
MTUATT/GATTdimensione operazione GATT
DLELink Layerdimensione pacchetto radio dati
PHYfisicovelocità/modulazione radio
Connection intervalscheduling linkfrequenza degli eventi
Notification/write modeGATToverhead e conferme

Throughput realistico

Il throughput BLE su ESP32 dipende da interferenze, connection interval, MTU, DLE e prestazioni del peer.

In condizioni buone, tra due ESP32 si possono ottenere valori nell'ordine di centinaia di Kbps. Dispositivi con 2M PHY possono spingersi oltre, ma ESP32 classico non supporta 2M PHY.

PHY disponibili

PHYCaratteristica
LE 1Mcompatibilità massima
LE 2Mpiù velocità, se supportato
LE Codedpiù range, meno throughput

BLE 5 non indica una sola funzione. È un insieme di estensioni, e nel firmware bisogna sempre controllare quali sono supportate dal chip, dallo stack e dal peer.

Le tre funzioni che creano più confusione sono queste:

Funzione BLE 5Cosa cambia davveroQuando serve
2M PHYradio a 2 Mb/s invece di 1 Mb/spiù throughput e meno tempo radio attivo
Coded PHYpacchetti codificati con più ridondanzapiù portata, meno throughput
Advertising extensionsadvertising più flessibile e payload molto più ampiobeacon, scan più ricchi, advertising sets

2M PHY lavora a livello fisico. Non cambia GATT e non raddoppia magicamente il throughput applicativo, perché restano in gioco MTU, DLE, connection interval, numero di pacchetti per connection event e prestazioni del peer. Però riduce il tempo necessario a trasmettere gli stessi bit rispetto a LE 1M. È utile quando il collegamento radio è buono e l'obiettivo è spostare dati più rapidamente.

Coded PHY fa il contrario: sacrifica velocità per rendere il segnale più robusto. Usa codifica ridondante, di solito indicata come S=2 o S=8. Con S=2 il payload lavora a 500 Kbps, con S=8 a 125 Kbps. La portata può migliorare, ma ogni pacchetto occupa la radio più a lungo. Su ESP32 con Wi-Fi attivo questo può pesare parecchio, perché Wi-Fi e Bluetooth condividono la stessa banda e devono contendersi il tempo radio.

Advertising extensions riguarda invece l'advertising, non la connessione GATT. Nel legacy advertising lo spazio utile resta molto piccolo: 31 byte per advertising data e 31 byte per scan response. Con le estensioni di BLE 5 l'advertising può usare pacchetti e canali secondari, arrivando a payload più ampi e a più advertising set. È utile per beacon più ricchi, scanner specializzati e scenari in cui vuoi trasmettere più metadati senza aprire subito una connessione. Non è comunque un invito a mettere dati sensibili in chiaro: advertising e scan response restano dati visibili.

ESP32 classico non supporta 2M PHY, Coded PHY e advertising extensions. ESP32-C3, ESP32-S3, ESP32-C6 e altri chip più recenti della famiglia Espressif possono invece supportare queste funzioni BLE 5, ma conviene verificare sempre la tabella di supporto della versione ESP-IDF usata.

Attenzione alla coesistenza Wi-Fi/BLE: Coded PHY occupa la radio più a lungo e può peggiorare le prestazioni quando Wi-Fi e Bluetooth devono condividere la stessa banda.

13. Sicurezza BLE: cosa protegge davvero

La sicurezza BLE non è automatica.

Una connessione può essere:

  • completamente aperta;
  • cifrata ma non autenticata;
  • cifrata e autenticata;
  • protetta contro attacchi man-in-the-middle.

Il protocollo che gestisce questa parte è SMP, Security Manager Protocol. SMP si occupa di pairing, bonding, distribuzione chiavi, encryption e identità.

Pairing, bonding, encryption

Questi tre termini vengono spesso confusi.

TermineSignificato
Pairinggenerazione e autenticazione delle chiavi
Bondingsalvataggio delle chiavi per connessioni future
Encryptioncifratura del link BLE usando chiavi valide

Il pairing può generare chiavi. Il bonding salva quelle chiavi. L'encryption usa quelle chiavi per proteggere il link.

Un'operazione GATT protetta porta normalmente la connessione attraverso pairing, distribuzione delle chiavi e cifratura del link prima di concedere l'accesso.

Pairing non significa sempre sicurezza forte

Il pairing può essere debole o forte. Dipende dal metodo.

MetodoProtezione MITMNote
Just Worksnosemplice, ma non autentica il peer
Passkey Entrysì, se implementato correttamenterichiede inserimento codice
Numeric Comparisonrichiede display e conferma
OOBsì, se il canale esterno è sicuroNFC, QR code o altro canale

MITM significa Man-In-The-Middle. Senza protezione MITM, un attaccante vicino potrebbe interporsi durante il pairing in alcuni scenari.

Security Mode 1

BLE Security Mode 1 ha quattro livelli principali.

LivelloSignificato
Level 1nessuna sicurezza
Level 2encryption con pairing non autenticato
Level 3encryption con pairing autenticato
Level 4LE Secure Connections autenticato con encryption

Ogni connessione parte dal livello più basso e può essere aggiornata in base al pairing usato.

LE Legacy Pairing e LE Secure Connections

BLE inizialmente usava LE Legacy Pairing, basato su Temporary Key e Short Term Key.

Con Bluetooth 4.2 è stato introdotto LE Secure Connections, basato su Elliptic-Curve Diffie-Hellman. È molto più robusto.

In pratica:

MetodoSicurezza
Legacy Just Worksdebole
Legacy Passkeymeglio, ma non moderno
LE Secure Connections Just Workscifrato ma non autenticato
LE Secure Connections + Passkey/Numeric Comparisonmolto meglio
LE Secure Connections + OOB sicuromolto forte

Su prodotti reali conviene usare Secure Connections quando possibile, soprattutto per evitare problemi legati al pairing legacy.

14. Sicurezza su ESP32: API e parametri importanti

In ESP-IDF Bluedroid la sicurezza BLE si configura soprattutto tramite GAP/SMP.

API principali

APIUso
esp_ble_gap_set_security_param()imposta parametri SMP
esp_ble_set_encryption()richiede encryption sul link
esp_ble_gap_security_rsp()accetta o rifiuta una security request
esp_ble_passkey_reply()risponde con passkey
esp_ble_confirm_reply()conferma numeric comparison
esp_ble_remove_bond_device()rimuove un dispositivo bonded
esp_ble_get_bond_device_num()conta i dispositivi bonded
esp_ble_gap_get_local_irk()ottiene IRK locale

Parametri SMP importanti

ParametroSignificato
ESP_BLE_SM_AUTHEN_REQ_MODErequisiti di autenticazione
ESP_BLE_SM_IOCAP_MODEcapacità input/output
ESP_BLE_SM_SET_INIT_KEYchiavi distribuite dall'initiator
ESP_BLE_SM_SET_RSP_KEYchiavi distribuite dal responder
ESP_BLE_SM_MAX_KEY_SIZEdimensione massima chiave
ESP_BLE_SM_MIN_KEY_SIZEdimensione minima chiave
ESP_BLE_SM_SET_STATIC_PASSKEYpasskey statica
ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTHaccetta solo requisiti specificati
ESP_BLE_SM_OOB_SUPPORTsupporto Out-of-Band

Per accettare solo Secure Connections, si usa il bit ESP_LE_AUTH_REQ_SC_ONLY in ESP_BLE_SM_AUTHEN_REQ_MODE e si abilita ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE tramite ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH.

Se servono bonding e protezione MITM, vanno aggiunti anche ESP_LE_AUTH_BOND e ESP_LE_AUTH_REQ_MITM.

Eventi sicurezza da gestire

Nel callback GAP bisogna gestire eventi come:

EventoSignificato
ESP_GAP_BLE_SEC_REQ_EVTil peer chiede sicurezza
ESP_GAP_BLE_PASSKEY_NOTIF_EVTmostrare passkey
ESP_GAP_BLE_NC_REQ_EVTnumeric comparison
ESP_GAP_BLE_KEY_EVTscambio chiavi
ESP_GAP_BLE_AUTH_CMPL_EVTautenticazione completata
ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVTbond rimosso
ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVTprivacy locale configurata

L'esempio gatt_security_server di Espressif è un buon punto di partenza perché mostra passkey, numeric comparison, security request, key exchange, authentication complete e local privacy.

15. Privacy BLE: indirizzi, tracciamento e IRK

La privacy BLE serve a ridurre la possibilità che un dispositivo venga tracciato nel tempo tramite il suo indirizzo radio.

Tipi di indirizzo BLE

TipoDescrizione
Public Device Addressindirizzo pubblico assegnato al dispositivo
Random Static Addressindirizzo casuale ma stabile finché non viene cambiato
Resolvable Private Address, RPAindirizzo che cambia e può essere risolto da peer autorizzati
Non-Resolvable Private Address, NRPAindirizzo casuale non risolvibile

Un dispositivo bonded può risolvere un RPA usando l'IRK, Identity Resolving Key.

IRK

IRK significa Identity Resolving Key.

È una chiave distribuita durante il bonding. Serve a riconoscere un dispositivo anche se cambia indirizzo RPA.

In pratica:

  1. il dispositivo cambia indirizzo periodicamente;
  2. il peer bonded riceve il nuovo indirizzo;
  3. usa l'IRK salvata per capire che è lo stesso dispositivo;
  4. un osservatore non autorizzato non dovrebbe poter fare questa associazione.

RPA non basta se il payload identifica il dispositivo

Esempio sbagliato:

Address: cambia ogni 15 minutiAdvertising name: "Marco_Glucometro_SN123456"Manufacturer data: ID fisso 0xA1B2C3D4

L'indirizzo cambia, ma il dispositivo resta riconoscibile.

Esempio migliore:

Address: RPAAdvertising name: generico o assenteManufacturer data: nessun ID permanenteConnessione: dati sensibili solo dopo encryption

La privacy BLE va progettata su tutto il pacchetto, non solo sull'indirizzo.

16. Encryption BLE: cosa viene cifrato e cosa no

L'encryption BLE protegge il link dopo che i dispositivi hanno stabilito chiavi valide.

Advertising non è un canale segreto

Nel caso normale, advertising e scan response vanno considerati pubblici.

DatoDove metterlo
nome generico dispositivoadvertising, se serve
UUID servizioadvertising
stato non sensibileadvertising, se accettabile
password Wi-Fimai in advertising
token cloudsolo dopo connessione sicura
dati personalisolo dopo encryption e access control
comandi criticicharacteristic protetta

La cifratura protegge i dati della connessione, non i normali pacchetti advertising legacy.

Encryption non sostituisce i controlli applicativi

Anche con link cifrato bisogna comunque:

  • controllare chi può scrivere una characteristic;
  • validare lunghezze e formati;
  • evitare overflow;
  • usare timeout;
  • non fidarsi dei valori ricevuti;
  • distinguere pairing mode e modalità operativa;
  • proteggere comandi critici con logica applicativa.

Permessi GATT cifrati

Per proteggere una characteristic bisogna configurare i permessi.

CharacteristicPropertyPermission
temperatura pubblicaRead/NotifyRead
configurazione sogliaRead/WriteRead Encrypted / Write Encrypted
comando serraturaWriteWrite Encrypted + MITM
token cloudWriteWrite Encrypted + MITM
dati medicaliRead/NotifyRead Encrypted + MITM

Su ESP-IDF Bluedroid i flag ESP_GATT_PERM_READ_ENCRYPTED, ESP_GATT_PERM_WRITE_ENCRYPTED, ESP_GATT_PERM_READ_ENC_MITM e ESP_GATT_PERM_WRITE_ENC_MITM servono proprio a definire questi requisiti.

17. Filter Accept List e pairing mode

In un prodotto reale non conviene restare sempre in pairing mode.

Una strategia più robusta è questa:

  1. all'avvio normale, accettare solo dispositivi già bonded;
  2. entrare in pairing mode solo con un'azione locale;
  3. mantenere pairing mode attiva per un tempo limitato;
  4. salvare il bond dopo il pairing;
  5. usare Filter Accept List o logica applicativa per limitare connessioni e scan request;
  6. permettere reset pairing solo con procedura controllata.

Perché serve un gesto fisico

Senza un gesto fisico, chiunque vicino al dispositivo potrebbe tentare pairing quando il dispositivo è disponibile.

Un pulsante locale riduce il rischio perché richiede presenza fisica.

Esempio:

  1. pressione pulsante per 5 secondi;
  2. LED lampeggiante;
  3. advertising connectable aperto per 60 secondi;
  4. pairing con passkey o numeric comparison;
  5. bonding salvato;
  6. uscita automatica dalla pairing mode.

18. Progettare un GATT server ESP32 sicuro

Un buon GATT server non espone tutto senza controllo.

Bisogna separare:

  • dati pubblici;
  • dati protetti;
  • comandi critici;
  • funzioni disponibili solo in provisioning;
  • funzioni disponibili solo con conferma fisica.

Esempio di servizio custom: Device Control Service.

CharacteristicOperazioniSicurezza
Device StatusRead/NotifyRead encrypted
Device NameRead/WriteWrite encrypted
LED CommandWriteWrite encrypted
Factory ResetWriteWrite encrypted + MITM + conferma fisica
Firmware VersionReadpubblico o encrypted
Diagnostic LogNotifyencrypted
Wi-Fi CredentialsWriteencrypted + MITM, solo in provisioning mode

Gli UUID custom non sono password

Un UUID a 128 bit non è un segreto.

Un client può fare service discovery e trovare servizi e characteristic. Non bisogna progettare la sicurezza pensando: "nessuno conosce l'UUID".

La sicurezza deve stare in:

  • pairing corretto;
  • encryption;
  • MITM quando serve;
  • permessi GATT;
  • controlli applicativi;
  • pairing mode limitata;
  • assenza di segreti in advertising.

Validare sempre le scritture

Ogni write deve essere controllata.

Almeno:

  • lunghezza;
  • formato;
  • range dei valori;
  • stato corrente del dispositivo;
  • autorizzazione;
  • rate limit;
  • checksum o framing, se serve;
  • protezione da replay, se il comando è critico.

Una characteristic che riceve un comando motore, per esempio, non dovrebbe accettare qualunque byte. Deve controllare comando, parametri, stato sicurezza, modalità operativa e timeout.

19. Privacy applicativa: oltre lo standard BLE

La privacy non riguarda solo l'indirizzo radio.

Riguarda tutto ciò che può identificare un utente, un dispositivo o un comportamento.

Dati da minimizzare

Evitare di esporre:

  • nome reale utente;
  • email;
  • seriale fisso;
  • posizione;
  • MAC Wi-Fi;
  • SSID di reti note;
  • dati sanitari;
  • pattern di utilizzo;
  • identificativi cloud permanenti.

Identificativi temporanei

Se devi trasmettere un identificativo in advertising, valuta identificativi temporanei:

  • generati dal server;
  • ruotati periodicamente;
  • non collegabili direttamente all'utente;
  • validi solo per una finestra temporale;
  • inutili senza backend o chiave.

Fasi di esposizione dei dati

Un buon schema può essere questo:

FaseDati esposti
Advertisingsolo dati minimi
Connessione non cifrataquasi nulla
Dopo pairing/encryptionconfigurazioni e stato
Dopo autenticazione applicativadati molto sensibili
Modalità manutenzionesolo con azione fisica

20. Consumi: cosa incide davvero

BLE consuma poco solo se configurato bene.

I parametri che aumentano il consumo sono:

ParametroEffetto
advertising interval molto bassoradio attiva più spesso
scanning continuoconsumo molto alto
connection interval bassoeventi frequenti
peripheral latency zeroperipheral sempre presente
TX power altapiù consumo
notification troppo frequentipiù traffico
log e callback pesantiCPU attiva più a lungo

Configurazioni indicative

ScenarioAdvertisingConnection intervalLatencyNote
pairing rapido20-100 ms30-50 ms0solo per finestra breve
sensore a batteria1-5 s250 ms - 1 saltamassimo risparmio
beacon500 ms - 5 snessuna connessione-non-connectable
streaming100-500 ms7,5-30 ms0throughput alto
app di configurazione100-500 ms30-100 ms0-4buon compromesso

Non esiste un valore migliore in assoluto. Dipende da latenza, consumo, esperienza utente e tipo di prodotto.

21. BLE e Wi-Fi insieme su ESP32

ESP32 usa la banda 2,4 GHz sia per Wi-Fi sia per Bluetooth. Le due radio devono convivere.

Problemi comuni:

ProblemaCausa possibile
disconnessioni BLEWi-Fi molto attivo, timeout basso
throughput BLE instabilecoesistenza radio
scanning perde dispositiviscan window piccola o Wi-Fi intenso
latenza altascheduling radio condiviso
consumo altoWi-Fi e BLE sempre attivi

Buone pratiche:

  • evitare scan BLE continuo se Wi-Fi è molto usato;
  • usare connection interval realistici;
  • aumentare supervision timeout in ambienti rumorosi;
  • ridurre log e traffico inutile;
  • usare BLE per provisioning e spegnerlo se non serve più;
  • evitare Coded PHY se non serve davvero long range.

Coded PHY può peggiorare la coesistenza perché occupa la radio più a lungo rispetto a 1M o 2M PHY.

22. Flusso firmware BLE server sicuro su ESP32

Un firmware BLE server robusto può seguire questo flusso:

  1. inizializzare NVS;
  2. inizializzare controller Bluetooth;
  3. abilitare Bluedroid o NimBLE;
  4. configurare un nome dispositivo non identificativo;
  5. configurare privacy locale, se usata;
  6. configurare parametri SMP;
  7. creare la tabella GATT;
  8. impostare permessi corretti per ogni attributo;
  9. configurare advertising data minimale;
  10. avviare advertising;
  11. alla connessione, aggiornare parametri se necessario;
  12. richiedere encryption se il servizio lo richiede;
  13. gestire pairing e bonding;
  14. gestire read, write, notify e indicate;
  15. alla disconnessione, riavviare advertising se opportuno;
  16. rimuovere pairing mode dopo timeout.

Pseudocodice:

app_main(){    init_nvs();    init_ble_controller();    init_ble_host(); // NimBLE o Bluedroid    configure_device_name("ESP32-Device");    configure_privacy_if_needed();    configure_smp_security();    create_gatt_database_with_secure_permissions();    configure_advertising_payload_minimal();    start_advertising();    // Da qui in poi: callback GAP/GATT}

Callback leggere

Le callback BLE devono essere rapide.

In pratica:

  • non scrivere su flash dentro callback se non necessario;
  • non fare parsing pesante;
  • non fare HTTP o MQTT direttamente;
  • usare queue e task separati;
  • copiare i dati e uscire rapidamente.

Una callback BLE non dovrebbe diventare il posto in cui vive tutta la logica applicativa.

23. Flusso BLE client ESP32

Un ESP32 può anche lavorare come client o gateway BLE.

Flusso tipico:

  1. configurare scanning;
  2. avviare scanning;
  3. filtrare per UUID servizio, nome o manufacturer data;
  4. fermare scanning quando viene trovato il target;
  5. aprire la connessione;
  6. eseguire MTU exchange;
  7. fare service discovery;
  8. trovare characteristic e CCCD;
  9. leggere valori o abilitare notification;
  10. gestire riconnessione e cache.

Filtrare bene

Non filtrare solo per nome. Il nome può cambiare, mancare o essere non univoco.

Meglio usare:

  • service UUID;
  • manufacturer data;
  • address solo se bonded e privacy gestita;
  • dati applicativi non sensibili;
  • Filter Accept List, quando applicabile.

24. Errori comuni

Mettere dati segreti in advertising

Advertising è visibile. Non usarlo per password, token, credenziali o dati personali.

Pensare che Just Works protegga da MITM

Just Works cifra il link, ma non autentica davvero il peer. Per comandi sensibili non basta.

Confondere encryption e autorizzazione

Encryption protegge il link. Non decide da sola se un comando è permesso. Questa decisione deve stare nello stack, nei permessi GATT e nella logica applicativa.

Usare UUID custom come password

Gli UUID si scoprono. Non sono segreti.

Assumere sempre MTU 517

La MTU finale è negoziata. Non dare per scontato che il peer accetti 517 byte.

Dimenticare il CCCD

Per notify e indicate il client deve abilitare la characteristic scrivendo nel CCCD. Senza CCCD configurato bene, le notifiche possono non arrivare.

Lasciare pairing sempre aperto

Pairing mode dovrebbe essere temporanea e, idealmente, attivata con un'azione fisica.

Cambiare GATT table senza gestire cache

Gli smartphone possono mantenere una vecchia cache GATT. Usa Service Changed o cancella bond/cache durante lo sviluppo.

25. Checklist per un progetto BLE ESP32

Architettura

  • Ho scelto NimBLE se mi serve solo BLE.
  • Ho scelto Bluedroid se mi serve anche Bluetooth Classic.
  • Ho verificato le funzioni supportate dal chip specifico.
  • Non sto assumendo funzioni BLE 5 su ESP32 classico.

Advertising

  • Advertising data sotto 31 byte se legacy.
  • Nessun dato sensibile in advertising.
  • Nome dispositivo generico.
  • Advertising interval coerente con consumo e UX.
  • Pairing advertising limitato nel tempo.

Connessione

  • Connection interval realistico.
  • Peripheral latency usata se il dispositivo è a batteria.
  • Supervision timeout non troppo aggressivo.
  • Parametri testati con smartphone reali.

GATT

  • Servizi e characteristic organizzati in modo logico.
  • UUID custom a 128 bit per servizi proprietari.
  • Properties e permissions configurate correttamente.
  • CCCD presente per notify/indicate.
  • Scritture validate lato applicazione.
  • Service Changed gestito se cambia il database GATT.

Sicurezza

  • SMP configurato.
  • LE Secure Connections usato dove possibile.
  • MITM richiesto per comandi sensibili.
  • Bonding usato per dispositivi personali.
  • Pairing mode attivabile solo localmente.
  • Bond rimovibile con procedura controllata.
  • Permessi GATT encrypted/MITM sui dati sensibili.

Privacy

  • RPA usato se serve anti-tracciamento.
  • IRK gestita tramite bonding.
  • Advertising senza identificativi permanenti.
  • Nome dispositivo non riconducibile all'utente.
  • Dati sensibili inviati solo dopo encryption.

Prestazioni

  • MTU negoziata e controllata.
  • DLE abilitata se serve throughput.
  • Notification usate per stream.
  • Indication usate solo per eventi critici.
  • Callback leggere.
  • Wi-Fi coexistence testata.

26. Glossario BLE essenziale

  • ACL: Asynchronous Connection-Less link. Nel contesto BLE indica il collegamento dati tra dispositivi connessi.
  • Advertising: trasmissione periodica di pacchetti BLE per farsi trovare o inviare piccoli dati.
  • Advertising Data: payload contenuto nel pacchetto advertising.
  • Advertising Extension: funzione BLE 5 che permette advertising più flessibile e payload più ampi rispetto al legacy advertising, se supportata dal chip.
  • Advertising Interval: tempo tra due eventi advertising.
  • ATT: Attribute Protocol. Definisce attributi, handle, lettura, scrittura, notifiche e indicazioni.
  • Attribute: unità base dati in ATT/GATT. Ha handle, UUID, permessi e valore.
  • Authentication: verifica dell'identità o della legittimità del peer durante il pairing.
  • Authorization: decisione applicativa o stack-level che stabilisce se un peer può accedere a una risorsa.
  • Bonding: salvataggio delle chiavi generate durante il pairing per riconnessioni future.
  • Broadcaster: dispositivo che invia advertising senza accettare connessioni.
  • CCCD: Client Characteristic Configuration Descriptor. Descriptor UUID 0x2902 usato dal client per abilitare notify o indicate.
  • Central: dispositivo GAP che avvia e gestisce la connessione. Spesso smartphone o gateway.
  • Characteristic: elemento GATT che rappresenta un dato o un comando.
  • Characteristic Declaration: attributo che descrive proprietà e handle del valore di una characteristic.
  • Characteristic Value: attributo che contiene il valore vero della characteristic.
  • Coded PHY: PHY BLE per long range. Usa codifica ridondante, aumenta la portata ma riduce il throughput.
  • Connection Event: finestra temporale in cui central e peripheral si scambiano pacchetti.
  • Connection Interval: tempo tra due connection event.
  • CSRK: Connection Signature Resolving Key. Chiave usata per firme dati in alcuni scenari BLE.
  • Data Length Extension, DLE: funzione che aumenta la dimensione del payload a livello Link Layer.
  • Descriptor: attributo che aggiunge metadati a una characteristic.
  • Encryption: cifratura del link BLE.
  • Filter Accept List: lista di dispositivi accettati per scanning, advertising o connessione.
  • GAP: Generic Access Profile. Gestisce discovery, advertising, scanning, ruoli, connessione e privacy.
  • GATT: Generic Attribute Profile. Organizza gli attributi in servizi, caratteristiche e descrittori.
  • GATT Client: dispositivo che scopre, legge, scrive e si iscrive ai dati di un GATT server.
  • GATT Server: dispositivo che espone una tabella di attributi.
  • Handle: identificatore numerico di un attributo GATT.
  • HCI: Host Controller Interface. Interfaccia tra host Bluetooth e controller.
  • Indication: messaggio server-to-client che richiede conferma.
  • Initiator: dispositivo GAP che avvia una connessione.
  • IRK: Identity Resolving Key. Chiave usata per risolvere Resolvable Private Address.
  • Just Works: metodo di pairing semplice, senza protezione MITM.
  • LE Secure Connections: metodo moderno di pairing BLE basato su ECDH, introdotto con Bluetooth 4.2.
  • L2CAP: livello di adattamento e multiplexing tra protocolli superiori e link BLE.
  • LTK: Long Term Key. Chiave usata per cifrare riconnessioni future.
  • MITM: Man-In-The-Middle. Attacco in cui un terzo si interpone tra due dispositivi.
  • MTU: Maximum Transmission Unit. In ATT/GATT indica la dimensione massima di una procedura GATT.
  • NimBLE: stack BLE leggero disponibile in ESP-IDF.
  • Notification: messaggio server-to-client senza conferma GATT.
  • NRPA: Non-Resolvable Private Address. Indirizzo privato non risolvibile.
  • OOB: Out-of-Band. Pairing tramite canale esterno, come NFC o QR code.
  • Pairing: processo di generazione e autenticazione delle chiavi di sicurezza.
  • Passkey Entry: metodo di pairing con codice numerico.
  • Peripheral: dispositivo GAP che accetta connessione da un central.
  • PHY: livello fisico radio: LE 1M, LE 2M, LE Coded.
  • Privacy: meccanismi per ridurre tracciamento e identificazione del dispositivo.
  • Properties: operazioni supportate da una characteristic: read, write, notify, indicate.
  • Permissions: regole di accesso e sicurezza sugli attributi GATT.
  • Resolvable Private Address, RPA: indirizzo privato che cambia e può essere risolto da peer autorizzati tramite IRK.
  • RSSI: Received Signal Strength Indicator. Indicatore della potenza del segnale ricevuto.
  • Scan Request: richiesta inviata da uno scanner attivo a un advertiser scannable.
  • Scan Response: risposta contenente dati aggiuntivi all'advertising.
  • Scanning: ascolto dei pacchetti advertising.
  • Security Manager Protocol, SMP: protocollo BLE per pairing, bonding, chiavi ed encryption.
  • Service: raggruppamento GATT di characteristic correlate.
  • Service Changed Indication: indicazione usata per informare il client che la tabella GATT è cambiata.
  • Supervision Timeout: tempo massimo senza comunicazione valida prima di considerare persa la connessione.
  • UUID: identificatore di servizi, caratteristiche e descrittori. Può essere 16 bit standard o 128 bit custom.
  • Whitelist: vecchio termine spesso usato per indicare Filter Accept List.
  • Write Without Response: scrittura GATT senza risposta del server. Utile per throughput, ma meno controllata.

27. Conclusione

BLE su ESP32 è molto utile, ma va progettato con attenzione.

Non è una seriale wireless e non è automaticamente sicuro. GAP gestisce advertising, scanning, ruoli e connessione. ATT e GATT organizzano i dati in attributi, servizi, characteristic e descriptor. SMP gestisce pairing, bonding, chiavi, privacy ed encryption.

In un progetto reale bisogna decidere con precisione:

  • quali dati sono pubblici;
  • quali dati richiedono encryption;
  • quali comandi richiedono MITM;
  • quando il dispositivo entra in pairing mode;
  • quali characteristic sono leggibili o scrivibili;
  • come vengono gestiti RPA, bonding e IRK;
  • come vengono configurati MTU, DLE, interval, latency e timeout;
  • come BLE convive con Wi-Fi.

La configurazione migliore non è sempre quella più veloce. È quella che bilancia consumo, latenza, throughput, compatibilità, sicurezza e privacy.

Su ESP32 classico bisogna ricordare i limiti hardware BLE 4.2. Per funzioni BLE 5 come 2M PHY, Coded PHY e advertising extensions serve scegliere un chip più recente della famiglia Espressif.

Fonti principali consultate

Ultimo aggiornamento 2026-07-03.
Sorgente dell’articolo content/blog/bluetooth_low_energy_esp32.

Autore

Nicolò è un software architect di Bergamo. Lavora su firmware ESP32, HMI, app Android native, backend, librerie software e integrazioni tra sistemi.

Prossimo articolo

2026-06-27
Scope guard in C++

Usare RAII per tenere il rollback vicino allo stato da proteggere.