mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 01:37:08 +00:00
Reorganize Guardian services (#58632)
This commit is contained in:
parent
9aa0994809
commit
3f2519bedf
@ -2,14 +2,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Awaitable
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import cast
|
||||
|
||||
from aioguardian import Client
|
||||
from aioguardian.errors import GuardianError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE_ID,
|
||||
CONF_FILENAME,
|
||||
CONF_IP_ADDRESS,
|
||||
CONF_PORT,
|
||||
CONF_URL,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.entity import DeviceInfo, EntityDescription
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
@ -28,16 +37,66 @@ from .const import (
|
||||
DATA_CLIENT,
|
||||
DATA_COORDINATOR,
|
||||
DATA_COORDINATOR_PAIRED_SENSOR,
|
||||
DATA_PAIRED_SENSOR_MANAGER,
|
||||
DOMAIN,
|
||||
LOGGER,
|
||||
SIGNAL_PAIRED_SENSOR_COORDINATOR_ADDED,
|
||||
)
|
||||
from .util import GuardianDataUpdateCoordinator
|
||||
|
||||
DATA_PAIRED_SENSOR_MANAGER = "paired_sensor_manager"
|
||||
|
||||
SERVICE_NAME_DISABLE_AP = "disable_ap"
|
||||
SERVICE_NAME_ENABLE_AP = "enable_ap"
|
||||
SERVICE_NAME_PAIR_SENSOR = "pair_sensor"
|
||||
SERVICE_NAME_REBOOT = "reboot"
|
||||
SERVICE_NAME_RESET_VALVE_DIAGNOSTICS = "reset_valve_diagnostics"
|
||||
SERVICE_NAME_UNPAIR_SENSOR = "unpair_sensor"
|
||||
SERVICE_NAME_UPGRADE_FIRMWARE = "upgrade_firmware"
|
||||
|
||||
SERVICES = (
|
||||
SERVICE_NAME_DISABLE_AP,
|
||||
SERVICE_NAME_ENABLE_AP,
|
||||
SERVICE_NAME_PAIR_SENSOR,
|
||||
SERVICE_NAME_REBOOT,
|
||||
SERVICE_NAME_RESET_VALVE_DIAGNOSTICS,
|
||||
SERVICE_NAME_UNPAIR_SENSOR,
|
||||
SERVICE_NAME_UPGRADE_FIRMWARE,
|
||||
)
|
||||
|
||||
SERVICE_PAIR_UNPAIR_SENSOR_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||
vol.Required(CONF_UID): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
SERVICE_UPGRADE_FIRMWARE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_DEVICE_ID): cv.string,
|
||||
vol.Optional(CONF_URL): cv.url,
|
||||
vol.Optional(CONF_PORT): cv.port,
|
||||
vol.Optional(CONF_FILENAME): cv.string,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
PLATFORMS = ["binary_sensor", "sensor", "switch"]
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_entry_id_for_service_call(hass: HomeAssistant, call: ServiceCall) -> str:
|
||||
"""Get the entry ID related to a service call (by device ID)."""
|
||||
device_id = call.data[CONF_DEVICE_ID]
|
||||
device_registry = dr.async_get(hass)
|
||||
|
||||
if device_entry := device_registry.async_get(device_id):
|
||||
for entry in hass.config_entries.async_entries(DOMAIN):
|
||||
if entry.entry_id in device_entry.config_entries:
|
||||
return entry.entry_id
|
||||
|
||||
raise ValueError(f"No client for device ID: {device_id}")
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Elexa Guardian from a config entry."""
|
||||
client = Client(entry.data[CONF_IP_ADDRESS], port=entry.data[CONF_PORT])
|
||||
@ -95,6 +154,97 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
# Set up all of the Guardian entity platforms:
|
||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||
|
||||
@callback
|
||||
def extract_client(func: Callable) -> Callable:
|
||||
"""Define a decorator to get the correct client for a service call."""
|
||||
|
||||
async def wrapper(call: ServiceCall) -> None:
|
||||
"""Wrap the service function."""
|
||||
entry_id = async_get_entry_id_for_service_call(hass, call)
|
||||
client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
|
||||
|
||||
try:
|
||||
async with client:
|
||||
await func(call, client)
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while executing %s: %s", func.__name__, err)
|
||||
|
||||
return wrapper
|
||||
|
||||
@extract_client
|
||||
async def async_disable_ap(call: ServiceCall, client: Client) -> None:
|
||||
"""Disable the onboard AP."""
|
||||
await client.wifi.disable_ap()
|
||||
|
||||
@extract_client
|
||||
async def async_enable_ap(call: ServiceCall, client: Client) -> None:
|
||||
"""Enable the onboard AP."""
|
||||
await client.wifi.enable_ap()
|
||||
|
||||
@extract_client
|
||||
async def async_pair_sensor(call: ServiceCall, client: Client) -> None:
|
||||
"""Add a new paired sensor."""
|
||||
entry_id = async_get_entry_id_for_service_call(hass, call)
|
||||
paired_sensor_manager = hass.data[DOMAIN][entry_id][DATA_PAIRED_SENSOR_MANAGER]
|
||||
uid = call.data[CONF_UID]
|
||||
|
||||
await client.sensor.pair_sensor(uid)
|
||||
await paired_sensor_manager.async_pair_sensor(uid)
|
||||
|
||||
@extract_client
|
||||
async def async_reboot(call: ServiceCall, client: Client) -> None:
|
||||
"""Reboot the valve controller."""
|
||||
await client.system.reboot()
|
||||
|
||||
@extract_client
|
||||
async def async_reset_valve_diagnostics(call: ServiceCall, client: Client) -> None:
|
||||
"""Fully reset system motor diagnostics."""
|
||||
await client.valve.reset()
|
||||
|
||||
@extract_client
|
||||
async def async_unpair_sensor(call: ServiceCall, client: Client) -> None:
|
||||
"""Remove a paired sensor."""
|
||||
entry_id = async_get_entry_id_for_service_call(hass, call)
|
||||
paired_sensor_manager = hass.data[DOMAIN][entry_id][DATA_PAIRED_SENSOR_MANAGER]
|
||||
uid = call.data[CONF_UID]
|
||||
|
||||
await client.sensor.unpair_sensor(uid)
|
||||
await paired_sensor_manager.async_unpair_sensor(uid)
|
||||
|
||||
@extract_client
|
||||
async def async_upgrade_firmware(call: ServiceCall, client: Client) -> None:
|
||||
"""Upgrade the device firmware."""
|
||||
await client.system.upgrade_firmware(
|
||||
url=call.data[CONF_URL],
|
||||
port=call.data[CONF_PORT],
|
||||
filename=call.data[CONF_FILENAME],
|
||||
)
|
||||
|
||||
for service_name, schema, method in (
|
||||
(SERVICE_NAME_DISABLE_AP, None, async_disable_ap),
|
||||
(SERVICE_NAME_ENABLE_AP, None, async_enable_ap),
|
||||
(
|
||||
SERVICE_NAME_PAIR_SENSOR,
|
||||
SERVICE_PAIR_UNPAIR_SENSOR_SCHEMA,
|
||||
async_pair_sensor,
|
||||
),
|
||||
(SERVICE_NAME_REBOOT, None, async_reboot),
|
||||
(SERVICE_NAME_RESET_VALVE_DIAGNOSTICS, None, async_reset_valve_diagnostics),
|
||||
(
|
||||
SERVICE_NAME_UNPAIR_SENSOR,
|
||||
SERVICE_PAIR_UNPAIR_SENSOR_SCHEMA,
|
||||
async_unpair_sensor,
|
||||
),
|
||||
(
|
||||
SERVICE_NAME_UPGRADE_FIRMWARE,
|
||||
SERVICE_UPGRADE_FIRMWARE_SCHEMA,
|
||||
async_upgrade_firmware,
|
||||
),
|
||||
):
|
||||
if hass.services.has_service(DOMAIN, service_name):
|
||||
continue
|
||||
hass.services.async_register(DOMAIN, service_name, method, schema=schema)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@ -104,6 +254,17 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
|
||||
loaded_entries = [
|
||||
entry
|
||||
for entry in hass.config_entries.async_entries(DOMAIN)
|
||||
if entry.state == ConfigEntryState.LOADED
|
||||
]
|
||||
if len(loaded_entries) == 1:
|
||||
# If this is the last loaded instance of Guardian, deregister any services
|
||||
# defined during integration setup:
|
||||
for service_name in SERVICES:
|
||||
hass.services.async_remove(DOMAIN, service_name)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
|
@ -17,6 +17,5 @@ CONF_UID = "uid"
|
||||
DATA_CLIENT = "client"
|
||||
DATA_COORDINATOR = "coordinator"
|
||||
DATA_COORDINATOR_PAIRED_SENSOR = "coordinator_paired_sensor"
|
||||
DATA_PAIRED_SENSOR_MANAGER = "paired_sensor_manager"
|
||||
|
||||
SIGNAL_PAIRED_SENSOR_COORDINATOR_ADDED = "guardian_paired_sensor_coordinator_added_{0}"
|
||||
|
@ -2,25 +2,36 @@
|
||||
disable_ap:
|
||||
name: Disable AP
|
||||
description: Disable the device's onboard access point.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller whose AP should be disabled
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
enable_ap:
|
||||
name: Enable AP
|
||||
description: Enable the device's onboard access point.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
pair_sensor:
|
||||
name: Pair sensor
|
||||
description: Add a new paired sensor to the valve controller.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller whose AP should be enabled
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
pair_sensor:
|
||||
name: Pair Sensor
|
||||
description: Add a new paired sensor to the valve controller.
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller to add the sensor to
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
uid:
|
||||
name: UID
|
||||
description: The UID of the paired sensor
|
||||
@ -31,25 +42,36 @@ pair_sensor:
|
||||
reboot:
|
||||
name: Reboot
|
||||
description: Reboot the device.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
reset_valve_diagnostics:
|
||||
name: Reset valve diagnostics
|
||||
description: Fully (and irrecoverably) reset all valve diagnostics.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
unpair_sensor:
|
||||
name: Unpair sensor
|
||||
description: Remove a paired sensor from the valve controller.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller to reboot
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
reset_valve_diagnostics:
|
||||
name: Reset Valve Diagnostics
|
||||
description: Fully (and irrecoverably) reset all valve diagnostics.
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller whose diagnostics should be reset
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
unpair_sensor:
|
||||
name: Unpair Sensor
|
||||
description: Remove a paired sensor from the valve controller.
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller to remove the sensor from
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
uid:
|
||||
name: UID
|
||||
description: The UID of the paired sensor
|
||||
@ -60,11 +82,14 @@ unpair_sensor:
|
||||
upgrade_firmware:
|
||||
name: Upgrade firmware
|
||||
description: Upgrade the device firmware.
|
||||
target:
|
||||
entity:
|
||||
integration: guardian
|
||||
domain: switch
|
||||
fields:
|
||||
device_id:
|
||||
name: Valve Controller
|
||||
description: The valve controller whose firmware should be upgraded
|
||||
required: true
|
||||
selector:
|
||||
device:
|
||||
integration: guardian
|
||||
url:
|
||||
name: URL
|
||||
description: The URL of the server hosting the firmware file.
|
||||
@ -76,7 +101,9 @@ upgrade_firmware:
|
||||
description: The port on which the firmware file is served.
|
||||
example: 443
|
||||
selector:
|
||||
text:
|
||||
number:
|
||||
min: 1
|
||||
max: 65535
|
||||
filename:
|
||||
name: Filename
|
||||
description: The firmware filename.
|
||||
|
@ -5,40 +5,21 @@ from typing import Any
|
||||
|
||||
from aioguardian import Client
|
||||
from aioguardian.errors import GuardianError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_FILENAME, CONF_PORT, CONF_URL
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from . import ValveControllerEntity
|
||||
from .const import (
|
||||
API_VALVE_STATUS,
|
||||
CONF_UID,
|
||||
DATA_CLIENT,
|
||||
DATA_COORDINATOR,
|
||||
DATA_PAIRED_SENSOR_MANAGER,
|
||||
DOMAIN,
|
||||
LOGGER,
|
||||
)
|
||||
from .const import API_VALVE_STATUS, DATA_CLIENT, DATA_COORDINATOR, DOMAIN, LOGGER
|
||||
|
||||
ATTR_AVG_CURRENT = "average_current"
|
||||
ATTR_INST_CURRENT = "instantaneous_current"
|
||||
ATTR_INST_CURRENT_DDT = "instantaneous_current_ddt"
|
||||
ATTR_TRAVEL_COUNT = "travel_count"
|
||||
|
||||
SERVICE_DISABLE_AP = "disable_ap"
|
||||
SERVICE_ENABLE_AP = "enable_ap"
|
||||
SERVICE_PAIR_SENSOR = "pair_sensor"
|
||||
SERVICE_REBOOT = "reboot"
|
||||
SERVICE_RESET_VALVE_DIAGNOSTICS = "reset_valve_diagnostics"
|
||||
SERVICE_UNPAIR_SENSOR = "unpair_sensor"
|
||||
SERVICE_UPGRADE_FIRMWARE = "upgrade_firmware"
|
||||
|
||||
SWITCH_KIND_VALVE = "valve"
|
||||
|
||||
SWITCH_DESCRIPTION_VALVE = SwitchEntityDescription(
|
||||
@ -52,31 +33,6 @@ async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up Guardian switches based on a config entry."""
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
for service_name, schema, method in (
|
||||
(SERVICE_DISABLE_AP, {}, "async_disable_ap"),
|
||||
(SERVICE_ENABLE_AP, {}, "async_enable_ap"),
|
||||
(SERVICE_PAIR_SENSOR, {vol.Required(CONF_UID): cv.string}, "async_pair_sensor"),
|
||||
(SERVICE_REBOOT, {}, "async_reboot"),
|
||||
(SERVICE_RESET_VALVE_DIAGNOSTICS, {}, "async_reset_valve_diagnostics"),
|
||||
(
|
||||
SERVICE_UPGRADE_FIRMWARE,
|
||||
{
|
||||
vol.Optional(CONF_URL): cv.url,
|
||||
vol.Optional(CONF_PORT): cv.port,
|
||||
vol.Optional(CONF_FILENAME): cv.string,
|
||||
},
|
||||
"async_upgrade_firmware",
|
||||
),
|
||||
(
|
||||
SERVICE_UNPAIR_SENSOR,
|
||||
{vol.Required(CONF_UID): cv.string},
|
||||
"async_unpair_sensor",
|
||||
),
|
||||
):
|
||||
platform.async_register_entity_service(service_name, schema, method)
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
ValveControllerSwitch(
|
||||
@ -135,78 +91,6 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
||||
}
|
||||
)
|
||||
|
||||
async def async_disable_ap(self) -> None:
|
||||
"""Disable the device's onboard access point."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.wifi.disable_ap()
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while disabling valve controller AP: %s", err)
|
||||
|
||||
async def async_enable_ap(self) -> None:
|
||||
"""Enable the device's onboard access point."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.wifi.enable_ap()
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while enabling valve controller AP: %s", err)
|
||||
|
||||
async def async_pair_sensor(self, *, uid: str) -> None:
|
||||
"""Add a new paired sensor."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.sensor.pair_sensor(uid)
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while adding paired sensor: %s", err)
|
||||
return
|
||||
|
||||
await self.hass.data[DOMAIN][self._entry.entry_id][
|
||||
DATA_PAIRED_SENSOR_MANAGER
|
||||
].async_pair_sensor(uid)
|
||||
|
||||
async def async_reboot(self) -> None:
|
||||
"""Reboot the device."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.system.reboot()
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while rebooting valve controller: %s", err)
|
||||
|
||||
async def async_reset_valve_diagnostics(self) -> None:
|
||||
"""Fully reset system motor diagnostics."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.valve.reset()
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while resetting valve diagnostics: %s", err)
|
||||
|
||||
async def async_unpair_sensor(self, *, uid: str) -> None:
|
||||
"""Add a new paired sensor."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.sensor.unpair_sensor(uid)
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while removing paired sensor: %s", err)
|
||||
return
|
||||
|
||||
await self.hass.data[DOMAIN][self._entry.entry_id][
|
||||
DATA_PAIRED_SENSOR_MANAGER
|
||||
].async_unpair_sensor(uid)
|
||||
|
||||
async def async_upgrade_firmware(
|
||||
self, *, url: str, port: int, filename: str
|
||||
) -> None:
|
||||
"""Upgrade the device firmware."""
|
||||
try:
|
||||
async with self._client:
|
||||
await self._client.system.upgrade_firmware(
|
||||
url=url,
|
||||
port=port,
|
||||
filename=filename,
|
||||
)
|
||||
except GuardianError as err:
|
||||
LOGGER.error("Error while upgrading firmware: %s", err)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the valve off (closed)."""
|
||||
try:
|
||||
|
@ -15,9 +15,6 @@
|
||||
"port": "Port"
|
||||
},
|
||||
"description": "Configure a local Elexa Guardian device."
|
||||
},
|
||||
"zeroconf_confirm": {
|
||||
"description": "Do you want to set up this Guardian device?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user