From 3aed58f825c310826d4ea16b785f34d49853d221 Mon Sep 17 00:00:00 2001 From: RDFurman Date: Tue, 7 Sep 2021 08:32:26 -0600 Subject: [PATCH] Try to avoid rate limiting in honeywell (#55304) * Limit parallel update and sleep loop * Use asyncio sleep instead * Extract sleep to const for testing * Make loop sleep 0 in test --- homeassistant/components/honeywell/__init__.py | 17 ++++++++++------- homeassistant/components/honeywell/climate.py | 4 +++- tests/components/honeywell/test_init.py | 4 ++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/honeywell/__init__.py b/homeassistant/components/honeywell/__init__.py index 29f0dbb8392..03dc9ea9c8c 100644 --- a/homeassistant/components/honeywell/__init__.py +++ b/homeassistant/components/honeywell/__init__.py @@ -1,4 +1,5 @@ """Support for Honeywell (US) Total Connect Comfort climate systems.""" +import asyncio from datetime import timedelta import somecomfort @@ -9,7 +10,8 @@ from homeassistant.util import Throttle from .const import _LOGGER, CONF_DEV_ID, CONF_LOC_ID, DOMAIN -MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180) +UPDATE_LOOP_SLEEP_TIME = 5 +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=300) PLATFORMS = ["climate"] @@ -42,7 +44,7 @@ async def async_setup_entry(hass, config): return False data = HoneywellData(hass, client, username, password, devices) - await data.update() + await data.async_update() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][config.entry_id] = data hass.config_entries.async_setup_platforms(config, PLATFORMS) @@ -102,18 +104,19 @@ class HoneywellData: self.devices = devices return True - def _refresh_devices(self): + async def _refresh_devices(self): """Refresh each enabled device.""" for device in self.devices: - device.refresh() + await self._hass.async_add_executor_job(device.refresh) + await asyncio.sleep(UPDATE_LOOP_SLEEP_TIME) @Throttle(MIN_TIME_BETWEEN_UPDATES) - async def update(self) -> None: + async def async_update(self) -> None: """Update the state.""" retries = 3 while retries > 0: try: - await self._hass.async_add_executor_job(self._refresh_devices) + await self._refresh_devices() break except ( somecomfort.client.APIRateLimited, @@ -124,7 +127,7 @@ class HoneywellData: if retries == 0: raise exp - result = await self._hass.async_add_executor_job(self._retry()) + result = await self._retry() if not result: raise exp diff --git a/homeassistant/components/honeywell/climate.py b/homeassistant/components/honeywell/climate.py index 230aa8ec424..8088a73506d 100644 --- a/homeassistant/components/honeywell/climate.py +++ b/homeassistant/components/honeywell/climate.py @@ -107,6 +107,8 @@ HW_FAN_MODE_TO_HA = { "follow schedule": FAN_AUTO, } +PARALLEL_UPDATES = 1 + async def async_setup_entry(hass, config, async_add_entities, discovery_info=None): """Set up the Honeywell thermostat.""" @@ -384,4 +386,4 @@ class HoneywellUSThermostat(ClimateEntity): async def async_update(self): """Get the latest state from the service.""" - await self._data.update() + await self._data.async_update() diff --git a/tests/components/honeywell/test_init.py b/tests/components/honeywell/test_init.py index 7cc6b64cd63..619d770c59e 100644 --- a/tests/components/honeywell/test_init.py +++ b/tests/components/honeywell/test_init.py @@ -1,11 +1,14 @@ """Test honeywell setup process.""" +from unittest.mock import patch + from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry +@patch("homeassistant.components.honeywell.UPDATE_LOOP_SLEEP_TIME", 0) async def test_setup_entry(hass: HomeAssistant, config_entry: MockConfigEntry): """Initialize the config entry.""" config_entry.add_to_hass(hass) @@ -15,6 +18,7 @@ async def test_setup_entry(hass: HomeAssistant, config_entry: MockConfigEntry): assert hass.states.async_entity_ids_count() == 1 +@patch("homeassistant.components.honeywell.UPDATE_LOOP_SLEEP_TIME", 0) async def test_setup_multiple_thermostats( hass: HomeAssistant, config_entry: MockConfigEntry, location, another_device ) -> None: