Await startup in homekit controller (#75021)

This commit is contained in:
J. Nick Koston 2022-07-14 14:44:27 +02:00 committed by GitHub
parent a3c1926da5
commit a31dde9cb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 30 deletions

View file

@ -7,6 +7,7 @@ import datetime
import logging
from typing import Any
from aiohomekit import Controller
from aiohomekit.exceptions import (
AccessoryDisconnectedError,
AccessoryNotFoundError,
@ -35,6 +36,7 @@ from .const import (
IDENTIFIER_SERIAL_NUMBER,
)
from .device_trigger import async_fire_triggers, async_setup_triggers_for_entry
from .storage import EntityMapStorage
DEFAULT_SCAN_INTERVAL = datetime.timedelta(seconds=60)
RETRY_INTERVAL = 60 # seconds
@ -70,11 +72,13 @@ class HKDevice:
# don't want to mutate a dict owned by a config entry.
self.pairing_data = pairing_data.copy()
self.pairing = hass.data[CONTROLLER].load_pairing(
connection: Controller = hass.data[CONTROLLER]
self.pairing = connection.load_pairing(
self.pairing_data["AccessoryPairingID"], self.pairing_data
)
self.accessories = None
self.accessories: list[Any] | None = None
self.config_num = 0
self.entity_map = Accessories()
@ -167,26 +171,23 @@ class HKDevice:
async def async_setup(self) -> bool:
"""Prepare to use a paired HomeKit device in Home Assistant."""
cache = self.hass.data[ENTITY_MAP].get_map(self.unique_id)
if not cache:
if await self.async_refresh_entity_map(self.config_num):
self._polling_interval_remover = async_track_time_interval(
self.hass, self.async_update, DEFAULT_SCAN_INTERVAL
)
return True
entity_storage: EntityMapStorage = self.hass.data[ENTITY_MAP]
if cache := entity_storage.get_map(self.unique_id):
self.accessories = cache["accessories"]
self.config_num = cache["config_num"]
self.entity_map = Accessories.from_list(self.accessories)
elif not await self.async_refresh_entity_map(self.config_num):
return False
self.accessories = cache["accessories"]
self.config_num = cache["config_num"]
self.entity_map = Accessories.from_list(self.accessories)
await self.async_process_entity_map()
if not self.pairing.is_connected:
return False
# If everything is up to date, we can create the entities
# since we know the data is not stale.
self.add_entities()
self._polling_interval_remover = async_track_time_interval(
self.hass, self.async_update, DEFAULT_SCAN_INTERVAL
)
self.hass.async_create_task(self.async_process_entity_map())
return True
def device_info_for_accessory(self, accessory: Accessory) -> DeviceInfo:
@ -361,7 +362,7 @@ class HKDevice:
# is especially important for BLE, as the Pairing instance relies on the entity map
# to map aid/iid to GATT characteristics. So push it to there as well.
self.pairing.pairing_data["accessories"] = self.accessories
self.pairing.pairing_data["accessories"] = self.accessories # type: ignore[attr-defined]
self.async_detect_workarounds()
@ -375,8 +376,6 @@ class HKDevice:
# Load any triggers for this config entry
await async_setup_triggers_for_entry(self.hass, self.config_entry)
self.add_entities()
if self.watchable_characteristics:
await self.pairing.subscribe(self.watchable_characteristics)
if not self.pairing.is_connected:
@ -395,6 +394,12 @@ class HKDevice:
self.config_entry, self.platforms
)
async def async_refresh_entity_map_and_entities(self, config_num: int) -> None:
"""Refresh the entity map and entities for this pairing."""
await self.async_refresh_entity_map(config_num)
await self.async_process_entity_map()
self.add_entities()
async def async_refresh_entity_map(self, config_num: int) -> bool:
"""Handle setup of a HomeKit accessory."""
try:
@ -404,15 +409,17 @@ class HKDevice:
# later when Bonjour spots c# is still not up to date.
return False
assert self.accessories is not None
self.entity_map = Accessories.from_list(self.accessories)
self.hass.data[ENTITY_MAP].async_create_or_update_map(
entity_storage: EntityMapStorage = self.hass.data[ENTITY_MAP]
entity_storage.async_create_or_update_map(
self.unique_id, config_num, self.accessories
)
self.config_num = config_num
self.hass.async_create_task(self.async_process_entity_map())
return True
def add_accessory_factory(self, add_entities_cb) -> None: