- status_text: decode the 24-bit "status" field into human-readable flag
names (e.g. "Cell Temp Low, Low Voltage") instead of raw hex, using the
bit table pulled from com.lithionics.bms's array/advanced resource (dumped
with aapt -- the app's own StatusCodeTable class references stale/wrong
resource IDs and can't be trusted for this). Applied to "status" only;
last_fault_code is a lifetime latch that accumulates many bits over time
and isn't meaningfully summarized the same way.
- Fixed the info sensors (total_consumed, firmware_version, serial_number,
etc.) showing "Unavailable" in HA a minute after connecting: they were
getting the same expire_after as the periodic telemetry sensors, but the
$info line the come from is only sent once per BLE connection, so HA's
expire timer always fired. These are retained-topic diagnostics meant to
hold their last value indefinitely; expire_after now only applies to the
periodic SENSORS group.
- STUCK_DISCOVERY_THRESHOLD 3 -> 1: restart bluetooth.service after the
first failed scan instead of waiting for three, cutting reconnect time
roughly in third. Still rate-limited via BLUETOOTH_RESTART_COOLDOWN_S.
Also removed the per-line "RAW ..." debug print (was flooding the journal).
All three changes verified live on host wan via journalctl/mosquitto_sub.
Decoded the "&" and "$" line formats from log1 by matching them against the
decompiled com.lithionics.bms app: TraceFormat/InfoFormat gate on the raw
line's first byte ('&'=trace, '$'=info) before BmsSeries.create() ever sees
the row, which is why the earlier decode (MainBmsCsParameters) never touched
them.
"&" trace lines stream continuously (enabled by our own $traceon) and carry
CAN-charger-bus fields: remaining_capacity, remaining_time, can_charger_
voltage/current, can_charger_status, can_status. These merge into the
existing periodic state message alongside the Cs telemetry.
"$" info is sent once per connection (response to $info) and never repeats:
total_consumed, last_fault_code, highest/lowest_recorded_temp, firmware_
version, aging_factor_temp/soc, serial_number. Published to its own retained
topic (van/<device_id>/info) instead of the periodic one, with its own
discovery config (entity_category: diagnostic) — so HA keeps the last known
value across BMS disconnects rather than expiring it.
Deployed and verified live on host wan: info message publishes once on
connect, state messages carry the merged fields, and 14 new HA entities
registered with correct precision.
Publishes the RV's 12V LiFePO4 house battery to HA via MQTT discovery
(pack voltage, 4 cell voltages, current, SOC, BMS/battery temp, status).
Connects over the battery's BLE HM-10 UART module (service ffe0/char
ffe1, no pairing) using bleak; protocol reverse-engineered from the
com.lithionics.bms Android app's own BLE/parsing code.
Deliberately named li3/ and van-li3-battery, not battery/van-battery —
that name is reserved for the host's own AC/UPS power-supply monitor
(different hardware, unrelated concern).
Self-heals a bluetoothd discovery-state wedge (Discovering stuck "yes",
connects failing with le-connection-abort-by-local) that shows up after
repeated failed connects to this device on the Pi's onboard adapter: the
daemon retries scan/connect internally (MQTT session and HA entities
stay up across retries) and restarts bluetooth.service itself after 3
consecutive scan failures, rate-limited to once per 5 min.