home-assistant-core/homeassistant/components/wilight/switch.py

323 lines
11 KiB
Python

"""Support for WiLight switches."""
from __future__ import annotations
from typing import Any
from pywilight.const import ITEM_SWITCH, SWITCH_PAUSE_VALVE, SWITCH_VALVE
from pywilight.wilight_device import PyWiLightDevice
import voluptuous as vol
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import DOMAIN, WiLightDevice
from .parent_device import WiLightParent
from .support import wilight_to_hass_trigger, wilight_trigger as wl_trigger
# Attr of features supported by the valve switch entities
ATTR_WATERING_TIME = "watering_time"
ATTR_PAUSE_TIME = "pause_time"
ATTR_TRIGGER_1 = "trigger_1"
ATTR_TRIGGER_2 = "trigger_2"
ATTR_TRIGGER_3 = "trigger_3"
ATTR_TRIGGER_4 = "trigger_4"
ATTR_TRIGGER_1_DESC = "trigger_1_description"
ATTR_TRIGGER_2_DESC = "trigger_2_description"
ATTR_TRIGGER_3_DESC = "trigger_3_description"
ATTR_TRIGGER_4_DESC = "trigger_4_description"
# Attr of services data supported by the valve switch entities
ATTR_TRIGGER = "trigger"
ATTR_TRIGGER_INDEX = "trigger_index"
# Service of features supported by the valve switch entities
SERVICE_SET_WATERING_TIME = "set_watering_time"
SERVICE_SET_PAUSE_TIME = "set_pause_time"
SERVICE_SET_TRIGGER = "set_trigger"
# Range of features supported by the valve switch entities
RANGE_WATERING_TIME = 1800
RANGE_PAUSE_TIME = 24
RANGE_TRIGGER_INDEX = 4
# Service call validation schemas
VALID_WATERING_TIME = vol.All(
vol.Coerce(int), vol.Range(min=1, max=RANGE_WATERING_TIME)
)
VALID_PAUSE_TIME = vol.All(vol.Coerce(int), vol.Range(min=1, max=RANGE_PAUSE_TIME))
VALID_TRIGGER_INDEX = vol.All(
vol.Coerce(int), vol.Range(min=1, max=RANGE_TRIGGER_INDEX)
)
# Descriptions of the valve switch entities
DESC_WATERING = "watering"
DESC_PAUSE = "pause"
# Icons of the valve switch entities
ICON_WATERING = "mdi:water"
ICON_PAUSE = "mdi:pause-circle-outline"
def entities_from_discovered_wilight(api_device: PyWiLightDevice) -> tuple[Any]:
"""Parse configuration and add WiLight switch entities."""
entities: Any = []
for item in api_device.items:
if item["type"] == ITEM_SWITCH:
index = item["index"]
item_name = item["name"]
if item["sub_type"] == SWITCH_VALVE:
entities.append(WiLightValveSwitch(api_device, index, item_name))
elif item["sub_type"] == SWITCH_PAUSE_VALVE:
entities.append(WiLightValvePauseSwitch(api_device, index, item_name))
return entities
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up WiLight switches from a config entry."""
parent: WiLightParent = hass.data[DOMAIN][entry.entry_id]
# Handle a discovered WiLight device.
assert parent.api
entities = entities_from_discovered_wilight(parent.api)
async_add_entities(entities)
# Handle services for a discovered WiLight device.
async def set_watering_time(entity, service: Any) -> None:
if not isinstance(entity, WiLightValveSwitch):
raise TypeError("Entity is not a WiLight valve switch")
watering_time = service.data[ATTR_WATERING_TIME]
await entity.async_set_watering_time(watering_time=watering_time)
async def set_trigger(entity, service: Any) -> None:
if not isinstance(entity, WiLightValveSwitch):
raise TypeError("Entity is not a WiLight valve switch")
trigger_index = service.data[ATTR_TRIGGER_INDEX]
trigger = service.data[ATTR_TRIGGER]
await entity.async_set_trigger(trigger_index=trigger_index, trigger=trigger)
async def set_pause_time(entity, service: Any) -> None:
if not isinstance(entity, WiLightValvePauseSwitch):
raise TypeError("Entity is not a WiLight valve pause switch")
pause_time = service.data[ATTR_PAUSE_TIME]
await entity.async_set_pause_time(pause_time=pause_time)
platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
SERVICE_SET_WATERING_TIME,
{
vol.Required(ATTR_WATERING_TIME): VALID_WATERING_TIME,
},
set_watering_time,
)
platform.async_register_entity_service(
SERVICE_SET_TRIGGER,
{
vol.Required(ATTR_TRIGGER_INDEX): VALID_TRIGGER_INDEX,
vol.Required(ATTR_TRIGGER): wl_trigger,
},
set_trigger,
)
platform.async_register_entity_service(
SERVICE_SET_PAUSE_TIME,
{
vol.Required(ATTR_PAUSE_TIME): VALID_PAUSE_TIME,
},
set_pause_time,
)
def wilight_to_hass_pause_time(value: int) -> int:
"""Convert wilight pause_time seconds to hass hour."""
return round(value / 3600)
def hass_to_wilight_pause_time(value: int) -> int:
"""Convert hass pause_time hours to wilight seconds."""
return round(value * 3600)
class WiLightValveSwitch(WiLightDevice, SwitchEntity):
"""Representation of a WiLights Valve switch."""
@property
def name(self) -> str:
"""Return the name of the switch."""
return f"{self._attr_name} {DESC_WATERING}"
@property
def is_on(self) -> bool:
"""Return true if device is on."""
return self._status.get("on", False)
@property
def watering_time(self) -> int | None:
"""Return watering time of valve switch.
None is unknown, 1 is minimum, 1800 is maximum.
"""
return self._status.get("timer_target")
@property
def trigger_1(self) -> str | None:
"""Return trigger_1 of valve switch."""
return self._status.get("trigger_1")
@property
def trigger_2(self) -> str | None:
"""Return trigger_2 of valve switch."""
return self._status.get("trigger_2")
@property
def trigger_3(self) -> str | None:
"""Return trigger_3 of valve switch."""
return self._status.get("trigger_3")
@property
def trigger_4(self) -> str | None:
"""Return trigger_4 of valve switch."""
return self._status.get("trigger_4")
@property
def trigger_1_description(self) -> str | None:
"""Return trigger_1_description of valve switch."""
return wilight_to_hass_trigger(self._status.get("trigger_1"))
@property
def trigger_2_description(self) -> str | None:
"""Return trigger_2_description of valve switch."""
return wilight_to_hass_trigger(self._status.get("trigger_2"))
@property
def trigger_3_description(self) -> str | None:
"""Return trigger_3_description of valve switch."""
return wilight_to_hass_trigger(self._status.get("trigger_3"))
@property
def trigger_4_description(self) -> str | None:
"""Return trigger_4_description of valve switch."""
return wilight_to_hass_trigger(self._status.get("trigger_4"))
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
attr: dict[str, Any] = {}
if self.watering_time is not None:
attr[ATTR_WATERING_TIME] = self.watering_time
if self.trigger_1 is not None:
attr[ATTR_TRIGGER_1] = self.trigger_1
if self.trigger_2 is not None:
attr[ATTR_TRIGGER_2] = self.trigger_2
if self.trigger_3 is not None:
attr[ATTR_TRIGGER_3] = self.trigger_3
if self.trigger_4 is not None:
attr[ATTR_TRIGGER_4] = self.trigger_4
if self.trigger_1_description is not None:
attr[ATTR_TRIGGER_1_DESC] = self.trigger_1_description
if self.trigger_2_description is not None:
attr[ATTR_TRIGGER_2_DESC] = self.trigger_2_description
if self.trigger_3_description is not None:
attr[ATTR_TRIGGER_3_DESC] = self.trigger_3_description
if self.trigger_4_description is not None:
attr[ATTR_TRIGGER_4_DESC] = self.trigger_4_description
return attr
@property
def icon(self) -> str:
"""Return the icon to use in the frontend."""
return ICON_WATERING
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
await self._client.turn_on(self._index)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
await self._client.turn_off(self._index)
async def async_set_watering_time(self, watering_time: int) -> None:
"""Set the watering time."""
await self._client.set_switch_time(self._index, watering_time)
async def async_set_trigger(self, trigger_index: int, trigger: str) -> None:
"""Set the trigger according to index."""
if trigger_index == 1:
await self._client.set_switch_trigger_1(self._index, trigger)
if trigger_index == 2:
await self._client.set_switch_trigger_2(self._index, trigger)
if trigger_index == 3:
await self._client.set_switch_trigger_3(self._index, trigger)
if trigger_index == 4:
await self._client.set_switch_trigger_4(self._index, trigger)
class WiLightValvePauseSwitch(WiLightDevice, SwitchEntity):
"""Representation of a WiLights Valve Pause switch."""
@property
def name(self) -> str:
"""Return the name of the switch."""
return f"{self._attr_name} {DESC_PAUSE}"
@property
def is_on(self) -> bool:
"""Return true if device is on."""
return self._status.get("on", False)
@property
def pause_time(self) -> int | None:
"""Return pause time of valve switch.
None is unknown, 1 is minimum, 24 is maximum.
"""
pause_time = self._status.get("timer_target")
if pause_time is not None:
return wilight_to_hass_pause_time(pause_time)
return pause_time
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
attr: dict[str, Any] = {}
if self.pause_time is not None:
attr[ATTR_PAUSE_TIME] = self.pause_time
return attr
@property
def icon(self) -> str:
"""Return the icon to use in the frontend."""
return ICON_PAUSE
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
await self._client.turn_on(self._index)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
await self._client.turn_off(self._index)
async def async_set_pause_time(self, pause_time: int) -> None:
"""Set the pause time."""
target_time = hass_to_wilight_pause_time(pause_time)
await self._client.set_switch_time(self._index, target_time)