Let a HiveTraffic counter's three emitter banks be switched individually - #170
Conversation
The counter's 48 IR emitters sit behind three MOSFETs, one per group of eight gates, and they dominate its power draw by an order of magnitude. Measured on the counter's 3.3 V rail, one bank draws ~0.14 A, two ~0.22 A and three ~0.30 A — roughly 80 mA per bank on top of a ~60 mA floor. For an entrance narrower than 24 gates, part of one closed for the season, or an off-grid supply that will not carry the whole board, switching a bank off is the coarsest and most effective control available, and unlike night mode it applies around the clock. The two compose: a counter can be running one bank and be suspended. Dashboard → HiveTraffic setup → Emitter banks: three checkboxes, all ticked by default, alongside the night window and with the measured current per configuration spelled out — the point of the setting is the power, so the numbers belong next to the boxes rather than in a doc. Stored per device as three booleans (migration 026, all defaulting to true) and assembled by the firmware into the bitmask HiveTraffic's SET_BANKS opcode takes. Three columns rather than one integer because the dashboard draws three checkboxes and "banks = 5" is a worse thing to find in a config dump than "bank2 = false". All three off is rejected — in the dashboard, and in update_device_config with a 400. The counter refuses a mask of zero outright (it keeps the mask it had), so storing one would only leave three unticked boxes next to a counter cheerfully counting all 24 gates with nothing saying why. The check needs the stored row as well as the patch, because a PATCH carries only what changed and "turn bank 3 off" is fine on its own and fatal if 1 and 2 are already off; that merge is what test_bee_counter_banks.py pins. There is deliberately no database CHECK: a constraint could not see "turn the last one off and another one on" as a single edit. The mask is written on the connection the measurement read already has, and only when the mask the counter just REPORTED differs from the configured one — never against a HiveHub-side memory of what it last sent. The counter does not persist the mask, so one that browned out or rebooted out of an OTA comes back running all 24 gates and the next cycle's read finds and fixes it; a HiveHub that remembered "already configured" would leave it wide open indefinitely. bee_counter_wire.h learns wire revision 5's "banks" field, defaulting to all three on rather than to zero — a counter too old to report it is running its whole entrance, and reading that absence as "everything is off" would write the misreading into stored history. Bits above the third bank are masked off. Backend to 0.3.2, firmware to 0.24.19. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TCTPLvKrrm1RmiaVHGxz4D
|
Heads up on the red Both environments die during dependency install, before a single source file is compiled: The PlatformIO registry has stopped resolving that package. Evidence it's upstream and not the diff:
Every other check on this PR is green: I'm deliberately not "fixing" this by loosening the pin. Worth knowing separately: I'm watching and will re-run the failed jobs once the registry is back. If it stays broken and the build needs unblocking sooner, the standard escape hatch is repinning that one library to an immutable git SHA — but that belongs in its own change, not folded in here. Generated by Claude Code |
The HiveHub half of MacNite/HiveTraffic#15 — the dashboard controls, the config column, and the BLE write.
A counter's 48 IR emitters sit behind three MOSFETs, one per group of eight gates, and they dominate its power draw by an order of magnitude. Measured on the counter's 3.3 V rail:
Roughly 80 mA per bank on top of a ~60 mA floor. For an entrance narrower than 24 gates, part of one closed for the season, or an off-grid supply that will not carry the whole board, this is the coarsest and most effective control available — and unlike night mode it applies around the clock. The two compose: a counter can be running one bank and be suspended.
Setup
Dashboard → HiveTraffic setup → Emitter banks: three checkboxes, all ticked by default, sitting alongside the night window. The measured current per configuration is shown next to the boxes rather than buried in a doc — the whole point of the setting is the power, and there is no way to guess the numbers from the UI otherwise. The panel also says what a switched-off bank does to the data: those crossings are not missing, they are not happening, so the totals step down and a narrowed counter should not be compared against its own history.
Mirrored into the demo dashboard so it does not go stale.
Storage
Migration 026 adds three booleans, all defaulting to
true, per device (like the night window — every counter on one hub shares an apiary). Three columns rather than one bitmask integer: the dashboard draws three checkboxes, the API is read by humans, andbanks = 5is a worse thing to find in a config dump thanbank2 = false. The firmware assembles the mask.All three off is rejected — in the dashboard, and in
update_device_configwith a400. The counter refuses a mask of zero outright (it keeps the mask it had), so storing one would only leave three unticked boxes next to a counter cheerfully counting all 24 gates, with nothing anywhere saying why. A counter that should count nothing is unpaired instead.The check needs the stored row as well as the patch: a PATCH carries only what changed, and "turn bank 3 off" is perfectly fine on its own and fatal if 1 and 2 are already off. There is deliberately no database CHECK constraint — it could not see "turn the last one off and another one on" as a single edit, and would fail a legitimate swap.
The write
The mask goes out on the connection the measurement read already has — no extra scan, no extra connect — and only when the mask the counter just reported differs from the configured one. Never against a HiveHub-side memory of what it last sent: the counter deliberately does not persist the mask, so one that browned out, watchdogged or rebooted out of an OTA comes back running all 24 gates, and the next cycle's read finds the disagreement and fixes it. A HiveHub that remembered "I already configured this one" would leave that counter wide open indefinitely; one that wrote unconditionally would spend a GATT write every ten minutes to change nothing.
Gated on the counter reporting wire revision 5. An older firmware has the control characteristic but not the opcode, and would log an "unknown opcode" line every cycle for the rest of its deployment.
The mask is persisted in NVS alongside the night window, so a hub that boots without WiFi still narrows its counters instead of running all 24 gates while it waits for a config it cannot fetch.
Wire revision 5
bee_counter_wire.hlearns"banks", defaulting to all three on rather than to zero. A counter too old to report it is running its whole entrance — it has no way not to — and reading that absence as "everything is off" would write the misreading into stored history for every counter the OTA relay has not reached yet. Bits above the third bank are masked off; a0is stored as read, because it is not a state the counter can be in and flattening it would hide a real problem.The value reaches storage as
hives[].bee_counter.banks(viaextra="allow"intoraw_json), emitted on every reading including the7of a counter nobody has narrowed — same argument asidle_s: a bank switched off produces the same permanently flat share of the totals a dead FET does, and this is the only thing separating them.Testing
test-data/test_bee_counter_banks.py, wired into CI: the patch/stored-row merge, the last-bank refusal, that turning off an already-off bank is a no-op, the legitimate swap, and that an unrelated patch skips the check entirely. Passes under bothpython3 …and pytest.test-data/test_bee_counter_wire.cppgains a v5 document, a narrowed (one-bank) document, the pre-v5 default, phantom-bit masking, and the shared constants.node --check.Backend to 0.3.2, firmware to 0.24.19. Requires HiveTraffic 0.3.0 on the counter; older counters keep all three banks on.
🤖 Generated with Claude Code
https://claude.ai/code/session_01TCTPLvKrrm1RmiaVHGxz4D
Generated by Claude Code