Files
core/homeassistant/components/sfr_box/button.py
T

111 lines
3.1 KiB
Python

"""SFR Box button platform."""
from collections.abc import Awaitable, Callable, Coroutine
from dataclasses import dataclass
from functools import wraps
from typing import Any, Concatenate, override
from sfrbox_api.bridge import SFRBox
from sfrbox_api.exceptions import SFRBoxError
from sfrbox_api.models import SystemInfo
from homeassistant.components.button import (
ButtonDeviceClass,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .coordinator import SFRConfigEntry
from .entity import SFREntity
# Coordinator is used to centralize the data updates
# but better to queue action calls to avoid conflicts
PARALLEL_UPDATES = 1
def with_error_wrapping[**_P, _R](
func: Callable[Concatenate[SFRBoxButton, _P], Awaitable[_R]],
) -> Callable[Concatenate[SFRBoxButton, _P], Coroutine[Any, Any, _R]]:
"""Catch SFR errors."""
@wraps(func)
async def wrapper(
self: SFRBoxButton,
*args: _P.args,
**kwargs: _P.kwargs,
) -> _R:
"""Catch SFRBoxError errors and raise HomeAssistantError."""
try:
return await func(self, *args, **kwargs)
except SFRBoxError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="unknown_error",
translation_placeholders={"error": str(err)},
) from err
return wrapper
@dataclass(frozen=True, kw_only=True)
class SFRBoxButtonEntityDescription(ButtonEntityDescription):
"""Description for SFR Box buttons."""
async_press: Callable[[SFRBox], Coroutine[None, None, None]]
BUTTON_TYPES: tuple[SFRBoxButtonEntityDescription, ...] = (
SFRBoxButtonEntityDescription(
async_press=lambda x: x.system_reboot(),
device_class=ButtonDeviceClass.RESTART,
entity_category=EntityCategory.CONFIG,
key="system_reboot",
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: SFRConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the buttons."""
data = entry.runtime_data
if not data.has_authentication:
# All buttons currently require authentication
return
system_info = data.system.data
entities = [
SFRBoxButton(data.box, description, system_info) for description in BUTTON_TYPES
]
async_add_entities(entities)
class SFRBoxButton(SFREntity, ButtonEntity):
"""SFR Box button."""
entity_description: SFRBoxButtonEntityDescription
def __init__(
self,
box: SFRBox,
description: SFRBoxButtonEntityDescription,
system_info: SystemInfo,
) -> None:
"""Initialize the button."""
super().__init__(description, system_info)
self._box = box
@with_error_wrapping
@override
async def async_press(self) -> None:
"""Process the button press."""
await self.entity_description.async_press(self._box)