From c2f6f3c6888652dc173afd33d0e81ea7af8c1aa2 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Sat, 1 Aug 2026 13:38:46 -0500 Subject: [PATCH 1/2] docs: add Shelly Gen2+ equivalent for iBeacon calibration probe Adds a Shelly scripting-engine equivalent to the ESPHome esp32_ble_beacon calibration probe example, for readers whose receivers are Shelly rather than ESPHome. Derives `minor` at runtime from the device's own IP (via WiFi.GetStatus) instead of hardcoding it, mirroring the ESPHome example's own static_ip-derived minor. Same UUID and major as the ESPHome example, so Shelly and ESPHome probes calibrate against each other with no special-casing needed. --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/README.md b/README.md index e5fc856..9f3e1be 100644 --- a/README.md +++ b/README.md @@ -426,6 +426,57 @@ esp32_ble_beacon: Nothing needs to be set up in Bermuda — BPS reads the probe-to-probe measurements through the `bermuda.dump_devices` service. +#### Shelly Gen2+ equivalent + +Shelly Gen2+ devices (Plus/Pro/Gen3/Gen4) don't have `esp32_ble_beacon`, but +their scripting engine can advertise the identical iBeacon. Add this as a +[Script](https://shelly-api-docs.shelly.cloud/gen2/Scripts/Overview/) on each +device (Settings → Scripts in Shelly's own web UI, or via the `Script.PutCode` +RPC for bulk provisioning), then enable it so it survives a reboot: + +```javascript +const appleCompanyId = "\x4c\x00"; // Apple's Bluetooth SIG Company Identifier +const ibeaconPrefix = "\x02\x15"; // iBeacon custom type indicator +const manufacturer_type = "\x1A\xFF"; // 0xFF manufacturer type +const measured_power = -59; // default dbM + +function create_ibeacon_advertisement_string(service_uuid_bytes, major, minor, measured_power) +{ + var majorBytes = String.fromCharCode((major >> 8) & 0xff, major & 0xff); + var minorBytes = String.fromCharCode((minor >> 8) & 0xff, minor & 0xff); + var powerByte = String.fromCharCode(measured_power & 0xff); + return manufacturer_type + appleCompanyId + ibeaconPrefix + service_uuid_bytes + majorBytes + minorBytes + powerByte; +} + +// fde3b150-2f64-43ba-aee9-867f75ee4a6f - same UUID as the ESPHome example above +const bsp_service_uuid_bytes = "\xFD\xE3\xB1\x50\x2F\x64\x43\xBA\xAE\xE9\x86\x7F\x75\xEE\x4A\x6F"; + +let this_device_minor_no = null; // resolved at runtime from this device's own IP + +function startBeaconTimer() { + Timer.set(1000, true, function() { + if (this_device_minor_no === null) { + return; // IP not resolved yet, skip this tick + } + BLE.advertiseOnce(create_ibeacon_advertisement_string(bsp_service_uuid_bytes, 1, this_device_minor_no, measured_power)); + }); +} + +function resolveMinorFromOwnIp() { + Shelly.call("WiFi.GetStatus", null, function(result, error_code, error_message) { + if (error_code !== 0 || !result || !result.sta_ip) { + Timer.set(2000, false, resolveMinorFromOwnIp); // WiFi not ready yet, retry + return; + } + let octets = result.sta_ip.split("."); + this_device_minor_no = +octets[3]; + }); +} + +resolveMinorFromOwnIp(); +startBeaconTimer(); +``` + ### Running it In the panel's **Receiver Calibration** section, select a floor and start a run From 4a8ffb392cf97bf74b4a80114fc82b643edf3b1b Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Sat, 1 Aug 2026 13:40:43 -0500 Subject: [PATCH 2/2] Tweak wording a bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f3e1be..cecbd5d 100644 --- a/README.md +++ b/README.md @@ -428,8 +428,8 @@ measurements through the `bermuda.dump_devices` service. #### Shelly Gen2+ equivalent -Shelly Gen2+ devices (Plus/Pro/Gen3/Gen4) don't have `esp32_ble_beacon`, but -their scripting engine can advertise the identical iBeacon. Add this as a +Shelly Gen2+ devices (Plus/Pro/Gen3/Gen4) can use the on-device +scripting engine to advertise the identical iBeacon. Add this as a [Script](https://shelly-api-docs.shelly.cloud/gen2/Scripts/Overview/) on each device (Settings → Scripts in Shelly's own web UI, or via the `Script.PutCode` RPC for bulk provisioning), then enable it so it survives a reboot: