From ee89922c1b8c86786e8d0fe0993b63975586b82c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 6 Mar 2023 14:24:35 -1000 Subject: [PATCH] Add support for bluetooth pairing in esphome (#88603) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/esphome/bluetooth/client.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/esphome/bluetooth/client.py b/homeassistant/components/esphome/bluetooth/client.py index 545a436ee8b..6ec51cabeb2 100644 --- a/homeassistant/components/esphome/bluetooth/client.py +++ b/homeassistant/components/esphome/bluetooth/client.py @@ -43,6 +43,7 @@ CCCD_NOTIFY_BYTES = b"\x01\x00" CCCD_INDICATE_BYTES = b"\x02\x00" MIN_BLUETOOTH_PROXY_VERSION_HAS_CACHE = 3 +MIN_BLUETOOTH_PROXY_HAS_PAIRING = 4 DEFAULT_MAX_WRITE_WITHOUT_RESPONSE = DEFAULT_MTU - GATT_HEADER_SIZE _LOGGER = logging.getLogger(__name__) @@ -386,13 +387,33 @@ class ESPHomeClient(BaseBleakClient): @api_error_as_bleak_error async def pair(self, *args: Any, **kwargs: Any) -> bool: """Attempt to pair.""" - raise NotImplementedError("Pairing is not available in ESPHome.") + if self._connection_version < MIN_BLUETOOTH_PROXY_HAS_PAIRING: + raise NotImplementedError( + "Pairing is not available in ESPHome with version {self._connection_version}." + ) + response = await self._client.bluetooth_device_pair(self._address_as_int) + if response.paired: + return True + _LOGGER.error( + "Pairing with %s failed due to error: %s", self.address, response.error + ) + return False @verify_connected @api_error_as_bleak_error async def unpair(self) -> bool: """Attempt to unpair.""" - raise NotImplementedError("Pairing is not available in ESPHome.") + if self._connection_version < MIN_BLUETOOTH_PROXY_HAS_PAIRING: + raise NotImplementedError( + "Unpairing is not available in ESPHome with version {self._connection_version}." + ) + response = await self._client.bluetooth_device_unpair(self._address_as_int) + if response.success: + return True + _LOGGER.error( + "Unpairing with %s failed due to error: %s", self.address, response.error + ) + return False @api_error_as_bleak_error async def get_services(