From a851bff95abe3d8f6f44f8ef163d0290bc654758 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 29 Mar 2021 12:51:39 -1000 Subject: [PATCH] Create async_config_entry_first_refresh to reduce coordinator boilerplate (#48451) --- .../components/accuweather/__init__.py | 6 +- .../components/advantage_air/__init__.py | 6 +- homeassistant/components/aemet/__init__.py | 2 +- homeassistant/components/airly/__init__.py | 6 +- homeassistant/components/airnow/__init__.py | 5 +- .../components/airvisual/__init__.py | 5 +- homeassistant/components/atag/__init__.py | 5 +- homeassistant/components/aurora/__init__.py | 6 +- homeassistant/components/awair/__init__.py | 6 +- homeassistant/components/broadlink/device.py | 4 +- homeassistant/components/brother/__init__.py | 6 +- homeassistant/components/canary/__init__.py | 5 +- .../components/cert_expiry/__init__.py | 6 +- .../components/climacell/__init__.py | 6 +- .../components/coolmaster/__init__.py | 2 +- homeassistant/components/dexcom/__init__.py | 4 +- .../components/faa_delays/__init__.py | 6 +- .../components/fireservicerota/__init__.py | 2 +- homeassistant/components/gios/__init__.py | 6 +- .../components/gogogate2/__init__.py | 6 +- .../components/huisbaasje/__init__.py | 6 +- homeassistant/components/ipp/__init__.py | 6 +- homeassistant/components/juicenet/__init__.py | 2 +- homeassistant/components/kmtronic/__init__.py | 6 +- homeassistant/components/lyric/__init__.py | 5 +- homeassistant/components/mazda/__init__.py | 4 +- homeassistant/components/met/__init__.py | 6 +- .../components/motion_blinds/__init__.py | 2 +- homeassistant/components/mullvad/__init__.py | 6 +- homeassistant/components/notion/__init__.py | 2 +- homeassistant/components/nut/__init__.py | 2 +- homeassistant/components/nzbget/__init__.py | 6 +- .../components/omnilogic/__init__.py | 5 +- .../components/openweathermap/__init__.py | 6 +- .../components/ovo_energy/__init__.py | 2 +- homeassistant/components/plaato/__init__.py | 5 +- homeassistant/components/plugwise/gateway.py | 5 +- .../components/poolsense/__init__.py | 6 +- .../components/powerwall/__init__.py | 2 +- .../components/proxmoxve/__init__.py | 2 +- .../components/recollect_waste/__init__.py | 6 +- homeassistant/components/risco/__init__.py | 2 +- homeassistant/components/roku/__init__.py | 6 +- .../components/ruckus_unleashed/__init__.py | 4 +- .../components/screenlogic/__init__.py | 2 +- homeassistant/components/sharkiq/__init__.py | 5 +- homeassistant/components/somfy/__init__.py | 2 +- homeassistant/components/tesla/__init__.py | 5 +- homeassistant/components/toon/__init__.py | 6 +- homeassistant/components/upcloud/__init__.py | 4 +- homeassistant/components/verisure/__init__.py | 5 +- homeassistant/components/withings/__init__.py | 5 +- homeassistant/components/wled/__init__.py | 6 +- homeassistant/components/xbox/__init__.py | 2 +- homeassistant/helpers/update_coordinator.py | 63 ++++++++++++---- tests/components/gogogate2/test_init.py | 25 ++++--- tests/helpers/test_update_coordinator.py | 72 ++++++++++++++++--- 57 files changed, 181 insertions(+), 225 deletions(-) diff --git a/homeassistant/components/accuweather/__init__.py b/homeassistant/components/accuweather/__init__.py index 90b939ab3b9..4ed471a50f5 100644 --- a/homeassistant/components/accuweather/__init__.py +++ b/homeassistant/components/accuweather/__init__.py @@ -8,7 +8,6 @@ from aiohttp.client_exceptions import ClientConnectorError from async_timeout import timeout from homeassistant.const import CONF_API_KEY -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -38,10 +37,7 @@ async def async_setup_entry(hass, config_entry) -> bool: coordinator = AccuWeatherDataUpdateCoordinator( hass, websession, api_key, location_key, forecast ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() undo_listener = config_entry.add_update_listener(update_listener) diff --git a/homeassistant/components/advantage_air/__init__.py b/homeassistant/components/advantage_air/__init__.py index d98e991364d..29270640a61 100644 --- a/homeassistant/components/advantage_air/__init__.py +++ b/homeassistant/components/advantage_air/__init__.py @@ -7,7 +7,6 @@ import logging from advantage_air import ApiError, advantage_air from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -57,10 +56,7 @@ async def async_setup_entry(hass, entry): except ApiError as err: _LOGGER.warning(err) - await coordinator.async_refresh() - - if not coordinator.data: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { "coordinator": coordinator, diff --git a/homeassistant/components/aemet/__init__.py b/homeassistant/components/aemet/__init__.py index 54c93f43a25..6ec6c6ed1ea 100644 --- a/homeassistant/components/aemet/__init__.py +++ b/homeassistant/components/aemet/__init__.py @@ -30,7 +30,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): aemet = AEMET(api_key) weather_coordinator = WeatherUpdateCoordinator(hass, aemet, latitude, longitude) - await weather_coordinator.async_refresh() + await weather_coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][config_entry.entry_id] = { ENTRY_NAME: name, diff --git a/homeassistant/components/airly/__init__.py b/homeassistant/components/airly/__init__.py index ff7a87f92fc..b373750e7b1 100644 --- a/homeassistant/components/airly/__init__.py +++ b/homeassistant/components/airly/__init__.py @@ -11,7 +11,6 @@ import async_timeout from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE from homeassistant.core import Config, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -71,10 +70,7 @@ async def async_setup_entry(hass, config_entry): coordinator = AirlyDataUpdateCoordinator( hass, websession, api_key, latitude, longitude, update_interval, use_nearest ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][config_entry.entry_id] = coordinator diff --git a/homeassistant/components/airnow/__init__.py b/homeassistant/components/airnow/__init__.py index 04e1567e067..b1770dcbde7 100644 --- a/homeassistant/components/airnow/__init__.py +++ b/homeassistant/components/airnow/__init__.py @@ -11,7 +11,6 @@ from pyairnow.errors import AirNowError from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -55,9 +54,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) # Sync with Coordinator - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() # Store Entity and Initialize Platforms hass.data.setdefault(DOMAIN, {}) diff --git a/homeassistant/components/airvisual/__init__.py b/homeassistant/components/airvisual/__init__.py index 7450ff2afcf..473cf3a32dd 100644 --- a/homeassistant/components/airvisual/__init__.py +++ b/homeassistant/components/airvisual/__init__.py @@ -23,7 +23,6 @@ from homeassistant.const import ( CONF_STATE, ) from homeassistant.core import callback -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client, config_validation as cv from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -272,9 +271,7 @@ async def async_setup_entry(hass, config_entry): update_method=async_update_data, ) - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] = coordinator diff --git a/homeassistant/components/atag/__init__.py b/homeassistant/components/atag/__init__.py index 02aab5036b3..f5507ff01bc 100644 --- a/homeassistant/components/atag/__init__.py +++ b/homeassistant/components/atag/__init__.py @@ -10,7 +10,6 @@ from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.water_heater import DOMAIN as WATER_HEATER from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, asyncio -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -52,9 +51,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): update_interval=timedelta(seconds=60), ) - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator if entry.unique_id is None: diff --git a/homeassistant/components/aurora/__init__.py b/homeassistant/components/aurora/__init__.py index 321b25de7b9..d685a983208 100644 --- a/homeassistant/components/aurora/__init__.py +++ b/homeassistant/components/aurora/__init__.py @@ -10,7 +10,6 @@ from auroranoaa import AuroraForecast from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_NAME, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -69,10 +68,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): threshold=threshold, ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { COORDINATOR: coordinator, diff --git a/homeassistant/components/awair/__init__.py b/homeassistant/components/awair/__init__.py index eefc7445d36..76c3e95f897 100644 --- a/homeassistant/components/awair/__init__.py +++ b/homeassistant/components/awair/__init__.py @@ -10,7 +10,6 @@ from python_awair.exceptions import AuthError from homeassistant.const import CONF_ACCESS_TOKEN from homeassistant.core import Config, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -29,10 +28,7 @@ async def async_setup_entry(hass, config_entry) -> bool: session = async_get_clientsession(hass) coordinator = AwairDataUpdateCoordinator(hass, config_entry, session) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][config_entry.entry_id] = coordinator diff --git a/homeassistant/components/broadlink/device.py b/homeassistant/components/broadlink/device.py index 104118a697c..2e6e09dd474 100644 --- a/homeassistant/components/broadlink/device.py +++ b/homeassistant/components/broadlink/device.py @@ -95,9 +95,7 @@ class BroadlinkDevice: update_manager = get_update_manager(self) coordinator = update_manager.coordinator - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady() + await coordinator.async_config_entry_first_refresh() self.update_manager = update_manager self.hass.data[DOMAIN].devices[config.entry_id] = self diff --git a/homeassistant/components/brother/__init__.py b/homeassistant/components/brother/__init__.py index 9cddf0efdd5..cfca805d51d 100644 --- a/homeassistant/components/brother/__init__.py +++ b/homeassistant/components/brother/__init__.py @@ -8,7 +8,6 @@ from brother import Brother, SnmpError, UnsupportedModel from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_TYPE from homeassistant.core import Config, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DATA_CONFIG_ENTRY, DOMAIN, SNMP @@ -36,10 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): coordinator = BrotherDataUpdateCoordinator( hass, host=host, kind=kind, snmp_engine=snmp_engine ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN].setdefault(DATA_CONFIG_ENTRY, {}) diff --git a/homeassistant/components/canary/__init__.py b/homeassistant/components/canary/__init__.py index b3fcf6e8641..ca6c4118753 100644 --- a/homeassistant/components/canary/__init__.py +++ b/homeassistant/components/canary/__init__.py @@ -95,10 +95,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool raise ConfigEntryNotReady from error coordinator = CanaryDataUpdateCoordinator(hass, api=canary_api) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() undo_listener = entry.add_update_listener(_async_update_listener) diff --git a/homeassistant/components/cert_expiry/__init__.py b/homeassistant/components/cert_expiry/__init__.py index 2d4be924a17..e8bc4c672ff 100644 --- a/homeassistant/components/cert_expiry/__init__.py +++ b/homeassistant/components/cert_expiry/__init__.py @@ -6,7 +6,6 @@ import logging from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PORT -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -30,10 +29,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): port = entry.data[CONF_PORT] coordinator = CertExpiryDataUpdateCoordinator(hass, host, port) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/climacell/__init__.py b/homeassistant/components/climacell/__init__.py index 96d7735a03c..4adddf71c79 100644 --- a/homeassistant/components/climacell/__init__.py +++ b/homeassistant/components/climacell/__init__.py @@ -24,7 +24,6 @@ from pyclimacell.pyclimacell import ( from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import ConfigType, HomeAssistantType from homeassistant.helpers.update_coordinator import ( @@ -112,10 +111,7 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry) _set_update_interval(hass, config_entry), ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][config_entry.entry_id] = coordinator diff --git a/homeassistant/components/coolmaster/__init__.py b/homeassistant/components/coolmaster/__init__.py index 14165bd93b3..2e1834ce8d8 100644 --- a/homeassistant/components/coolmaster/__init__.py +++ b/homeassistant/components/coolmaster/__init__.py @@ -31,7 +31,7 @@ async def async_setup_entry(hass, entry): except (OSError, ConnectionRefusedError, TimeoutError) as error: raise ConfigEntryNotReady() from error coordinator = CoolmasterDataUpdateCoordinator(hass, coolmaster) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { DATA_INFO: info, DATA_COORDINATOR: coordinator, diff --git a/homeassistant/components/dexcom/__init__.py b/homeassistant/components/dexcom/__init__.py index 5455c49232b..ad386bb701c 100644 --- a/homeassistant/components/dexcom/__init__.py +++ b/homeassistant/components/dexcom/__init__.py @@ -68,7 +68,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): UNDO_UPDATE_LISTENER: entry.add_update_listener(update_listener), } - await hass.data[DOMAIN][entry.entry_id][COORDINATOR].async_refresh() + await hass.data[DOMAIN][entry.entry_id][ + COORDINATOR + ].async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/faa_delays/__init__.py b/homeassistant/components/faa_delays/__init__.py index fd834da48d8..2669105469e 100644 --- a/homeassistant/components/faa_delays/__init__.py +++ b/homeassistant/components/faa_delays/__init__.py @@ -10,7 +10,6 @@ from faadelays import Airport from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_ID from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -32,10 +31,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): code = entry.data[CONF_ID] coordinator = FAADataUpdateCoordinator(hass, code) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/fireservicerota/__init__.py b/homeassistant/components/fireservicerota/__init__.py index 513a572b2c2..45849c20a8c 100644 --- a/homeassistant/components/fireservicerota/__init__.py +++ b/homeassistant/components/fireservicerota/__init__.py @@ -57,7 +57,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: update_interval=MIN_TIME_BETWEEN_UPDATES, ) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { DATA_CLIENT: client, diff --git a/homeassistant/components/gios/__init__.py b/homeassistant/components/gios/__init__.py index 005cc4c9c26..ef35c84fa90 100644 --- a/homeassistant/components/gios/__init__.py +++ b/homeassistant/components/gios/__init__.py @@ -6,7 +6,6 @@ from async_timeout import timeout from gios import ApiError, Gios, InvalidSensorsData, NoStationError from homeassistant.core import Config, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -28,10 +27,7 @@ async def async_setup_entry(hass, config_entry): websession = async_get_clientsession(hass) coordinator = GiosDataUpdateCoordinator(hass, websession, station_id) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][config_entry.entry_id] = coordinator diff --git a/homeassistant/components/gogogate2/__init__.py b/homeassistant/components/gogogate2/__init__.py index 6d0318b99ad..877145dea3d 100644 --- a/homeassistant/components/gogogate2/__init__.py +++ b/homeassistant/components/gogogate2/__init__.py @@ -6,7 +6,6 @@ from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_DEVICE from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from .common import get_data_update_coordinator from .const import DEVICE_TYPE_GOGOGATE2 @@ -34,10 +33,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b hass.config_entries.async_update_entry(config_entry, **config_updates) data_update_coordinator = get_data_update_coordinator(hass, config_entry) - await data_update_coordinator.async_refresh() - - if not data_update_coordinator.last_update_success: - raise ConfigEntryNotReady() + await data_update_coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/huisbaasje/__init__.py b/homeassistant/components/huisbaasje/__init__.py index f06ad444cc0..3af6db3efb5 100644 --- a/homeassistant/components/huisbaasje/__init__.py +++ b/homeassistant/components/huisbaasje/__init__.py @@ -8,7 +8,6 @@ from huisbaasje import Huisbaasje, HuisbaasjeException from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import ( @@ -61,10 +60,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): update_interval=timedelta(seconds=POLLING_INTERVAL), ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() # Load the client in the data of home assistant hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = { diff --git a/homeassistant/components/ipp/__init__.py b/homeassistant/components/ipp/__init__.py index 6e522a999c0..86bde4bba6c 100644 --- a/homeassistant/components/ipp/__init__.py +++ b/homeassistant/components/ipp/__init__.py @@ -18,7 +18,6 @@ from homeassistant.const import ( CONF_VERIFY_SSL, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -63,10 +62,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) hass.data[DOMAIN][entry.entry_id] = coordinator - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/juicenet/__init__.py b/homeassistant/components/juicenet/__init__.py index 42bce53f911..a7fb5e6b9b5 100644 --- a/homeassistant/components/juicenet/__init__.py +++ b/homeassistant/components/juicenet/__init__.py @@ -89,7 +89,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): JUICENET_COORDINATOR: coordinator, } - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/kmtronic/__init__.py b/homeassistant/components/kmtronic/__init__.py index 2903eb926e5..241e65fbe7f 100644 --- a/homeassistant/components/kmtronic/__init__.py +++ b/homeassistant/components/kmtronic/__init__.py @@ -9,7 +9,7 @@ from pykmtronic.auth import Auth from pykmtronic.hub import KMTronicHubAPI import voluptuous as vol -from homeassistant.config_entries import ConfigEntry, ConfigEntryNotReady +from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.helpers import aiohttp_client @@ -61,9 +61,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): update_method=async_update_data, update_interval=timedelta(seconds=30), ) - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { DATA_HUB: hub, diff --git a/homeassistant/components/lyric/__init__.py b/homeassistant/components/lyric/__init__.py index 8536fa03e8a..c3ef18e7c7f 100644 --- a/homeassistant/components/lyric/__init__.py +++ b/homeassistant/components/lyric/__init__.py @@ -15,7 +15,6 @@ import voluptuous as vol from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import ( aiohttp_client, config_entry_oauth2_flow, @@ -111,9 +110,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN][entry.entry_id] = coordinator # Fetch initial data so we have data when entities subscribe - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/mazda/__init__.py b/homeassistant/components/mazda/__init__.py index 8731fa256a6..2f4e0e84f13 100644 --- a/homeassistant/components/mazda/__init__.py +++ b/homeassistant/components/mazda/__init__.py @@ -117,9 +117,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): } # Fetch initial data so we have data when entities subscribe - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() # Setup components for platform in PLATFORMS: diff --git a/homeassistant/components/met/__init__.py b/homeassistant/components/met/__init__.py index 5a357467920..4367ca98536 100644 --- a/homeassistant/components/met/__init__.py +++ b/homeassistant/components/met/__init__.py @@ -14,7 +14,6 @@ from homeassistant.const import ( LENGTH_METERS, ) from homeassistant.core import Config, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.util.distance import convert as convert_distance @@ -37,10 +36,7 @@ async def async_setup(hass: HomeAssistant, config: Config) -> bool: async def async_setup_entry(hass, config_entry): """Set up Met as config entry.""" coordinator = MetDataUpdateCoordinator(hass, config_entry) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() if config_entry.data.get(CONF_TRACK_HOME, False): coordinator.track_home() diff --git a/homeassistant/components/motion_blinds/__init__.py b/homeassistant/components/motion_blinds/__init__.py index d4a5dd1f79b..73a27c90140 100644 --- a/homeassistant/components/motion_blinds/__init__.py +++ b/homeassistant/components/motion_blinds/__init__.py @@ -141,7 +141,7 @@ async def async_setup_entry( ) # Fetch initial data so we have data when entities subscribe - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { KEY_GATEWAY: motion_gateway, diff --git a/homeassistant/components/mullvad/__init__.py b/homeassistant/components/mullvad/__init__.py index b506be93100..541c6075cc3 100644 --- a/homeassistant/components/mullvad/__init__.py +++ b/homeassistant/components/mullvad/__init__.py @@ -8,7 +8,6 @@ from mullvad_api import MullvadAPI from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import update_coordinator from .const import DOMAIN @@ -36,10 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: dict): update_method=async_get_mullvad_api_data, update_interval=timedelta(minutes=1), ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN] = coordinator diff --git a/homeassistant/components/notion/__init__.py b/homeassistant/components/notion/__init__.py index c8c385143cf..ca0ccf08c89 100644 --- a/homeassistant/components/notion/__init__.py +++ b/homeassistant/components/notion/__init__.py @@ -97,7 +97,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: update_method=async_update, ) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/nut/__init__.py b/homeassistant/components/nut/__init__.py index 3aba05ddd2b..be86ca5951c 100644 --- a/homeassistant/components/nut/__init__.py +++ b/homeassistant/components/nut/__init__.py @@ -74,7 +74,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) # Fetch initial data so we have data when entities subscribe - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() status = data.status if not status: diff --git a/homeassistant/components/nzbget/__init__.py b/homeassistant/components/nzbget/__init__.py index 57a741f0469..48abe597f5a 100644 --- a/homeassistant/components/nzbget/__init__.py +++ b/homeassistant/components/nzbget/__init__.py @@ -13,7 +13,6 @@ from homeassistant.const import ( CONF_SSL, CONF_USERNAME, ) -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -95,10 +94,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool options=entry.options, ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() undo_listener = entry.add_update_listener(_async_update_listener) diff --git a/homeassistant/components/omnilogic/__init__.py b/homeassistant/components/omnilogic/__init__.py index 7196cd28cd7..e5a545e4806 100644 --- a/homeassistant/components/omnilogic/__init__.py +++ b/homeassistant/components/omnilogic/__init__.py @@ -56,10 +56,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): name="Omnilogic", polling_interval=polling_interval, ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { COORDINATOR: coordinator, diff --git a/homeassistant/components/openweathermap/__init__.py b/homeassistant/components/openweathermap/__init__.py index 82b1545e359..f6d47d1dcae 100644 --- a/homeassistant/components/openweathermap/__init__.py +++ b/homeassistant/components/openweathermap/__init__.py @@ -14,7 +14,6 @@ from homeassistant.const import ( CONF_NAME, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from .const import ( CONF_LANGUAGE, @@ -54,10 +53,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): owm, latitude, longitude, forecast_mode, hass ) - await weather_coordinator.async_refresh() - - if not weather_coordinator.last_update_success: - raise ConfigEntryNotReady + await weather_coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][config_entry.entry_id] = { diff --git a/homeassistant/components/ovo_energy/__init__.py b/homeassistant/components/ovo_energy/__init__.py index 7bf79f47991..902b594fce3 100644 --- a/homeassistant/components/ovo_energy/__init__.py +++ b/homeassistant/components/ovo_energy/__init__.py @@ -86,7 +86,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool } # Fetch initial data so we have data when entities subscribe - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() # Setup components hass.async_create_task( diff --git a/homeassistant/components/plaato/__init__.py b/homeassistant/components/plaato/__init__.py index 2cf97d5fd9a..2ec6028f9f9 100644 --- a/homeassistant/components/plaato/__init__.py +++ b/homeassistant/components/plaato/__init__.py @@ -37,7 +37,6 @@ from homeassistant.const import ( VOLUME_LITERS, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client import homeassistant.helpers.config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_send @@ -134,9 +133,7 @@ async def async_setup_coordinator(hass: HomeAssistant, entry: ConfigEntry): update_interval = timedelta(minutes=DEFAULT_SCAN_INTERVAL) coordinator = PlaatoCoordinator(hass, auth_token, device_type, update_interval) - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() _set_entry_data(entry, hass, coordinator, auth_token) diff --git a/homeassistant/components/plugwise/gateway.py b/homeassistant/components/plugwise/gateway.py index 3f8bc7ea626..70a4a822431 100644 --- a/homeassistant/components/plugwise/gateway.py +++ b/homeassistant/components/plugwise/gateway.py @@ -103,10 +103,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: update_interval=update_interval, ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() api.get_all_devices() diff --git a/homeassistant/components/poolsense/__init__.py b/homeassistant/components/poolsense/__init__.py index b11b7732e19..cfc2abb0316 100644 --- a/homeassistant/components/poolsense/__init__.py +++ b/homeassistant/components/poolsense/__init__.py @@ -10,7 +10,6 @@ from poolsense.exceptions import PoolSenseError from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -49,10 +48,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): coordinator = PoolSenseDataUpdateCoordinator(hass, entry) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/powerwall/__init__.py b/homeassistant/components/powerwall/__init__.py index b529680da50..22c052e7d06 100644 --- a/homeassistant/components/powerwall/__init__.py +++ b/homeassistant/components/powerwall/__init__.py @@ -156,7 +156,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): } ) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: hass.async_create_task( diff --git a/homeassistant/components/proxmoxve/__init__.py b/homeassistant/components/proxmoxve/__init__.py index 663afc69b1d..a149c8b6034 100644 --- a/homeassistant/components/proxmoxve/__init__.py +++ b/homeassistant/components/proxmoxve/__init__.py @@ -185,7 +185,7 @@ async def async_setup(hass: HomeAssistant, config: dict): hass.data[DOMAIN][COORDINATOR] = coordinator # Fetch initial data - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() for platform in PLATFORMS: await hass.async_create_task( diff --git a/homeassistant/components/recollect_waste/__init__.py b/homeassistant/components/recollect_waste/__init__.py index f37cabdd698..2e6f780c749 100644 --- a/homeassistant/components/recollect_waste/__init__.py +++ b/homeassistant/components/recollect_waste/__init__.py @@ -9,7 +9,6 @@ from aiorecollect.errors import RecollectError from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -55,10 +54,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: update_method=async_get_pickup_events, ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id] = coordinator diff --git a/homeassistant/components/risco/__init__.py b/homeassistant/components/risco/__init__.py index f5ebc4e13ef..eec30553870 100644 --- a/homeassistant/components/risco/__init__.py +++ b/homeassistant/components/risco/__init__.py @@ -47,7 +47,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): scan_interval = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) coordinator = RiscoDataUpdateCoordinator(hass, risco, scan_interval) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() events_coordinator = RiscoEventsDataUpdateCoordinator( hass, risco, entry.entry_id, 60 ) diff --git a/homeassistant/components/roku/__init__.py b/homeassistant/components/roku/__init__.py index 174bd71b77a..4a349265459 100644 --- a/homeassistant/components/roku/__init__.py +++ b/homeassistant/components/roku/__init__.py @@ -13,7 +13,6 @@ from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_NAME, CONF_HOST -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import HomeAssistantType @@ -49,10 +48,7 @@ async def async_setup(hass: HomeAssistantType, config: dict) -> bool: async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: """Set up Roku from a config entry.""" coordinator = RokuDataUpdateCoordinator(hass, host=entry.data[CONF_HOST]) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/ruckus_unleashed/__init__.py b/homeassistant/components/ruckus_unleashed/__init__.py index 2bab1747f0f..2eb4f143131 100644 --- a/homeassistant/components/ruckus_unleashed/__init__.py +++ b/homeassistant/components/ruckus_unleashed/__init__.py @@ -47,9 +47,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: coordinator = RuckusUnleashedDataUpdateCoordinator(hass, ruckus=ruckus) - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() system_info = await hass.async_add_executor_job(ruckus.system_info) diff --git a/homeassistant/components/screenlogic/__init__.py b/homeassistant/components/screenlogic/__init__.py index cca3e7e8785..4189158b178 100644 --- a/homeassistant/components/screenlogic/__init__.py +++ b/homeassistant/components/screenlogic/__init__.py @@ -66,7 +66,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): device_data = defaultdict(list) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() for circuit in coordinator.data["circuits"]: device_data["switch"].append(circuit) diff --git a/homeassistant/components/sharkiq/__init__.py b/homeassistant/components/sharkiq/__init__.py index 5ccb3e00f27..94b6a8f2e3b 100644 --- a/homeassistant/components/sharkiq/__init__.py +++ b/homeassistant/components/sharkiq/__init__.py @@ -64,10 +64,7 @@ async def async_setup_entry(hass, config_entry): _LOGGER.debug("Found %d Shark IQ device(s): %s", len(shark_vacs), device_names) coordinator = SharkIqUpdateCoordinator(hass, config_entry, ayla_api, shark_vacs) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise exceptions.ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][config_entry.entry_id] = coordinator diff --git a/homeassistant/components/somfy/__init__.py b/homeassistant/components/somfy/__init__.py index 0a83ac2fc52..9d67675f10e 100644 --- a/homeassistant/components/somfy/__init__.py +++ b/homeassistant/components/somfy/__init__.py @@ -108,7 +108,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): ) data[COORDINATOR] = coordinator - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() if all(not bool(device.states) for device in coordinator.data.values()): _LOGGER.debug( diff --git a/homeassistant/components/tesla/__init__.py b/homeassistant/components/tesla/__init__.py index 76b7f872024..b090e1c96ef 100644 --- a/homeassistant/components/tesla/__init__.py +++ b/homeassistant/components/tesla/__init__.py @@ -21,7 +21,6 @@ from homeassistant.const import ( HTTP_UNAUTHORIZED, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client, config_validation as cv from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -178,9 +177,7 @@ async def async_setup_entry(hass, config_entry): } _LOGGER.debug("Connected to the Tesla API") - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() all_devices = controller.get_homeassistant_components() diff --git a/homeassistant/components/toon/__init__.py b/homeassistant/components/toon/__init__.py index 2a3322991e1..87c68b5addb 100644 --- a/homeassistant/components/toon/__init__.py +++ b/homeassistant/components/toon/__init__.py @@ -15,7 +15,6 @@ from homeassistant.const import ( EVENT_HOMEASSISTANT_STARTED, ) from homeassistant.core import CoreState, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv, device_registry as dr from homeassistant.helpers.config_entry_oauth2_flow import ( OAuth2Session, @@ -98,10 +97,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await coordinator.toon.activate_agreement( agreement_id=entry.data[CONF_AGREEMENT_ID] ) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/upcloud/__init__.py b/homeassistant/components/upcloud/__init__.py index 756862456f0..c118f12954d 100644 --- a/homeassistant/components/upcloud/__init__.py +++ b/homeassistant/components/upcloud/__init__.py @@ -207,9 +207,7 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry) ) # Call the UpCloud API to refresh data - await coordinator.async_request_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() # Listen to config entry updates coordinator.unsub_handlers.append( diff --git a/homeassistant/components/verisure/__init__.py b/homeassistant/components/verisure/__init__.py index 013142504f1..32893aec88b 100644 --- a/homeassistant/components/verisure/__init__.py +++ b/homeassistant/components/verisure/__init__.py @@ -24,7 +24,6 @@ from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, ) from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.storage import STORAGE_DIR @@ -134,9 +133,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, coordinator.async_logout) - await coordinator.async_refresh() - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/withings/__init__.py b/homeassistant/components/withings/__init__.py index 7ccff020c0d..2cf6d297f12 100644 --- a/homeassistant/components/withings/__init__.py +++ b/homeassistant/components/withings/__init__.py @@ -21,7 +21,6 @@ from homeassistant.components.webhook import ( from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_WEBHOOK_ID from homeassistant.core import HomeAssistant, callback -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.event import async_call_later from homeassistant.helpers.typing import ConfigType @@ -121,9 +120,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: data_manager = await async_get_data_manager(hass, entry) _LOGGER.debug("Confirming %s is authenticated to withings", data_manager.profile) - await data_manager.poll_data_update_coordinator.async_refresh() - if not data_manager.poll_data_update_coordinator.last_update_success: - raise ConfigEntryNotReady() + await data_manager.poll_data_update_coordinator.async_config_entry_first_refresh() webhook.async_register( hass, diff --git a/homeassistant/components/wled/__init__.py b/homeassistant/components/wled/__init__.py index 069c12a2d06..a54635f26b8 100644 --- a/homeassistant/components/wled/__init__.py +++ b/homeassistant/components/wled/__init__.py @@ -14,7 +14,6 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_NAME, CONF_HOST from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -41,10 +40,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Create WLED instance for this entry coordinator = WLEDDataUpdateCoordinator(hass, host=entry.data[CONF_HOST]) - await coordinator.async_refresh() - - if not coordinator.last_update_success: - raise ConfigEntryNotReady + await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator diff --git a/homeassistant/components/xbox/__init__.py b/homeassistant/components/xbox/__init__.py index 938a392dd69..d287e515cef 100644 --- a/homeassistant/components/xbox/__init__.py +++ b/homeassistant/components/xbox/__init__.py @@ -95,7 +95,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): ) coordinator = XboxUpdateCoordinator(hass, client, consoles) - await coordinator.async_refresh() + await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id] = { "client": XboxLiveClient(auth), diff --git a/homeassistant/helpers/update_coordinator.py b/homeassistant/helpers/update_coordinator.py index 5b892ea79c4..53e92c433a9 100644 --- a/homeassistant/helpers/update_coordinator.py +++ b/homeassistant/helpers/update_coordinator.py @@ -13,6 +13,7 @@ import requests from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import CALLBACK_TYPE, Event, HassJob, HomeAssistant, callback +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import entity, event from homeassistant.util.dt import utcnow @@ -57,6 +58,7 @@ class DataUpdateCoordinator(Generic[T]): self._unsub_refresh: CALLBACK_TYPE | None = None self._request_refresh_task: asyncio.TimerHandle | None = None self.last_update_success = True + self.last_exception: Exception | None = None if request_refresh_debouncer is None: request_refresh_debouncer = Debouncer( @@ -140,7 +142,25 @@ class DataUpdateCoordinator(Generic[T]): raise NotImplementedError("Update method not implemented") return await self.update_method() + async def async_config_entry_first_refresh(self) -> None: + """Refresh data for the first time when a config entry is setup. + + Will automatically raise ConfigEntryNotReady if the refresh + fails. Additionally logging is handled by config entry setup + to ensure that multiple retries do not cause log spam. + """ + await self._async_refresh(log_failures=False) + if self.last_update_success: + return + ex = ConfigEntryNotReady() + ex.__cause__ = self.last_exception + raise ex + async def async_refresh(self) -> None: + """Refresh data and log errors.""" + await self._async_refresh(log_failures=True) + + async def _async_refresh(self, log_failures: bool = True) -> None: """Refresh data.""" if self._unsub_refresh: self._unsub_refresh() @@ -152,37 +172,50 @@ class DataUpdateCoordinator(Generic[T]): try: self.data = await self._async_update_data() - except (asyncio.TimeoutError, requests.exceptions.Timeout): + except (asyncio.TimeoutError, requests.exceptions.Timeout) as err: + self.last_exception = err if self.last_update_success: - self.logger.error("Timeout fetching %s data", self.name) + if log_failures: + self.logger.error("Timeout fetching %s data", self.name) self.last_update_success = False except (aiohttp.ClientError, requests.exceptions.RequestException) as err: + self.last_exception = err if self.last_update_success: - self.logger.error("Error requesting %s data: %s", self.name, err) - self.last_update_success = False - - except urllib.error.URLError as err: - if self.last_update_success: - if err.reason == "timed out": - self.logger.error("Timeout fetching %s data", self.name) - else: + if log_failures: self.logger.error("Error requesting %s data: %s", self.name, err) self.last_update_success = False - except UpdateFailed as err: + except urllib.error.URLError as err: + self.last_exception = err if self.last_update_success: - self.logger.error("Error fetching %s data: %s", self.name, err) + if log_failures: + if err.reason == "timed out": + self.logger.error("Timeout fetching %s data", self.name) + else: + self.logger.error( + "Error requesting %s data: %s", self.name, err + ) + self.last_update_success = False + + except UpdateFailed as err: + self.last_exception = err + if self.last_update_success: + if log_failures: + self.logger.error("Error fetching %s data: %s", self.name, err) self.last_update_success = False except NotImplementedError as err: + self.last_exception = err raise err except Exception as err: # pylint: disable=broad-except + self.last_exception = err self.last_update_success = False - self.logger.exception( - "Unexpected error fetching %s data: %s", self.name, err - ) + if log_failures: + self.logger.exception( + "Unexpected error fetching %s data: %s", self.name, err + ) else: if not self.last_update_success: diff --git a/tests/components/gogogate2/test_init.py b/tests/components/gogogate2/test_init.py index f51f08b2319..7bcd2f8d2f2 100644 --- a/tests/components/gogogate2/test_init.py +++ b/tests/components/gogogate2/test_init.py @@ -1,11 +1,11 @@ """Tests for the GogoGate2 component.""" +import asyncio from unittest.mock import MagicMock, patch from gogogate2_api import GogoGate2Api import pytest from homeassistant.components.gogogate2 import DEVICE_TYPE_GOGOGATE2, async_setup_entry -from homeassistant.components.gogogate2.common import DeviceDataUpdateCoordinator from homeassistant.components.gogogate2.const import DEVICE_TYPE_ISMARTGATE, DOMAIN from homeassistant.config_entries import SOURCE_USER from homeassistant.const import ( @@ -78,19 +78,22 @@ async def test_config_no_update(ismartgateapi_mock, hass: HomeAssistant) -> None } -async def test_auth_fail(hass: HomeAssistant) -> None: - """Test authorization failures.""" - - coordinator_mock: DeviceDataUpdateCoordinator = MagicMock( - spec=DeviceDataUpdateCoordinator +async def test_api_failure_on_startup(hass: HomeAssistant) -> None: + """Test api failure on startup raises ConfigEntryNotReady.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + source=SOURCE_USER, + data={ + CONF_DEVICE: DEVICE_TYPE_ISMARTGATE, + CONF_IP_ADDRESS: "127.0.0.1", + CONF_USERNAME: "admin", + CONF_PASSWORD: "password", + }, ) - coordinator_mock.last_update_success = False - - config_entry = MockConfigEntry() config_entry.add_to_hass(hass) with patch( - "homeassistant.components.gogogate2.get_data_update_coordinator", - return_value=coordinator_mock, + "homeassistant.components.gogogate2.common.ISmartGateApi.async_info", + side_effect=asyncio.TimeoutError, ), pytest.raises(ConfigEntryNotReady): await async_setup_entry(hass, config_entry) diff --git a/tests/helpers/test_update_coordinator.py b/tests/helpers/test_update_coordinator.py index e9754f83a26..391f2be38ec 100644 --- a/tests/helpers/test_update_coordinator.py +++ b/tests/helpers/test_update_coordinator.py @@ -11,6 +11,7 @@ import requests from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import CoreState +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import update_coordinator from homeassistant.util.dt import utcnow @@ -18,6 +19,36 @@ from tests.common import async_fire_time_changed _LOGGER = logging.getLogger(__name__) +KNOWN_ERRORS = [ + (asyncio.TimeoutError, asyncio.TimeoutError, "Timeout fetching test data"), + ( + requests.exceptions.Timeout, + requests.exceptions.Timeout, + "Timeout fetching test data", + ), + ( + urllib.error.URLError("timed out"), + urllib.error.URLError, + "Timeout fetching test data", + ), + (aiohttp.ClientError, aiohttp.ClientError, "Error requesting test data"), + ( + requests.exceptions.RequestException, + requests.exceptions.RequestException, + "Error requesting test data", + ), + ( + urllib.error.URLError("something"), + urllib.error.URLError, + "Error requesting test data", + ), + ( + update_coordinator.UpdateFailed, + update_coordinator.UpdateFailed, + "Error fetching test data", + ), +] + def get_crd(hass, update_interval): """Make coordinator mocks.""" @@ -113,15 +144,7 @@ async def test_request_refresh_no_auto_update(crd_without_update_interval): @pytest.mark.parametrize( "err_msg", - [ - (asyncio.TimeoutError, "Timeout fetching test data"), - (requests.exceptions.Timeout, "Timeout fetching test data"), - (urllib.error.URLError("timed out"), "Timeout fetching test data"), - (aiohttp.ClientError, "Error requesting test data"), - (requests.exceptions.RequestException, "Error requesting test data"), - (urllib.error.URLError("something"), "Error requesting test data"), - (update_coordinator.UpdateFailed, "Error fetching test data"), - ], + KNOWN_ERRORS, ) async def test_refresh_known_errors(err_msg, crd, caplog): """Test raising known errors.""" @@ -131,7 +154,8 @@ async def test_refresh_known_errors(err_msg, crd, caplog): assert crd.data is None assert crd.last_update_success is False - assert err_msg[1] in caplog.text + assert isinstance(crd.last_exception, err_msg[1]) + assert err_msg[2] in caplog.text async def test_refresh_fail_unknown(crd, caplog): @@ -310,3 +334,31 @@ async def test_stop_refresh_on_ha_stop(hass, crd): async_fire_time_changed(hass, utcnow() + update_interval) await hass.async_block_till_done() assert crd.data == 1 + + +@pytest.mark.parametrize( + "err_msg", + KNOWN_ERRORS, +) +async def test_async_config_entry_first_refresh_failure(err_msg, crd, caplog): + """Test async_config_entry_first_refresh raises ConfigEntryNotReady on failure. + + Verify we do not log the exception since raising ConfigEntryNotReady + will be caught by config_entries.async_setup which will log it with + a decreasing level of logging once the first message is logged. + """ + crd.update_method = AsyncMock(side_effect=err_msg[0]) + + with pytest.raises(ConfigEntryNotReady): + await crd.async_config_entry_first_refresh() + + assert crd.last_update_success is False + assert isinstance(crd.last_exception, err_msg[1]) + assert err_msg[2] not in caplog.text + + +async def test_async_config_entry_first_refresh_success(crd, caplog): + """Test first refresh successfully.""" + await crd.async_config_entry_first_refresh() + + assert crd.last_update_success is True