mirror of
https://github.com/home-assistant/core.git
synced 2025-07-03 19:37:10 +00:00
Replace Guardian reboot
and reset_valve_diagnostics
services with buttons (#75028)
This commit is contained in:
parent
d40978742c
commit
b54fe14a10
@ -450,6 +450,7 @@ omit =
|
|||||||
homeassistant/components/gtfs/sensor.py
|
homeassistant/components/gtfs/sensor.py
|
||||||
homeassistant/components/guardian/__init__.py
|
homeassistant/components/guardian/__init__.py
|
||||||
homeassistant/components/guardian/binary_sensor.py
|
homeassistant/components/guardian/binary_sensor.py
|
||||||
|
homeassistant/components/guardian/button.py
|
||||||
homeassistant/components/guardian/sensor.py
|
homeassistant/components/guardian/sensor.py
|
||||||
homeassistant/components/guardian/switch.py
|
homeassistant/components/guardian/switch.py
|
||||||
homeassistant/components/guardian/util.py
|
homeassistant/components/guardian/util.py
|
||||||
|
@ -88,8 +88,7 @@ SERVICE_UPGRADE_FIRMWARE_SCHEMA = vol.Schema(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR, Platform.SWITCH]
|
||||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR, Platform.SWITCH]
|
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -106,6 +105,25 @@ def async_get_entry_id_for_service_call(hass: HomeAssistant, call: ServiceCall)
|
|||||||
raise ValueError(f"No client for device ID: {device_id}")
|
raise ValueError(f"No client for device ID: {device_id}")
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_log_deprecated_service_call(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
call: ServiceCall,
|
||||||
|
alternate_service: str,
|
||||||
|
alternate_target: str,
|
||||||
|
) -> None:
|
||||||
|
"""Log a warning about a deprecated service call."""
|
||||||
|
LOGGER.warning(
|
||||||
|
(
|
||||||
|
'The "%s" service is deprecated and will be removed in a future version; '
|
||||||
|
'use the "%s" service and pass it a target entity ID of "%s"'
|
||||||
|
),
|
||||||
|
f"{call.domain}.{call.service}",
|
||||||
|
alternate_service,
|
||||||
|
alternate_target,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up Elexa Guardian from a config entry."""
|
"""Set up Elexa Guardian from a config entry."""
|
||||||
client = Client(entry.data[CONF_IP_ADDRESS], port=entry.data[CONF_PORT])
|
client = Client(entry.data[CONF_IP_ADDRESS], port=entry.data[CONF_PORT])
|
||||||
@ -164,17 +182,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def extract_client(func: Callable) -> Callable:
|
def hydrate_with_entry_and_client(func: Callable) -> Callable:
|
||||||
"""Define a decorator to get the correct client for a service call."""
|
"""Define a decorator to hydrate a method with args based on service call."""
|
||||||
|
|
||||||
async def wrapper(call: ServiceCall) -> None:
|
async def wrapper(call: ServiceCall) -> None:
|
||||||
"""Wrap the service function."""
|
"""Wrap the service function."""
|
||||||
entry_id = async_get_entry_id_for_service_call(hass, call)
|
entry_id = async_get_entry_id_for_service_call(hass, call)
|
||||||
client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
|
client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
|
||||||
|
entry = hass.config_entries.async_get_entry(entry_id)
|
||||||
|
assert entry
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with client:
|
async with client:
|
||||||
await func(call, client)
|
await func(call, entry, client)
|
||||||
except GuardianError as err:
|
except GuardianError as err:
|
||||||
raise HomeAssistantError(
|
raise HomeAssistantError(
|
||||||
f"Error while executing {func.__name__}: {err}"
|
f"Error while executing {func.__name__}: {err}"
|
||||||
@ -182,48 +202,76 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_disable_ap(call: ServiceCall, client: Client) -> None:
|
async def async_disable_ap(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Disable the onboard AP."""
|
"""Disable the onboard AP."""
|
||||||
await client.wifi.disable_ap()
|
await client.wifi.disable_ap()
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_enable_ap(call: ServiceCall, client: Client) -> None:
|
async def async_enable_ap(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Enable the onboard AP."""
|
"""Enable the onboard AP."""
|
||||||
await client.wifi.enable_ap()
|
await client.wifi.enable_ap()
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_pair_sensor(call: ServiceCall, client: Client) -> None:
|
async def async_pair_sensor(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Add a new paired sensor."""
|
"""Add a new paired sensor."""
|
||||||
entry_id = async_get_entry_id_for_service_call(hass, call)
|
paired_sensor_manager = hass.data[DOMAIN][entry.entry_id][
|
||||||
paired_sensor_manager = hass.data[DOMAIN][entry_id][DATA_PAIRED_SENSOR_MANAGER]
|
DATA_PAIRED_SENSOR_MANAGER
|
||||||
|
]
|
||||||
uid = call.data[CONF_UID]
|
uid = call.data[CONF_UID]
|
||||||
|
|
||||||
await client.sensor.pair_sensor(uid)
|
await client.sensor.pair_sensor(uid)
|
||||||
await paired_sensor_manager.async_pair_sensor(uid)
|
await paired_sensor_manager.async_pair_sensor(uid)
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_reboot(call: ServiceCall, client: Client) -> None:
|
async def async_reboot(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Reboot the valve controller."""
|
"""Reboot the valve controller."""
|
||||||
|
async_log_deprecated_service_call(
|
||||||
|
hass,
|
||||||
|
call,
|
||||||
|
"button.press",
|
||||||
|
f"button.guardian_valve_controller_{entry.data[CONF_UID]}_reboot",
|
||||||
|
)
|
||||||
await client.system.reboot()
|
await client.system.reboot()
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_reset_valve_diagnostics(call: ServiceCall, client: Client) -> None:
|
async def async_reset_valve_diagnostics(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Fully reset system motor diagnostics."""
|
"""Fully reset system motor diagnostics."""
|
||||||
|
async_log_deprecated_service_call(
|
||||||
|
hass,
|
||||||
|
call,
|
||||||
|
"button.press",
|
||||||
|
f"button.guardian_valve_controller_{entry.data[CONF_UID]}_reset_valve_diagnostics",
|
||||||
|
)
|
||||||
await client.valve.reset()
|
await client.valve.reset()
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_unpair_sensor(call: ServiceCall, client: Client) -> None:
|
async def async_unpair_sensor(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Remove a paired sensor."""
|
"""Remove a paired sensor."""
|
||||||
entry_id = async_get_entry_id_for_service_call(hass, call)
|
paired_sensor_manager = hass.data[DOMAIN][entry.entry_id][
|
||||||
paired_sensor_manager = hass.data[DOMAIN][entry_id][DATA_PAIRED_SENSOR_MANAGER]
|
DATA_PAIRED_SENSOR_MANAGER
|
||||||
|
]
|
||||||
uid = call.data[CONF_UID]
|
uid = call.data[CONF_UID]
|
||||||
|
|
||||||
await client.sensor.unpair_sensor(uid)
|
await client.sensor.unpair_sensor(uid)
|
||||||
await paired_sensor_manager.async_unpair_sensor(uid)
|
await paired_sensor_manager.async_unpair_sensor(uid)
|
||||||
|
|
||||||
@extract_client
|
@hydrate_with_entry_and_client
|
||||||
async def async_upgrade_firmware(call: ServiceCall, client: Client) -> None:
|
async def async_upgrade_firmware(
|
||||||
|
call: ServiceCall, entry: ConfigEntry, client: Client
|
||||||
|
) -> None:
|
||||||
"""Upgrade the device firmware."""
|
"""Upgrade the device firmware."""
|
||||||
await client.system.upgrade_firmware(
|
await client.system.upgrade_firmware(
|
||||||
url=call.data[CONF_URL],
|
url=call.data[CONF_URL],
|
||||||
@ -389,7 +437,6 @@ class GuardianEntity(CoordinatorEntity):
|
|||||||
|
|
||||||
This should be extended by Guardian platforms.
|
This should be extended by Guardian platforms.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class PairedSensorEntity(GuardianEntity):
|
class PairedSensorEntity(GuardianEntity):
|
||||||
@ -454,7 +501,6 @@ class ValveControllerEntity(GuardianEntity):
|
|||||||
|
|
||||||
This should be extended by Guardian platforms.
|
This should be extended by Guardian platforms.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_add_coordinator_update_listener(self, api: str) -> None:
|
def async_add_coordinator_update_listener(self, api: str) -> None:
|
||||||
|
113
homeassistant/components/guardian/button.py
Normal file
113
homeassistant/components/guardian/button.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
"""Buttons for the Elexa Guardian integration."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from aioguardian import Client
|
||||||
|
from aioguardian.errors import GuardianError
|
||||||
|
|
||||||
|
from homeassistant.components.button import (
|
||||||
|
ButtonDeviceClass,
|
||||||
|
ButtonEntity,
|
||||||
|
ButtonEntityDescription,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
|
from . import ValveControllerEntity
|
||||||
|
from .const import DATA_CLIENT, DATA_COORDINATOR, DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GuardianButtonDescriptionMixin:
|
||||||
|
"""Define an entity description mixin for Guardian buttons."""
|
||||||
|
|
||||||
|
push_action: Callable[[Client], Awaitable]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GuardianButtonDescription(
|
||||||
|
ButtonEntityDescription, GuardianButtonDescriptionMixin
|
||||||
|
):
|
||||||
|
"""Describe a Guardian button description."""
|
||||||
|
|
||||||
|
|
||||||
|
BUTTON_KIND_REBOOT = "reboot"
|
||||||
|
BUTTON_KIND_RESET_VALVE_DIAGNOSTICS = "reset_valve_diagnostics"
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_reboot(client: Client) -> None:
|
||||||
|
"""Reboot the Guardian."""
|
||||||
|
await client.system.reboot()
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_valve_reset(client: Client) -> None:
|
||||||
|
"""Reset the valve diagnostics on the Guardian."""
|
||||||
|
await client.valve.reset()
|
||||||
|
|
||||||
|
|
||||||
|
BUTTON_DESCRIPTIONS = (
|
||||||
|
GuardianButtonDescription(
|
||||||
|
key=BUTTON_KIND_REBOOT,
|
||||||
|
name="Reboot",
|
||||||
|
push_action=_async_reboot,
|
||||||
|
),
|
||||||
|
GuardianButtonDescription(
|
||||||
|
key=BUTTON_KIND_RESET_VALVE_DIAGNOSTICS,
|
||||||
|
name="Reset valve diagnostics",
|
||||||
|
push_action=_async_valve_reset,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
|
) -> None:
|
||||||
|
"""Set up Guardian buttons based on a config entry."""
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
GuardianButton(
|
||||||
|
entry,
|
||||||
|
hass.data[DOMAIN][entry.entry_id][DATA_CLIENT],
|
||||||
|
hass.data[DOMAIN][entry.entry_id][DATA_COORDINATOR],
|
||||||
|
description,
|
||||||
|
)
|
||||||
|
for description in BUTTON_DESCRIPTIONS
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class GuardianButton(ValveControllerEntity, ButtonEntity):
|
||||||
|
"""Define a Guardian button."""
|
||||||
|
|
||||||
|
_attr_device_class = ButtonDeviceClass.RESTART
|
||||||
|
_attr_entity_category = EntityCategory.CONFIG
|
||||||
|
|
||||||
|
entity_description: GuardianButtonDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
entry: ConfigEntry,
|
||||||
|
client: Client,
|
||||||
|
coordinators: dict[str, DataUpdateCoordinator],
|
||||||
|
description: GuardianButtonDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
super().__init__(entry, coordinators, description)
|
||||||
|
|
||||||
|
self._client = client
|
||||||
|
|
||||||
|
async def async_press(self) -> None:
|
||||||
|
"""Send out a restart command."""
|
||||||
|
try:
|
||||||
|
async with self._client:
|
||||||
|
await self.entity_description.push_action(self._client)
|
||||||
|
except GuardianError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
f'Error while pressing button "{self.entity_id}": {err}'
|
||||||
|
) from err
|
Loading…
x
Reference in New Issue
Block a user