2020-07-05 22:09:40 +00:00
|
|
|
"""Define Guardian-specific utilities."""
|
2021-04-20 15:40:41 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2024-01-06 22:56:19 +00:00
|
|
|
from collections.abc import Callable, Coroutine, Iterable
|
2022-09-17 21:01:57 +00:00
|
|
|
from dataclasses import dataclass
|
2020-07-05 22:09:40 +00:00
|
|
|
from datetime import timedelta
|
2024-01-06 22:56:19 +00:00
|
|
|
from functools import wraps
|
2024-01-16 22:38:20 +00:00
|
|
|
from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar
|
2020-07-05 22:09:40 +00:00
|
|
|
|
|
|
|
from aioguardian.errors import GuardianError
|
|
|
|
|
2022-07-31 20:10:29 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
|
|
from homeassistant.core import HomeAssistant, callback
|
2024-01-06 22:56:19 +00:00
|
|
|
from homeassistant.exceptions import HomeAssistantError
|
2023-03-01 07:24:56 +00:00
|
|
|
from homeassistant.helpers import entity_registry as er
|
2020-07-05 22:09:40 +00:00
|
|
|
|
2022-09-29 17:24:52 +00:00
|
|
|
from .const import LOGGER
|
2020-07-05 22:09:40 +00:00
|
|
|
|
2024-01-06 22:56:19 +00:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from . import GuardianEntity
|
|
|
|
|
|
|
|
_GuardianEntityT = TypeVar("_GuardianEntityT", bound=GuardianEntity)
|
|
|
|
|
2020-07-05 22:09:40 +00:00
|
|
|
DEFAULT_UPDATE_INTERVAL = timedelta(seconds=30)
|
|
|
|
|
2022-07-31 20:10:29 +00:00
|
|
|
SIGNAL_REBOOT_REQUESTED = "guardian_reboot_requested_{0}"
|
|
|
|
|
2024-01-16 22:38:20 +00:00
|
|
|
_P = ParamSpec("_P")
|
|
|
|
|
2020-07-05 22:09:40 +00:00
|
|
|
|
2022-09-17 21:01:57 +00:00
|
|
|
@dataclass
|
|
|
|
class EntityDomainReplacementStrategy:
|
|
|
|
"""Define an entity replacement."""
|
|
|
|
|
|
|
|
old_domain: str
|
|
|
|
old_unique_id: str
|
|
|
|
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def async_finish_entity_domain_replacements(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
entry: ConfigEntry,
|
|
|
|
entity_replacement_strategies: Iterable[EntityDomainReplacementStrategy],
|
|
|
|
) -> None:
|
|
|
|
"""Remove old entities and create a repairs issue with info on their replacement."""
|
2023-03-01 07:24:56 +00:00
|
|
|
ent_reg = er.async_get(hass)
|
2022-09-17 21:01:57 +00:00
|
|
|
for strategy in entity_replacement_strategies:
|
|
|
|
try:
|
|
|
|
[registry_entry] = [
|
|
|
|
registry_entry
|
2024-02-04 20:11:56 +00:00
|
|
|
for registry_entry in er.async_entries_for_config_entry(
|
|
|
|
ent_reg, entry.entry_id
|
|
|
|
)
|
|
|
|
if registry_entry.domain == strategy.old_domain
|
2022-09-17 21:01:57 +00:00
|
|
|
and registry_entry.unique_id == strategy.old_unique_id
|
|
|
|
]
|
|
|
|
except ValueError:
|
|
|
|
continue
|
|
|
|
|
|
|
|
old_entity_id = registry_entry.entity_id
|
2024-01-04 20:50:45 +00:00
|
|
|
LOGGER.info('Removing old entity: "%s"', old_entity_id)
|
|
|
|
ent_reg.async_remove(old_entity_id)
|
2022-09-17 21:01:57 +00:00
|
|
|
|
|
|
|
|
2024-01-06 22:56:19 +00:00
|
|
|
@callback
|
|
|
|
def convert_exceptions_to_homeassistant_error(
|
|
|
|
func: Callable[Concatenate[_GuardianEntityT, _P], Coroutine[Any, Any, Any]],
|
|
|
|
) -> Callable[Concatenate[_GuardianEntityT, _P], Coroutine[Any, Any, None]]:
|
|
|
|
"""Decorate to handle exceptions from the Guardian API."""
|
|
|
|
|
|
|
|
@wraps(func)
|
|
|
|
async def wrapper(
|
|
|
|
entity: _GuardianEntityT, *args: _P.args, **kwargs: _P.kwargs
|
|
|
|
) -> None:
|
|
|
|
"""Wrap the provided function."""
|
|
|
|
try:
|
|
|
|
await func(entity, *args, **kwargs)
|
|
|
|
except GuardianError as err:
|
|
|
|
raise HomeAssistantError(
|
|
|
|
f"Error while calling {func.__name__}: {err}"
|
|
|
|
) from err
|
|
|
|
|
|
|
|
return wrapper
|