1
mirror of https://github.com/home-assistant/core synced 2024-08-02 23:40:32 +02:00

Create async_config_entry_first_refresh to reduce coordinator boilerplate (#48451)

This commit is contained in:
J. Nick Koston 2021-03-29 12:51:39 -10:00 committed by GitHub
parent 569c536a8e
commit a851bff95a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 181 additions and 225 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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, {})

View File

@ -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

View File

@ -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:

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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, {})

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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(

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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(

View File

@ -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] = {

View File

@ -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(

View File

@ -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(

View File

@ -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,

View File

@ -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(

View File

@ -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:

View File

@ -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()

View File

@ -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,

View File

@ -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

View File

@ -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(

View File

@ -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:

View File

@ -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)

View File

@ -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,

View File

@ -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] = {

View File

@ -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(

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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(

View File

@ -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(

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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(

View File

@ -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()

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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),

View File

@ -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:

View File

@ -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)

View File

@ -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