Home Assistant Unofficial Reference 2024.12.1
light.py
Go to the documentation of this file.
1 """Provides a light for Home Connect."""
2 
3 from dataclasses import dataclass
4 import logging
5 from math import ceil
6 from typing import Any
7 
8 from homeconnect.api import HomeConnectError
9 
11  ATTR_BRIGHTNESS,
12  ATTR_HS_COLOR,
13  ATTR_RGB_COLOR,
14  ColorMode,
15  LightEntity,
16  LightEntityDescription,
17 )
18 from homeassistant.core import HomeAssistant
19 from homeassistant.exceptions import ServiceValidationError
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 import homeassistant.util.color as color_util
22 
23 from . import HomeConnectConfigEntry, get_dict_from_home_connect_error
24 from .api import HomeConnectDevice
25 from .const import (
26  ATTR_VALUE,
27  BSH_AMBIENT_LIGHT_BRIGHTNESS,
28  BSH_AMBIENT_LIGHT_COLOR,
29  BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR,
30  BSH_AMBIENT_LIGHT_CUSTOM_COLOR,
31  BSH_AMBIENT_LIGHT_ENABLED,
32  COOKING_LIGHTING,
33  COOKING_LIGHTING_BRIGHTNESS,
34  DOMAIN,
35  REFRIGERATION_EXTERNAL_LIGHT_BRIGHTNESS,
36  REFRIGERATION_EXTERNAL_LIGHT_POWER,
37  REFRIGERATION_INTERNAL_LIGHT_BRIGHTNESS,
38  REFRIGERATION_INTERNAL_LIGHT_POWER,
39  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
40 )
41 from .entity import HomeConnectEntity
42 
43 _LOGGER = logging.getLogger(__name__)
44 
45 
46 @dataclass(frozen=True, kw_only=True)
48  """Light entity description."""
49 
50  brightness_key: str | None = None
51  color_key: str | None = None
52  enable_custom_color_value_key: str | None = None
53  custom_color_key: str | None = None
54  brightness_scale: tuple[float, float] = (0.0, 100.0)
55 
56 
57 LIGHTS: tuple[HomeConnectLightEntityDescription, ...] = (
59  key=REFRIGERATION_INTERNAL_LIGHT_POWER,
60  brightness_key=REFRIGERATION_INTERNAL_LIGHT_BRIGHTNESS,
61  brightness_scale=(1.0, 100.0),
62  translation_key="internal_light",
63  ),
65  key=REFRIGERATION_EXTERNAL_LIGHT_POWER,
66  brightness_key=REFRIGERATION_EXTERNAL_LIGHT_BRIGHTNESS,
67  brightness_scale=(1.0, 100.0),
68  translation_key="external_light",
69  ),
71  key=COOKING_LIGHTING,
72  brightness_key=COOKING_LIGHTING_BRIGHTNESS,
73  brightness_scale=(10.0, 100.0),
74  translation_key="cooking_lighting",
75  ),
77  key=BSH_AMBIENT_LIGHT_ENABLED,
78  brightness_key=BSH_AMBIENT_LIGHT_BRIGHTNESS,
79  color_key=BSH_AMBIENT_LIGHT_COLOR,
80  enable_custom_color_value_key=BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR,
81  custom_color_key=BSH_AMBIENT_LIGHT_CUSTOM_COLOR,
82  brightness_scale=(10.0, 100.0),
83  translation_key="ambient_light",
84  ),
85 )
86 
87 
89  hass: HomeAssistant,
90  entry: HomeConnectConfigEntry,
91  async_add_entities: AddEntitiesCallback,
92 ) -> None:
93  """Set up the Home Connect light."""
94 
95  def get_entities() -> list[LightEntity]:
96  """Get a list of entities."""
97  return [
98  HomeConnectLight(device, description)
99  for description in LIGHTS
100  for device in entry.runtime_data.devices
101  if description.key in device.appliance.status
102  ]
103 
104  async_add_entities(await hass.async_add_executor_job(get_entities), True)
105 
106 
108  """Light for Home Connect."""
109 
110  entity_description: LightEntityDescription
111 
112  def __init__(
113  self, device: HomeConnectDevice, desc: HomeConnectLightEntityDescription
114  ) -> None:
115  """Initialize the entity."""
116  super().__init__(device, desc)
117 
118  def get_setting_key_if_setting_exists(setting_key: str | None) -> str | None:
119  if setting_key and setting_key in device.appliance.status:
120  return setting_key
121  return None
122 
123  self._brightness_key_brightness_key = get_setting_key_if_setting_exists(desc.brightness_key)
124  self._custom_color_key_custom_color_key = get_setting_key_if_setting_exists(
125  desc.custom_color_key
126  )
127  self._color_key_color_key = get_setting_key_if_setting_exists(desc.color_key)
128  self._enable_custom_color_value_key_enable_custom_color_value_key = desc.enable_custom_color_value_key
129  self._custom_color_key_custom_color_key = get_setting_key_if_setting_exists(
130  desc.custom_color_key
131  )
132  self._brightness_scale_brightness_scale = desc.brightness_scale
133 
134  match (self._brightness_key_brightness_key, self._custom_color_key_custom_color_key):
135  case (None, None):
136  self._attr_color_mode_attr_color_mode = ColorMode.ONOFF
137  self._attr_supported_color_modes_attr_supported_color_modes = {ColorMode.ONOFF}
138  case (_, None):
139  self._attr_color_mode_attr_color_mode = ColorMode.BRIGHTNESS
140  self._attr_supported_color_modes_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
141  case (_, _):
142  self._attr_color_mode_attr_color_mode = ColorMode.HS
143  self._attr_supported_color_modes_attr_supported_color_modes = {ColorMode.HS, ColorMode.RGB}
144 
145  async def async_turn_on(self, **kwargs: Any) -> None:
146  """Switch the light on, change brightness, change color."""
147  _LOGGER.debug("Switching light on for: %s", self.namename)
148  try:
149  await self.hasshass.async_add_executor_job(
150  self.devicedevice.appliance.set_setting, self.bsh_keybsh_key, True
151  )
152  except HomeConnectError as err:
154  translation_domain=DOMAIN,
155  translation_key="turn_on_light",
156  translation_placeholders={
158  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_identity_id,
159  },
160  ) from err
161  if self._custom_color_key_custom_color_key:
162  if (
163  ATTR_RGB_COLOR in kwargs or ATTR_HS_COLOR in kwargs
164  ) and self._enable_custom_color_value_key_enable_custom_color_value_key:
165  try:
166  await self.hasshass.async_add_executor_job(
167  self.devicedevice.appliance.set_setting,
168  self._color_key_color_key,
169  self._enable_custom_color_value_key_enable_custom_color_value_key,
170  )
171  except HomeConnectError as err:
173  translation_domain=DOMAIN,
174  translation_key="select_light_custom_color",
175  translation_placeholders={
177  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_identity_id,
178  },
179  ) from err
180 
181  if ATTR_RGB_COLOR in kwargs:
182  hex_val = color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR])
183  try:
184  await self.hasshass.async_add_executor_job(
185  self.devicedevice.appliance.set_setting,
186  self._custom_color_key_custom_color_key,
187  f"#{hex_val}",
188  )
189  except HomeConnectError as err:
191  translation_domain=DOMAIN,
192  translation_key="set_light_color",
193  translation_placeholders={
195  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_identity_id,
196  },
197  ) from err
198  elif (ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs) and (
199  self._attr_brightness_attr_brightness is not None or ATTR_BRIGHTNESS in kwargs
200  ):
201  brightness = 10 + ceil(
202  color_util.brightness_to_value(
203  self._brightness_scale_brightness_scale,
204  kwargs.get(ATTR_BRIGHTNESS, self._attr_brightness_attr_brightness),
205  )
206  )
207 
208  hs_color = kwargs.get(ATTR_HS_COLOR, self._attr_hs_color_attr_hs_color)
209 
210  if hs_color is not None:
211  rgb = color_util.color_hsv_to_RGB(
212  hs_color[0], hs_color[1], brightness
213  )
214  hex_val = color_util.color_rgb_to_hex(*rgb)
215  try:
216  await self.hasshass.async_add_executor_job(
217  self.devicedevice.appliance.set_setting,
218  self._custom_color_key_custom_color_key,
219  f"#{hex_val}",
220  )
221  except HomeConnectError as err:
223  translation_domain=DOMAIN,
224  translation_key="set_light_color",
225  translation_placeholders={
227  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_identity_id,
228  },
229  ) from err
230 
231  elif self._brightness_key_brightness_key and ATTR_BRIGHTNESS in kwargs:
232  _LOGGER.debug(
233  "Changing brightness for: %s, to: %s",
234  self.namename,
235  kwargs[ATTR_BRIGHTNESS],
236  )
237  brightness = ceil(
238  color_util.brightness_to_value(
239  self._brightness_scale_brightness_scale, kwargs[ATTR_BRIGHTNESS]
240  )
241  )
242  try:
243  await self.hasshass.async_add_executor_job(
244  self.devicedevice.appliance.set_setting, self._brightness_key_brightness_key, brightness
245  )
246  except HomeConnectError as err:
248  translation_domain=DOMAIN,
249  translation_key="set_light_brightness",
250  translation_placeholders={
252  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_identity_id,
253  },
254  ) from err
255 
256  self.async_entity_updateasync_entity_update()
257 
258  async def async_turn_off(self, **kwargs: Any) -> None:
259  """Switch the light off."""
260  _LOGGER.debug("Switching light off for: %s", self.namename)
261  try:
262  await self.hasshass.async_add_executor_job(
263  self.devicedevice.appliance.set_setting, self.bsh_keybsh_key, False
264  )
265  except HomeConnectError as err:
267  translation_domain=DOMAIN,
268  translation_key="turn_off_light",
269  translation_placeholders={
271  SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_identity_id,
272  },
273  ) from err
274  self.async_entity_updateasync_entity_update()
275 
276  async def async_update(self) -> None:
277  """Update the light's status."""
278  if self.devicedevice.appliance.status.get(self.bsh_keybsh_key, {}).get(ATTR_VALUE) is True:
279  self._attr_is_on_attr_is_on = True
280  elif (
281  self.devicedevice.appliance.status.get(self.bsh_keybsh_key, {}).get(ATTR_VALUE) is False
282  ):
283  self._attr_is_on_attr_is_on = False
284  else:
285  self._attr_is_on_attr_is_on = None
286 
287  _LOGGER.debug("Updated, new light state: %s", self._attr_is_on_attr_is_on)
288 
289  if self._custom_color_key_custom_color_key:
290  color = self.devicedevice.appliance.status.get(self._custom_color_key_custom_color_key, {})
291 
292  if not color:
293  self._attr_rgb_color_attr_rgb_color = None
294  self._attr_hs_color_attr_hs_color = None
295  self._attr_brightness_attr_brightness = None
296  else:
297  color_value = color.get(ATTR_VALUE)[1:]
298  rgb = color_util.rgb_hex_to_rgb_list(color_value)
299  self._attr_rgb_color_attr_rgb_color = (rgb[0], rgb[1], rgb[2])
300  hsv = color_util.color_RGB_to_hsv(*rgb)
301  self._attr_hs_color_attr_hs_color = (hsv[0], hsv[1])
302  self._attr_brightness_attr_brightness = color_util.value_to_brightness(
303  self._brightness_scale_brightness_scale, hsv[2]
304  )
305  _LOGGER.debug(
306  "Updated, new color (%s) and new brightness (%s) ",
307  color_value,
308  self._attr_brightness_attr_brightness,
309  )
310  elif self._brightness_key_brightness_key:
311  brightness = self.devicedevice.appliance.status.get(self._brightness_key_brightness_key, {})
312  if brightness is None:
313  self._attr_brightness_attr_brightness = None
314  else:
315  self._attr_brightness_attr_brightness = color_util.value_to_brightness(
316  self._brightness_scale_brightness_scale, brightness[ATTR_VALUE]
317  )
318  _LOGGER.debug("Updated, new brightness: %s", self._attr_brightness_attr_brightness)
None __init__(self, HomeConnectDevice device, HomeConnectLightEntityDescription desc)
Definition: light.py:114
str|UndefinedType|None name(self)
Definition: entity.py:738
list[BaseAprilaireSensor] get_entities(type[BaseAprilaireSensor] entity_class, AprilaireCoordinator coordinator, str unique_id, tuple[AprilaireSensorDescription,...] descriptions)
Definition: sensor.py:64
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_entry(HomeAssistant hass, HomeConnectConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: light.py:92
dict[str, Any] get_dict_from_home_connect_error(api.HomeConnectError err)
Definition: __init__.py:334