Skip to content

Name the node behind each firmware row, not just the hive it sits in - #171

Merged
MacNite merged 2 commits into
mainfrom
claude/hiveinside-device-name-tooltip-vf78y3
Aug 24, 2026
Merged

Name the node behind each firmware row, not just the hive it sits in#171
MacNite merged 2 commits into
mainfrom
claude/hiveinside-device-name-tooltip-vf78y3

Conversation

@MacNite

@MacNite MacNite commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Why

Every row under Firmware → HiveInside nodes / HiveTraffic counters is headed by the hive name (shire-01). That says where a node sits and nothing about which unit it is, so a beekeeper running several identical nodes had no way to tell them apart from the dashboard — least of all when two rows both read relay failed and the question is which device to walk out to.

What changed

Each row's label carries a ? that names the node itself: the local name it advertises, and the BLE address it is paired on.

  • Named node → Advertises itself as "HiveInside-8A3F". BLE address C4:9D:ED:8A:3F:11.
  • No name → the address plus a note that HiveInside 0.5.0 onwards advertises HiveInside-XXXX, so the "why is this blank" question answers itself rather than reading as a fault.
  • Neither → no ? at all. A tooltip that opens onto nothing is worse than no tooltip.

Firmware

hives[].ble.device_name / .mac. The name is captured from the scan response alongside the identity record, on the same terms (active scan, may arrive on a report carrying no measurement) and for every beacon type — a beekeeper telling two HolyIots apart has the same problem.

HiveTraffic

Same plumbing, end to end. bee_counter_wire.h reads an optional "name" from the counter's measurement JSON → hives[].bee_counter.device_name. No counter firmware sends one yet — a document without it parses exactly as before — so until then the row falls back to hives[].bee_counter.mac, which HiveHub writes before the !present return and therefore reports even for a counter that never answered. That is precisely the "relay failed" row where the identity matters most.

The counter's paired MAC is passed to writeSnapshotToHive rather than carried on beecnt::Snapshot: it is configuration, the call site already has it, and that struct is a MAX_HIVES-sized stack array (carrying it there cost ~324 bytes of stack for something already in hand).

Server

Two schema declarations, no migration. Both fields ride in hive_readings.raw_json rather than earning a column, like the HiveTraffic image version — they change only when a node is re-paired and nothing charts them. Declared on HiveBleIn / HiveBeeCounterIn so they are typed at the boundary rather than left to extra="allow".

The ble pair sits after the !present return, unlike the counter's: a hive with no beacon heard emits no ble object at all, and creating one just to carry an address would change what the presence of that object means for every reader of hive_readings. The dashboard reads the newest reading that has the field, so a node that missed one scan window keeps its identity anyway.

Files

Area Files
Firmware — BLE ble_sensor.{h,cpp}
Firmware — HiveTraffic bee_counter_wire.h, bee_counter_client.{h,cpp}, sensors.cpp
Server schemas.py
Dashboard server/dashboard/assets/views.js, website/dashboard-demo/assets/views.js
Docs hiveinside-ble-sensor.md, hivetraffic-bee-counter.md
Tests test_bee_counter_wire.cpp

Testing

Passing locally:

  • Wire decoder — new name cases: read when present, empty when absent, truncated not overrun, unterminated refused. Plus the existing fw:2–fw:5 contract suite.
  • Firmware host tests — 111 / 35 / 41 checks, 0 failures.
  • Server suite — all standalone scripts and the pytest set (39 passed).
  • Server round trip — identity fields verified through _hive_reading_row_paramsraw_json_hive_reading_row_to_dict.
  • Dashboard — rendered in headless Chromium against fixture data with nested hives[]. Confirmed all four cases (named node, unnamed node, named counter, identity-less counter → no ?), no console errors.

Not built: the ESP32 firmware. PlatformIO's registry (*.platformio.org) is blocked by this environment's network policy, so pio run cannot fetch scons or the NimBLE / ArduinoJson deps. The changed C++ is unbuilt here — CI is the first real compile.

