ESP32 (32) – BLE, iBeacon

by luca
18 comments

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:

ibeacon-002

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:

ibeacon-003

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:

ibeacon-004

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-009

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.

ibeacon-001

Le specifiche dei dispositivi iBeacon si trovano sul portale sviluppatore Apple. Gli iBeacon funzionano inserendo nei pacchetti di advertising un particolare payload (ADV DATA):

ibeacon-006

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:

ibeacon-008

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.

Per effettuare il parsing del pacchetto ricevuto ed estrarre il valore di UUID ho utilizzato nel mio programma la tecnica descritta in questo mio articolo (parsing attraverso l’uso di struct).

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:

Nel video utilizzo un iBeacon di WGX. Se vi interessa avere maggiori informazioni, in questo post ne faccio una recensione…

[youtube id=”upeHpyTW1ZM” width=”600″ height=”350″]

Related Posts

18 comments

Stefano Bordini 22 marzo 2018 - 11:18

Ciao complimenti per le tue guide molto istruttive,e possibile rilevare un cellulare invece di un iBeacon,per far attivare il relay?

Reply
luca 22 marzo 2018 - 13:05

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.

Reply
Stefano Bordini 22 marzo 2018 - 23:28

Grazie Luca provo a documentarmi devo chiudere una porta quando esco da una certa area

Reply
serkan 3 aprile 2018 - 08:31

Hi,Luca
Thank your for these tutorials. Did you try to use esp32 with both ble and wifi?

Reply
luca 3 aprile 2018 - 08:37

Hi! Yes, it works fine (BLE + Wifi). I think I’ll post a tutorial about it when I complete the “BLE” serie 😉

Reply
Achille 18 luglio 2018 - 18:52

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

Reply
luca 4 agosto 2018 - 13:26

Hi Achille, in a future tutorial I’ll explain it!

Reply
serkan 3 aprile 2018 - 08:54

I’m waiting impatiently.

Reply
serkan 3 aprile 2018 - 19:32

Hi luca ağain:D What esp-idf version do you use?

Reply
luca 3 aprile 2018 - 19:45

I usually keep my local repository updated with Github, so I use the (almost) the latest version

Reply
Martin 10 luglio 2018 - 21:46

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

Reply
luca 11 luglio 2018 - 20:23

it usually takes a couple of seconds to boot the esp32

Reply
Martin 10 luglio 2018 - 23:15

Could you make this sketch work with the tile mate key finder?

Reply
luca 11 luglio 2018 - 20:22

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

Reply
Alican 3 novembre 2018 - 13:55

Hi Luca,
Is it possible to use more than one ibeacon and could we control different pinouts with these beacons?

Reply
luca 10 novembre 2018 - 21:44

Sure! Each iBeacon has its own “id” so your program can look for them and act accordingly

Reply
Darshan 20 agosto 2019 - 08:49

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..

Reply
luca 28 agosto 2019 - 14:39

Darshan, you’re using arduino but my examples are not for that IDE/environment. To compile and run my tutorials you need esp-idf.

Reply

Rispondi a luca Cancel Reply

cinque × 2 =