Skip to content

Beakin — User Guide

A practical reference for operating, monitoring, and maintaining a Beakin deployment.

← Handbook home · Provisioning Guide


Table of Contents


System Overview

A Beakin deployment consists of:

Component Role
Beakin (beacon HW) Broadcasts its identity (UUID + major + minor) over BLE from a fixed location. May include an OLED display and battery.
Gateway (gateway HW) A scanning version of the beakin board — listens for nearby beakins and forwards sightings to the server over MQTT. Requires WiFi.
Mobile app iOS/Android field tool for scanning, identifying, and provisioning beakins.
beakin-server Raspberry Pi backend — central registry, live dashboard, and MQTT event store. Optional for basic operation.

Most day-to-day tasks involve three activities: flashing firmware onto a board, provisioning its location identity via the app, and monitoring that it is advertising correctly.


The Fleet Config File

beakin-fw/scripts/beacons.yaml is the source of truth for your physical fleet. Every board that you own should have an entry here.

Reading an entry

- serial: 98:A3:16:8F:F6:D8 # board's hardware ID (MAC or USB serial)
  label: Kids Vitamins # human-readable location name
  env: xiao_esp32c6 # board type (determines firmware build)
  site_id: "heb-373" # deployment site namespace
  power_profile: performance # performance | balanced | endurance
  antenna: external # internal (default) | external (C6 only)
  major: 1 # iBeacon major value — opaque device ID
  minor: 1 # iBeacon minor value — opaque device ID
  area: "01" # planogram area code
  aisle: 23 # aisle number
  side: "B" # aisle side
  section: 3 # section within aisle/side
  shelf: 8 # shelf level
  psa_description: "Aisle 23" # display description
  display:
    type: oled
    width: 128
    height: 64 # 32 = small display, 64 = large display
  battery:
    connected: auto # auto | yes | no
    capacity_mah: 1000

Key points:

  • serial is the unique identifier for the physical board. Never change it once set.
  • major and minor are opaque integers — they identify the device, not its location. Location is tracked separately in the provisioning layer.
  • site_id must match the site namespace used in the mobile app and server.
  • After any change to this file, regenerate VS Code tasks (see Regenerating Tasks).

Supported board types (env)

Value Board
xiao_esp32c6 XIAO ESP32-C6 (default beacon board)
xiao_esp32s3 XIAO ESP32-S3
xiao_nrf52840_sense XIAO nRF52840 Sense
xiao_esp32c6_gateway XIAO ESP32-C6 configured as gateway

Hardware: Boards and Roles

Beacon boards

All three XIAO variants can act as beacons. The ESP32-C6 is the default because it offers WiFi 6, external antenna support, and the best cost-to-performance ratio for a beacon role.

Board BLE TX Power Best for
ESP32-C6 up to +9 dBm Primary beacon — good range, supports external antenna
ESP32-S3 up to +9 dBm General beacon; slightly more flash/RAM
nRF52840 Sense up to +4 dBm Battery-sensitive deployments; has onboard IMU

Gateway boards

Gateways run a different firmware role — they scan for nearby beakins and publish sighting events over MQTT. Only ESP32 boards support the gateway role (WiFi is required). Use env: xiao_esp32c6_gateway in beacons.yaml.

Gateways require WiFi credentials at flash time. Set these in your shell environment before running the gateway flash task:

export WIFI_SSID="YourNetworkName"
export WIFI_PASS="YourPassword"
export MQTT_BROKER="192.168.1.50"
export MQTT_PORT="1883"

Status LED Patterns

Every board has a status LED that shows what the firmware is doing — no serial monitor needed.

Pattern What it means
Fast blink (5 Hz) Booting — running startup checks
Medium blink (2 Hz) Initializing BLE stack
Short pulse + long pause Healthy — advertising iBeacon packets normally
Triple flash + pause Error — check serial output for details

On the nRF52840 Sense, the RGB LED adds color coding:

Color State
🔵 Blue Booting
🩵 Cyan BLE initializing
🟢 Green Advertising (healthy)
🔴 Red Error

On ESP32 boards, there is only a single amber LED, so only the blink pattern matters.

Tip: If you see the error pattern (triple flash), connect over USB and open the serial monitor to read the failure reason.


Connecting a Beakin via USB

Use a data-capable USB-C cable. Charge-only cables will not work.

To list all connected boards and their serial IDs:

cd beakin-fw
python3 scripts/list_mcus.py

Example output:

Product Name      Serial                Port
XIAO-ESP32C6      98:A3:16:8F:F6:D8    /dev/cu.usbmodem11401
XIAO-ESP32S3      84:FC:E6:78:25:58    /dev/cu.usbmodem11501

Use the Serial column value when adding new devices to beacons.yaml.

nRF52840 bootloader mode

If an nRF52840 board fails to upload normally:

  1. Double-press the RESET button quickly.
  2. The board appears as a USB mass storage drive.
  3. Then retry the flash task.

Flashing Firmware

After generating tasks (see below), open the VS Code command palette:

Tasks: Run Task

Per-device task labels follow this pattern:

  • flash: Kids Vitamins [xiao_esp32c6 / sn:98:A3...]
  • dev: Kids Vitamins [...] — flash then open serial monitor

Aggregate tasks:

  • ⚡ Build All — compile all environments
  • 🔌 Flash All — flash every device in beacons.yaml
  • 🚀 Dev All (flash then monitor) — flash all, then tail all serial logs

Regenerating Tasks

Run this after any change to beacons.yaml:

cd beakin-fw
./scripts/gen_tasks.sh

This rewrites .vscode/tasks.json with up-to-date per-device tasks that resolve USB ports dynamically.

