You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

6.1 KiB

FindMy / OpenHaystack Beacon

This document describes the experimental FindMy locator beacon for nRF52 MeshCore nodes.

Purpose

When enabled, a node advertises an Apple FindMy / OpenHaystack "offline finding" beacon alongside its normal mesh duties. Nearby iPhones anonymously relay its encrypted location to Apple's servers, letting you locate a deployed node through the global Find My network — no extra infrastructure, GPS, or cellular needed.

This is particularly useful for repeater nodes. To maximise coverage they are often deployed in exposed, unattended, hard-to-reach spots — rooftops, towers, hilltops, remote solar sites — which makes them especially prone to going missing, whether through theft, weather, a failed mount, or simply being forgotten. A FindMy beacon gives you a way to locate (or recover) such a node, or at least get a last-known position, without having to physically visit the site.

The node only ever broadcasts a public advertising key. Decrypting the location reports requires the matching private key, which you keep off-device on your own machine.

Supported hardware

nRF52840 boards only (Adafruit Bluefruit BLE stack), but the implementation is easily ported to ESP32 and other BLE capable chips. The challenge is with concurrent BLE usage, ie. companion nodes. TODO/Future work check if ble adverisements can be sent when the companion is disconnected from the phone, and disable when reconnected.

Pre-defined build environments:

Environment Board
RAK_4631_repeater_findmy RAK4631 / RAK WisMesh (repeater, incl. Solar Repeater Mini)
LilyGo_T-Echo_repeater_findmy LilyGo T-Echo

The feature is gated behind the WITH_FINDMY_BEACON build flag, so it adds nothing to other builds. It is intended for always-on roles (repeater/sensor) where BLE is otherwise unused. It is not for the phone-companion firmware, which needs BLE for its own link — a node can be a FindMy beacon or a phone companion, not both at once.

Generating keys

Keys are generated off-device with the OpenHaystack / macless-haystack tooling — see macless-haystack (or the original OpenHaystack). Its generate_keys.py produces three values per key; use them as follows:

Value Where it goes Purpose
Advertisement key (public, 28 bytes) the node (set findmy.key) broadcast in the BLE advert + MAC
Private key your server only decrypts the location reports
Hashed adv key your server (lookup id) used to query Apple for reports

Only the advertisement (public) key goes on the node. Never load the private key onto the device — it would be broadcast publicly and reports would not decrypt. (Note: the private key is also 28 bytes, so the firmware cannot tell them apart by length — pick the value labelled advertisement.)

Node configuration

Configure over the local USB serial console (115200 baud) or remotely from the MeshCore app's Command Line tab when logged in as admin. Configuration is stored in /findmy on the node's internal filesystem (independent of the normal node preferences).

set findmy.key <base64-advertisement-key>   ->  OK - reboot to apply
set findmy on                                ->  OK - on, reboot to apply
get findmy                                   ->  > on, mac DF:41:B5:D7:F3:BF
reboot
  • set findmy.key must decode to exactly 28 bytes, otherwise it reports Error: decoded N bytes, expected 28.
  • get findmy shows the enabled state and the derived BLE MAC (it never echoes the key). The MAC is key[0]|0xC0 : key[1] : key[2] : key[3] : key[4] : key[5].
  • The beacon starts only at boot, so reboot (or a power cycle) is required to apply changes. On boot the node prints FindMy beacon started.
  • set findmy off then reboot stops advertising (the stored key is kept).

Verifying

  1. On air: scan with a BLE tool (e.g. nRF Connect). You should see a non-connectable advertiser at the address get findmy reported (address type Random) carrying Apple manufacturer data beginning 4C 00 12 19 ….
  2. Key sanity: run heystack's tools/showmac.py on the advertisement key you loaded — it must print the same MAC as get findmy. A mismatch means the wrong key was loaded.

Retrieving location data

Use your own server with the private key — the node cannot retrieve anything itself. With macless-haystack, query and decrypt reports using its scripts, e.g. fetch_reports.py (a findmy.py-style query), which authenticates to Apple (via Anisette), pulls the encrypted reports for the hashed adv key, and decrypts them with the private key. See the macless-haystack README for setup (Anisette/Apple-ID requirements) and exact invocation.

Notes and caveats

  • Latency: Find My is deliberately latency-tolerant. Reports appear only after the node is near a passing iPhone and can take minutes to a few hours.
  • Power: continuous BLE advertising keeps the SoftDevice awake, so idle current is higher than a node with BLE off. The advertising interval defaults to ~2 s; override with -D FINDMY_ADV_INTERVAL=<0.625ms-units>.
  • Privacy: the key is static (no rotation), so anyone holding it can track the node.
  • Static key may be rate-limited / blocked (TODO): genuine AirTags rotate their advertising key roughly daily, and Apple's network is tuned for that. A single never-changing key can be treated as anomalous and may have its reports throttled or dropped over time, so long-term reliability is not guaranteed. Future work: add key rotation — store a sequence of keys and advance the index on a daily schedule (matching AirTag behaviour), and extend the key generator to emit a batch of keys with daily-incrementing indices that the server side can resolve.
  • OTA: the beacon coexists with start ota — triggering a firmware update reuses the running BLE stack and switches to the DFU advertiser automatically.