mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add services to geniushub (#30918)
adds: - `set_zone_override`, and - `set_zone_mode`
This commit is contained in:
parent
8630a076a7
commit
bfa8cb760f
@ -8,6 +8,7 @@ from geniushubclient import GeniusHub
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_MAC,
|
CONF_MAC,
|
||||||
@ -26,11 +27,10 @@ from homeassistant.helpers.dispatcher import (
|
|||||||
)
|
)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.helpers.service import verify_domain_control
|
||||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
ATTR_DURATION = "duration"
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = "geniushub"
|
DOMAIN = "geniushub"
|
||||||
@ -68,6 +68,30 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
{DOMAIN: vol.Any(V3_API_SCHEMA, V1_API_SCHEMA)}, extra=vol.ALLOW_EXTRA
|
{DOMAIN: vol.Any(V3_API_SCHEMA, V1_API_SCHEMA)}, extra=vol.ALLOW_EXTRA
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ATTR_ZONE_MODE = "mode"
|
||||||
|
ATTR_DURATION = "duration"
|
||||||
|
|
||||||
|
SVC_SET_ZONE_MODE = "set_zone_mode"
|
||||||
|
SVC_SET_ZONE_OVERRIDE = "set_zone_override"
|
||||||
|
|
||||||
|
SET_ZONE_MODE_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||||
|
vol.Required(ATTR_ZONE_MODE): vol.In(["off", "timer", "footprint"]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SET_ZONE_OVERRIDE_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||||
|
vol.Required(ATTR_TEMPERATURE): vol.All(
|
||||||
|
vol.Coerce(float), vol.Range(min=4, max=28)
|
||||||
|
),
|
||||||
|
vol.Optional(ATTR_DURATION): vol.All(
|
||||||
|
cv.time_period, vol.Range(min=timedelta(minutes=5), max=timedelta(days=1)),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
|
||||||
"""Create a Genius Hub system."""
|
"""Create a Genius Hub system."""
|
||||||
@ -96,9 +120,45 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
|
|||||||
for platform in ["climate", "water_heater", "sensor", "binary_sensor", "switch"]:
|
for platform in ["climate", "water_heater", "sensor", "binary_sensor", "switch"]:
|
||||||
hass.async_create_task(async_load_platform(hass, platform, DOMAIN, {}, config))
|
hass.async_create_task(async_load_platform(hass, platform, DOMAIN, {}, config))
|
||||||
|
|
||||||
|
setup_service_functions(hass, broker)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def setup_service_functions(hass: HomeAssistantType, broker):
|
||||||
|
"""Set up the service functions."""
|
||||||
|
|
||||||
|
@verify_domain_control(hass, DOMAIN)
|
||||||
|
async def set_zone_mode(call) -> None:
|
||||||
|
"""Set the system mode."""
|
||||||
|
entity_id = call.data[ATTR_ENTITY_ID]
|
||||||
|
|
||||||
|
registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
registry_entry = registry.async_get(entity_id)
|
||||||
|
|
||||||
|
if registry_entry is None or registry_entry.platform != DOMAIN:
|
||||||
|
raise ValueError(f"'{entity_id}' is not a known {DOMAIN} entity")
|
||||||
|
|
||||||
|
if registry_entry.domain != "climate":
|
||||||
|
raise ValueError(f"'{entity_id}' is not an {DOMAIN} zone")
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"unique_id": registry_entry.unique_id,
|
||||||
|
"service": call.service,
|
||||||
|
"data": call.data,
|
||||||
|
}
|
||||||
|
|
||||||
|
async_dispatcher_send(hass, DOMAIN, payload)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN, SVC_SET_ZONE_MODE, set_zone_mode, schema=SET_ZONE_MODE_SCHEMA
|
||||||
|
)
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN, SVC_SET_ZONE_OVERRIDE, set_zone_mode, schema=SET_ZONE_OVERRIDE_SCHEMA
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class GeniusBroker:
|
class GeniusBroker:
|
||||||
"""Container for geniushub client and data."""
|
"""Container for geniushub client and data."""
|
||||||
|
|
||||||
@ -146,8 +206,8 @@ class GeniusEntity(Entity):
|
|||||||
"""Set up a listener when this entity is added to HA."""
|
"""Set up a listener when this entity is added to HA."""
|
||||||
async_dispatcher_connect(self.hass, DOMAIN, self._refresh)
|
async_dispatcher_connect(self.hass, DOMAIN, self._refresh)
|
||||||
|
|
||||||
@callback
|
async def _refresh(self, payload: Optional[dict] = None) -> None:
|
||||||
def _refresh(self) -> None:
|
"""Process any signals."""
|
||||||
self.async_schedule_update_ha_state(force_refresh=True)
|
self.async_schedule_update_ha_state(force_refresh=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -175,7 +235,6 @@ class GeniusDevice(GeniusEntity):
|
|||||||
|
|
||||||
self._device = device
|
self._device = device
|
||||||
self._unique_id = f"{broker.hub_uid}_device_{device.id}"
|
self._unique_id = f"{broker.hub_uid}_device_{device.id}"
|
||||||
|
|
||||||
self._last_comms = self._state_attr = None
|
self._last_comms = self._state_attr = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -188,7 +247,7 @@ class GeniusDevice(GeniusEntity):
|
|||||||
attrs["last_comms"] = self._last_comms.isoformat()
|
attrs["last_comms"] = self._last_comms.isoformat()
|
||||||
|
|
||||||
state = dict(self._device.data["state"])
|
state = dict(self._device.data["state"])
|
||||||
if "_state" in self._device.data: # only for v3 API
|
if "_state" in self._device.data: # only via v3 API
|
||||||
state.update(self._device.data["_state"])
|
state.update(self._device.data["_state"])
|
||||||
|
|
||||||
attrs["state"] = {
|
attrs["state"] = {
|
||||||
@ -199,7 +258,7 @@ class GeniusDevice(GeniusEntity):
|
|||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Update an entity's state data."""
|
"""Update an entity's state data."""
|
||||||
if "_state" in self._device.data: # only for v3 API
|
if "_state" in self._device.data: # only via v3 API
|
||||||
self._last_comms = dt_util.utc_from_timestamp(
|
self._last_comms = dt_util.utc_from_timestamp(
|
||||||
self._device.data["_state"]["lastComms"]
|
self._device.data["_state"]["lastComms"]
|
||||||
)
|
)
|
||||||
@ -215,6 +274,32 @@ class GeniusZone(GeniusEntity):
|
|||||||
self._zone = zone
|
self._zone = zone
|
||||||
self._unique_id = f"{broker.hub_uid}_zone_{zone.id}"
|
self._unique_id = f"{broker.hub_uid}_zone_{zone.id}"
|
||||||
|
|
||||||
|
async def _refresh(self, payload: Optional[dict] = None) -> None:
|
||||||
|
"""Process any signals."""
|
||||||
|
if payload is None:
|
||||||
|
self.async_schedule_update_ha_state(force_refresh=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if payload["unique_id"] != self._unique_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
if payload["service"] == SVC_SET_ZONE_OVERRIDE:
|
||||||
|
temperature = round(payload["data"][ATTR_TEMPERATURE] * 10) / 10
|
||||||
|
duration = payload["data"].get(ATTR_DURATION, timedelta(hours=1))
|
||||||
|
|
||||||
|
await self._zone.set_override(temperature, int(duration.total_seconds()))
|
||||||
|
return
|
||||||
|
|
||||||
|
mode = payload["data"][ATTR_ZONE_MODE]
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
if mode == "footprint" and not self._zone._has_pir:
|
||||||
|
raise TypeError(
|
||||||
|
f"'{self.entity_id}' can not support footprint mode (it has no PIR)"
|
||||||
|
)
|
||||||
|
|
||||||
|
await self._zone.set_mode(mode)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
"""Return the name of the climate device."""
|
"""Return the name of the climate device."""
|
||||||
|
29
homeassistant/components/geniushub/services.yaml
Normal file
29
homeassistant/components/geniushub/services.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Support for a Genius Hub system
|
||||||
|
# Describes the format for available services
|
||||||
|
|
||||||
|
set_zone_mode:
|
||||||
|
description: >-
|
||||||
|
Set the zone to an operating mode.
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
description: The zone's entity_id.
|
||||||
|
example: climate.kitchen
|
||||||
|
mode:
|
||||||
|
description: 'One of: off, timer or footprint.'
|
||||||
|
example: timer
|
||||||
|
|
||||||
|
set_zone_override:
|
||||||
|
description: >-
|
||||||
|
Override the zone's setpoint for a given duration.
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
description: The zone's entity_id.
|
||||||
|
example: climate.bathroom
|
||||||
|
temperature:
|
||||||
|
description: The target temperature, to 0.1 C.
|
||||||
|
example: 19.2
|
||||||
|
duration:
|
||||||
|
description: >-
|
||||||
|
The duration of the override. Optional, default 1 hour, maximum 24 hours.
|
||||||
|
example: '{"minutes": 135}'
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user