diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index 8068f26aaa3..1cb2131fb8f 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -103,6 +103,10 @@ class HKDevice: # this method. self._polling_interval_remover = None + # Never allow concurrent polling of the same accessory or bridge + self._polling_lock = asyncio.Lock() + self._polling_lock_warned = False + def add_pollable_characteristics(self, characteristics): """Add (aid, iid) pairs that we need to poll.""" self.pollable_characteristics.extend(characteristics) @@ -247,25 +251,40 @@ class HKDevice: _LOGGER.debug("HomeKit connection not polling any characteristics.") return - _LOGGER.debug("Starting HomeKit controller update") + if self._polling_lock.locked(): + if not self._polling_lock_warned: + _LOGGER.warning( + "HomeKit controller update skipped as previous poll still in flight" + ) + self._polling_lock_warned = True + return - try: - new_values_dict = await self.get_characteristics( - self.pollable_characteristics + if self._polling_lock_warned: + _LOGGER.info( + "HomeKit controller no longer detecting back pressure - not skipping poll" ) - except AccessoryNotFoundError: - # Not only did the connection fail, but also the accessory is not - # visible on the network. - self.async_set_unavailable() - return - except (AccessoryDisconnectedError, EncryptionError): - # Temporary connection failure. Device is still available but our - # connection was dropped. - return + self._polling_lock_warned = False - self.process_new_events(new_values_dict) + async with self._polling_lock: + _LOGGER.debug("Starting HomeKit controller update") - _LOGGER.debug("Finished HomeKit controller update") + try: + new_values_dict = await self.get_characteristics( + self.pollable_characteristics + ) + except AccessoryNotFoundError: + # Not only did the connection fail, but also the accessory is not + # visible on the network. + self.async_set_unavailable() + return + except (AccessoryDisconnectedError, EncryptionError): + # Temporary connection failure. Device is still available but our + # connection was dropped. + return + + self.process_new_events(new_values_dict) + + _LOGGER.debug("Finished HomeKit controller update") def process_new_events(self, new_values_dict): """Process events from accessory into HA state."""