Avoid loading platforms in HKC if we are going to raise ConfigEntryNotReady (#75177)

This commit is contained in:
J. Nick Koston 2022-07-14 17:17:16 +02:00 committed by GitHub
parent 2286dea636
commit 89985b93fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 7 deletions

View File

@ -14,7 +14,7 @@ from aiohomekit.exceptions import (
EncryptionError, EncryptionError,
) )
from aiohomekit.model import Accessories, Accessory from aiohomekit.model import Accessories, Accessory
from aiohomekit.model.characteristics import Characteristic from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes
from aiohomekit.model.services import Service from aiohomekit.model.services import Service
from homeassistant.const import ATTR_VIA_DEVICE from homeassistant.const import ATTR_VIA_DEVICE
@ -169,6 +169,29 @@ class HKDevice:
self.available = available self.available = available
async_dispatcher_send(self.hass, self.signal_state_updated) async_dispatcher_send(self.hass, self.signal_state_updated)
async def async_ensure_available(self) -> bool:
"""Verify the accessory is available after processing the entity map."""
if self.available:
return True
if self.watchable_characteristics and self.pollable_characteristics:
# We already tried, no need to try again
return False
# We there are no watchable and not pollable characteristics,
# we need to force a connection to the device to verify its alive.
#
# This is similar to iOS's behavior for keeping alive connections
# to cameras.
#
primary = self.entity_map.accessories[0]
aid = primary.aid
iid = primary.accessory_information[CharacteristicsTypes.SERIAL_NUMBER].iid
try:
await self.pairing.get_characteristics([(aid, iid)])
except (AccessoryDisconnectedError, EncryptionError, AccessoryNotFoundError):
return False
self.async_set_available_state(True)
return True
async def async_setup(self) -> bool: async def async_setup(self) -> bool:
"""Prepare to use a paired HomeKit device in Home Assistant.""" """Prepare to use a paired HomeKit device in Home Assistant."""
entity_storage: EntityMapStorage = self.hass.data[ENTITY_MAP] entity_storage: EntityMapStorage = self.hass.data[ENTITY_MAP]
@ -180,16 +203,22 @@ class HKDevice:
return False return False
await self.async_process_entity_map() await self.async_process_entity_map()
if not self.pairing.is_connected:
if not await self.async_ensure_available():
return False return False
# If everything is up to date, we can create the entities # If everything is up to date, we can create the entities
# since we know the data is not stale. # since we know the data is not stale.
self.add_entities() await self.async_add_new_entities()
self._polling_interval_remover = async_track_time_interval( self._polling_interval_remover = async_track_time_interval(
self.hass, self.async_update, DEFAULT_SCAN_INTERVAL self.hass, self.async_update, DEFAULT_SCAN_INTERVAL
) )
return True return True
async def async_add_new_entities(self) -> None:
"""Add new entities to Home Assistant."""
await self.async_load_platforms()
self.add_entities()
def device_info_for_accessory(self, accessory: Accessory) -> DeviceInfo: def device_info_for_accessory(self, accessory: Accessory) -> DeviceInfo:
"""Build a DeviceInfo for a given accessory.""" """Build a DeviceInfo for a given accessory."""
identifiers = { identifiers = {
@ -369,8 +398,6 @@ class HKDevice:
# Migrate to new device ids # Migrate to new device ids
self.async_migrate_devices() self.async_migrate_devices()
await self.async_load_platforms()
self.async_create_devices() self.async_create_devices()
# Load any triggers for this config entry # Load any triggers for this config entry
@ -398,7 +425,7 @@ class HKDevice:
"""Refresh the entity map and entities for this pairing.""" """Refresh the entity map and entities for this pairing."""
await self.async_refresh_entity_map(config_num) await self.async_refresh_entity_map(config_num)
await self.async_process_entity_map() await self.async_process_entity_map()
self.add_entities() await self.async_add_new_entities()
async def async_refresh_entity_map(self, config_num: int) -> bool: async def async_refresh_entity_map(self, config_num: int) -> bool:
"""Handle setup of a HomeKit accessory.""" """Handle setup of a HomeKit accessory."""

View File

@ -3,7 +3,7 @@
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from unittest.mock import patch
from aiohomekit import exceptions from aiohomekit import AccessoryDisconnectedError, exceptions
from aiohomekit.model import Accessory from aiohomekit.model import Accessory
from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.characteristics import CharacteristicsTypes
from aiohomekit.model.services import ServicesTypes from aiohomekit.model.services import ServicesTypes
@ -111,6 +111,9 @@ async def test_offline_device_raises(hass):
nonlocal is_connected nonlocal is_connected
return is_connected return is_connected
def get_characteristics(self, chars, *args, **kwargs):
raise AccessoryDisconnectedError("any")
class OfflineFakeDiscovery(FakeDiscovery): class OfflineFakeDiscovery(FakeDiscovery):
"""Fake discovery that returns an offline pairing.""" """Fake discovery that returns an offline pairing."""