Skip to content

Feat: add bms_cooldown_on_error option and clear raw BLE stream buffer during JK-BMS AT-command flood - #392

Open
aka-raveren wants to merge 5 commits into
fl4p:masterfrom
aka-raveren:master
Open

Feat: add bms_cooldown_on_error option and clear raw BLE stream buffer during JK-BMS AT-command flood#392
aka-raveren wants to merge 5 commits into
fl4p:masterfrom
aka-raveren:master

Conversation

@aka-raveren

@aka-raveren aka-raveren commented Jul 29, 2026

Copy link
Copy Markdown

The Problem:
Some JK BMS (Jikong) models running specific inverter-interfacing firmware versions actively broadcast non-protocol telemetry text messages starting with AT\r\n (AT-command flood) onto the shared BLE/UART bus (as referenced in issue #370).

When heavy load, solar inverter EMI, or prolonged connection sessions cause data packet fragmentation, these junk bytes accumulate exponentially inside BleakClient incoming streams. Under the original code logic, bmslib/models/jikong.py counts these bytes (discarded junk bytes) but leaves them inside self._buffer. Within a few poll cycles, this unmanaged binary noise chokes the asyncio loop queue, leading to continuous TimeoutError spikes. Worse, the Linux host Bluetooth daemon (BlueZ) eventually drops into a critical deadlock state (org.bluez.Error.InProgress / Operation already in progress), which completely freezes data fetching for all other healthy, connected BMS units (e.g., JBD).

The Solution:
This PR introduces a two-tier escalation recovery strategy controlled via options.json / config.yaml:

  1. Low-Level Junk Buffer Suppression (bmslib/models/jikong.py):
    Directly inside the if dropped: routine, we execute .clear() on self._buffer on the fly. This instantaneously vaporizes the AT\r\n text flood out of the active Python RAM before it can bottleneck the async parser. Crucially, the valid static device configuration mappings inside _resp_table (such as num_cells index mapping) are completely preserved, preventing KeyError or IndexError code crashes.

  2. First Tier: Software Isolation (bms_cooldown_on_error):
    If a sampling timeout still slips through, the main loop catches the error, forces a programmatic .close() sequence on the troubled client, and wipes the static Bleak GATT descriptors memory cache using BleakClient._gatt_cache.clear(). This isolates the faulty battery, giving its internal MCU buffer exactly one polling period of silent cooldown time to auto-reset, while allowing other adjacent healthy BMS nodes to continue reporting data to Home Assistant without a single dropped packet.

  3. Second Tier: Hardware Remediation (bt_power_cycle_on_error):
    If the software cache flush fails to bypass a severe OS-level kernel freeze, this option executes a hot power cycle of the hci0 radio controller interface utilizing hciconfig hci0 down/up hooks with proper hardware delay sleep constraints (3 seconds), safely reviving the host adapter state without restarting the daemon container.

Testing:
Tested in a real-world multi-BMS ecosystem (JK BMS + JBD BMS) running continuously for hours under volatile grid load. Programmatic cache and stream clearing successfully bypasses 3800+ junk byte/sec streams on the fly, reducing host CPU overhead and achieving unbroken long-term data collection stability in Home Assistant Core.

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.

1 participant