HiveInside is a stand-alone, battery-powered in-hive sensor on a board the size of a thumbnail. It measures comb vibration, hive acoustics, temperature and humidity, reduces each to FFT bands on the device, and broadcasts the result as a BLE beacon — no cables into the hive, no pairing window, no wake-sync schedule.
Because the one measurement that predicts swarming can't be taken from outside the hive.
Per the literature (Ramsey et al. 2020, Sci. Rep.), the frame-mounted accelerometer is the only reliable way to predict swarming up to ~30 days ahead. The critical signature sits around 20 Hz — a vibration in the comb that a microphone simply cannot capture.
A wired in-hive accelerometer means a cable through the wall of every box, and a connector that propolis and moisture will eventually find. HiveInside puts the accelerometer, mic and climate sensor on one small wireless board that just sits inside.
It runs from a small LiPo, switches its sensor rail off between measurements, and takes firmware updates over the air — so a node can be closed into an enclosure and left there.
Everything below is implemented in the firmware today. What is still open is field validation on production hardware — see the status note at the bottom.
The complete measurement — climate, vibration and acoustic FFT bands, battery — rides in a single 29-byte manufacturer-data advertisement, repeated every second. Reading it needs no connection, no pairing, no wake-sync. Any number of receivers can listen at once, and it costs the sensor nothing extra.
~1024 samples at ~400 Hz from the on-board 6-axis IMU, gravity removed, reduced to the swarm / fanning / activity bands — including the ~20 Hz pre-swarm signature.
The on-board PDM microphone is reduced to five bands from sub-bass to 3 kHz, covering hum, piping and stress — plus RMS and peak level in dBFS.
An external SHT40 gives temperature and humidity at 0.1 °C / 0.1 %RH resolution; the on-board nPM1300 fuel gauge reports battery voltage and state of charge with every measurement.
Between measurements the nRF54 idles with only the ~1 s advertiser running. The IMU + microphone rail is switched off for about 98.9 % of each five-minute cycle, and a dedicated low-power build profile drops the console UART and the status LED for deployment.
MCUboot dual-slot updates: a small GATT service streams the signed image into the secondary slot, verifies size and CRC-32, then test-swaps with automatic rollback. A dropped or corrupted transfer always leaves the node on its old image.
A sealed node has no console and nobody watching it. wdt31 is armed with a 60 s timeout and fed from the main loop, so a driver that wedges — a stuck I²C transfer, a PDM read that never returns — resets the node instead of quietly re-advertising a stale measurement forever.
The FFT bands are exactly the ones HiveHub and HiveScale use, so a value means the same thing wherever it is read — and a HiveInside reading can be compared to a wired sensor's directly.
The accelerometer probe identifies the chip by WHO_AM_I, so an external LIS3DH / LIS2DH12 breakout at 0x18/0x19 runs the same pipeline as the on-board IMU — a bench setup behaves like the real thing.
Each sensor group carries its own validity flag. A missing or failed sensor prints n/a and clears its flag rather than sending zeroes, so the backend never mistakes a dead sensor for a real reading.
Surface the data through HiveHub, or decode the advertisement locally with an ESPHome esp32_ble_tracker or a Bluetooth proxy — the frame layout is fully documented.
One toolchain for everything: west --sysbuild builds MCUboot and the signed application together, and a checked-in west.yml pins the Zephyr revision so the workspace is reproducible. CI builds both profiles on every push.
One module, one external sensor, one battery. The Seeed XIAO nRF54LM20A Sense folds the IMU, microphone, power management, charging and USB-C onto the board itself, so the whole node is a module, an SHT40 on four wires, and a LiPo.
| Function | Part | Interface | Where |
|---|---|---|---|
| 3-axis vibration (swarm prediction, ~20 Hz) | LSM6DS3TR-C 6-axis IMU | I²C 0x6A | on-board |
| Acoustics (hum, piping, stress) | MSM261DGT006 PDM microphone | PDM | on-board |
| Temperature + humidity | SHT40 | I²C 0x44 | external |
| Battery voltage + state of charge | nPM1300 PMIC fuel gauge | — | on-board |
| Charging + USB-C | nPM1300 PMIC | USB-C | on-board |
| Flashing + serial console | SAMD11 CMSIS-DAP debugger | USB-C | on-board |
Four wires to the XIAO's I²C header: VIN → 3V3, GND → GND, SDA → D4, SCL → D5. That is the entire external wiring. The on-board IMU sits on the internal i2c30 bus and needs nothing.
A single-cell 500 mAh LiPo on the XIAO's battery connector. The nPM1300 handles charging over USB-C and reports the fuel gauge with every measurement.
A 3D-printable enclosure sized for the XIAO Sense, the SHT40 and the 500 mAh cell lives in enclosure/.
The board's 2 MiB RRAM is partitioned for MCUboot: a 64 KiB bootloader plus two matching 449 KiB application slots, which is what makes the dual-slot OTA with rollback possible.
The on-board SAMD11 debugger means no external probe: west flash and the 115200 8N1 serial console both ride the same USB-C cable.
No Sense module to hand? Wire an external LIS3DH / LIS2DH12 to the same D4/D5 pads — the firmware detects it and runs the identical vibration pipeline.
Full connection reference in docs/wiring.md.
Every five minutes (by default) the node reads all four sensors, runs the FFTs on-device, and updates one advertisement. The Bluetooth controller then repeats that advertisement every second while the CPU sleeps — so a receiver's scan never has to be synchronised with anything.
Plus acceleration RMS and peak.
Plus microphone RMS and peak.
Manufacturer-specific data, company ID 0x02E5, magic 0x48
('H'), format version 2. All multi-byte fields are little-endian and
offsets include the two company-ID bytes. Each group is only meaningful when its validity
bit is set — a failed sensor clears the bit rather than sending zeroes.
| Offset | Field | Encoding | Valid when |
|---|---|---|---|
0..1 | Company ID | 0x02E5 | always |
2 | Magic | 0x48 (H) | always |
3 | Format version | 2 | always |
4 | Validity flags | bit 0 climate, 1 accel, 2 mic, 3 battery | always |
5..6 | Temperature | int16, 0.1 °C/LSB | climate |
7..8 | Humidity | uint16, 0.1 %RH/LSB | climate |
9..10 | Battery voltage | uint16, 1 mV/LSB | battery |
11 | Battery charge | uint8, % (0–100) | battery |
12..13 | Acceleration RMS | uint16, 0.1 mg/LSB | accel |
14..19 | Vibration bands — swarm, fanning, activity | 3× uint16, 0.1 mg/LSB | accel |
20 | Microphone RMS | int8, 1 dBFS/LSB | mic |
21..25 | Acoustic bands — sub-bass, hum, piping, stress, high | 5× int8, 1 dBFS/LSB | mic |
26..27 | Acceleration peak (v2) | uint16, 0.1 mg/LSB | accel |
28 | Microphone peak (v2) | int8, 1 dBFS/LSB | mic |
Version 2 keeps every version-1 field at the same
offset, so an older decoder that only understands the 26-byte prefix safely ignores the two
trailing peaks and keeps working. An active scan additionally receives a compact identity
record (board ID and firmware version) and the device name HiveInside in the
scan response — the measurement advertisement itself is unchanged.
---- HiveInside readout ---- climate : 24.31 C 47.8 %RH accel : x=-3.2 y=1.8 z=1004.6 mg |a|=1004.6 mg accel AC: rms=2.4 peak=9.1 mg (1024@416Hz) vib FFT : swarm=0.42 fan=0.18 act=0.09 mg sound : rms=-61.4 dBFS peak=-42.1 dBFS (8000 frames) ac FFT : sub=-58.2 hum=-49.7 pipe=-63.1 stress=-71.4 hi=-88.0 dBFS battery : 4.011 V ~78% ---------------------------- [BLE] measurement advertised (flags=0x0f)
The firmware is a Zephyr application built with west and sysbuild — the only supported build path. Everything below runs over the single USB-C cable; no external debug probe is needed.
The manifest pins the Zephyr revision the firmware is built against, so the workspace is reproducible.
west init -m https://github.com/MacNite/HiveInside hiveinside-workspace cd hiveinside-workspace && west update
--sysbuild is not optional: the firmware boots through MCUboot, so a bootable
device needs the bootloader and the signed application — and only a sysbuild
build produces both (plus the OTA payload).
west build --sysbuild -b xiao_nrf54lm20a/nrf54lm20a/cpuapp \ -d debug hiveinside/firmware-nrf54lm20a
--sysbuild. With MCUboot
enabled the application links at the slot-0 offset, so flashing it alone leaves nothing at
0x0: the device goes silent — no serial, no BLE.west flash programs MCUboot and the signed app through the on-board debugger.
The console runs at 115200 8N1 on the same cable.
west flash -d debug picocom -b 115200 /dev/ttyACM0 # Linux picocom -b 115200 /dev/cu.usbmodemXXXX # macOS
Prefer an IDE? The nRF Connect extension for VS Code / VSCodium is documented in docs/vscode-build.md.
The default build keeps the UART console, floating-point printk() and the
measurement LED for bring-up. For a sealed, battery-powered node, layer the low-power
profile on top — it drops all three and stops the sensor island being held powered from reset.
west build --sysbuild -b xiao_nrf54lm20a/nrf54lm20a/cpuapp \ -d lowpower hiveinside/firmware-nrf54lm20a -- \ -DEXTRA_CONF_FILE=low-power.conf \ -DEXTRA_DTC_OVERLAY_FILE=low-power.overlay
BLE advertising and OTA are unchanged by the profile. See docs/low-power.md for the full audit and the measurement method.
Print the enclosure, seal the node in with the SHT40 and battery, and pair it from HiveHub by its identity address as HiveInside (nRF54LM20A) — beacon. From then on updates go over the air.
Each build writes a version-stamped copy of the signed image, e.g.
hiveinside-nrf54lm20a-v0.4.5-lowpower.signed.bin — upload that file
rather than zephyr.signed.bin, so a console-enabled bring-up image can never be
mistaken for a deployment one. The HiveHub dashboard reads the target and version straight
out of the filename.
HiveInside is a sensor, not a system — it has no Wi-Fi and talks to nobody directly. A HiveHub collector is what turns its broadcasts into stored, charted history.
HiveHub is the ESP32 data collector for up to 16 hives: weight, temperature, humidity, sound, vibration and power state, sent to your own self-hosted FastAPI + PostgreSQL backend with a built-in dashboard. It already runs a shared passive BLE scan, so picking up a HiveInside node costs it nothing extra — pair it and the readings appear alongside the rest of the hive.
Open the HiveHub site →Weight and external sensing — the other half of the ecosystem, and the relay that streams an OTA image down to HiveInside over BLE.
Entrance traffic counting: bees in and out, bridged into the same backend.
Take the data from HiveHub, or decode the advertisement locally with ESPHome or a Bluetooth proxy.
The readout format, the full BLE frame layout, the watchdog, and the roadmap.
Flashing details, the external-probe alternative, and what to do when a device is silent.
The code-and-hardware audit, the deployment build profile, and how to measure the result properly.
The streaming relay, the partition layout, and the release artifact naming.
The nRF Connect extension setup with the debug and lowpower configurations.