Browse Source

Implement service caching for faster reconnects (#69)

J. Nick Koston 1 year ago
parent
commit
4921858aca
1 changed files with 16 additions and 3 deletions
  1. 16 3
      switchbot/devices/device.py

+ 16 - 3
switchbot/devices/device.py

@@ -10,7 +10,12 @@ from uuid import UUID
 import async_timeout
 import bleak
 from bleak.backends.device import BLEDevice
-from bleak_retry_connector import BleakClient, establish_connection
+from bleak.backends.service import BleakGATTServiceCollection
+from bleak_retry_connector import (
+    BleakClientWithServiceCache,
+    ble_device_has_changed,
+    establish_connection,
+)
 
 from ..const import DEFAULT_RETRY_COUNT, DEFAULT_SCAN_TIMEOUT
 from ..discovery import GetSwitchbotDevices
@@ -61,6 +66,7 @@ class SwitchbotDevice:
             self._password_encoded = "%08x" % (
                 binascii.crc32(password.encode("ascii")) & 0xFFFFFFFF
             )
+        self._cached_services: BleakGATTServiceCollection | None = None
 
     def _commandkey(self, key: str) -> str:
         """Add password to key if set."""
@@ -98,12 +104,17 @@ class SwitchbotDevice:
 
     async def _send_command_locked(self, key: str, command: bytes) -> bytes:
         """Send command to device and read response."""
-        client: BleakClient | None = None
+        client: BleakClientWithServiceCache | None = None
         try:
             _LOGGER.debug("%s: Connnecting to switchbot", self.name)
             client = await establish_connection(
-                BleakClient, self._device, self.name, max_attempts=1
+                BleakClientWithServiceCache,
+                self._device,
+                self.name,
+                max_attempts=1,
+                cached_services=self._cached_services,
             )
+            self._cached_services = client.services
             _LOGGER.debug(
                 "%s: Connnected to switchbot: %s", self.name, client.is_connected
             )
@@ -158,6 +169,8 @@ class SwitchbotDevice:
     def update_from_advertisement(self, advertisement: SwitchBotAdvertisement) -> None:
         """Update device data from advertisement."""
         self._sb_adv_data = advertisement
+        if self._device and ble_device_has_changed(self._device, advertisement.device):
+            self._cached_services = None
         self._device = advertisement.device
 
     async def get_device_data(