Using the CLI directly

To build one board type:

pio run -e xiao_esp32c6

To flash manually (you need to know the port):

pio run -e xiao_esp32c6 -t upload --upload-port /dev/cu.usbmodemXXXX

Monitoring Serial Output

Serial monitor baud rate: 115200

Via VS Code task: monitor: <label>

Via CLI:

pio device monitor --port /dev/cu.usbmodemXXXX --baud 115200

What to look for at boot

A healthy boot log looks like:

[APP] Booting...
[APP] Board: XIAO ESP32-C6
[APP] Power profile: performance
[APP] UUID: f7826da6-4fa2-4e98-8024-bc5b71e0893e
[APP] Major: 1  Minor: 1
[BLE] Initializing...
[BLE] Advertising started

Log prefixes:

  • [APP] — application layer
  • [BLE] — Bluetooth stack
  • [POWER] — power profile
  • [DEMO] — demo scenario (if applicable)
  • [MQTT] — gateway MQTT events

Identifying a Beakin

Sometimes you need to confirm which physical board corresponds to which beacons.yaml entry — especially when boards are installed in the field.

Via USB (serial identify)

# Blink the LED on a specific board
python3 scripts/identify.py --serial 98:A3:16:8F:F6:D8

# Blink all connected boards sequentially
python3 scripts/identify.py --all

The target board's LED will flash rapidly for a few seconds so you can spot it.

Via the mobile app (BLE identify)

From the Find screen in the Beakin app, tap a beakin in the list, then tap ⚡ Identify. The board's LED flashes briefly to confirm which physical unit was contacted.


Using the Mobile App

The Beakin mobile app (iOS and Android) is the field tool for scanning, identifying, and provisioning beakins.

Find screen

  • Lists all beakins visible via BLE scan.
  • Shows signal strength (RSSI) per device.
  • Color-coded signal bars: 🟢 excellent / 🟡 good / 🟠 fair / 🔴 weak.
  • Provisioned beakins show their label and location. Unprovisioned ones appear as their major/minor values until provisioned.

Beacon detail screen

Tap any beakin in the list to see:

  • Signal strength and TX power
  • UUID, major, and minor
  • Provisioning status and assigned location fields
  • Identify and provision actions

Provisioning status badges

Badge Meaning
Unprovisioned No name or location assigned yet
Draft Form saved locally; not yet written to the device
Provisioned (pending) Saved locally; waiting to write to device hardware
Provisioned Device and app registry are in sync

See Provisioning Guide for full step-by-step flows.


Using the Server Dashboard

When a beakin-server instance is running on your Raspberry Pi 5, access the web dashboard at:

http://<pi-hostname>.local:8080

The dashboard shows:

  • Live gateway sighting events via MQTT
  • Beacon registry — all provisioned devices and their locations
  • Gateway health — WiFi status, beacon count, last-seen timestamps
  • Battery telemetry for devices with battery monitors enabled

The server is deployed by running the 🚀 Deploy VS Code task from the beakin-server folder, or:

cd beakin-server
python3 ansible/deploy.py deploy

Common Tasks

Add a new beakin to the fleet

  1. Plug in the new board via USB.
  2. Run python3 scripts/list_mcus.py to get the serial ID.
  3. Add an entry to beacons.yaml with the serial, label, site_id, env, major, minor, and location fields.
  4. Run ./scripts/gen_tasks.sh to regenerate tasks.
  5. Flash firmware using the new per-device task.
  6. Open the mobile app and provision the beakin from the Find screen.

Full details: Provisioning Guide → Adding a New Beakin.

Replace a failed beakin

  1. Flash the replacement board using the same beacons.yaml entry (same major/minor).
  2. The provisioning registry in the app already has the location data — the replacement board doesn't need to be re-provisioned in the app unless the GATT write to NVS failed previously.
  3. If the GATT write is needed, tap Retry write on the beakin's detail screen.

Change a beakin's location

  1. Update the planogram fields (aisle, side, section, shelf, etc.) in beacons.yaml.
  2. Re-run ./scripts/gen_tasks.sh.
  3. Reflash firmware (the planogram fields are compiled in as display/status data).
  4. In the app, tap Reconfigure on the beakin and update the location fields, then tap Mark as Provisioned.

Check battery status

Battery voltage is logged on the serial monitor and (if MQTT is configured) sent to the server. For a quick field check, connect over USB and open the monitor — battery voltage is logged periodically at the configured log_interval_ms.


Troubleshooting

Board not found in list_mcus.py

  • Try a different USB-C cable (must be data-capable).
  • Check that the board appears in System Information → USB.
  • On nRF52840: double-press RESET to enter bootloader mode.

Upload fails ("port not found")

Port detection uses the serial ID. If the port changes after a reflash, the script will re-resolve it automatically on next run. If it still fails:

  1. Confirm the board is connected: ls /dev/cu.usbmodem*
  2. Check beacons.yaml has the correct serial.

Beakin not visible in app

  • Confirm the UUID in config/beakin.config.ts in the app matches the UUID compiled into firmware (include/config.hBEACON_UUID).
  • Confirm BLE is enabled on the phone/tablet.
  • Check the serial log — look for [BLE] Advertising started.

Serial log shows [BLE] Error

BLE init failures are usually caused by:

  • BLE stack already initialized (reflash the firmware).
  • Insufficient NVS space (rare; contact the engineering team).

nRF52840 upload hangs or fails

DFU uploads are serialized. If a previous task was force-killed, stale lock files may remain:

rm -rf .pio/nrf_build.lock .pio/nrf_upload.lock

Then retry the flash task.