From 95641fa780a36bc3e1b53e72c658a930c369a401 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 11 Dec 2022 17:50:18 -1000 Subject: [PATCH] Revert "Move esphome gatt services cache to be per device" #81265 (#83793) --- .../components/esphome/bluetooth/client.py | 18 +++++---- .../components/esphome/domain_data.py | 39 +++++++++++++++++++ .../components/esphome/entry_data.py | 39 +------------------ 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/homeassistant/components/esphome/bluetooth/client.py b/homeassistant/components/esphome/bluetooth/client.py index 0eb57420b3c..073c3f2ca6a 100644 --- a/homeassistant/components/esphome/bluetooth/client.py +++ b/homeassistant/components/esphome/bluetooth/client.py @@ -230,12 +230,14 @@ class ESPHomeClient(BaseBleakClient): Boolean representing connection status. """ await self._wait_for_free_connection_slot(CONNECT_FREE_SLOT_TIMEOUT) + domain_data = self.domain_data entry_data = self.entry_data - self._mtu = entry_data.get_gatt_mtu_cache(self._address_as_int) + + self._mtu = domain_data.get_gatt_mtu_cache(self._address_as_int) has_cache = bool( dangerous_use_bleak_cache and self._connection_version >= MIN_BLUETOOTH_PROXY_VERSION_HAS_CACHE - and entry_data.get_gatt_services_cache(self._address_as_int) + and domain_data.get_gatt_services_cache(self._address_as_int) and self._mtu ) connected_future: asyncio.Future[bool] = asyncio.Future() @@ -257,7 +259,7 @@ class ESPHomeClient(BaseBleakClient): self._is_connected = True if not self._mtu: self._mtu = mtu - entry_data.set_gatt_mtu_cache(self._address_as_int, mtu) + domain_data.set_gatt_mtu_cache(self._address_as_int, mtu) else: self._async_ble_device_disconnected() @@ -392,14 +394,14 @@ class ESPHomeClient(BaseBleakClient): A :py:class:`bleak.backends.service.BleakGATTServiceCollection` with this device's services tree. """ address_as_int = self._address_as_int - entry_data = self.entry_data + domain_data = self.domain_data # If the connection version >= 3, we must use the cache # because the esp has already wiped the services list to # save memory. if ( self._connection_version >= MIN_BLUETOOTH_PROXY_VERSION_HAS_CACHE or dangerous_use_bleak_cache - ) and (cached_services := entry_data.get_gatt_services_cache(address_as_int)): + ) and (cached_services := domain_data.get_gatt_services_cache(address_as_int)): _LOGGER.debug( "%s: %s - %s: Cached services hit", self._source_name, @@ -458,7 +460,7 @@ class ESPHomeClient(BaseBleakClient): self._ble_device.name, self._ble_device.address, ) - entry_data.set_gatt_services_cache(address_as_int, services) + domain_data.set_gatt_services_cache(address_as_int, services) return services def _resolve_characteristic( @@ -475,8 +477,8 @@ class ESPHomeClient(BaseBleakClient): async def clear_cache(self) -> None: """Clear the GATT cache.""" - self.entry_data.clear_gatt_services_cache(self._address_as_int) - self.entry_data.clear_gatt_mtu_cache(self._address_as_int) + self.domain_data.clear_gatt_services_cache(self._address_as_int) + self.domain_data.clear_gatt_mtu_cache(self._address_as_int) @verify_connected @api_error_as_bleak_error diff --git a/homeassistant/components/esphome/domain_data.py b/homeassistant/components/esphome/domain_data.py index 29226fdd792..93ff69852a0 100644 --- a/homeassistant/components/esphome/domain_data.py +++ b/homeassistant/components/esphome/domain_data.py @@ -1,9 +1,13 @@ """Support for esphome domain data.""" from __future__ import annotations +from collections.abc import MutableMapping from dataclasses import dataclass, field from typing import TypeVar, cast +from bleak.backends.service import BleakGATTServiceCollection +from lru import LRU # pylint: disable=no-name-in-module + from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.json import JSONEncoder @@ -13,6 +17,7 @@ from .entry_data import RuntimeEntryData STORAGE_VERSION = 1 DOMAIN = "esphome" +MAX_CACHED_SERVICES = 128 _DomainDataSelfT = TypeVar("_DomainDataSelfT", bound="DomainData") @@ -23,6 +28,40 @@ class DomainData: _entry_datas: dict[str, RuntimeEntryData] = field(default_factory=dict) _stores: dict[str, Store] = field(default_factory=dict) + _gatt_services_cache: MutableMapping[int, BleakGATTServiceCollection] = field( + default_factory=lambda: LRU(MAX_CACHED_SERVICES) # type: ignore[no-any-return] + ) + _gatt_mtu_cache: MutableMapping[int, int] = field( + default_factory=lambda: LRU(MAX_CACHED_SERVICES) # type: ignore[no-any-return] + ) + + def get_gatt_services_cache( + self, address: int + ) -> BleakGATTServiceCollection | None: + """Get the BleakGATTServiceCollection for the given address.""" + return self._gatt_services_cache.get(address) + + def set_gatt_services_cache( + self, address: int, services: BleakGATTServiceCollection + ) -> None: + """Set the BleakGATTServiceCollection for the given address.""" + self._gatt_services_cache[address] = services + + def clear_gatt_services_cache(self, address: int) -> None: + """Clear the BleakGATTServiceCollection for the given address.""" + self._gatt_services_cache.pop(address, None) + + def get_gatt_mtu_cache(self, address: int) -> int | None: + """Get the mtu cache for the given address.""" + return self._gatt_mtu_cache.get(address) + + def set_gatt_mtu_cache(self, address: int, mtu: int) -> None: + """Set the mtu cache for the given address.""" + self._gatt_mtu_cache[address] = mtu + + def clear_gatt_mtu_cache(self, address: int) -> None: + """Clear the mtu cache for the given address.""" + self._gatt_mtu_cache.pop(address, None) def get_entry_data(self, entry: ConfigEntry) -> RuntimeEntryData: """Return the runtime entry data associated with this config entry. diff --git a/homeassistant/components/esphome/entry_data.py b/homeassistant/components/esphome/entry_data.py index 2e05e01309e..07a15c17f05 100644 --- a/homeassistant/components/esphome/entry_data.py +++ b/homeassistant/components/esphome/entry_data.py @@ -2,7 +2,7 @@ from __future__ import annotations import asyncio -from collections.abc import Callable, MutableMapping +from collections.abc import Callable from dataclasses import dataclass, field import logging from typing import Any, cast @@ -30,8 +30,6 @@ from aioesphomeapi import ( UserService, ) from aioesphomeapi.model import ButtonInfo -from bleak.backends.service import BleakGATTServiceCollection -from lru import LRU # pylint: disable=no-name-in-module from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform @@ -59,7 +57,6 @@ INFO_TYPE_TO_PLATFORM: dict[type[EntityInfo], str] = { SwitchInfo: Platform.SWITCH, TextSensorInfo: Platform.SENSOR, } -MAX_CACHED_SERVICES = 128 @dataclass @@ -95,46 +92,12 @@ class RuntimeEntryData: _ble_connection_free_futures: list[asyncio.Future[int]] = field( default_factory=list ) - _gatt_services_cache: MutableMapping[int, BleakGATTServiceCollection] = field( - default_factory=lambda: LRU(MAX_CACHED_SERVICES) # type: ignore[no-any-return] - ) - _gatt_mtu_cache: MutableMapping[int, int] = field( - default_factory=lambda: LRU(MAX_CACHED_SERVICES) # type: ignore[no-any-return] - ) @property def name(self) -> str: """Return the name of the device.""" return self.device_info.name if self.device_info else self.entry_id - def get_gatt_services_cache( - self, address: int - ) -> BleakGATTServiceCollection | None: - """Get the BleakGATTServiceCollection for the given address.""" - return self._gatt_services_cache.get(address) - - def set_gatt_services_cache( - self, address: int, services: BleakGATTServiceCollection - ) -> None: - """Set the BleakGATTServiceCollection for the given address.""" - self._gatt_services_cache[address] = services - - def clear_gatt_services_cache(self, address: int) -> None: - """Clear the BleakGATTServiceCollection for the given address.""" - self._gatt_services_cache.pop(address, None) - - def get_gatt_mtu_cache(self, address: int) -> int | None: - """Get the mtu cache for the given address.""" - return self._gatt_mtu_cache.get(address) - - def set_gatt_mtu_cache(self, address: int, mtu: int) -> None: - """Set the mtu cache for the given address.""" - self._gatt_mtu_cache[address] = mtu - - def clear_gatt_mtu_cache(self, address: int) -> None: - """Clear the mtu cache for the given address.""" - self._gatt_mtu_cache.pop(address, None) - @callback def async_update_ble_connection_limits(self, free: int, limit: int) -> None: """Update the BLE connection limits."""