Home Assistant Unofficial Reference 2024.12.1
light.py
Go to the documentation of this file.
1 """Zerproc light platform."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import logging
7 from typing import Any
8 
9 import pyzerproc
10 
12  ATTR_BRIGHTNESS,
13  ATTR_HS_COLOR,
14  ColorMode,
15  LightEntity,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.const import EVENT_HOMEASSISTANT_STOP
19 from homeassistant.core import Event, HomeAssistant
20 from homeassistant.helpers.device_registry import DeviceInfo
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 from homeassistant.helpers.event import async_track_time_interval
23 import homeassistant.util.color as color_util
24 
25 from .const import DATA_ADDRESSES, DATA_DISCOVERY_SUBSCRIPTION, DOMAIN
26 
27 _LOGGER = logging.getLogger(__name__)
28 
29 DISCOVERY_INTERVAL = timedelta(seconds=60)
30 
31 
32 async def discover_entities(hass: HomeAssistant) -> list[ZerprocLight]:
33  """Attempt to discover new lights."""
34  lights = await pyzerproc.discover()
35 
36  # Filter out already discovered lights
37  new_lights = [
38  light
39  for light in lights
40  if light.address not in hass.data[DOMAIN][DATA_ADDRESSES]
41  ]
42 
43  entities = []
44  for light in new_lights:
45  hass.data[DOMAIN][DATA_ADDRESSES].add(light.address)
46  entities.append(ZerprocLight(light))
47 
48  return entities
49 
50 
52  hass: HomeAssistant,
53  config_entry: ConfigEntry,
54  async_add_entities: AddEntitiesCallback,
55 ) -> None:
56  """Set up Zerproc light devices."""
57  warned = False
58 
59  async def discover(*args):
60  """Wrap discovery to include params."""
61  nonlocal warned
62  try:
63  entities = await discover_entities(hass)
64  async_add_entities(entities, update_before_add=True)
65  warned = False
66  except pyzerproc.ZerprocException:
67  if warned is False:
68  _LOGGER.warning("Error discovering Zerproc lights", exc_info=True)
69  warned = True
70 
71  # Initial discovery
72  hass.async_create_task(discover())
73 
74  # Perform recurring discovery of new devices
75  hass.data[DOMAIN][DATA_DISCOVERY_SUBSCRIPTION] = async_track_time_interval(
76  hass, discover, DISCOVERY_INTERVAL
77  )
78 
79 
81  """Representation of a Zerproc Light."""
82 
83  _attr_color_mode = ColorMode.HS
84  _attr_supported_color_modes = {ColorMode.HS}
85  _attr_has_entity_name = True
86  _attr_name = None
87  _attr_translation_key = "light"
88 
89  def __init__(self, light) -> None:
90  """Initialize a Zerproc light."""
91  self._light_light = light
92  self._attr_unique_id_attr_unique_id = light.address
93  self._attr_device_info_attr_device_info = DeviceInfo(
94  identifiers={(DOMAIN, light.address)},
95  manufacturer="Zerproc",
96  name=light.name,
97  )
98 
99  async def async_added_to_hass(self) -> None:
100  """Run when entity about to be added to hass."""
101  self.async_on_removeasync_on_remove(
102  self.hasshass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self._hass_stop_hass_stop)
103  )
104 
105  async def _hass_stop(self, event: Event) -> None:
106  """Run on EVENT_HOMEASSISTANT_STOP."""
107  await self.async_will_remove_from_hassasync_will_remove_from_hassasync_will_remove_from_hass()
108 
109  async def async_will_remove_from_hass(self) -> None:
110  """Run when entity will be removed from hass."""
111  try:
112  await self._light_light.disconnect()
113  except pyzerproc.ZerprocException:
114  _LOGGER.debug(
115  "Exception disconnecting from %s", self._light_light.address, exc_info=True
116  )
117 
118  async def async_turn_on(self, **kwargs: Any) -> None:
119  """Instruct the light to turn on."""
120  if ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs:
121  default_hs = (0, 0) if self.hs_colorhs_color is None else self.hs_colorhs_color
122  hue_sat = kwargs.get(ATTR_HS_COLOR, default_hs)
123 
124  default_brightness = 255 if self.brightnessbrightness is None else self.brightnessbrightness
125  brightness = kwargs.get(ATTR_BRIGHTNESS, default_brightness)
126 
127  rgb = color_util.color_hsv_to_RGB(
128  hue_sat[0], hue_sat[1], brightness / 255 * 100
129  )
130  await self._light_light.set_color(*rgb)
131  else:
132  await self._light_light.turn_on()
133 
134  async def async_turn_off(self, **kwargs: Any) -> None:
135  """Instruct the light to turn off."""
136  await self._light_light.turn_off()
137 
138  async def async_update(self) -> None:
139  """Fetch new state data for this light."""
140  try:
141  if not self.availableavailable:
142  await self._light_light.connect()
143  state = await self._light_light.get_state()
144  except pyzerproc.ZerprocException:
145  if self.availableavailable:
146  _LOGGER.warning("Unable to connect to %s", self._light_light.address)
147  self._attr_available_attr_available = False
148  return
149  if not self.availableavailable:
150  _LOGGER.warning("Reconnected to %s", self._light_light.address)
151  self._attr_available_attr_available = True
152  self._attr_is_on_attr_is_on = state.is_on
153  hsv = color_util.color_RGB_to_hsv(*state.color)
154  self._attr_hs_color_attr_hs_color = hsv[:2]
155  self._attr_brightness_attr_brightness = int(round((hsv[2] / 100) * 255))
tuple[float, float]|None hs_color(self)
Definition: __init__.py:947
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None turn_off(self, **Any kwargs)
Definition: entity.py:1705
None turn_on(self, **Any kwargs)
Definition: entity.py:1697
bool add(self, _T matcher)
Definition: match.py:185
str|float get_state(dict[str, float] data, str key)
Definition: sensor.py:26
list[tuple[str, int]] discover(HomeAssistant hass)
Definition: config_flow.py:97
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: light.py:55
list[ZerprocLight] discover_entities(HomeAssistant hass)
Definition: light.py:32
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
Definition: event.py:1679