Home Assistant Unofficial Reference 2024.12.1
light.py
Go to the documentation of this file.
1 """Support for Crownstone devices."""
2 
3 from __future__ import annotations
4 
5 from functools import partial
6 from typing import TYPE_CHECKING, Any
7 
8 from crownstone_cloud.cloud_models.crownstones import Crownstone
9 from crownstone_cloud.const import DIMMING_ABILITY
10 from crownstone_cloud.exceptions import CrownstoneAbilityError
11 from crownstone_uart import CrownstoneUart
12 
13 from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.core import HomeAssistant
16 from homeassistant.exceptions import HomeAssistantError
17 from homeassistant.helpers.dispatcher import async_dispatcher_connect
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 
20 from .const import (
21  CROWNSTONE_INCLUDE_TYPES,
22  CROWNSTONE_SUFFIX,
23  DOMAIN,
24  SIG_CROWNSTONE_STATE_UPDATE,
25  SIG_UART_STATE_CHANGE,
26 )
27 from .entity import CrownstoneEntity
28 from .helpers import map_from_to
29 
30 if TYPE_CHECKING:
31  from .entry_manager import CrownstoneEntryManager
32 
33 
35  hass: HomeAssistant,
36  config_entry: ConfigEntry,
37  async_add_entities: AddEntitiesCallback,
38 ) -> None:
39  """Set up crownstones from a config entry."""
40  manager: CrownstoneEntryManager = hass.data[DOMAIN][config_entry.entry_id]
41 
42  entities: list[CrownstoneLightEntity] = []
43 
44  # Add Crownstone entities that support switching/dimming
45  for sphere in manager.cloud.cloud_data:
46  for crownstone in sphere.crownstones:
47  if crownstone.type in CROWNSTONE_INCLUDE_TYPES:
48  # Crownstone can communicate with Crownstone USB
49  if manager.uart and sphere.cloud_id == manager.usb_sphere_id:
50  entities.append(CrownstoneLightEntity(crownstone, manager.uart))
51  # Crownstone can't communicate with Crownstone USB
52  else:
53  entities.append(CrownstoneLightEntity(crownstone))
54 
55  async_add_entities(entities)
56 
57 
58 def crownstone_state_to_hass(value: int) -> int:
59  """Crownstone 0..100 to hass 0..255."""
60  return map_from_to(value, 0, 100, 0, 255)
61 
62 
63 def hass_to_crownstone_state(value: int) -> int:
64  """Hass 0..255 to Crownstone 0..100."""
65  return map_from_to(value, 0, 255, 0, 100)
66 
67 
69  """Representation of a crownstone.
70 
71  Light platform is used to support dimming.
72  """
73 
74  _attr_name = None
75  _attr_translation_key = "german_power_outlet"
76 
77  def __init__(
78  self, crownstone_data: Crownstone, usb: CrownstoneUart | None = None
79  ) -> None:
80  """Initialize the crownstone."""
81  super().__init__(crownstone_data)
82  self.usbusb = usb
83  # Entity class attributes
84  self._attr_unique_id_attr_unique_id = f"{self.cloud_id}-{CROWNSTONE_SUFFIX}"
85 
86  @property
87  def brightness(self) -> int | None:
88  """Return the brightness if dimming enabled."""
89  return crownstone_state_to_hass(self.devicedevice.state)
90 
91  @property
92  def is_on(self) -> bool:
93  """Return if the device is on."""
94  return crownstone_state_to_hass(self.devicedevice.state) > 0
95 
96  @property
97  def color_mode(self) -> str:
98  """Return the color mode of the light."""
99  if self.devicedevice.abilities.get(DIMMING_ABILITY).is_enabled:
100  return ColorMode.BRIGHTNESS
101  return ColorMode.ONOFF
102 
103  @property
104  def supported_color_modes(self) -> set[str] | None:
105  """Flag supported color modes."""
106  return {self.color_modecolor_modecolor_mode}
107 
108  async def async_added_to_hass(self) -> None:
109  """Set up a listener when this entity is added to HA."""
110  # new state received
111  self.async_on_removeasync_on_remove(
113  self.hasshass, SIG_CROWNSTONE_STATE_UPDATE, self.async_write_ha_stateasync_write_ha_state
114  )
115  )
116  # updates state attributes when usb connects/disconnects
117  self.async_on_removeasync_on_remove(
119  self.hasshass, SIG_UART_STATE_CHANGE, self.async_write_ha_stateasync_write_ha_state
120  )
121  )
122 
123  async def async_turn_on(self, **kwargs: Any) -> None:
124  """Turn on this light via dongle or cloud."""
125  if ATTR_BRIGHTNESS in kwargs:
126  if self.usbusb is not None and self.usbusb.is_ready():
127  await self.hasshass.async_add_executor_job(
128  partial(
129  self.usbusb.dim_crownstone,
130  self.devicedevice.unique_id,
131  hass_to_crownstone_state(kwargs[ATTR_BRIGHTNESS]),
132  )
133  )
134  else:
135  try:
136  await self.devicedevice.async_set_brightness(
137  hass_to_crownstone_state(kwargs[ATTR_BRIGHTNESS])
138  )
139  except CrownstoneAbilityError as ability_error:
140  raise HomeAssistantError(ability_error) from ability_error
141 
142  # assume brightness is set on device
143  self.devicedevice.state = hass_to_crownstone_state(kwargs[ATTR_BRIGHTNESS])
144  self.async_write_ha_stateasync_write_ha_state()
145 
146  elif self.usbusb is not None and self.usbusb.is_ready():
147  await self.hasshass.async_add_executor_job(
148  partial(self.usbusb.switch_crownstone, self.devicedevice.unique_id, on=True)
149  )
150  self.devicedevice.state = 100
151  self.async_write_ha_stateasync_write_ha_state()
152 
153  else:
154  await self.devicedevice.async_turn_on()
155  self.devicedevice.state = 100
156  self.async_write_ha_stateasync_write_ha_state()
157 
158  async def async_turn_off(self, **kwargs: Any) -> None:
159  """Turn off this device via dongle or cloud."""
160  if self.usbusb is not None and self.usbusb.is_ready():
161  await self.hasshass.async_add_executor_job(
162  partial(self.usbusb.switch_crownstone, self.devicedevice.unique_id, on=False)
163  )
164 
165  else:
166  await self.devicedevice.async_turn_off()
167 
168  self.devicedevice.state = 0
169  self.async_write_ha_stateasync_write_ha_state()
None __init__(self, Crownstone crownstone_data, CrownstoneUart|None usb=None)
Definition: light.py:79
ColorMode|str|None color_mode(self)
Definition: __init__.py:909
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
int map_from_to(int val, int in_min, int in_max, int out_min, int out_max)
Definition: helpers.py:58
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: light.py:38
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103