Nel precedente articolo ho introdotto la tecnologia Bluetooth Low Energy e il processo di advertising.
Abbiamo visto che un dispositivo BLE può sfruttare i pacchetti di advertising per inviare dati; in tal caso il dispositivo viene chiamato broadcaster, mentre i dispositivi che ricevono i dati sono chiamati observers.
Il payload di un pacchetto di advertising ha la seguente struttura:
ADV ADDR è l’indirizzo MAC del dispositivo (indirizzo che veniva visualizzato in console dal programma sviluppato nel precedente articolo), mentre ADV DATA è un campo, lungo un massimo di 31 bytes, organizzato in una o più strutture formate da 3 elementi:
[checklist]
- AD length è la lunghezza complessiva (in bytes) della singola struttura dati
- AD type è il tipo di informazione riportata in tale struttura
- AD data è l’informazione
[/checklist]
Il sito ufficiale del Bluetooth Special Interest Group riporta l’elenco dei possibili AD types.
Un dispositivo può ad esempio trasmettere il proprio nome utilizzando l’AD type 0x09:
Durante lo scan, il driver Bluetooth mette a disposizione del programma i dati (ADV DATA) ricevuti nell’array scan_result->scan_rst.ble_adv. Tale array contiene valori uint8_t ed ha dimensione scan_result->scan_rst.adv_data_len.
La libreria Bluedroid contiene un metodo, esp_ble_resolve_adv_data(), che consente di ottenere il valore di un particolare AD type passando i dati grezzi (raw data). Il file di header esp_gap_ble_api.h contiene anche la definzione degli AD types più comuni:
Nel mio repository Github trovate una nuova versione del programma che effettua lo scan: utilizzando quanto spiegato sopra ora estrae anche – se disponibile – il nome del device e lo visualizza in console:
iBeacon
Una particolare famiglia di dispositivi broadcasters sono gli iBeacon. Tali dispositivi sono stati pensati da Apple per consentire interazioni con dispositivi IOS (iPhone…) basati sulla location awareness. Facciamo un esempio: un telefono iPhone può “accorgersi” di essere vicino ad un particolare iBeacon, associato ad una stanza di un museo, e proporre all’utente la visualizzazione di una breve guida delle opere esposte.
Le specifiche dei dispositivi iBeacon si trovano sul portale sviluppatore Apple. Gli iBeacon funzionano inserendo nei pacchetti di advertising un particolare payload (ADV DATA):
Il primo dato inviato è di tipo flags (0x01). Ogni bit ha un diverso significato, tipicamente gli iBeacon utilizzano il valore 0x0A.
Il secondo dato inviato è di tipo 0xFF, ovvero Manufacturer Specific Data. Lo standard Bluetooth lascia liberi i vari produttori di usare l’ID 0xFF per inviare dati custom. I dati inviati hanno lunghezza 25 bytes (0x1A – 0x01 che è la lunghezza del campo AD type).
Le specifiche Apple per gli iBeacon suddividono ulteriormente il campo AD data in diversi elementi:
Il primo campo indica il produttore; normalmente gli iBeacon utilizzano il codice 0x004C, assegnato ad Apple Inc. I successivi due indicano il tipo di iBeacon e hanno valore fisso (0x02 e 0x15). Il campo UUID, insieme con i campi Major e Minor (facoltativi, possono essere impostati a 0) identificano univocamente il singolo iBeacon. Infine il campo TX power contiene una misurazione, ad un metro di distanza dall’iBeacon, della potenza ricevuta ed è utile per rendere più accurata la stima della distanza tra il telefono e l’iBeacon stesso.
esp32
Ho sviluppato un programma per il chip esp32 che attiva un relay se rileva un particolare iBeacon. Tramite menuconfig è possibile configurare l’UUID dell’iBeacon da monitorare, il pin a cui è collegato il led e il timeout in secondi trascorsi i quali – se non viene nuovamente rilevato l’iBeacon – il programma spegne il led. E’ inoltre possibile impostare una soglia minima di potenza in modo da poter regolare la distanza di rilevamento dell’iBeacon.
Il programma verifica se il pacchetto ricevuto (evento ESP_GAP_SEARCH_INQ_RES_EVT) è stato inviato da un iBeacon verificando che tale pacchetto sia di 30 bytes e che contenga nel suo header i valori indicati sopra:
// iBeacon fixed header ibeacon_header_t ibeacon_fixed_header = { .flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = 0x004C, .beacon_type = 0x1502 }; |
La verifica avviene utilizzando il comando memcmp che confronta due blocchi di memoria:
if(memcmp(adv_data, ibeacon_fixed_header, sizeof(ibeacon_fixed_header))) result = true; |
Il sorgente del programma si trova nel mio repository Github, ecco un video che mostra il suo funzionamento:
Ciao complimenti per le tue guide molto istruttive,e possibile rilevare un cellulare invece di un iBeacon,per far attivare il relay?
ciao Stefano, sicuramente sì… puoi usare una app che trasmette un pacchetto broadcast di tipo iBeacon o inventarti tu un formato che condividerai tra l’app e il codice sull’esp32.
Grazie Luca provo a documentarmi devo chiudere una porta quando esco da una certa area
Hi,Luca
Thank your for these tutorials. Did you try to use esp32 with both ble and wifi?
Hi! Yes, it works fine (BLE + Wifi). I think I’ll post a tutorial about it when I complete the “BLE” serie 😉
Hi Luca,
Thanks so much for the great tutorial.
Could you please explain how to program the ESP32 to run both BLE and WIFI? Do you have an implemented code?
Thank you again for your support.
Kind regards, Achille
Hi Achille, in a future tutorial I’ll explain it!
I’m waiting impatiently.
Hi luca ağain:D What esp-idf version do you use?
I usually keep my local repository updated with Github, so I use the (almost) the latest version
Hi Luca,
thanks for the great tutorial. Could you recommend a beacon that I can use with your code that is small, reliable, with a good battery life and that can be used as a keychain. I have trouble finding anything.
Another question: What is the fastest time from startup of the ESP32 till a successful scan of a nearby beacon. It would help me a lot if I knew that.
Kind regards, Martin
it usually takes a couple of seconds to boot the esp32
Could you make this sketch work with the tile mate key finder?
Hi Martin, I don’t own a tile make key finder but from what I see it’s a standard BLE device so if you know its mac address, you can scan for it
Hi Luca,
Is it possible to use more than one ibeacon and could we control different pinouts with these beacons?
Sure! Each iBeacon has its own “id” so your program can look for them and act accordingly
Hi Luca,
We are getting an error like “C:\Users\Specvinuser1\Documents\Arduino\sketch_aug20a\sketch_aug20a.ino:27:1: sorry, unimplemented: non-trivial designated initializers not supported” we are using your 26_ble_advertise code please help us out to resolve this issue…
Thanks in advance..
Darshan, you’re using arduino but my examples are not for that IDE/environment. To compile and run my tutorials you need esp-idf.
Ciao Luca bell’articolo, e ottimo il tutorial.
Avrei una domanda sui beacon. Volevo interfacciare una esp32 con dei dispositivi a bassa potenza, dei sensori di temperatura che sono alimentati da pannelli fotovoltaici. Il chip a bordo invia i suoi dati in base a quanta batterie ha a disposizione. Quindi non spedisce i dati a tempo fisso. Lato esp32, a questo punto, come faccio ad essere certo di non perdere dati inviati da dispositivi che, inviano sporadicamente perchè hanno il livello di batteria bassa?
Dovrei effettuare degli scan in modo “continuo”? Quale è la “buona” regola per questi casi?
Grazie.
Matteo
ciao Matteo! Ipotizzo che i dati vengano trasmessi nei pacchetti di advertising, giusto? In tal caso puoi fare in modo che al termine di uno scan lanci subito il seguente, così di fatto il chip esp32 è sempre in ascolto di pacchetti di ADV
Si i dati vengono inviati attraverso i pacchetti di advertising. Va bene grazie dell’aiuto e complimenti ancora per gli articoli.
Grazie
Matteo