From 462e2a8ea1a9461389b2c286c072d38e0738aad2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 8 Nov 2022 04:03:37 -0600 Subject: [PATCH] Fix HomeKit reset accessory procedure (#81573) fixes https://github.com/home-assistant/core/issues/81571 --- homeassistant/components/homekit/__init__.py | 28 ++++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index b809f6db205..333d6052d17 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -10,8 +10,10 @@ import os from typing import Any, cast from aiohttp import web +from pyhap.characteristic import Characteristic from pyhap.const import STANDALONE_AID from pyhap.loader import get_loader +from pyhap.service import Service import voluptuous as vol from zeroconf.asyncio import AsyncZeroconf @@ -139,7 +141,7 @@ STATUS_WAIT = 3 PORT_CLEANUP_CHECK_INTERVAL_SECS = 1 _HOMEKIT_CONFIG_UPDATE_TIME = ( - 5 # number of seconds to wait for homekit to see the c# change + 10 # number of seconds to wait for homekit to see the c# change ) @@ -529,6 +531,7 @@ class HomeKit: self.status = STATUS_READY self.driver: HomeDriver | None = None self.bridge: HomeBridge | None = None + self._reset_lock = asyncio.Lock() def setup(self, async_zeroconf_instance: AsyncZeroconf, uuid: str) -> None: """Set up bridge and accessory driver.""" @@ -558,21 +561,24 @@ class HomeKit: async def async_reset_accessories(self, entity_ids: Iterable[str]) -> None: """Reset the accessory to load the latest configuration.""" - if not self.bridge: - await self.async_reset_accessories_in_accessory_mode(entity_ids) - return - await self.async_reset_accessories_in_bridge_mode(entity_ids) + async with self._reset_lock: + if not self.bridge: + await self.async_reset_accessories_in_accessory_mode(entity_ids) + return + await self.async_reset_accessories_in_bridge_mode(entity_ids) async def _async_shutdown_accessory(self, accessory: HomeAccessory) -> None: """Shutdown an accessory.""" assert self.driver is not None await accessory.stop() # Deallocate the IIDs for the accessory - iid_manager = self.driver.iid_manager - for service in accessory.services: - iid_manager.remove_iid(iid_manager.remove_obj(service)) - for char in service.characteristics: - iid_manager.remove_iid(iid_manager.remove_obj(char)) + iid_manager = accessory.iid_manager + services: list[Service] = accessory.services + for service in services: + iid_manager.remove_obj(service) + characteristics: list[Characteristic] = service.characteristics + for char in characteristics: + iid_manager.remove_obj(char) async def async_reset_accessories_in_accessory_mode( self, entity_ids: Iterable[str] @@ -581,7 +587,6 @@ class HomeKit: assert self.driver is not None acc = cast(HomeAccessory, self.driver.accessory) - await self._async_shutdown_accessory(acc) if acc.entity_id not in entity_ids: return if not (state := self.hass.states.get(acc.entity_id)): @@ -589,6 +594,7 @@ class HomeKit: "The underlying entity %s disappeared during reset", acc.entity_id ) return + await self._async_shutdown_accessory(acc) if new_acc := self._async_create_single_accessory([state]): self.driver.accessory = new_acc self.hass.async_add_job(new_acc.run)