ESP32 (32) – BLE, iBeacon

luca 05/03/2018 18

In my previous article I explained the Bluetooth Low Energy technology and the advertising process.

You learned that a BLE device can leverage the advertising packets to send data; in this case the device is called broadcaster and the devices which receive data are called observers.

The payload of an advertising packet has the following structure:


ADV ADDR is the device MAC address (this is the address displayed by the program developed in the previous article) and ADV DATA is a field, with a max length of 31 bytes, that contains one or more structures, each with 3 elements:

  • AD length is the total length (in bytes) of each data structure
  • AD type is the type of data contained in the structure
  • AD data is the real data

The official website of the Bluetooth Special Interest Group lists all the available AD types.

A device, for example, can transmit its local name using the AD type 0x09:


In scan mode, the Bluetooth driver returns to the program the received data (ADV DATA) in the scan_result->scan_rst.ble_adv array. This array contains uint8_t values and it’s size is scan_result->scan_rst.adv_data_len.

The Bluedroid library contains a method, esp_ble_resolve_adv_data(), which allows to get the value for a specific AD type passing the raw data. The header file esp_gap_ble_api.h contains definitions for the most common AD types:


In my Github repository you can find an updated version of the scan program. Thanks to what explained above, now the program can also display – if available – the name of the device:



A particular family of broadcaster devices are the iBeacons. These devices have been designed by Apple to allow interaction with IOS devices (iPhone …) based on location awareness. Let’s make an example: an iPhone can “notice” that it is close to a particular iBeacon, associated with a room in a museum, and therefore offer the user a brief guide to the exhibited works.


iBeacon specifications are available on Apple’s developer portal. iBeacons work transmitting advertising packets with  specific payload (ADV DATA):


The first structure has AD type = flags (0x01). Each bit has a different meaning, usually iBeacons use 0x0A value for AD data.

The second structure has type = 0xFF, that is Manufacturer Specific Data. The Bluetooth standard allows the different manufacturers to use this ID to transmit custom data. The total data length is 25 bytes (0x1A – 0x01 that is the length of the AD type field).

Apple specifications further subdivide the AD data field in several elements:


The first field is the manufacturer/company; iBeacons normally use the code 0x004C, assigned to Apple Inc. The next two fields define the iBeacon type and have a fixed value (0x02 e 0x15). The UUID field, together with the Major and Minor ones (optional, they can have a value of 0) uniquely identifies each iBeacon.  (insieme con i campi Major e Minor (facoltativi, possono essere impostati a 0) identificano univocamente il singolo iBeacon. Finally, the TX power field contains a measurement, one meter away from the iBeacon, of the received power and is useful for  precisely estimate the distance between the phone and the iBeacon itself.


I developed a program for the esp32 chip which turns a relay on if it detects a specific iBeacon. Via menuconfig you can configure the UUID of the iBeacon which triggers the led, the pin the led is connected to and the timeout – in seconds – after which the program turns the led off if the iBeacon is not detected anymore. You can moreover set a power threshold to control the distance at which the iBeacon is detected.

To parse the received packet and get the UUID value, in my program I used the method described in this article (parsing using a struct).

The program verifies if the received packet (event ESP_GAP_SEARCH_INQ_RES_EVT) was sent by an iBeacon checking that the packet length is 30 bytes and that its header contains the values listed above:

// iBeacon fixed header
ibeacon_header_t ibeacon_fixed_header = {
  .flags = {0x02, 0x01, 0x06},
  .length = 0x1A,
  .type = 0xFF,
  .company_id = 0x004C,
  .beacon_type = 0x1502

It compares the fixed header with the received one using memcmp, function that compares two blocks in memory:

if(memcmp(adv_data, ibeacon_fixed_header, sizeof(ibeacon_fixed_header)))
  result = true;

The source program is available in my Github repository, here’s a video that shows how it works:

In the video I use an iBeacon from WGX. If you want more information about it, in this blog post I review this iBeacon…


  1. Stefano Bordini 22/03/2018 at 11:18 - Reply

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

    • luca 22/03/2018 at 13:05 - Reply

      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.

  2. Stefano Bordini 22/03/2018 at 23:28 - Reply

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

  3. serkan 03/04/2018 at 08:31 - Reply

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

    • luca 03/04/2018 at 08:37 - Reply

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

      • Achille 18/07/2018 at 18:52 - Reply

        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

        • luca 04/08/2018 at 13:26 - Reply

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

  4. serkan 03/04/2018 at 08:54 - Reply

    I’m waiting impatiently.

  5. serkan 03/04/2018 at 19:32 - Reply

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

    • luca 03/04/2018 at 19:45 - Reply

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

  6. Martin 10/07/2018 at 21:46 - Reply

    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

    • luca 11/07/2018 at 20:23 - Reply

      it usually takes a couple of seconds to boot the esp32

  7. Martin 10/07/2018 at 23:15 - Reply

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

    • luca 11/07/2018 at 20:22 - Reply

      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

  8. Alican 03/11/2018 at 13:55 - Reply

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

    • luca 10/11/2018 at 21:44 - Reply

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

  9. Darshan 20/08/2019 at 08:49 - Reply

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

    • luca 28/08/2019 at 14:39 - Reply

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

Leave A Response »

This website uses cookies to ensure you get the best experience on our website maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.