Beakin — Provisioning Guide¶
How to assign a name, site, and planogram location to a beakin — from fresh firmware to fully provisioned.
Table of Contents¶
- What is Provisioning?
- Provisioning Lifecycle
- Status Definitions
- Data Layers and Precedence
- Adding a New Beakin
- Step 1 — Add to beacons.yaml
- Step 2 — Regenerate Tasks
- Step 3 — Flash Firmware
- Step 4 — Generate the Provisioning Seed
- Step 5 — Provision via the App
- The Provisioning Seed
- Provisioning via the App
- Set Up a New Beakin
- Reconfigure an Existing Beakin
- Retry a Pending Write
- Factory Reset a Beakin
- Device Identity Keys
- Export and Import the Registry
- Common Provisioning Scenarios
- Troubleshooting
What is Provisioning?¶
When a beakin is first flashed, it broadcasts a BLE iBeacon signal with a UUID and a pair of numbers (major and minor). That's all the device knows about itself.
Provisioning is the process of giving a beakin a human-readable identity: a name, a store site, and a planogram location (aisle, side, section, shelf). This metadata lives in two places:
- The mobile app — persisted to local storage on the phone/tablet.
- The device's onboard storage (NVS) — written over Bluetooth so the beakin's OLED display shows the correct label and location, and so it survives firmware updates without needing to be re-provisioned.
When a beakin-server is deployed on Raspberry Pi, it becomes a third (centralized) source of truth that all field operators can sync with.
Provisioning Lifecycle¶
[freshly flashed board]
│
▼
┌───────────────┐
│ unprovisioned │ ← visible in app; no name or location assigned yet
└───────┬───────┘
│ tap "Set up" in the app
▼
┌─────────────┐
│ draft │ ← form filled and saved locally; device not yet written
└──────┬──────┘
│ tap "Mark as Provisioned"
▼
┌────────────────────┐ out of range / BLE failure
│ provisioning... │ ─────────────────────────────────► ┌──────────────────────┐
└────────┬───────────┘ │ provisioned-pending │
│ GATT write confirmed │ (retry on next scan) │
▼ └───────────────────────┘
┌──────────────┐
│ provisioned │ ← app registry and device NVS are in sync
└──────────────┘
Status Definitions¶
| Status | What it means |
|---|---|
| unprovisioned | Seen on scan; no local record exists for this device |
| draft | Setup form has been filled and saved on the phone; device has not been written yet |
| provisioned-pending | Marked provisioned locally; Bluetooth write to the device is queued |
| provisioned | Both the app registry and the device's onboard storage agree on the identity |
Data Layers and Precedence¶
Provisioning data is resolved from multiple sources. Higher-numbered layers win on conflict.
| Priority | Layer | Source | Description |
|---|---|---|---|
| 1 (lowest) | runtime |
Live BLE scan | Identity only — UUID, major, minor |
| 2 | seed |
Generated from beacons.yaml |
Pre-loaded names and location data |
| 3 | server |
Pi 5 registry API | Central registry (when available) |
| 4 (highest) | local |
Operator edits on phone/tablet | Explicit field overrides always win |
In practice: the seed layer means new beakins appear in the app with their label and location already filled in, as long as beacons.yaml was synced before the app was built. Operators can then confirm or override any field.
Adding a New Beakin¶
Step 1 — Add to beacons.yaml¶
Open beakin-fw/scripts/beacons.yaml and add a new entry under devices:.
Required fields:
- serial: 98:A3:16:8F:F6:D8 # from `python3 scripts/list_mcus.py`
label: "Product Name"
env: xiao_esp32c6 # board type
site_id: "heb-373" # your store's site ID
major: 1 # next available major (check existing entries)
minor: 7 # next available minor (must be unique per site)
Common optional fields:
power_profile: balanced # performance | balanced | endurance
antenna: internal # internal | external (C6 only)
area: "01"
aisle: 12
side: "A"
section: 2
shelf: 4
location_type: 1
psa_description: "Aisle 12"
display:
type: oled
width: 128
height: 64
major and minor rules: - Must be integers between 0 and 65535. - Must be unique within your site — no two beakins should share the same major/minor pair at the same site. - They are not derived from aisle or shelf numbers. Pick the next available sequential values.
Step 2 — Regenerate Tasks¶
After saving beacons.yaml, regenerate the VS Code tasks:
A new set of per-device tasks (flash:, monitor:, dev:, identify:) will appear in the task list for the new board.
Step 3 — Flash Firmware¶
Connect the board via USB-C (data cable required). Then in VS Code:
Watch the serial log for a clean boot:
Step 4 — Generate the Provisioning Seed¶
The mobile app reads a pre-generated seed file that maps beakin identity to label and location. Regenerate it after any beacons.yaml change:
If you need to sync beacons.yaml from the firmware repo first:
After regenerating, rebuild and deploy the app to pick up the new seed data.
Step 5 — Provision via the App¶
Open the Beakin app and go to the Find screen. The new beakin will appear (it may show as M1-m7 or its label if the seed was loaded). Tap it, then tap Set up to begin the provisioning flow.
See Provisioning via the App below for full steps.
The Provisioning Seed¶
The seed is a static snapshot of beacons.yaml compiled into the mobile app. It pre-populates the provisioning registry so operators see real labels rather than raw major/minor values when they first open the app.
When to regenerate:
- After adding or renaming any device in beacons.yaml
- After changing planogram fields (aisle, side, shelf, etc.)
- After adding a new site_id
Command:
The seed data lives in config/provisioningSeed.ts and is committed to the app repo. Operators with an older app build will see the previous seed until they update.
Provisioning via the App¶
Set Up a New Beakin¶
- Open the app → Find screen.
- Locate the beakin in the list (it shows as unprovisioned or with its seed-provided label).
- Tap the beakin to open its detail screen.
- Tap Set up.
- Fill in the provisioning form:
- Name — human-readable label (e.g. "Kids Vitamins – Aisle 23B")
- Site — your deployment site ID
- Area, Aisle, Side, Section, Shelf — planogram location
- Tap Save — status becomes
draft. - While in range of the beakin, tap Mark as Provisioned.
- The app connects over Bluetooth and writes the config to the device's onboard storage.
- Status becomes provisioned when the write is confirmed. If the beakin goes out of range first, status becomes provisioned-pending and the write will retry automatically.
Tip: Stay within 3–5 meters of the beakin when tapping "Mark as Provisioned" to ensure a reliable Bluetooth write.
Reconfigure an Existing Beakin¶
- Open the app → Find screen and tap the beakin.
- Tap Reconfigure (shown as ⚙ Reconfigure for already-provisioned beakins).
- Edit any fields on the form.
- Tap Save, then Mark as Provisioned to push the update to the device.
Location updates will show on the beakin's OLED display immediately after the Bluetooth write succeeds.
Retry a Pending Write¶
If a beakin shows as provisioned-pending, the config is saved on your phone but not yet written to the device:
- The app retries automatically whenever the beakin is detected in range.
- To trigger a write immediately: tap the beakin → tap Retry write.
Factory Reset a Beakin¶
Two methods:
Via the app: 1. Open the beakin's detail screen. 2. Tap Reconfigure → scroll down → Factory Reset. 3. The device wipes its onboard storage and reboots as unprovisioned.
Via hardware button: 1. Power on the beakin. 2. Hold the BOOT/USER button for 5 seconds during normal operation. 3. The device reboots as unprovisioned.
After a factory reset, the beakin reappears as unprovisioned in the app. Your local record is preserved and can be re-written to the device.
Device Identity Keys¶
Two identity key formats are used across the system:
Provisioning key (canonical)¶
Used in the app registry and the server database:
Example:
Runtime key (gateway/MQTT)¶
Used for live sighting events from gateways:
Example:
Important rules:
- site_id is a stable string per deployment site.
- UUID must always be stored in lowercase.
- Major and minor are plain integers (no zero-padding).
- Never change a beakin's major/minor after it has been provisioned — any server-side records use this key as their identifier.
Export and Import the Registry¶
The app's local registry can be exported to JSON for backup, migration to a new device, or auditing.
Export: Settings → Provisioning → Export Registry
Saves a timestamped JSON file to your device's Documents folder. Share or copy it as needed.
Import: Settings → Provisioning → Import Registry
Loads a previously exported JSON file. Imported records merge with existing ones using the standard layer precedence — local edits always win.
Common Provisioning Scenarios¶
Replacing a failed beakin¶
The replacement board should flash firmware with the same major/minor as the failed unit. The app already has the provisioning record; you only need to re-do the GATT write to the new device:
- Flash replacement board with the same
beacons.yamlentry. - Power it on in range of your phone.
- In the app, the beakin appears as provisioned-pending (existing record, no confirmed write to new hardware).
- Tap Retry write to push the config to the replacement board.
Moving a beakin to a new location¶
- Update
beacons.yamlwith the new planogram fields. - Regenerate tasks and reflash firmware (so the OLED shows the correct location).
- In the app, tap Reconfigure → update the location fields → Mark as Provisioned.
Setting up a batch of beakins¶
For a bulk deployment, set up all entries in beacons.yaml before going to the store:
- Add all devices to
beacons.yamlwith correct serials, labels, and location data. - Flash all boards:
Tasks: Run Task → 🔌 Flash All. - Generate the provisioning seed:
npm run provisioning:seed:generate. - Build and deploy the updated app.
In the field, the app will show all expected beakins in the Find screen with seed-provided names. Walk the floor and tap Mark as Provisioned for each one to confirm the GATT write.
Adding a gateway¶
Gateways are provisioned differently from beacons — they use WiFi and MQTT credentials set at flash time, not through the app:
- Add a gateway entry to
beacons.yamlwithrole: gatewayandenv: xiao_esp32c6_gateway. - Export WiFi and MQTT credentials in your shell:
- Run the gateway flash task:
Tasks: Run Task → 📡 flash gateway: <label>. - The gateway connects to WiFi on boot and begins publishing beacon sightings over MQTT.
Troubleshooting¶
Beakin stays "provisioned-pending" after tapping "Mark as Provisioned"¶
- Move closer to the beakin (within 2–3 meters).
- Confirm BLE is on and the app has Bluetooth permission.
- Check the serial log — look for GATT write callbacks and any
ERR:responses. - If the error repeats, try a factory reset and re-provision from scratch.
Beakin shows wrong label in the app¶
The app resolves labels from multiple layers. The most likely causes:
- Wrong seed: beacons.yaml was updated but the seed was not regenerated. Run npm run provisioning:seed:generate and rebuild the app.
- Local override present: a previous operator edit on the phone/tablet overrides the seed. Tap Reconfigure and clear or correct the label field.
Two beakins show the same name¶
Major/minor values may have been accidentally duplicated in beacons.yaml. Check that every device has a unique major/minor pair within the same site_id. Run the validator:
Import fails or registry looks wrong after import¶
- Confirm the imported JSON was exported from a Beakin app — the format is not compatible with other tools.
- If the registry looks inconsistent, clear local storage (Settings → Provisioning → Clear Local Registry) and re-import.