Add asyncio locks to screenlogic api access points (#48457)

This commit is contained in:
Kevin Worrel 2021-03-29 16:27:17 -07:00 committed by GitHub
parent c1d5638739
commit 42a060ad33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 15 deletions

View file

@ -60,8 +60,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
_LOGGER.error("Error while connecting to the gateway %s: %s", connect_info, ex)
raise ConfigEntryNotReady from ex
# The api library uses a shared socket connection and does not handle concurrent
# requests very well.
api_lock = asyncio.Lock()
coordinator = ScreenlogicDataUpdateCoordinator(
hass, config_entry=entry, gateway=gateway
hass, config_entry=entry, gateway=gateway, api_lock=api_lock
)
device_data = defaultdict(list)
@ -127,10 +131,11 @@ async def async_update_listener(hass: HomeAssistant, entry: ConfigEntry):
class ScreenlogicDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage the data update for the Screenlogic component."""
def __init__(self, hass, *, config_entry, gateway):
def __init__(self, hass, *, config_entry, gateway, api_lock):
"""Initialize the Screenlogic Data Update Coordinator."""
self.config_entry = config_entry
self.gateway = gateway
self.api_lock = api_lock
self.screenlogic_data = {}
interval = timedelta(
seconds=config_entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
@ -145,7 +150,8 @@ class ScreenlogicDataUpdateCoordinator(DataUpdateCoordinator):
async def _async_update_data(self):
"""Fetch data from the Screenlogic gateway."""
try:
await self.hass.async_add_executor_job(self.gateway.update)
async with self.api_lock:
await self.hass.async_add_executor_job(self.gateway.update)
except ScreenLogicError as error:
raise UpdateFailed(error) from error
return self.gateway.get_data()

View file

@ -138,9 +138,12 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
raise ValueError(f"Expected attribute {ATTR_TEMPERATURE}")
if await self.hass.async_add_executor_job(
self.gateway.set_heat_temp, int(self._data_key), int(temperature)
):
async with self.coordinator.api_lock:
success = await self.hass.async_add_executor_job(
self.gateway.set_heat_temp, int(self._data_key), int(temperature)
)
if success:
await self.coordinator.async_request_refresh()
else:
raise HomeAssistantError(
@ -153,9 +156,13 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
mode = HEAT_MODE.OFF
else:
mode = HEAT_MODE.NUM_FOR_NAME[self.preset_mode]
if await self.hass.async_add_executor_job(
self.gateway.set_heat_mode, int(self._data_key), int(mode)
):
async with self.coordinator.api_lock:
success = await self.hass.async_add_executor_job(
self.gateway.set_heat_mode, int(self._data_key), int(mode)
)
if success:
await self.coordinator.async_request_refresh()
else:
raise HomeAssistantError(
@ -168,9 +175,13 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
self._last_preset = mode = HEAT_MODE.NUM_FOR_NAME[preset_mode]
if self.hvac_mode == HVAC_MODE_OFF:
return
if await self.hass.async_add_executor_job(
self.gateway.set_heat_mode, int(self._data_key), int(mode)
):
async with self.coordinator.api_lock:
success = await self.hass.async_add_executor_job(
self.gateway.set_heat_mode, int(self._data_key), int(mode)
)
if success:
await self.coordinator.async_request_refresh()
else:
raise HomeAssistantError(

View file

@ -44,9 +44,12 @@ class ScreenLogicSwitch(ScreenlogicEntity, SwitchEntity):
return await self._async_set_circuit(ON_OFF.OFF)
async def _async_set_circuit(self, circuit_value) -> None:
if await self.hass.async_add_executor_job(
self.gateway.set_circuit, self._data_key, circuit_value
):
async with self.coordinator.api_lock:
success = await self.hass.async_add_executor_job(
self.gateway.set_circuit, self._data_key, circuit_value
)
if success:
_LOGGER.debug("Turn %s %s", self._data_key, circuit_value)
await self.coordinator.async_request_refresh()
else: