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.