Support ESPHome BLE proxies via HA Bluetooth subsystem
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>
This commit is contained in:
@@ -6,6 +6,7 @@ import logging
|
||||
import struct
|
||||
|
||||
from bleak import BleakClient, BleakError
|
||||
from bleak.backends.device import BLEDevice
|
||||
|
||||
from .const import (
|
||||
FRAME_END,
|
||||
@@ -42,13 +43,17 @@ class BmsBluetoothHandler:
|
||||
def is_connected(self) -> bool:
|
||||
return self._client is not None and self._client.is_connected
|
||||
|
||||
async def connect(self) -> None:
|
||||
"""Open BLE connection and start notifications."""
|
||||
async def connect(self, ble_device: BLEDevice) -> None:
|
||||
"""Open BLE connection and start notifications.
|
||||
|
||||
Accepts a BLEDevice resolved by HA's Bluetooth subsystem so that
|
||||
ESPHome BLE proxies are used transparently alongside local adapters.
|
||||
"""
|
||||
if self.is_connected:
|
||||
return
|
||||
_LOGGER.debug("Connecting to BMS at %s", self._address)
|
||||
_LOGGER.debug("Connecting to BMS at %s (via %s)", self._address, ble_device.name)
|
||||
self._client = BleakClient(
|
||||
self._address,
|
||||
ble_device,
|
||||
disconnected_callback=self._on_disconnect,
|
||||
)
|
||||
await self._client.connect()
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from homeassistant.components.bluetooth import async_ble_device_from_address
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
@@ -35,9 +36,22 @@ class BmsCoordinator(DataUpdateCoordinator[dict]):
|
||||
# Lifecycle
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _get_ble_device(self):
|
||||
"""Resolve the best available BLE device via HA's Bluetooth subsystem.
|
||||
|
||||
This automatically uses ESPHome BLE proxies if they can reach the BMS
|
||||
and the local adapter cannot (or vice versa).
|
||||
"""
|
||||
device = async_ble_device_from_address(self.hass, self.address, connectable=True)
|
||||
if device is None:
|
||||
raise UpdateFailed(
|
||||
f"BMS ({self.address}) not reachable by any Bluetooth adapter or proxy"
|
||||
)
|
||||
return device
|
||||
|
||||
async def async_setup(self) -> None:
|
||||
"""Connect to the BMS. Called once during config entry setup."""
|
||||
await self._handler.connect()
|
||||
await self._handler.connect(self._get_ble_device())
|
||||
|
||||
async def async_teardown(self) -> None:
|
||||
"""Disconnect cleanly. Called on entry unload."""
|
||||
@@ -52,7 +66,9 @@ class BmsCoordinator(DataUpdateCoordinator[dict]):
|
||||
if not self._handler.is_connected:
|
||||
_LOGGER.debug("BMS not connected, attempting reconnect…")
|
||||
try:
|
||||
await self._handler.connect()
|
||||
await self._handler.connect(self._get_ble_device())
|
||||
except UpdateFailed:
|
||||
raise
|
||||
except Exception as exc:
|
||||
raise UpdateFailed(f"BMS reconnect failed: {exc}") from exc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user