The BMS only allows one simultaneous BLE connection. Keeping a persistent
connection blocked the mobile app from connecting at all.
Changes:
- BmsBluetoothHandler: replace connect()/disconnect()/request() public API
with a single poll() method that owns the full connect→read→disconnect
lifecycle. Connection is held only for the duration of one data fetch.
- Coordinator: gutted connection-state management — _async_update_data now
just calls handler.poll() and processes results. No reconnect loop needed.
- Poll interval defaults: 15s default, 10s min, 300s max. The BLE connect
overhead (~2s) makes sub-10s intervals impractical.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously a failed connect() / start_notify() left self._client pointing
at a broken BleakClient. On the next poll is_connected returned False but
the stale object caused confusing errors. Now the client is only assigned
after both steps succeed; on any exception we try a clean disconnect and
reset to None so the next attempt starts completely fresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Retries (bluetooth_handler):
- request() now retries up to 3× with 0.5s pause between attempts
- Tries Write With Response first, falls back to Write Without Response
automatically if the characteristic rejects it — handles both BMS variants
Number entity (number.py):
- "Nominal Capacity (Override)" lets user correct a stale BMS capacity value
(e.g. after a cell upgrade) without PC software
- Value is restored across HA restarts via RestoreEntity
- Immediately patches coordinator.data so the sensor reflects it without
waiting for the next poll
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HA expects translations at custom_components/<domain>/translations/en.json
not at the repo root.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use write_gatt_char with response=True (Write With Response) — many BMS
firmwares ignore Write Without Response packets
- Add 0.5s delay after start_notify before sending first command to avoid
race where BMS hasn't registered the notification subscription yet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Don't connect eagerly in async_setup — let the first coordinator poll
handle it. If the BMS is out of range at startup, UpdateFailed becomes
ConfigEntryNotReady and HA retries automatically instead of crashing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use async_ble_device_from_address() to resolve the BMS through whichever
adapter (local or ESPHome proxy) can reach it, instead of connecting by
raw MAC address directly. BleakClient now receives a BLEDevice object.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>