Not included

  • No firmware version bump — this repo bumps FIRMWARE_VERSION in separate commits.
  • The Status card's In-hive sensors list could take the same tooltip; left alone as out of scope.
  • The dashboard demo's sample data emits no nested hives[], so the relay sections do not appear there. views.js is kept in sync per dashboard-demo/README.md, but wiring up demo fixtures would be a separate change.

Companion

Needs MacNite/HiveInside#70 for HiveInside nodes to advertise a name at all. This side is useful without it — the address fallback works today — and the tooltip tells you what to relay to get a name.

🤖 Generated with Claude Code

https://claude.ai/code/session_01T9ZUAmc45AB5Mf7ETM82Uv


Generated by Claude Code

Every row under Firmware -> HiveInside nodes / HiveTraffic counters is headed by
the HIVE name ("shire-01"). That says where a node sits and nothing about which
unit it is, so a beekeeper running several identical nodes had no way to tell
them apart from the dashboard — least of all when two rows both read "relay
failed" and the question is which device to walk out to.

Each row's label now carries a "?" that names the node itself: the local name it
advertises, and the BLE address it is paired on. HiveInside 0.5.0 advertises
"HiveInside-XXXX" (the last two bytes of its address); for a node still on older
firmware the tooltip says so and offers the address, which is then the only
identifier there is. A row with neither gets no "?" rather than one that opens
onto nothing.

Firmware forwards both as nested hives[].ble.device_name / .mac. The name is
captured from the scan response alongside the identity record, on the same terms
(active scan, may arrive on a report carrying no measurement) and for every
beacon type, not only HiveInside.

HiveTraffic gets the same plumbing: bee_counter_wire.h now reads an optional
"name" from the counter's measurement JSON and forwards it as
hives[].bee_counter.device_name. No counter firmware sends one yet — a document
without it parses exactly as before — so until then the row falls back to
hives[].bee_counter.mac, which HiveHub writes before the !present return and
therefore reports even for a counter that never answered.

The counter's paired MAC is passed to writeSnapshotToHive rather than carried on
beecnt::Snapshot: it is configuration, the call site already has it, and that
struct is a MAX_HIVES-sized stack array.

Both identity fields ride in hive_readings.raw_json rather than earning a
column, like the HiveTraffic image version — they change only when a node is
re-paired and nothing charts them. Declared on HiveBleIn / HiveBeeCounterIn so
they are typed at the boundary rather than left to extra="allow".

Tests: the wire decoder gains a "name" case (read when present, empty when
absent, truncated not overrun, unterminated refused).
CI began failing on 2026-08-22 with

    UnknownPackageError: Could not find the package with
    'adafruit/Adafruit SHT4x Library @ 1.0.4' requirements

on a commit that had passed the same workflow fourteen hours earlier. Nothing in
the repo changed between those two runs: the PlatformIO registry pruned every
published version of this library except the newest, so the exact pin stopped
resolving. Developer machines kept building throughout, because ~/.platformio
already held the package and a cached install never re-queries the registry —
which is why this only ever showed up on a clean runner.

The registry now lists 1.0.5 alone (`pio pkg show`), and the upstream 1.0.4 tag
still exists, so this is a registry-side prune rather than an upstream
withdrawal.

Bumping is safe and slightly better than a straight unblock. Adafruit_SHT4x.h is
byte-identical between the two tags, so there is no API change; the only code
difference is that 1.0.5 deletes i2c_dev, temp_sensor and humidity_sensor before
reassigning them in begin(). This firmware re-runs begin() on every I2C heal
(see sht4x_recovery.h — reinit() is a required step of the recovery sequence, not
an edge case), so on 1.0.4 each heal leaked an Adafruit_I2CDevice and two
Adafruit_Sensor objects on a device expected to run for months.

The pinning rules at the top of platformio.ini gain a note on this failure mode,
including the instruction NOT to relax the pin to a caret range to dodge it — a
range that resolves differently on two machines is the exact problem this file is
arranged to prevent.
@MacNite
MacNite merged commit 445a684 into main Aug 24, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants