Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Support for WiLight switches."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from pywilight.const import ITEM_SWITCH, SWITCH_PAUSE_VALVE, SWITCH_VALVE
8 from pywilight.wilight_device import PyWiLightDevice
9 import voluptuous as vol
10 
11 from homeassistant.components.switch import SwitchEntity
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.core import HomeAssistant
14 from homeassistant.helpers import entity_platform
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 
17 from .const import DOMAIN
18 from .entity import WiLightDevice
19 from .parent_device import WiLightParent
20 from .support import wilight_to_hass_trigger, wilight_trigger as wl_trigger
21 
22 # Attr of features supported by the valve switch entities
23 ATTR_WATERING_TIME = "watering_time"
24 ATTR_PAUSE_TIME = "pause_time"
25 ATTR_TRIGGER_1 = "trigger_1"
26 ATTR_TRIGGER_2 = "trigger_2"
27 ATTR_TRIGGER_3 = "trigger_3"
28 ATTR_TRIGGER_4 = "trigger_4"
29 ATTR_TRIGGER_1_DESC = "trigger_1_description"
30 ATTR_TRIGGER_2_DESC = "trigger_2_description"
31 ATTR_TRIGGER_3_DESC = "trigger_3_description"
32 ATTR_TRIGGER_4_DESC = "trigger_4_description"
33 
34 # Attr of services data supported by the valve switch entities
35 ATTR_TRIGGER = "trigger"
36 ATTR_TRIGGER_INDEX = "trigger_index"
37 
38 # Service of features supported by the valve switch entities
39 SERVICE_SET_WATERING_TIME = "set_watering_time"
40 SERVICE_SET_PAUSE_TIME = "set_pause_time"
41 SERVICE_SET_TRIGGER = "set_trigger"
42 
43 # Range of features supported by the valve switch entities
44 RANGE_WATERING_TIME = 1800
45 RANGE_PAUSE_TIME = 24
46 RANGE_TRIGGER_INDEX = 4
47 
48 # Service call validation schemas
49 VALID_WATERING_TIME = vol.All(
50  vol.Coerce(int), vol.Range(min=1, max=RANGE_WATERING_TIME)
51 )
52 VALID_PAUSE_TIME = vol.All(vol.Coerce(int), vol.Range(min=1, max=RANGE_PAUSE_TIME))
53 VALID_TRIGGER_INDEX = vol.All(
54  vol.Coerce(int), vol.Range(min=1, max=RANGE_TRIGGER_INDEX)
55 )
56 
57 # Descriptions of the valve switch entities
58 DESC_WATERING = "watering"
59 DESC_PAUSE = "pause"
60 
61 
62 def entities_from_discovered_wilight(api_device: PyWiLightDevice) -> tuple[Any]:
63  """Parse configuration and add WiLight switch entities."""
64  entities: Any = []
65  for item in api_device.items:
66  if item["type"] == ITEM_SWITCH:
67  index = item["index"]
68  item_name = item["name"]
69  if item["sub_type"] == SWITCH_VALVE:
70  entities.append(WiLightValveSwitch(api_device, index, item_name))
71  elif item["sub_type"] == SWITCH_PAUSE_VALVE:
72  entities.append(WiLightValvePauseSwitch(api_device, index, item_name))
73 
74  return entities
75 
76 
78  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
79 ) -> None:
80  """Set up WiLight switches from a config entry."""
81  parent: WiLightParent = hass.data[DOMAIN][entry.entry_id]
82 
83  # Handle a discovered WiLight device.
84  assert parent.api
85  entities = entities_from_discovered_wilight(parent.api)
86  async_add_entities(entities)
87 
88  # Handle services for a discovered WiLight device.
89  async def set_watering_time(entity, service: Any) -> None:
90  if not isinstance(entity, WiLightValveSwitch):
91  raise TypeError("Entity is not a WiLight valve switch")
92  watering_time = service.data[ATTR_WATERING_TIME]
93  await entity.async_set_watering_time(watering_time=watering_time)
94 
95  async def set_trigger(entity, service: Any) -> None:
96  if not isinstance(entity, WiLightValveSwitch):
97  raise TypeError("Entity is not a WiLight valve switch")
98  trigger_index = service.data[ATTR_TRIGGER_INDEX]
99  trigger = service.data[ATTR_TRIGGER]
100  await entity.async_set_trigger(trigger_index=trigger_index, trigger=trigger)
101 
102  async def set_pause_time(entity, service: Any) -> None:
103  if not isinstance(entity, WiLightValvePauseSwitch):
104  raise TypeError("Entity is not a WiLight valve pause switch")
105  pause_time = service.data[ATTR_PAUSE_TIME]
106  await entity.async_set_pause_time(pause_time=pause_time)
107 
108  platform = entity_platform.async_get_current_platform()
109 
110  platform.async_register_entity_service(
111  SERVICE_SET_WATERING_TIME,
112  {
113  vol.Required(ATTR_WATERING_TIME): VALID_WATERING_TIME,
114  },
115  set_watering_time,
116  )
117 
118  platform.async_register_entity_service(
119  SERVICE_SET_TRIGGER,
120  {
121  vol.Required(ATTR_TRIGGER_INDEX): VALID_TRIGGER_INDEX,
122  vol.Required(ATTR_TRIGGER): wl_trigger,
123  },
124  set_trigger,
125  )
126 
127  platform.async_register_entity_service(
128  SERVICE_SET_PAUSE_TIME,
129  {
130  vol.Required(ATTR_PAUSE_TIME): VALID_PAUSE_TIME,
131  },
132  set_pause_time,
133  )
134 
135 
136 def wilight_to_hass_pause_time(value: int) -> int:
137  """Convert wilight pause_time seconds to hass hour."""
138  return round(value / 3600)
139 
140 
141 def hass_to_wilight_pause_time(value: int) -> int:
142  """Convert hass pause_time hours to wilight seconds."""
143  return round(value * 3600)
144 
145 
147  """Representation of a WiLights Valve switch."""
148 
149  _attr_translation_key = "watering"
150 
151  @property
152  def is_on(self) -> bool:
153  """Return true if device is on."""
154  return self._status_status.get("on", False)
155 
156  @property
157  def watering_time(self) -> int | None:
158  """Return watering time of valve switch.
159 
160  None is unknown, 1 is minimum, 1800 is maximum.
161  """
162  return self._status_status.get("timer_target")
163 
164  @property
165  def trigger_1(self) -> str | None:
166  """Return trigger_1 of valve switch."""
167  return self._status_status.get("trigger_1")
168 
169  @property
170  def trigger_2(self) -> str | None:
171  """Return trigger_2 of valve switch."""
172  return self._status_status.get("trigger_2")
173 
174  @property
175  def trigger_3(self) -> str | None:
176  """Return trigger_3 of valve switch."""
177  return self._status_status.get("trigger_3")
178 
179  @property
180  def trigger_4(self) -> str | None:
181  """Return trigger_4 of valve switch."""
182  return self._status_status.get("trigger_4")
183 
184  @property
185  def trigger_1_description(self) -> str | None:
186  """Return trigger_1_description of valve switch."""
187  return wilight_to_hass_trigger(self._status_status.get("trigger_1"))
188 
189  @property
190  def trigger_2_description(self) -> str | None:
191  """Return trigger_2_description of valve switch."""
192  return wilight_to_hass_trigger(self._status_status.get("trigger_2"))
193 
194  @property
195  def trigger_3_description(self) -> str | None:
196  """Return trigger_3_description of valve switch."""
197  return wilight_to_hass_trigger(self._status_status.get("trigger_3"))
198 
199  @property
200  def trigger_4_description(self) -> str | None:
201  """Return trigger_4_description of valve switch."""
202  return wilight_to_hass_trigger(self._status_status.get("trigger_4"))
203 
204  @property
205  def extra_state_attributes(self) -> dict[str, Any]:
206  """Return the state attributes."""
207  attr: dict[str, Any] = {}
208 
209  if self.watering_timewatering_time is not None:
210  attr[ATTR_WATERING_TIME] = self.watering_timewatering_time
211 
212  if self.trigger_1trigger_1 is not None:
213  attr[ATTR_TRIGGER_1] = self.trigger_1trigger_1
214 
215  if self.trigger_2trigger_2 is not None:
216  attr[ATTR_TRIGGER_2] = self.trigger_2trigger_2
217 
218  if self.trigger_3trigger_3 is not None:
219  attr[ATTR_TRIGGER_3] = self.trigger_3trigger_3
220 
221  if self.trigger_4trigger_4 is not None:
222  attr[ATTR_TRIGGER_4] = self.trigger_4trigger_4
223 
224  if self.trigger_1_descriptiontrigger_1_description is not None:
225  attr[ATTR_TRIGGER_1_DESC] = self.trigger_1_descriptiontrigger_1_description
226 
227  if self.trigger_2_descriptiontrigger_2_description is not None:
228  attr[ATTR_TRIGGER_2_DESC] = self.trigger_2_descriptiontrigger_2_description
229 
230  if self.trigger_3_descriptiontrigger_3_description is not None:
231  attr[ATTR_TRIGGER_3_DESC] = self.trigger_3_descriptiontrigger_3_description
232 
233  if self.trigger_4_descriptiontrigger_4_description is not None:
234  attr[ATTR_TRIGGER_4_DESC] = self.trigger_4_descriptiontrigger_4_description
235 
236  return attr
237 
238  async def async_turn_on(self, **kwargs: Any) -> None:
239  """Turn the device on."""
240  await self._client_client.turn_on(self._index_index)
241 
242  async def async_turn_off(self, **kwargs: Any) -> None:
243  """Turn the device off."""
244  await self._client_client.turn_off(self._index_index)
245 
246  async def async_set_watering_time(self, watering_time: int) -> None:
247  """Set the watering time."""
248  await self._client_client.set_switch_time(self._index_index, watering_time)
249 
250  async def async_set_trigger(self, trigger_index: int, trigger: str) -> None:
251  """Set the trigger according to index."""
252  if trigger_index == 1:
253  await self._client_client.set_switch_trigger_1(self._index_index, trigger)
254  if trigger_index == 2:
255  await self._client_client.set_switch_trigger_2(self._index_index, trigger)
256  if trigger_index == 3:
257  await self._client_client.set_switch_trigger_3(self._index_index, trigger)
258  if trigger_index == 4:
259  await self._client_client.set_switch_trigger_4(self._index_index, trigger)
260 
261 
263  """Representation of a WiLights Valve Pause switch."""
264 
265  _attr_translation_key = "pause"
266 
267  @property
268  def is_on(self) -> bool:
269  """Return true if device is on."""
270  return self._status_status.get("on", False)
271 
272  @property
273  def pause_time(self) -> int | None:
274  """Return pause time of valve switch.
275 
276  None is unknown, 1 is minimum, 24 is maximum.
277  """
278  pause_time = self._status_status.get("timer_target")
279  if pause_time is not None:
280  return wilight_to_hass_pause_time(pause_time)
281  return pause_time
282 
283  @property
284  def extra_state_attributes(self) -> dict[str, Any]:
285  """Return the state attributes."""
286  attr: dict[str, Any] = {}
287 
288  if self.pause_timepause_time is not None:
289  attr[ATTR_PAUSE_TIME] = self.pause_timepause_time
290 
291  return attr
292 
293  async def async_turn_on(self, **kwargs: Any) -> None:
294  """Turn the device on."""
295  await self._client_client.turn_on(self._index_index)
296 
297  async def async_turn_off(self, **kwargs: Any) -> None:
298  """Turn the device off."""
299  await self._client_client.turn_off(self._index_index)
300 
301  async def async_set_pause_time(self, pause_time: int) -> None:
302  """Set the pause time."""
303  target_time = hass_to_wilight_pause_time(pause_time)
304  await self._client_client.set_switch_time(self._index_index, target_time)
None async_set_watering_time(self, int watering_time)
Definition: switch.py:246
None async_set_trigger(self, int trigger_index, str trigger)
Definition: switch.py:250
None turn_off(self, **Any kwargs)
Definition: entity.py:1705
None turn_on(self, **Any kwargs)
Definition: entity.py:1697
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
str|None wilight_to_hass_trigger(str|None value)
Definition: support.py:55
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: switch.py:79
int wilight_to_hass_pause_time(int value)
Definition: switch.py:136
int hass_to_wilight_pause_time(int value)
Definition: switch.py:141
tuple[Any] entities_from_discovered_wilight(PyWiLightDevice api_device)
Definition: switch.py:62