Home Assistant Unofficial Reference 2024.12.1
light.py
Go to the documentation of this file.
1 """Kuler Sky 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 pykulersky
10 
12  ATTR_BRIGHTNESS,
13  ATTR_RGBW_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 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 
24 from .const import DATA_ADDRESSES, DATA_DISCOVERY_SUBSCRIPTION, DOMAIN
25 
26 _LOGGER = logging.getLogger(__name__)
27 
28 DISCOVERY_INTERVAL = timedelta(seconds=60)
29 
30 
32  hass: HomeAssistant,
33  config_entry: ConfigEntry,
34  async_add_entities: AddEntitiesCallback,
35 ) -> None:
36  """Set up Kuler sky light devices."""
37 
38  async def discover(*args):
39  """Attempt to discover new lights."""
40  lights = await pykulersky.discover()
41 
42  # Filter out already discovered lights
43  new_lights = [
44  light
45  for light in lights
46  if light.address not in hass.data[DOMAIN][DATA_ADDRESSES]
47  ]
48 
49  new_entities = []
50  for light in new_lights:
51  hass.data[DOMAIN][DATA_ADDRESSES].add(light.address)
52  new_entities.append(KulerskyLight(light))
53 
54  async_add_entities(new_entities, update_before_add=True)
55 
56  # Start initial discovery
57  hass.async_create_task(discover())
58 
59  # Perform recurring discovery of new devices
60  hass.data[DOMAIN][DATA_DISCOVERY_SUBSCRIPTION] = async_track_time_interval(
61  hass, discover, DISCOVERY_INTERVAL
62  )
63 
64 
66  """Representation of a Kuler Sky Light."""
67 
68  _attr_has_entity_name = True
69  _attr_name = None
70  _attr_available = False
71  _attr_supported_color_modes = {ColorMode.RGBW}
72  _attr_color_mode = ColorMode.RGBW
73 
74  def __init__(self, light: pykulersky.Light) -> None:
75  """Initialize a Kuler Sky light."""
76  self._light_light = light
77  self._attr_unique_id_attr_unique_id = light.address
78  self._attr_device_info_attr_device_info = DeviceInfo(
79  identifiers={(DOMAIN, light.address)},
80  manufacturer="Brightech",
81  name=light.name,
82  )
83 
84  async def async_added_to_hass(self) -> None:
85  """Run when entity about to be added to hass."""
86  self.async_on_removeasync_on_remove(
87  self.hasshass.bus.async_listen_once(
88  EVENT_HOMEASSISTANT_STOP, self.async_will_remove_from_hassasync_will_remove_from_hassasync_will_remove_from_hass
89  )
90  )
91 
92  async def async_will_remove_from_hass(self, *args) -> None:
93  """Run when entity will be removed from hass."""
94  try:
95  await self._light_light.disconnect()
96  except pykulersky.PykulerskyException:
97  _LOGGER.debug(
98  "Exception disconnected from %s", self._light_light.address, exc_info=True
99  )
100 
101  @property
102  def is_on(self):
103  """Return true if light is on."""
104  return self.brightnessbrightness > 0
105 
106  async def async_turn_on(self, **kwargs: Any) -> None:
107  """Instruct the light to turn on."""
108  default_rgbw = (255,) * 4 if self.rgbw_colorrgbw_color is None else self.rgbw_colorrgbw_color
109  rgbw = kwargs.get(ATTR_RGBW_COLOR, default_rgbw)
110 
111  default_brightness = 0 if self.brightnessbrightness is None else self.brightnessbrightness
112  brightness = kwargs.get(ATTR_BRIGHTNESS, default_brightness)
113 
114  if brightness == 0 and not kwargs:
115  # If the light would be off, and no additional parameters were
116  # passed, just turn the light on full brightness.
117  brightness = 255
118  rgbw = (255,) * 4
119 
120  rgbw_scaled = [round(x * brightness / 255) for x in rgbw]
121 
122  await self._light_light.set_color(*rgbw_scaled)
123 
124  async def async_turn_off(self, **kwargs: Any) -> None:
125  """Instruct the light to turn off."""
126  await self._light_light.set_color(0, 0, 0, 0)
127 
128  async def async_update(self) -> None:
129  """Fetch new state data for this light."""
130  try:
131  if not self._attr_available_attr_available_attr_available:
132  await self._light_light.connect()
133  rgbw = await self._light_light.get_color()
134  except pykulersky.PykulerskyException as exc:
135  if self._attr_available_attr_available_attr_available:
136  _LOGGER.warning("Unable to connect to %s: %s", self._light_light.address, exc)
137  self._attr_available_attr_available_attr_available = False
138  return
139  if self._attr_available_attr_available_attr_available is False:
140  _LOGGER.warning("Reconnected to %s", self._light_light.address)
141 
142  self._attr_available_attr_available_attr_available = True
143  brightness = max(rgbw)
144  if not brightness:
145  self._attr_rgbw_color_attr_rgbw_color = (0, 0, 0, 0)
146  else:
147  rgbw_normalized = [round(x * 255 / brightness) for x in rgbw]
148  self._attr_rgbw_color_attr_rgbw_color = (
149  rgbw_normalized[0],
150  rgbw_normalized[1],
151  rgbw_normalized[2],
152  rgbw_normalized[3],
153  )
154  self._attr_brightness_attr_brightness = brightness
None __init__(self, pykulersky.Light light)
Definition: light.py:74
tuple[int, int, int, int]|None rgbw_color(self)
Definition: __init__.py:962
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
bool add(self, _T matcher)
Definition: match.py:185
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: light.py:35
list[tuple[str, int]] discover(HomeAssistant hass)
Definition: config_flow.py:97
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