Merge branch 'dev' into homee-switch

This commit is contained in:
Markus Adrario 2025-02-08 11:02:31 +01:00 committed by GitHub
commit 45708c6f9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
194 changed files with 1701 additions and 1144 deletions

View File

@ -716,109 +716,6 @@ def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
return domains
class _WatchPendingSetups:
"""Periodic log and dispatch of setups that are pending."""
def __init__(
self,
hass: core.HomeAssistant,
setup_started: dict[tuple[str, str | None], float],
) -> None:
"""Initialize the WatchPendingSetups class."""
self._hass = hass
self._setup_started = setup_started
self._duration_count = 0
self._handle: asyncio.TimerHandle | None = None
self._previous_was_empty = True
self._loop = hass.loop
def _async_watch(self) -> None:
"""Periodic log of setups that are pending."""
now = monotonic()
self._duration_count += SLOW_STARTUP_CHECK_INTERVAL
remaining_with_setup_started: defaultdict[str, float] = defaultdict(float)
for integration_group, start_time in self._setup_started.items():
domain, _ = integration_group
remaining_with_setup_started[domain] += now - start_time
if remaining_with_setup_started:
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
elif waiting_tasks := self._hass._active_tasks: # noqa: SLF001
_LOGGER.debug("Waiting on tasks: %s", waiting_tasks)
self._async_dispatch(remaining_with_setup_started)
if (
self._setup_started
and self._duration_count % LOG_SLOW_STARTUP_INTERVAL == 0
):
# We log every LOG_SLOW_STARTUP_INTERVAL until all integrations are done
# once we take over LOG_SLOW_STARTUP_INTERVAL (60s) to start up
_LOGGER.warning(
"Waiting on integrations to complete setup: %s",
self._setup_started,
)
_LOGGER.debug("Running timeout Zones: %s", self._hass.timeout.zones)
self._async_schedule_next()
def _async_dispatch(self, remaining_with_setup_started: dict[str, float]) -> None:
"""Dispatch the signal."""
if remaining_with_setup_started or not self._previous_was_empty:
async_dispatcher_send_internal(
self._hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, remaining_with_setup_started
)
self._previous_was_empty = not remaining_with_setup_started
def _async_schedule_next(self) -> None:
"""Schedule the next call."""
self._handle = self._loop.call_later(
SLOW_STARTUP_CHECK_INTERVAL, self._async_watch
)
def async_start(self) -> None:
"""Start watching."""
self._async_schedule_next()
def async_stop(self) -> None:
"""Stop watching."""
self._async_dispatch({})
if self._handle:
self._handle.cancel()
self._handle = None
async def async_setup_multi_components(
hass: core.HomeAssistant,
domains: set[str],
config: dict[str, Any],
) -> None:
"""Set up multiple domains. Log on failure."""
# Avoid creating tasks for domains that were setup in a previous stage
domains_not_yet_setup = domains - hass.config.components
# Create setup tasks for base platforms first since everything will have
# to wait to be imported, and the sooner we can get the base platforms
# loaded the sooner we can start loading the rest of the integrations.
futures = {
domain: hass.async_create_task_internal(
async_setup_component(hass, domain, config),
f"setup component {domain}",
eager_start=True,
)
for domain in sorted(
domains_not_yet_setup, key=SETUP_ORDER_SORT_KEY, reverse=True
)
}
results = await asyncio.gather(*futures.values(), return_exceptions=True)
for idx, domain in enumerate(futures):
result = results[idx]
if isinstance(result, BaseException):
_LOGGER.error(
"Error setting up integration %s - received exception",
domain,
exc_info=(type(result), result, result.__traceback__),
)
async def _async_resolve_domains_to_setup(
hass: core.HomeAssistant, config: dict[str, Any]
) -> tuple[set[str], dict[str, loader.Integration]]:
@ -1038,7 +935,7 @@ async def _async_set_up_integrations(
for dep in integration.all_dependencies
)
async_set_domains_to_be_loaded(hass, to_be_loaded)
await async_setup_multi_components(hass, domain_group, config)
await _async_setup_multi_components(hass, domain_group, config)
# Enables after dependencies when setting up stage 1 domains
async_set_domains_to_be_loaded(hass, stage_1_domains)
@ -1050,7 +947,7 @@ async def _async_set_up_integrations(
async with hass.timeout.async_timeout(
STAGE_1_TIMEOUT, cool_down=COOLDOWN_TIME
):
await async_setup_multi_components(hass, stage_1_domains, config)
await _async_setup_multi_components(hass, stage_1_domains, config)
except TimeoutError:
_LOGGER.warning(
"Setup timed out for stage 1 waiting on %s - moving forward",
@ -1066,7 +963,7 @@ async def _async_set_up_integrations(
async with hass.timeout.async_timeout(
STAGE_2_TIMEOUT, cool_down=COOLDOWN_TIME
):
await async_setup_multi_components(hass, stage_2_domains, config)
await _async_setup_multi_components(hass, stage_2_domains, config)
except TimeoutError:
_LOGGER.warning(
"Setup timed out for stage 2 waiting on %s - moving forward",
@ -1092,3 +989,106 @@ async def _async_set_up_integrations(
"Integration setup times: %s",
dict(sorted(setup_time.items(), key=itemgetter(1), reverse=True)),
)
class _WatchPendingSetups:
"""Periodic log and dispatch of setups that are pending."""
def __init__(
self,
hass: core.HomeAssistant,
setup_started: dict[tuple[str, str | None], float],
) -> None:
"""Initialize the WatchPendingSetups class."""
self._hass = hass
self._setup_started = setup_started
self._duration_count = 0
self._handle: asyncio.TimerHandle | None = None
self._previous_was_empty = True
self._loop = hass.loop
def _async_watch(self) -> None:
"""Periodic log of setups that are pending."""
now = monotonic()
self._duration_count += SLOW_STARTUP_CHECK_INTERVAL
remaining_with_setup_started: defaultdict[str, float] = defaultdict(float)
for integration_group, start_time in self._setup_started.items():
domain, _ = integration_group
remaining_with_setup_started[domain] += now - start_time
if remaining_with_setup_started:
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
elif waiting_tasks := self._hass._active_tasks: # noqa: SLF001
_LOGGER.debug("Waiting on tasks: %s", waiting_tasks)
self._async_dispatch(remaining_with_setup_started)
if (
self._setup_started
and self._duration_count % LOG_SLOW_STARTUP_INTERVAL == 0
):
# We log every LOG_SLOW_STARTUP_INTERVAL until all integrations are done
# once we take over LOG_SLOW_STARTUP_INTERVAL (60s) to start up
_LOGGER.warning(
"Waiting on integrations to complete setup: %s",
self._setup_started,
)
_LOGGER.debug("Running timeout Zones: %s", self._hass.timeout.zones)
self._async_schedule_next()
def _async_dispatch(self, remaining_with_setup_started: dict[str, float]) -> None:
"""Dispatch the signal."""
if remaining_with_setup_started or not self._previous_was_empty:
async_dispatcher_send_internal(
self._hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, remaining_with_setup_started
)
self._previous_was_empty = not remaining_with_setup_started
def _async_schedule_next(self) -> None:
"""Schedule the next call."""
self._handle = self._loop.call_later(
SLOW_STARTUP_CHECK_INTERVAL, self._async_watch
)
def async_start(self) -> None:
"""Start watching."""
self._async_schedule_next()
def async_stop(self) -> None:
"""Stop watching."""
self._async_dispatch({})
if self._handle:
self._handle.cancel()
self._handle = None
async def _async_setup_multi_components(
hass: core.HomeAssistant,
domains: set[str],
config: dict[str, Any],
) -> None:
"""Set up multiple domains. Log on failure."""
# Avoid creating tasks for domains that were setup in a previous stage
domains_not_yet_setup = domains - hass.config.components
# Create setup tasks for base platforms first since everything will have
# to wait to be imported, and the sooner we can get the base platforms
# loaded the sooner we can start loading the rest of the integrations.
futures = {
domain: hass.async_create_task_internal(
async_setup_component(hass, domain, config),
f"setup component {domain}",
eager_start=True,
)
for domain in sorted(
domains_not_yet_setup, key=SETUP_ORDER_SORT_KEY, reverse=True
)
}
results = await asyncio.gather(*futures.values(), return_exceptions=True)
for idx, domain in enumerate(futures):
result = results[idx]
if isinstance(result, BaseException):
_LOGGER.error(
"Error setting up integration %s - received exception",
domain,
exc_info=(type(result), result, result.__traceback__),
)

View File

@ -16,7 +16,7 @@
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]",
"requests_exceeded": "The allowed number of requests to Accuweather API has been exceeded. You have to wait or change API Key."
"requests_exceeded": "The allowed number of requests to the AccuWeather API has been exceeded. You have to wait or change the API key."
}
},
"entity": {

View File

@ -6,21 +6,18 @@ from datetime import timedelta
import logging
from homeassistant.components.air_quality import DOMAIN as AIR_QUALITY_PLATFORM
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONF_USE_NEAREST, DOMAIN, MIN_UPDATE_INTERVAL
from .coordinator import AirlyDataUpdateCoordinator
from .coordinator import AirlyConfigEntry, AirlyDataUpdateCoordinator
PLATFORMS = [Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
type AirlyConfigEntry = ConfigEntry[AirlyDataUpdateCoordinator]
async def async_setup_entry(hass: HomeAssistant, entry: AirlyConfigEntry) -> bool:
"""Set up Airly as config entry."""
@ -60,7 +57,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirlyConfigEntry) -> boo
update_interval = timedelta(minutes=MIN_UPDATE_INTERVAL)
coordinator = AirlyDataUpdateCoordinator(
hass, websession, api_key, latitude, longitude, update_interval, use_nearest
hass,
entry,
websession,
api_key,
latitude,
longitude,
update_interval,
use_nearest,
)
await coordinator.async_config_entry_first_refresh()

View File

@ -10,6 +10,7 @@ from aiohttp.client_exceptions import ClientConnectorError
from airly import Airly
from airly.exceptions import AirlyError
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util
@ -27,6 +28,8 @@ from .const import (
_LOGGER = logging.getLogger(__name__)
type AirlyConfigEntry = ConfigEntry[AirlyDataUpdateCoordinator]
def set_update_interval(instances_count: int, requests_remaining: int) -> timedelta:
"""Return data update interval.
@ -58,9 +61,12 @@ def set_update_interval(instances_count: int, requests_remaining: int) -> timede
class AirlyDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str | float | int]]):
"""Define an object to hold Airly data."""
config_entry: AirlyConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AirlyConfigEntry,
session: ClientSession,
api_key: str,
latitude: float,
@ -76,7 +82,13 @@ class AirlyDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str | float | i
self.airly = Airly(api_key, session, language=language)
self.use_nearest = use_nearest
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=update_interval,
)
async def _async_update_data(self) -> dict[str, str | float | int]:
"""Update data via library."""

View File

@ -13,7 +13,7 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant
from . import AirlyConfigEntry
from .coordinator import AirlyConfigEntry
TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_UNIQUE_ID}

View File

@ -24,7 +24,6 @@ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AirlyConfigEntry, AirlyDataUpdateCoordinator
from .const import (
ATTR_ADVICE,
ATTR_API_ADVICE,
@ -52,6 +51,7 @@ from .const import (
SUFFIX_PERCENT,
URL,
)
from .coordinator import AirlyConfigEntry, AirlyDataUpdateCoordinator
PARALLEL_UPDATES = 1

View File

@ -9,8 +9,8 @@ from airly import Airly
from homeassistant.components import system_health
from homeassistant.core import HomeAssistant, callback
from . import AirlyConfigEntry
from .const import DOMAIN
from .coordinator import AirlyConfigEntry
@callback

View File

@ -15,13 +15,11 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .coordinator import AirNowDataUpdateCoordinator
from .coordinator import AirNowConfigEntry, AirNowDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [Platform.SENSOR]
type AirNowConfigEntry = ConfigEntry[AirNowDataUpdateCoordinator]
async def async_setup_entry(hass: HomeAssistant, entry: AirNowConfigEntry) -> bool:
"""Set up AirNow from a config entry."""
@ -38,7 +36,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirNowConfigEntry) -> bo
# Setup the Coordinator
session = async_get_clientsession(hass)
coordinator = AirNowDataUpdateCoordinator(
hass, session, api_key, latitude, longitude, distance, update_interval
hass, entry, session, api_key, latitude, longitude, distance, update_interval
)
# Sync with Coordinator

View File

@ -10,6 +10,7 @@ from pyairnow import WebServiceAPI
from pyairnow.conv import aqi_to_concentration
from pyairnow.errors import AirNowError
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -34,13 +35,18 @@ from .const import (
_LOGGER = logging.getLogger(__name__)
type AirNowConfigEntry = ConfigEntry[AirNowDataUpdateCoordinator]
class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""The AirNow update coordinator."""
config_entry: AirNowConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AirNowConfigEntry,
session: ClientSession,
api_key: str,
latitude: float,
@ -55,7 +61,13 @@ class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
self.airnow = WebServiceAPI(api_key, session=session)
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=update_interval,
)
async def _async_update_data(self) -> dict[str, Any]:
"""Update data via library."""

View File

@ -13,7 +13,7 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant
from . import AirNowConfigEntry
from .coordinator import AirNowConfigEntry
ATTR_LATITUDE_CAP = "Latitude"
ATTR_LONGITUDE_CAP = "Longitude"

View File

@ -25,7 +25,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AirNowConfigEntry, AirNowDataUpdateCoordinator
from .const import (
ATTR_API_AQI,
ATTR_API_AQI_DESCRIPTION,
@ -43,6 +42,7 @@ from .const import (
DOMAIN,
US_TZ_OFFSETS,
)
from .coordinator import AirNowConfigEntry, AirNowDataUpdateCoordinator
ATTRIBUTION = "Data provided by AirNow"

View File

@ -15,7 +15,6 @@ from aioairzone.const import (
)
from aioairzone.localapi import AirzoneLocalApi, ConnectionOptions
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PORT, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import (
@ -25,7 +24,7 @@ from homeassistant.helpers import (
)
from .const import DOMAIN, MANUFACTURER
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
@ -38,8 +37,6 @@ PLATFORMS: list[Platform] = [
_LOGGER = logging.getLogger(__name__)
type AirzoneConfigEntry = ConfigEntry[AirzoneUpdateCoordinator]
async def _async_migrate_unique_ids(
hass: HomeAssistant,
@ -90,7 +87,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirzoneConfigEntry) -> b
)
airzone = AirzoneLocalApi(aiohttp_client.async_get_clientsession(hass), options)
coordinator = AirzoneUpdateCoordinator(hass, airzone)
coordinator = AirzoneUpdateCoordinator(hass, entry, airzone)
await coordinator.async_config_entry_first_refresh()
await _async_migrate_unique_ids(hass, entry, coordinator)

View File

@ -25,8 +25,7 @@ from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneConfigEntry
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
from .entity import AirzoneEntity, AirzoneSystemEntity, AirzoneZoneEntity

View File

@ -50,9 +50,8 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneConfigEntry
from .const import API_TEMPERATURE_STEP, TEMP_UNIT_LIB_TO_HASS
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
from .entity import AirzoneZoneEntity
BASE_FAN_SPEEDS: Final[dict[int, str]] = {

View File

@ -10,6 +10,7 @@ from typing import Any
from aioairzone.exceptions import AirzoneError
from aioairzone.localapi import AirzoneLocalApi
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -19,17 +20,27 @@ SCAN_INTERVAL = timedelta(seconds=60)
_LOGGER = logging.getLogger(__name__)
type AirzoneConfigEntry = ConfigEntry[AirzoneUpdateCoordinator]
class AirzoneUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Class to manage fetching data from the Airzone device."""
def __init__(self, hass: HomeAssistant, airzone: AirzoneLocalApi) -> None:
config_entry: AirzoneConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AirzoneConfigEntry,
airzone: AirzoneLocalApi,
) -> None:
"""Initialize."""
self.airzone = airzone
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
)

View File

@ -10,7 +10,7 @@ from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_UNIQUE_ID
from homeassistant.core import HomeAssistant
from . import AirzoneConfigEntry
from .coordinator import AirzoneConfigEntry
TO_REDACT_API = [
API_MAC,

View File

@ -31,9 +31,8 @@ from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AirzoneConfigEntry
from .const import DOMAIN, MANUFACTURER
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
_LOGGER = logging.getLogger(__name__)

View File

@ -27,8 +27,7 @@ from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneConfigEntry
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
from .entity import AirzoneEntity, AirzoneZoneEntity

View File

@ -30,9 +30,8 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneConfigEntry
from .const import TEMP_UNIT_LIB_TO_HASS
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
from .entity import (
AirzoneEntity,
AirzoneHotWaterEntity,

View File

@ -16,8 +16,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneConfigEntry
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
from .entity import AirzoneEntity, AirzoneZoneEntity

View File

@ -30,9 +30,8 @@ from homeassistant.const import ATTR_TEMPERATURE, STATE_OFF
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AirzoneConfigEntry
from .const import TEMP_UNIT_LIB_TO_HASS
from .coordinator import AirzoneUpdateCoordinator
from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator
from .entity import AirzoneHotWaterEntity
OPERATION_LIB_TO_HASS: Final[dict[HotWaterOperation, str]] = {

View File

@ -2,14 +2,11 @@
import amberelectric
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_TOKEN
from homeassistant.core import HomeAssistant
from .const import CONF_SITE_ID, PLATFORMS
from .coordinator import AmberUpdateCoordinator
type AmberConfigEntry = ConfigEntry[AmberUpdateCoordinator]
from .coordinator import AmberConfigEntry, AmberUpdateCoordinator
async def async_setup_entry(hass: HomeAssistant, entry: AmberConfigEntry) -> bool:
@ -19,7 +16,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AmberConfigEntry) -> boo
api_instance = amberelectric.AmberApi(api_client)
site_id = entry.data[CONF_SITE_ID]
coordinator = AmberUpdateCoordinator(hass, api_instance, site_id)
coordinator = AmberUpdateCoordinator(hass, entry, api_instance, site_id)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -12,9 +12,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AmberConfigEntry
from .const import ATTRIBUTION
from .coordinator import AmberUpdateCoordinator
from .coordinator import AmberConfigEntry, AmberUpdateCoordinator
PRICE_SPIKE_ICONS = {
"none": "mdi:power-plug",

View File

@ -13,11 +13,14 @@ from amberelectric.models.forecast_interval import ForecastInterval
from amberelectric.models.price_descriptor import PriceDescriptor
from amberelectric.rest import ApiException
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import LOGGER
type AmberConfigEntry = ConfigEntry[AmberUpdateCoordinator]
def is_current(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
"""Return true if the supplied interval is a CurrentInterval."""
@ -70,13 +73,20 @@ def normalize_descriptor(descriptor: PriceDescriptor | None) -> str | None:
class AmberUpdateCoordinator(DataUpdateCoordinator):
"""AmberUpdateCoordinator - In charge of downloading the data for a site, which all the sensors read."""
config_entry: AmberConfigEntry
def __init__(
self, hass: HomeAssistant, api: amberelectric.AmberApi, site_id: str
self,
hass: HomeAssistant,
config_entry: AmberConfigEntry,
api: amberelectric.AmberApi,
site_id: str,
) -> None:
"""Initialise the data service."""
super().__init__(
hass,
LOGGER,
config_entry=config_entry,
name="amberelectric",
update_interval=timedelta(minutes=1),
)

View File

@ -22,9 +22,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AmberConfigEntry
from .const import ATTRIBUTION
from .coordinator import AmberUpdateCoordinator, normalize_descriptor
from .coordinator import AmberConfigEntry, AmberUpdateCoordinator, normalize_descriptor
UNIT = f"{CURRENCY_DOLLAR}/{UnitOfEnergy.KILO_WATT_HOUR}"

View File

@ -4,13 +4,10 @@ from __future__ import annotations
from aioambient.open_api import OpenAPI
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from .coordinator import AmbientNetworkDataUpdateCoordinator
type AmbientNetworkConfigEntry = ConfigEntry[AmbientNetworkDataUpdateCoordinator]
from .coordinator import AmbientNetworkConfigEntry, AmbientNetworkDataUpdateCoordinator
PLATFORMS: list[Platform] = [Platform.SENSOR]
@ -21,7 +18,7 @@ async def async_setup_entry(
"""Set up the Ambient Weather Network from a config entry."""
api = OpenAPI()
coordinator = AmbientNetworkDataUpdateCoordinator(hass, api)
coordinator = AmbientNetworkDataUpdateCoordinator(hass, entry, api)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -19,17 +19,27 @@ from .helper import get_station_name
SCAN_INTERVAL = timedelta(minutes=5)
type AmbientNetworkConfigEntry = ConfigEntry[AmbientNetworkDataUpdateCoordinator]
class AmbientNetworkDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""The Ambient Network Data Update Coordinator."""
config_entry: ConfigEntry
config_entry: AmbientNetworkConfigEntry
station_name: str
last_measured: datetime | None = None
def __init__(self, hass: HomeAssistant, api: OpenAPI) -> None:
def __init__(
self, hass: HomeAssistant, config_entry: AmbientNetworkConfigEntry, api: OpenAPI
) -> None:
"""Initialize the coordinator."""
super().__init__(hass, LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
super().__init__(
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
)
self.api = api
async def _async_update_data(self) -> dict[str, Any]:

View File

@ -28,8 +28,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import dt as dt_util
from . import AmbientNetworkConfigEntry
from .coordinator import AmbientNetworkDataUpdateCoordinator
from .coordinator import AmbientNetworkConfigEntry, AmbientNetworkDataUpdateCoordinator
from .entity import AmbientNetworkEntity
TYPE_AQI_PM25 = "aqi_pm25"

View File

@ -48,7 +48,7 @@ async def async_setup_entry(
continue
names[integration] = integrations[integration].title
coordinator = HomeassistantAnalyticsDataUpdateCoordinator(hass, client)
coordinator = HomeassistantAnalyticsDataUpdateCoordinator(hass, entry, client)
await coordinator.async_config_entry_first_refresh()

View File

@ -46,12 +46,16 @@ class HomeassistantAnalyticsDataUpdateCoordinator(DataUpdateCoordinator[Analytic
config_entry: AnalyticsInsightsConfigEntry
def __init__(
self, hass: HomeAssistant, client: HomeassistantAnalyticsClient
self,
hass: HomeAssistant,
config_entry: AnalyticsInsightsConfigEntry,
client: HomeassistantAnalyticsClient,
) -> None:
"""Initialize the Homeassistant Analytics data coordinator."""
super().__init__(
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=timedelta(hours=12),
)

View File

@ -35,6 +35,7 @@ class AndroidIPCamDataUpdateCoordinator(DataUpdateCoordinator[None]):
super().__init__(
self.hass,
_LOGGER,
config_entry=config_entry,
name=f"{DOMAIN} {config_entry.data[CONF_HOST]}",
update_interval=timedelta(seconds=10),
)

View File

@ -35,13 +35,9 @@ async def async_setup_entry(
@callback
def is_available_updated(is_available: bool) -> None:
if is_available:
_LOGGER.info(
"Reconnected to %s at %s", entry.data[CONF_NAME], entry.data[CONF_HOST]
)
else:
_LOGGER.warning(
"Disconnected from %s at %s",
"%s %s at %s",
"Reconnected to" if is_available else "Disconnected from",
entry.data[CONF_NAME],
entry.data[CONF_HOST],
)

View File

@ -18,8 +18,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client
from .coordinator import AnovaCoordinator
from .models import AnovaConfigEntry, AnovaData
from .coordinator import AnovaConfigEntry, AnovaCoordinator, AnovaData
PLATFORMS = [Platform.SENSOR]
@ -59,7 +58,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AnovaConfigEntry) -> boo
# websocket client
assert api.websocket_handler is not None
devices = list(api.websocket_handler.devices.values())
coordinators = [AnovaCoordinator(hass, device) for device in devices]
coordinators = [AnovaCoordinator(hass, entry, device) for device in devices]
entry.runtime_data = AnovaData(api_jwt=api.jwt, coordinators=coordinators, api=api)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True

View File

@ -1,8 +1,9 @@
"""Support for Anova Coordinators."""
from dataclasses import dataclass
import logging
from anova_wifi import APCUpdate, APCWifiDevice
from anova_wifi import AnovaApi, APCUpdate, APCWifiDevice
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -14,15 +15,33 @@ from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
@dataclass
class AnovaData:
"""Data for the Anova integration."""
api_jwt: str
coordinators: list["AnovaCoordinator"]
api: AnovaApi
type AnovaConfigEntry = ConfigEntry[AnovaData]
class AnovaCoordinator(DataUpdateCoordinator[APCUpdate]):
"""Anova custom coordinator."""
config_entry: ConfigEntry
config_entry: AnovaConfigEntry
def __init__(self, hass: HomeAssistant, anova_device: APCWifiDevice) -> None:
def __init__(
self,
hass: HomeAssistant,
config_entry: AnovaConfigEntry,
anova_device: APCWifiDevice,
) -> None:
"""Set up Anova Coordinator."""
super().__init__(
hass,
config_entry=config_entry,
name="Anova Precision Cooker",
logger=_LOGGER,
)

View File

@ -1,20 +0,0 @@
"""Dataclass models for the Anova integration."""
from dataclasses import dataclass
from anova_wifi import AnovaApi
from homeassistant.config_entries import ConfigEntry
from .coordinator import AnovaCoordinator
type AnovaConfigEntry = ConfigEntry[AnovaData]
@dataclass
class AnovaData:
"""Data for the Anova integration."""
api_jwt: str
coordinators: list[AnovaCoordinator]
api: AnovaApi

View File

@ -18,9 +18,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .coordinator import AnovaCoordinator
from .coordinator import AnovaConfigEntry, AnovaCoordinator
from .entity import AnovaDescriptionEntity
from .models import AnovaConfigEntry
@dataclass(frozen=True, kw_only=True)

View File

@ -4,13 +4,10 @@ from __future__ import annotations
from typing import Final
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
from homeassistant.core import HomeAssistant
from .coordinator import APCUPSdCoordinator
type APCUPSdConfigEntry = ConfigEntry[APCUPSdCoordinator]
from .coordinator import APCUPSdConfigEntry, APCUPSdCoordinator
PLATFORMS: Final = (Platform.BINARY_SENSOR, Platform.SENSOR)
@ -20,7 +17,7 @@ async def async_setup_entry(
) -> bool:
"""Use config values to set up a function enabling status retrieval."""
host, port = config_entry.data[CONF_HOST], config_entry.data[CONF_PORT]
coordinator = APCUPSdCoordinator(hass, host, port)
coordinator = APCUPSdCoordinator(hass, config_entry, host, port)
await coordinator.async_config_entry_first_refresh()

View File

@ -12,8 +12,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import APCUPSdConfigEntry
from .coordinator import APCUPSdCoordinator
from .coordinator import APCUPSdConfigEntry, APCUPSdCoordinator
PARALLEL_UPDATES = 0

View File

@ -25,6 +25,8 @@ _LOGGER = logging.getLogger(__name__)
UPDATE_INTERVAL: Final = timedelta(seconds=60)
REQUEST_REFRESH_COOLDOWN: Final = 5
type APCUPSdConfigEntry = ConfigEntry[APCUPSdCoordinator]
class APCUPSdData(dict[str, str]):
"""Store data about an APCUPSd and provide a few helper methods for easier accesses."""
@ -57,13 +59,20 @@ class APCUPSdCoordinator(DataUpdateCoordinator[APCUPSdData]):
updates from the server.
"""
config_entry: ConfigEntry
config_entry: APCUPSdConfigEntry
def __init__(self, hass: HomeAssistant, host: str, port: int) -> None:
def __init__(
self,
hass: HomeAssistant,
config_entry: APCUPSdConfigEntry,
host: str,
port: int,
) -> None:
"""Initialize the data object."""
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=UPDATE_INTERVAL,
request_refresh_debouncer=Debouncer(

View File

@ -7,7 +7,7 @@ from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.core import HomeAssistant
from . import APCUPSdConfigEntry
from .coordinator import APCUPSdConfigEntry
TO_REDACT = {"SERIALNO", "HOSTNAME"}

View File

@ -24,9 +24,8 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import APCUPSdConfigEntry
from .const import LAST_S_TEST
from .coordinator import APCUPSdCoordinator
from .coordinator import APCUPSdConfigEntry, APCUPSdCoordinator
PARALLEL_UPDATES = 0

View File

@ -5,18 +5,15 @@ from __future__ import annotations
from aioaquacell import AquacellApi
from aioaquacell.const import Brand
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONF_BRAND
from .coordinator import AquacellCoordinator
from .coordinator import AquacellConfigEntry, AquacellCoordinator
PLATFORMS = [Platform.SENSOR]
type AquacellConfigEntry = ConfigEntry[AquacellCoordinator]
async def async_setup_entry(hass: HomeAssistant, entry: AquacellConfigEntry) -> bool:
"""Set up Aquacell from a config entry."""
@ -26,7 +23,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AquacellConfigEntry) ->
aquacell_api = AquacellApi(session, brand)
coordinator = AquacellCoordinator(hass, aquacell_api)
coordinator = AquacellCoordinator(hass, entry, aquacell_api)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
@ -36,6 +33,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: AquacellConfigEntry) ->
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: AquacellConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

View File

@ -26,17 +26,25 @@ from .const import (
_LOGGER = logging.getLogger(__name__)
type AquacellConfigEntry = ConfigEntry[AquacellCoordinator]
class AquacellCoordinator(DataUpdateCoordinator[dict[str, Softener]]):
"""My aquacell coordinator."""
config_entry: ConfigEntry
config_entry: AquacellConfigEntry
def __init__(self, hass: HomeAssistant, aquacell_api: AquacellApi) -> None:
def __init__(
self,
hass: HomeAssistant,
config_entry: AquacellConfigEntry,
aquacell_api: AquacellApi,
) -> None:
"""Initialize coordinator."""
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name="Aquacell Coordinator",
update_interval=UPDATE_INTERVAL,
)

View File

@ -18,8 +18,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import AquacellConfigEntry
from .coordinator import AquacellCoordinator
from .coordinator import AquacellConfigEntry, AquacellCoordinator
from .entity import AquacellEntity
PARALLEL_UPDATES = 1

View File

@ -13,7 +13,7 @@ PLATFORMS: list[Platform] = [Platform.SENSOR]
async def async_setup_entry(hass: HomeAssistant, entry: ArveConfigEntry) -> bool:
"""Set up Arve from a config entry."""
coordinator = ArveCoordinator(hass)
coordinator = ArveCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()

View File

@ -30,11 +30,12 @@ class ArveCoordinator(DataUpdateCoordinator[ArveSensProData]):
config_entry: ArveConfigEntry
devices: ArveDevices
def __init__(self, hass: HomeAssistant) -> None:
def __init__(self, hass: HomeAssistant, config_entry: ArveConfigEntry) -> None:
"""Initialize Arve coordinator."""
super().__init__(
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=timedelta(seconds=60),
)

View File

@ -1093,16 +1093,18 @@ class PipelineRun:
agent_id = conversation.HOME_ASSISTANT_AGENT
processed_locally = True
# It was already handled, create response and add to chat history
if intent_response is not None:
with (
chat_session.async_get_chat_session(
self.hass, user_input.conversation_id
) as session,
conversation.async_get_chat_log(
self.hass, session, user_input
self.hass,
session,
user_input,
) as chat_log,
):
# It was already handled, create response and add to chat history
if intent_response is not None:
speech: str = intent_response.speech.get("plain", {}).get(
"speech", ""
)

View File

@ -23,7 +23,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AuroraAbbConfigEntry) ->
comport = entry.data[CONF_PORT]
address = entry.data[CONF_ADDRESS]
coordinator = AuroraAbbDataUpdateCoordinator(hass, comport, address)
coordinator = AuroraAbbDataUpdateCoordinator(hass, entry, comport, address)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator

View File

@ -21,12 +21,26 @@ type AuroraAbbConfigEntry = ConfigEntry[AuroraAbbDataUpdateCoordinator]
class AuroraAbbDataUpdateCoordinator(DataUpdateCoordinator[dict[str, float]]):
"""Class to manage fetching AuroraAbbPowerone data."""
def __init__(self, hass: HomeAssistant, comport: str, address: int) -> None:
config_entry: AuroraAbbConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AuroraAbbConfigEntry,
comport: str,
address: int,
) -> None:
"""Initialize the data update coordinator."""
self.available_prev = False
self.available = False
self.client = AuroraSerialClient(address, comport, parity="N", timeout=1)
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
)
def _update_data(self) -> dict[str, float]:
"""Fetch new state data for the sensors.

View File

@ -45,7 +45,7 @@ async def async_setup_entry(
# Initiate a Data Update Coordinator for each service
for service in services:
service["coordinator"] = AussieBroadbandDataUpdateCoordinator(
hass, client, service["service_id"]
hass, entry, client, service["service_id"]
)
await service["coordinator"].async_config_entry_first_refresh()

View File

@ -34,11 +34,20 @@ type AussieBroadbandConfigEntry = ConfigEntry[list[AussieBroadbandServiceData]]
class AussieBroadbandDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Aussie Broadand data update coordinator."""
def __init__(self, hass: HomeAssistant, client: AussieBB, service_id: str) -> None:
config_entry: AussieBroadbandConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AussieBroadbandConfigEntry,
client: AussieBB,
service_id: str,
) -> None:
"""Initialize Atag coordinator."""
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=f"Aussie Broadband {service_id}",
update_interval=timedelta(minutes=DEFAULT_UPDATE_INTERVAL),
)

View File

@ -6,18 +6,15 @@ import asyncio
from autarco import Autarco, AutarcoConnectionError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .coordinator import AutarcoDataUpdateCoordinator
from .coordinator import AutarcoConfigEntry, AutarcoDataUpdateCoordinator
PLATFORMS: list[Platform] = [Platform.SENSOR]
type AutarcoConfigEntry = ConfigEntry[list[AutarcoDataUpdateCoordinator]]
async def async_setup_entry(hass: HomeAssistant, entry: AutarcoConfigEntry) -> bool:
"""Set up Autarco from a config entry."""
@ -34,7 +31,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: AutarcoConfigEntry) -> b
raise ConfigEntryNotReady from err
coordinators: list[AutarcoDataUpdateCoordinator] = [
AutarcoDataUpdateCoordinator(hass, client, site) for site in account_sites
AutarcoDataUpdateCoordinator(hass, entry, client, site)
for site in account_sites
]
await asyncio.gather(

View File

@ -22,6 +22,8 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
from .const import DOMAIN, LOGGER, SCAN_INTERVAL
type AutarcoConfigEntry = ConfigEntry[list[AutarcoDataUpdateCoordinator]]
class AutarcoData(NamedTuple):
"""Class for defining data in dict."""
@ -35,11 +37,12 @@ class AutarcoData(NamedTuple):
class AutarcoDataUpdateCoordinator(DataUpdateCoordinator[AutarcoData]):
"""Class to manage fetching Autarco data from the API."""
config_entry: ConfigEntry
config_entry: AutarcoConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: AutarcoConfigEntry,
client: Autarco,
account_site: AccountSite,
) -> None:
@ -47,6 +50,7 @@ class AutarcoDataUpdateCoordinator(DataUpdateCoordinator[AutarcoData]):
super().__init__(
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
)

View File

@ -6,7 +6,7 @@ from typing import Any
from homeassistant.core import HomeAssistant
from . import AutarcoConfigEntry, AutarcoDataUpdateCoordinator
from .coordinator import AutarcoConfigEntry, AutarcoDataUpdateCoordinator
async def async_get_config_entry_diagnostics(

View File

@ -20,9 +20,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AutarcoConfigEntry
from .const import DOMAIN
from .coordinator import AutarcoDataUpdateCoordinator
from .coordinator import AutarcoConfigEntry, AutarcoDataUpdateCoordinator
@dataclass(frozen=True, kw_only=True)

View File

@ -9,9 +9,7 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from .const import CONF_PAT, CONF_PROJECT
from .coordinator import AzureDevOpsDataUpdateCoordinator
type AzureDevOpsConfigEntry = ConfigEntry[AzureDevOpsDataUpdateCoordinator]
from .coordinator import AzureDevOpsConfigEntry, AzureDevOpsDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
@ -22,11 +20,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AzureDevOpsConfigEntry)
"""Set up Azure DevOps from a config entry."""
# Create the data update coordinator
coordinator = AzureDevOpsDataUpdateCoordinator(
hass,
_LOGGER,
entry=entry,
)
coordinator = AzureDevOpsDataUpdateCoordinator(hass, entry, _LOGGER)
# Store the coordinator in runtime data
entry.runtime_data = coordinator

View File

@ -28,6 +28,8 @@ from .data import AzureDevOpsData
BUILDS_QUERY: Final = "?queryOrder=queueTimeDescending&maxBuildsPerDefinition=1"
IGNORED_CATEGORIES: Final[list[Category]] = [Category.COMPLETED, Category.REMOVED]
type AzureDevOpsConfigEntry = ConfigEntry[AzureDevOpsDataUpdateCoordinator]
def ado_exception_none_handler(func: Callable) -> Callable:
"""Handle exceptions or None to always return a value or raise."""
@ -50,28 +52,29 @@ class AzureDevOpsDataUpdateCoordinator(DataUpdateCoordinator[AzureDevOpsData]):
"""Class to manage and fetch Azure DevOps data."""
client: DevOpsClient
config_entry: AzureDevOpsConfigEntry
organization: str
project: Project
def __init__(
self,
hass: HomeAssistant,
config_entry: AzureDevOpsConfigEntry,
logger: logging.Logger,
*,
entry: ConfigEntry,
) -> None:
"""Initialize global Azure DevOps data updater."""
self.title = entry.title
self.title = config_entry.title
super().__init__(
hass=hass,
logger=logger,
config_entry=config_entry,
name=DOMAIN,
update_interval=timedelta(seconds=300),
)
self.client = DevOpsClient(session=async_get_clientsession(hass))
self.organization = entry.data[CONF_ORG]
self.organization = config_entry.data[CONF_ORG]
@ado_exception_none_handler
async def authorize(

View File

@ -21,8 +21,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util import dt as dt_util
from . import AzureDevOpsConfigEntry
from .coordinator import AzureDevOpsDataUpdateCoordinator
from .coordinator import AzureDevOpsConfigEntry, AzureDevOpsDataUpdateCoordinator
from .entity import AzureDevOpsEntity
_LOGGER = logging.getLogger(__name__)

View File

@ -85,7 +85,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: BlinkConfigEntry) -> boo
auth_data = deepcopy(dict(entry.data))
blink.auth = Auth(auth_data, no_prompt=True, session=session)
blink.refresh_rate = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
coordinator = BlinkUpdateCoordinator(hass, blink)
coordinator = BlinkUpdateCoordinator(hass, entry, blink)
try:
await blink.start()

View File

@ -23,12 +23,17 @@ type BlinkConfigEntry = ConfigEntry[BlinkUpdateCoordinator]
class BlinkUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""BlinkUpdateCoordinator - In charge of downloading the data for a site."""
def __init__(self, hass: HomeAssistant, api: Blink) -> None:
config_entry: BlinkConfigEntry
def __init__(
self, hass: HomeAssistant, config_entry: BlinkConfigEntry, api: Blink
) -> None:
"""Initialize the data service."""
self.api = api
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=timedelta(seconds=SCAN_INTERVAL),
)

View File

@ -7,14 +7,11 @@ from typing import Final
from aiohttp import CookieJar
from pybravia import BraviaClient
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_MAC, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from .coordinator import BraviaTVCoordinator
BraviaTVConfigEntry = ConfigEntry[BraviaTVCoordinator]
from .coordinator import BraviaTVConfigEntry, BraviaTVCoordinator
PLATFORMS: Final[list[Platform]] = [
Platform.BUTTON,
@ -36,8 +33,8 @@ async def async_setup_entry(
client = BraviaClient(host, mac, session=session)
coordinator = BraviaTVCoordinator(
hass=hass,
config_entry=config_entry,
client=client,
config=config_entry.data,
)
config_entry.async_on_unload(config_entry.add_update_listener(update_listener))

View File

@ -14,8 +14,7 @@ from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BraviaTVConfigEntry
from .coordinator import BraviaTVCoordinator
from .coordinator import BraviaTVConfigEntry, BraviaTVCoordinator
from .entity import BraviaTVEntity

View File

@ -6,7 +6,6 @@ from collections.abc import Awaitable, Callable, Coroutine, Iterable
from datetime import datetime, timedelta
from functools import wraps
import logging
from types import MappingProxyType
from typing import Any, Concatenate, Final
from pybravia import (
@ -20,6 +19,7 @@ from pybravia import (
)
from homeassistant.components.media_player import MediaType
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_CLIENT_ID, CONF_PIN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
@ -39,6 +39,8 @@ _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL: Final = timedelta(seconds=10)
type BraviaTVConfigEntry = ConfigEntry["BraviaTVCoordinator"]
def catch_braviatv_errors[_BraviaTVCoordinatorT: BraviaTVCoordinator, **_P](
func: Callable[Concatenate[_BraviaTVCoordinatorT, _P], Awaitable[None]],
@ -64,19 +66,21 @@ def catch_braviatv_errors[_BraviaTVCoordinatorT: BraviaTVCoordinator, **_P](
class BraviaTVCoordinator(DataUpdateCoordinator[None]):
"""Representation of a Bravia TV Coordinator."""
config_entry: BraviaTVConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: BraviaTVConfigEntry,
client: BraviaClient,
config: MappingProxyType[str, Any],
) -> None:
"""Initialize Bravia TV Client."""
self.client = client
self.pin = config[CONF_PIN]
self.use_psk = config.get(CONF_USE_PSK, False)
self.client_id = config.get(CONF_CLIENT_ID, LEGACY_CLIENT_ID)
self.nickname = config.get(CONF_NICKNAME, NICKNAME_PREFIX)
self.pin = config_entry.data[CONF_PIN]
self.use_psk = config_entry.data.get(CONF_USE_PSK, False)
self.client_id = config_entry.data.get(CONF_CLIENT_ID, LEGACY_CLIENT_ID)
self.nickname = config_entry.data.get(CONF_NICKNAME, NICKNAME_PREFIX)
self.source: str | None = None
self.source_list: list[str] = []
self.source_map: dict[str, dict] = {}
@ -98,6 +102,7 @@ class BraviaTVCoordinator(DataUpdateCoordinator[None]):
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
request_refresh_debouncer=Debouncer(

View File

@ -6,7 +6,7 @@ from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_MAC, CONF_PIN
from homeassistant.core import HomeAssistant
from . import BraviaTVConfigEntry
from .coordinator import BraviaTVConfigEntry
TO_REDACT = {CONF_MAC, CONF_PIN, "macAddr"}

View File

@ -3,8 +3,8 @@
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import BraviaTVCoordinator
from .const import ATTR_MANUFACTURER, DOMAIN
from .coordinator import BraviaTVCoordinator
class BraviaTVEntity(CoordinatorEntity[BraviaTVCoordinator]):

View File

@ -18,8 +18,8 @@ from homeassistant.components.media_player import (
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BraviaTVConfigEntry
from .const import SourceType
from .coordinator import BraviaTVConfigEntry
from .entity import BraviaTVEntity

View File

@ -9,7 +9,7 @@ from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BraviaTVConfigEntry
from .coordinator import BraviaTVConfigEntry
from .entity import BraviaTVEntity

View File

@ -25,7 +25,7 @@
},
"data_description": {
"email": "[%key:component::bring::config::step::user::data_description::email%]",
"password": "[%key:component::bring::config::step::user::data_description::email%]"
"password": "[%key:component::bring::config::step::user::data_description::password%]"
}
},
"reconfigure": {
@ -37,7 +37,7 @@
},
"data_description": {
"email": "[%key:component::bring::config::step::user::data_description::email%]",
"password": "[%key:component::bring::config::step::user::data_description::email%]"
"password": "[%key:component::bring::config::step::user::data_description::password%]"
}
}
},

View File

@ -5,17 +5,14 @@ from __future__ import annotations
from brother import Brother, SnmpError
from homeassistant.components.snmp import async_get_snmp_engine
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_TYPE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from .coordinator import BrotherDataUpdateCoordinator
from .coordinator import BrotherConfigEntry, BrotherDataUpdateCoordinator
PLATFORMS = [Platform.SENSOR]
type BrotherConfigEntry = ConfigEntry[BrotherDataUpdateCoordinator]
async def async_setup_entry(hass: HomeAssistant, entry: BrotherConfigEntry) -> bool:
"""Set up Brother from a config entry."""
@ -30,7 +27,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: BrotherConfigEntry) -> b
except (ConnectionError, SnmpError, TimeoutError) as error:
raise ConfigEntryNotReady from error
coordinator = BrotherDataUpdateCoordinator(hass, brother)
coordinator = BrotherDataUpdateCoordinator(hass, entry, brother)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator

View File

@ -5,6 +5,7 @@ import logging
from brother import Brother, BrotherSensors, SnmpError, UnsupportedModelError
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -12,17 +13,24 @@ from .const import DOMAIN, UPDATE_INTERVAL
_LOGGER = logging.getLogger(__name__)
type BrotherConfigEntry = ConfigEntry[BrotherDataUpdateCoordinator]
class BrotherDataUpdateCoordinator(DataUpdateCoordinator[BrotherSensors]):
"""Class to manage fetching Brother data from the printer."""
def __init__(self, hass: HomeAssistant, brother: Brother) -> None:
config_entry: BrotherConfigEntry
def __init__(
self, hass: HomeAssistant, config_entry: BrotherConfigEntry, brother: Brother
) -> None:
"""Initialize."""
self.brother = brother
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=UPDATE_INTERVAL,
)

View File

@ -7,7 +7,7 @@ from typing import Any
from homeassistant.core import HomeAssistant
from . import BrotherConfigEntry
from .coordinator import BrotherConfigEntry
async def async_get_config_entry_diagnostics(

View File

@ -24,8 +24,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import BrotherConfigEntry, BrotherDataUpdateCoordinator
from .const import DOMAIN
from .coordinator import BrotherConfigEntry, BrotherDataUpdateCoordinator
ATTR_COUNTER = "counter"
ATTR_REMAINING_PAGES = "remaining_pages"

View File

@ -38,6 +38,7 @@ class BSBLanUpdateCoordinator(DataUpdateCoordinator[BSBLanCoordinatorData]):
super().__init__(
hass,
logger=LOGGER,
config_entry=config_entry,
name=f"{DOMAIN}_{config_entry.data[CONF_HOST]}",
update_interval=self._get_update_interval(),
)

View File

@ -4,23 +4,20 @@ from __future__ import annotations
from aioelectricitymaps import ElectricityMaps
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .coordinator import CO2SignalCoordinator
from .coordinator import CO2SignalConfigEntry, CO2SignalCoordinator
PLATFORMS = [Platform.SENSOR]
type CO2SignalConfigEntry = ConfigEntry[CO2SignalCoordinator]
async def async_setup_entry(hass: HomeAssistant, entry: CO2SignalConfigEntry) -> bool:
"""Set up CO2 Signal from a config entry."""
session = async_get_clientsession(hass)
coordinator = CO2SignalCoordinator(
hass, ElectricityMaps(token=entry.data[CONF_API_KEY], session=session)
hass, entry, ElectricityMaps(token=entry.data[CONF_API_KEY], session=session)
)
await coordinator.async_config_entry_first_refresh()

View File

@ -22,16 +22,27 @@ from .helpers import fetch_latest_carbon_intensity
_LOGGER = logging.getLogger(__name__)
type CO2SignalConfigEntry = ConfigEntry[CO2SignalCoordinator]
class CO2SignalCoordinator(DataUpdateCoordinator[CarbonIntensityResponse]):
"""Data update coordinator."""
config_entry: ConfigEntry
config_entry: CO2SignalConfigEntry
def __init__(self, hass: HomeAssistant, client: ElectricityMaps) -> None:
def __init__(
self,
hass: HomeAssistant,
config_entry: CO2SignalConfigEntry,
client: ElectricityMaps,
) -> None:
"""Initialize the coordinator."""
super().__init__(
hass, _LOGGER, name=DOMAIN, update_interval=timedelta(minutes=15)
hass,
_LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=timedelta(minutes=15),
)
self.client = client

View File

@ -9,7 +9,7 @@ from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant
from . import CO2SignalConfigEntry
from .coordinator import CO2SignalConfigEntry
TO_REDACT = {CONF_API_KEY}

View File

@ -18,9 +18,8 @@ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import CO2SignalConfigEntry
from .const import ATTRIBUTION, DOMAIN
from .coordinator import CO2SignalCoordinator
from .coordinator import CO2SignalConfigEntry, CO2SignalCoordinator
@dataclass(frozen=True, kw_only=True)

View File

@ -4,7 +4,6 @@ from __future__ import annotations
import asyncio
from datetime import datetime, timedelta
from typing import cast
from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.const import (
@ -43,9 +42,7 @@ async def async_setup_platform(
if not discovery_info:
return
discovery_info = cast(DiscoveryInfoType, discovery_info)
binary_sensor_config = discovery_info
command: str = binary_sensor_config[CONF_COMMAND]
payload_off: str = binary_sensor_config[CONF_PAYLOAD_OFF]
payload_on: str = binary_sensor_config[CONF_PAYLOAD_ON]

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import asyncio
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, Any
from homeassistant.components.cover import CoverEntity
from homeassistant.const import (
@ -41,7 +41,6 @@ async def async_setup_platform(
return
covers = []
discovery_info = cast(DiscoveryInfoType, discovery_info)
entities: dict[str, dict[str, Any]] = {
slugify(discovery_info[CONF_NAME]): discovery_info
}

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import logging
import subprocess
from typing import Any, cast
from typing import Any
from homeassistant.components.notify import BaseNotificationService
from homeassistant.const import CONF_COMMAND
@ -26,7 +26,6 @@ def get_service(
if not discovery_info:
return None
discovery_info = cast(DiscoveryInfoType, discovery_info)
notify_config = discovery_info
command: str = notify_config[CONF_COMMAND]
timeout: int = notify_config[CONF_COMMAND_TIMEOUT]

View File

@ -6,7 +6,7 @@ import asyncio
from collections.abc import Mapping
from datetime import datetime, timedelta
import json
from typing import Any, cast
from typing import Any
from jsonpath import jsonpath
@ -51,9 +51,7 @@ async def async_setup_platform(
if not discovery_info:
return
discovery_info = cast(DiscoveryInfoType, discovery_info)
sensor_config = discovery_info
command: str = sensor_config[CONF_COMMAND]
command_timeout: int = sensor_config[CONF_COMMAND_TIMEOUT]
json_attributes: list[str] | None = sensor_config.get(CONF_JSON_ATTRIBUTES)

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import asyncio
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, Any
from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchEntity
from homeassistant.const import (
@ -40,7 +40,6 @@ async def async_setup_platform(
return
switches = []
discovery_info = cast(DiscoveryInfoType, discovery_info)
entities: dict[str, dict[str, Any]] = {
slugify(discovery_info[CONF_NAME]): discovery_info
}

View File

@ -79,6 +79,9 @@ async def async_converse(
extra_system_prompt: str | None = None,
) -> ConversationResult:
"""Process text and get intent."""
if agent_id is None:
agent_id = HOME_ASSISTANT_AGENT
agent = async_get_agent(hass, agent_id)
if agent is None:

View File

@ -1,9 +1,11 @@
"""Conversation history."""
"""Conversation chat log."""
from __future__ import annotations
import asyncio
from collections.abc import AsyncGenerator, Generator
from contextlib import contextmanager
from contextvars import ContextVar
from dataclasses import dataclass, field, replace
import logging
@ -19,10 +21,14 @@ from . import trace
from .const import DOMAIN
from .models import ConversationInput, ConversationResult
DATA_CHAT_HISTORY: HassKey[dict[str, ChatLog]] = HassKey("conversation_chat_log")
DATA_CHAT_LOGS: HassKey[dict[str, ChatLog]] = HassKey("conversation_chat_logs")
LOGGER = logging.getLogger(__name__)
current_chat_log: ContextVar[ChatLog | None] = ContextVar(
"current_chat_log", default=None
)
@contextmanager
def async_get_chat_log(
@ -31,41 +37,50 @@ def async_get_chat_log(
user_input: ConversationInput | None = None,
) -> Generator[ChatLog]:
"""Return chat log for a specific chat session."""
all_history = hass.data.get(DATA_CHAT_HISTORY)
if all_history is None:
all_history = {}
hass.data[DATA_CHAT_HISTORY] = all_history
if chat_log := current_chat_log.get():
# If a chat log is already active and it's the requested conversation ID,
# return that. We won't update the last updated time in this case.
if chat_log.conversation_id == session.conversation_id:
yield chat_log
return
history = all_history.get(session.conversation_id)
all_chat_logs = hass.data.get(DATA_CHAT_LOGS)
if all_chat_logs is None:
all_chat_logs = {}
hass.data[DATA_CHAT_LOGS] = all_chat_logs
if history:
history = replace(history, content=history.content.copy())
chat_log = all_chat_logs.get(session.conversation_id)
if chat_log:
chat_log = replace(chat_log, content=chat_log.content.copy())
else:
history = ChatLog(hass, session.conversation_id)
chat_log = ChatLog(hass, session.conversation_id)
if user_input is not None:
history.async_add_user_content(UserContent(content=user_input.text))
chat_log.async_add_user_content(UserContent(content=user_input.text))
last_message = history.content[-1]
last_message = chat_log.content[-1]
yield history
token = current_chat_log.set(chat_log)
yield chat_log
current_chat_log.reset(token)
if history.content[-1] is last_message:
if chat_log.content[-1] is last_message:
LOGGER.debug(
"History opened but no assistant message was added, ignoring update"
"Chat Log opened but no assistant message was added, ignoring update"
)
return
if session.conversation_id not in all_history:
if session.conversation_id not in all_chat_logs:
@callback
def do_cleanup() -> None:
"""Handle cleanup."""
all_history.pop(session.conversation_id)
all_chat_logs.pop(session.conversation_id)
session.async_on_cleanup(do_cleanup)
all_history[session.conversation_id] = history
all_chat_logs[session.conversation_id] = chat_log
class ConverseError(HomeAssistantError):
@ -112,7 +127,7 @@ class AssistantContent:
role: str = field(init=False, default="assistant")
agent_id: str
content: str
content: str | None = None
tool_calls: list[llm.ToolInput] | None = None
@ -143,6 +158,7 @@ class ChatLog:
@callback
def async_add_user_content(self, content: UserContent) -> None:
"""Add user content to the log."""
LOGGER.debug("Adding user content: %s", content)
self.content.append(content)
@callback
@ -150,14 +166,24 @@ class ChatLog:
self, content: AssistantContent
) -> None:
"""Add assistant content to the log."""
LOGGER.debug("Adding assistant content: %s", content)
if content.tool_calls is not None:
raise ValueError("Tool calls not allowed")
self.content.append(content)
async def async_add_assistant_content(
self, content: AssistantContent
self,
content: AssistantContent,
/,
tool_call_tasks: dict[str, asyncio.Task] | None = None,
) -> AsyncGenerator[ToolResultContent]:
"""Add assistant content."""
"""Add assistant content and execute tool calls.
tool_call_tasks can contains tasks for tool calls that are already in progress.
This method is an async generator and will yield the tool results as they come in.
"""
LOGGER.debug("Adding assistant content: %s", content)
self.content.append(content)
if content.tool_calls is None:
@ -166,13 +192,22 @@ class ChatLog:
if self.llm_api is None:
raise ValueError("No LLM API configured")
if tool_call_tasks is None:
tool_call_tasks = {}
for tool_input in content.tool_calls:
if tool_input.id not in tool_call_tasks:
tool_call_tasks[tool_input.id] = self.hass.async_create_task(
self.llm_api.async_call_tool(tool_input),
name=f"llm_tool_{tool_input.id}",
)
for tool_input in content.tool_calls:
LOGGER.debug(
"Tool call: %s(%s)", tool_input.tool_name, tool_input.tool_args
)
try:
tool_result = await self.llm_api.async_call_tool(tool_input)
tool_result = await tool_call_tasks[tool_input.id]
except (HomeAssistantError, vol.Invalid) as e:
tool_result = {"error": type(e).__name__}
if str(e):

View File

@ -381,7 +381,7 @@ class DefaultAgent(ConversationEntity):
speech: str = response.speech.get("plain", {}).get("speech", "")
chat_log.async_add_assistant_content_without_tools(
AssistantContent(
agent_id=user_input.agent_id, # type: ignore[arg-type]
agent_id=user_input.agent_id,
content=speech,
)
)

View File

@ -195,7 +195,7 @@ async def websocket_hass_agent_debug(
conversation_id=None,
device_id=msg.get("device_id"),
language=msg.get("language", hass.config.language),
agent_id=None,
agent_id=agent.entity_id,
)
result_dict: dict[str, Any] | None = None

View File

@ -37,7 +37,7 @@ class ConversationInput:
language: str
"""Language of the request."""
agent_id: str | None = None
agent_id: str
"""Agent to use for processing."""
extra_system_prompt: str | None = None

View File

@ -6,18 +6,15 @@ from pydiscovergy import Discovergy
from pydiscovergy.authentication import BasicAuth
import pydiscovergy.error as discovergyError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.httpx_client import get_async_client
from .coordinator import DiscovergyUpdateCoordinator
from .coordinator import DiscovergyConfigEntry, DiscovergyUpdateCoordinator
PLATFORMS = [Platform.SENSOR]
type DiscovergyConfigEntry = ConfigEntry[list[DiscovergyUpdateCoordinator]]
async def async_setup_entry(hass: HomeAssistant, entry: DiscovergyConfigEntry) -> bool:
"""Set up Discovergy from a config entry."""
@ -46,6 +43,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: DiscovergyConfigEntry) -
# so we have data when entities are added
coordinator = DiscovergyUpdateCoordinator(
hass=hass,
config_entry=entry,
meter=meter,
discovergy_client=client,
)

View File

@ -9,19 +9,25 @@ from pydiscovergy import Discovergy
from pydiscovergy.error import DiscovergyClientError, HTTPError, InvalidLogin
from pydiscovergy.models import Meter, Reading
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
_LOGGER = logging.getLogger(__name__)
type DiscovergyConfigEntry = ConfigEntry[list[DiscovergyUpdateCoordinator]]
class DiscovergyUpdateCoordinator(DataUpdateCoordinator[Reading]):
"""The Discovergy update coordinator."""
config_entry: DiscovergyConfigEntry
def __init__(
self,
hass: HomeAssistant,
config_entry: DiscovergyConfigEntry,
meter: Meter,
discovergy_client: Discovergy,
) -> None:
@ -32,6 +38,7 @@ class DiscovergyUpdateCoordinator(DataUpdateCoordinator[Reading]):
super().__init__(
hass,
_LOGGER,
config_entry=config_entry,
name=f"Discovergy meter {meter.meter_id}",
update_interval=timedelta(seconds=30),
)

View File

@ -8,7 +8,7 @@ from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.core import HomeAssistant
from . import DiscovergyConfigEntry
from .coordinator import DiscovergyConfigEntry
TO_REDACT_METER = {
"serial_number",

View File

@ -24,9 +24,8 @@ from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import DiscovergyConfigEntry
from .const import DOMAIN, MANUFACTURER
from .coordinator import DiscovergyUpdateCoordinator
from .coordinator import DiscovergyConfigEntry, DiscovergyUpdateCoordinator
PARALLEL_UPDATES = 0

View File

@ -29,7 +29,7 @@ async def async_setup_entry(
f"Unable to connect to Dremel 3D Printer: {ex}"
) from ex
coordinator = Dremel3DPrinterDataUpdateCoordinator(hass, api)
coordinator = Dremel3DPrinterDataUpdateCoordinator(hass, config_entry, api)
await coordinator.async_config_entry_first_refresh()
config_entry.runtime_data = coordinator
platforms = list(PLATFORMS)

View File

@ -18,11 +18,14 @@ class Dremel3DPrinterDataUpdateCoordinator(DataUpdateCoordinator[None]):
config_entry: DremelConfigEntry
def __init__(self, hass: HomeAssistant, api: Dremel3DPrinter) -> None:
def __init__(
self, hass: HomeAssistant, config_entry: DremelConfigEntry, api: Dremel3DPrinter
) -> None:
"""Initialize Dremel 3D Printer data update coordinator."""
super().__init__(
hass=hass,
logger=LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=timedelta(seconds=10),
)

View File

@ -16,7 +16,7 @@ async def async_setup_entry(
device_registry = dr.async_get(hass)
if device_registry.async_get_device(identifiers={(DOMAIN, entry.entry_id)}):
device_registry.async_clear_config_entry(entry.entry_id)
coordinator = DwdWeatherWarningsCoordinator(hass)
coordinator = DwdWeatherWarningsCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator

View File

@ -28,10 +28,16 @@ class DwdWeatherWarningsCoordinator(DataUpdateCoordinator[None]):
config_entry: DwdWeatherWarningsConfigEntry
api: DwdWeatherWarningsAPI
def __init__(self, hass: HomeAssistant) -> None:
def __init__(
self, hass: HomeAssistant, config_entry: DwdWeatherWarningsConfigEntry
) -> None:
"""Initialize the dwd_weather_warnings coordinator."""
super().__init__(
hass, LOGGER, name=DOMAIN, update_interval=DEFAULT_SCAN_INTERVAL
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=DEFAULT_SCAN_INTERVAL,
)
self._device_tracker = None

View File

@ -2,25 +2,22 @@
from __future__ import annotations
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntry
from .const import DOMAIN
from .coordinator import EheimDigitalUpdateCoordinator
from .coordinator import EheimDigitalConfigEntry, EheimDigitalUpdateCoordinator
PLATFORMS = [Platform.CLIMATE, Platform.LIGHT]
type EheimDigitalConfigEntry = ConfigEntry[EheimDigitalUpdateCoordinator]
async def async_setup_entry(
hass: HomeAssistant, entry: EheimDigitalConfigEntry
) -> bool:
"""Set up EHEIM Digital from a config entry."""
coordinator = EheimDigitalUpdateCoordinator(hass)
coordinator = EheimDigitalUpdateCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator

View File

@ -23,9 +23,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import EheimDigitalConfigEntry
from .const import HEATER_BIO_MODE, HEATER_PRESET_TO_HEATER_MODE, HEATER_SMART_MODE
from .coordinator import EheimDigitalUpdateCoordinator
from .coordinator import EheimDigitalConfigEntry, EheimDigitalUpdateCoordinator
from .entity import EheimDigitalEntity
# Coordinator is used to centralize the data updates

View File

@ -22,18 +22,26 @@ type AsyncSetupDeviceEntitiesCallback = Callable[
[str | dict[str, EheimDigitalDevice]], None
]
type EheimDigitalConfigEntry = ConfigEntry[EheimDigitalUpdateCoordinator]
class EheimDigitalUpdateCoordinator(
DataUpdateCoordinator[dict[str, EheimDigitalDevice]]
):
"""The EHEIM Digital data update coordinator."""
config_entry: ConfigEntry
config_entry: EheimDigitalConfigEntry
def __init__(self, hass: HomeAssistant) -> None:
def __init__(
self, hass: HomeAssistant, config_entry: EheimDigitalConfigEntry
) -> None:
"""Initialize the EHEIM Digital data update coordinator."""
super().__init__(
hass, LOGGER, name=DOMAIN, update_interval=DEFAULT_SCAN_INTERVAL
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=DEFAULT_SCAN_INTERVAL,
)
self.hub = EheimDigitalHub(
host=self.config_entry.data[CONF_HOST],

View File

@ -19,9 +19,8 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.color import brightness_to_value, value_to_brightness
from . import EheimDigitalConfigEntry
from .const import EFFECT_DAYCL_MODE, EFFECT_TO_LIGHT_MODE
from .coordinator import EheimDigitalUpdateCoordinator
from .coordinator import EheimDigitalConfigEntry, EheimDigitalUpdateCoordinator
from .entity import EheimDigitalEntity
BRIGHTNESS_SCALE = (1, 100)

View File

@ -2,7 +2,6 @@
from pyemoncms import EmoncmsClient
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_URL, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@ -10,12 +9,10 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from .const import DOMAIN, EMONCMS_UUID_DOC_URL, LOGGER
from .coordinator import EmoncmsCoordinator
from .coordinator import EmonCMSConfigEntry, EmoncmsCoordinator
PLATFORMS: list[Platform] = [Platform.SENSOR]
type EmonCMSConfigEntry = ConfigEntry[EmoncmsCoordinator]
def _migrate_unique_id(
hass: HomeAssistant, entry: EmonCMSConfigEntry, emoncms_unique_id: str
@ -68,7 +65,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: EmonCMSConfigEntry) -> b
session=async_get_clientsession(hass),
)
await _check_unique_id_migration(hass, entry, emoncms_client)
coordinator = EmoncmsCoordinator(hass, emoncms_client)
coordinator = EmoncmsCoordinator(hass, entry, emoncms_client)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
@ -77,11 +74,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: EmonCMSConfigEntry) -> b
return True
async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
async def update_listener(hass: HomeAssistant, entry: EmonCMSConfigEntry):
"""Handle options update."""
await hass.config_entries.async_reload(entry.entry_id)
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: EmonCMSConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

Some files were not shown because too many files have changed in this diff Show More