An exploration of BLE_iBeacon.ino – A Bluetooth BLE iBeacon on an ESP32.
The example presented builds using Platformio with the espressif arduino-esp32 core, and leverages the NimBLE-Arduino Bluetooth library.
Project source code
; File: platformio.ini
; 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
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
Ported to Arduino ESP32 by pcbreflux
Changed and augmented by <green@bug-eyed.monster> - MIT License.
*/
// Create a BLE server that will send periodic iBeacon frames.
// 1. Create a BLE Server
// 2. Create advertising data
// 3. Start advertising.
#include <Arduino.h>
#include "NimBLEDevice.h"
#include "NimBLEBeacon.h"
// Freshly generated beacon UUID:
// https://www.uuidgenerator.net/
// or linux tool uuidgen
// msb nsb Address type:
// 0 0 private random non-resolvable
// 0 1 private random resolvable
// 1 1 random static address
// Make 2 most significant bits 1 to indicate a random static address for iBeacon.
#define BEACON_UUID "C6dd05d0-b428-4bd5-8831-4b62651e2b41" // Beacon UUID 128-Bit
// Comment-out to disable iBeacon naming.
#define NAMED_iBEACON
// Select iBeacon name to advertise.
#define iBEACON_NAME "ESP32-iBeacon"
// Choose a transmit power.
// -12dBmW - 0.0625mW
// -9dBmW - 0.125mW
// -6dBmW - 0.250mW
// -3dBmW - 0.500mW
// 0dBmW - 1.000mW
// 3dBmW - 2.000mW
// 6dBmW - 4.000mW
// 9dBmW - 8.000mW
#define iBEACON_POWER ESP_PWR_LVL_N0 // 1.000mW
// Average received transmission power in dBmW @ 1 meter.
// Measure and record RSSI at 1 meter over 10-sec then record the average.
#define MEASURED_POWER -60
// Global Advertising(er) object used to control the Advertisement.
BLEAdvertising *pAdvertising;
void setup() {
Serial.begin(115200);
Serial.printf("start %s\n", iBEACON_NAME);
// Initialise the NimBLE library, witholding any advertisable name for now.
BLEDevice::init("");
// Set transmitter power.
BLEDevice::setPower(iBEACON_POWER);
// Get a pointer to an Advertising(er) instance, for subsequent population.
pAdvertising = BLEDevice::getAdvertising();
// Create and initialise AdvertisementData object.
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
#ifdef NAMED_iBEACON
// Create and initialise ScanResponseData object.
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
// Populate ScanResponse with iBeacon's name.
oScanResponseData.setName(iBEACON_NAME);
#endif
// Set Advertisement flags to indicate capabilities and features of
// this Bluetooth device. iBeacon is a generally discoverable BLE device.
// LE Limited Discoverable Mode 0x01
// LE General Discoverable Mode 0x02
// BR/ERD Not Supported 0x04 (device only supports BLE)
// LE and BR/EDR Capable (Controller) 0x08
// LE and BR/EDR Capable (Host) 0x0F
oAdvertisementData.setFlags(0x06); // LE General Discoverable Mode 0x02 | BR/ERD Not Supported 0x04
// Assemble the manufacturer_data.
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setManufacturerId(0x4C00); // Use Apple 0x004C ID without license, as no iPhone App
oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));
oBeacon.setMajor(1);
oBeacon.setMinor(1);
oBeacon.setSignalPower((char)MEASURED_POWER); // Add the measured power value
// Add manufacturer_data to AdvertisementData.
std::string strServiceData = "";
strServiceData += (char)(26); // Length of the manufacturer_data
strServiceData += (char)0xFF; // Indicates that type is manufacturer_data
strServiceData += oBeacon.getData();
oAdvertisementData.addData(strServiceData);
// Add AdvertisementData to Advertising(er).
pAdvertising->setAdvertisementData(oAdvertisementData);
#ifdef NAMED_iBEACON
// Add ScanResponseData to Advertising(er).
pAdvertising->setScanResponseData(oScanResponseData);
#endif
// Choose an Advertising mode for the Advertising(er).
// iBeacon is a non-connectable, undirected broadcaster,
// set the appropriate PDU type in the packet header.
// BLE_GAP_CONN_MODE_NON (non-connectable; 3.C.9.3.2).
// BLE_GAP_CONN_MODE_DIR (directed-connectable; 3.C.9.3.3).
// BLE_GAP_CONN_MODE_UND (undirected-connectable; 3.C.9.3.4).
pAdvertising->setAdvertisementType(BLE_GAP_CONN_MODE_NON);
// Start advertising
pAdvertising->start();
Serial.println("Advertising started...");
}
void loop() {
}
Nordic nRF Connect mobile app screenshots
passive scan of nameless build
active scan of build with name
Prototypical reference: https://github.com/h2zero/NimBLE-Arduino/blob/master/examples/Refactored_original_examples/BLE_iBeacon/BLE_iBeacon.ino
Suggested reading: https://www.elektor.com/products/develop-your-own-bluetooth-low-energy-applications (no affiliation).