A Bluetooth BLE iBeacon observer, that scans for a list of available beacons, then for each iBeacon found, it reads and processes it’s gathered data.
The example presented builds using Platformio with the espressif arduino-esp32 core, and leverages the NimBLE-Arduino Bluetooth library.
Project source code
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps = h2zero/NimBLE-Arduino@^1.4.0
// File: main.cpp
// ESP32_NimBLE_scanner_iBeacon_decoder.
// <green@bug-eyed.monster> MIT License.
//
// An iBeacon observer.
// Scan for servers and log each unique result.
// Read each logged BLE beacon in turn, filter for
// iBeacons, then process their manufacturer_data.
// Repeat.
#include <Arduino.h>
#include "NimBLEBeacon.h"
#include "NimBLEDevice.h"
#define ENDIAN_CHANGE_U16(x) ((((x)&0xff00) >> 8) + (((x)&0xff) << 8))
void setup() {
Serial.begin(115200);
// Initialise the NimBLE library, witholding any advertisable name.
NimBLEDevice::init("");
// Create a Scan(ner):
// Get a pointer to a newly created Scan instance.
NimBLEScan *pScan = NimBLEDevice::getScan();
// Set active scanning, this will get more data from the advertiser.
// Comment-out if not interested in iBeacon name.
pScan->setActiveScan(true);
// Block whilst scanning for advertising servers, storing
// a list of all results, over a period given in seconds.
Serial.printf("Scanning for BLE advertisers\n");
NimBLEScanResults results = pScan->start(10);
Serial.printf("Found %d BLE advertisers\n", results.getCount());
// Iterate through the list of NimBLEAdvertisedDevice's stored
// in the NimBLEScanResults scan results list.
for(int i = 0; i < results.getCount(); i++) {
// Get a pointer to the iterated Device instance.
NimBLEAdvertisedDevice advertisedDevice = results.getDevice(i);
// Retrieve the BLE beacon's manufacturer_data.
std::string strManufacturerData = advertisedDevice.getManufacturerData();
// Did we find any manufacturer_data?
if (strManufacturerData != "")
{
// Look for Apple ID and iBeacon length
if (strManufacturerData.length() == 25 &&
strManufacturerData[0] == 0x4c &&
strManufacturerData[1] == 0x00 &&
strManufacturerData[2] == 0x02 &&
strManufacturerData[3] == 0x15)
{
// Leverage the NimBLEBeacon library
// to help process the iBeacon data.
NimBLEBeacon iBeacon = NimBLEBeacon();
// Load our NimBLEBeacon object with manufacturer_data.
iBeacon.setData(strManufacturerData);
// Process this found iBeacon's data
Serial.printf("Name : %s\n",
advertisedDevice.getName().c_str());
Serial.printf("Address : %s\n",
advertisedDevice.getAddress().toString().c_str());
Serial.printf("UUID : %s\n",
iBeacon.getProximityUUID().toString().c_str());
Serial.printf("Major : %d\n",
ENDIAN_CHANGE_U16(iBeacon.getMajor()));
Serial.printf("Minor : %d\n",
ENDIAN_CHANGE_U16(iBeacon.getMinor()));
Serial.printf("TX power : %d dBm\n",
iBeacon.getSignalPower());
Serial.printf("RSSI : %d dBm\n",
advertisedDevice.getRSSI());
Serial.println("-----------------------------------------------");
}
}
}
}
void loop() {
setup();
}
Serial Port Output
Output obtained when run in proximity to one BLE iBeacon device flashed with the companion Bluetooth BLE iBeacon on ESP32.
Scanning for BLE advertisers
Found 2 BLE advertisers
Name : ESP32-iBeacon
Address : 08:b6:1f:37:f3:92
UUID : c6dd05d0-b428-4bd5-8831-4b62651e2b41
Major : 1
Minor : 1
TX power : -60 dBm
RSSI : -64 dBm
-----------------------------------------------
Scanning for BLE advertisers
Suggested reading: https://www.elektor.com/products/develop-your-own-bluetooth-low-energy-applications (no affiliation).