-
Notifications
You must be signed in to change notification settings - Fork 1
/
light.py
249 lines (208 loc) · 8.55 KB
/
light.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
"""Support for VeSync bulbs and wall dimmers."""
import logging
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP,
LightEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .common import VeSyncDevice, is_humidifier
from .const import DEV_TYPE_TO_HA, DOMAIN, VS_DISCOVERY, VS_LIGHTS
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up lights."""
@callback
def discover(devices):
"""Add new devices to platform."""
_setup_entities(devices, async_add_entities)
config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_LIGHTS), discover)
)
_setup_entities(hass.data[DOMAIN][VS_LIGHTS], async_add_entities)
@callback
def _setup_entities(devices, async_add_entities):
"""Check if device is online and add entity."""
entities = []
for dev in devices:
if DEV_TYPE_TO_HA.get(dev.device_type) in ("walldimmer", "bulb-dimmable"):
entities.append(VeSyncDimmableLightHA(dev))
elif DEV_TYPE_TO_HA.get(dev.device_type) in ("bulb-tunable-white",):
entities.append(VeSyncTunableWhiteLightHA(dev))
elif is_humidifier(dev.device_type):
entities.append(VeSyncHumidifierNightLightHA(dev))
else:
_LOGGER.debug(
"%s - Unknown device type - %s", dev.device_name, dev.device_type
)
continue
async_add_entities(entities, update_before_add=True)
def _vesync_brightness_to_ha(vesync_brightness):
try:
# check for validity of brightness value received
brightness_value = int(vesync_brightness)
except ValueError:
# deal if any unexpected/non numeric value
_LOGGER.debug(
"VeSync - received unexpected 'brightness' value from pyvesync api: %s",
vesync_brightness,
)
return 0
# convert percent brightness to ha expected range
return round((max(1, brightness_value) / 100) * 255)
def _ha_brightness_to_vesync(ha_brightness):
# get brightness from HA data
brightness = int(ha_brightness)
# ensure value between 1-255
brightness = max(1, min(brightness, 255))
# convert to percent that vesync api expects
brightness = round((brightness / 255) * 100)
# ensure value between 1-100
brightness = max(1, min(brightness, 100))
return brightness
class VeSyncBaseLight(VeSyncDevice, LightEntity):
"""Base class for VeSync Light Devices Representations."""
@property
def brightness(self):
"""Get light brightness."""
# get value from pyvesync library api,
return _vesync_brightness_to_ha(self.device.brightness)
def turn_on(self, **kwargs):
"""Turn the device on."""
attribute_adjustment_only = False
# set white temperature
if self.color_mode in (COLOR_MODE_COLOR_TEMP,) and ATTR_COLOR_TEMP in kwargs:
# get white temperature from HA data
color_temp = int(kwargs[ATTR_COLOR_TEMP])
# ensure value between min-max supported Mireds
color_temp = max(self.min_mireds, min(color_temp, self.max_mireds))
# convert Mireds to Percent value that api expects
color_temp = round(
((color_temp - self.min_mireds) / (self.max_mireds - self.min_mireds))
* 100
)
# flip cold/warm to what pyvesync api expects
color_temp = 100 - color_temp
# ensure value between 0-100
color_temp = max(0, min(color_temp, 100))
# call pyvesync library api method to set color_temp
self.device.set_color_temp(color_temp)
# flag attribute_adjustment_only, so it doesn't turn_on the device redundantly
attribute_adjustment_only = True
# set brightness level
if (
self.color_mode in (COLOR_MODE_BRIGHTNESS, COLOR_MODE_COLOR_TEMP)
and ATTR_BRIGHTNESS in kwargs
):
# get brightness from HA data
brightness = _ha_brightness_to_vesync(kwargs[ATTR_BRIGHTNESS])
self.device.set_brightness(brightness)
# flag attribute_adjustment_only, so it doesn't turn_on the device redundantly
attribute_adjustment_only = True
# check flag if should skip sending the turn_on command
if attribute_adjustment_only:
return
# send turn_on command to pyvesync api
self.device.turn_on()
class VeSyncDimmableLightHA(VeSyncBaseLight, LightEntity):
"""Representation of a VeSync dimmable light device."""
@property
def color_mode(self):
"""Set color mode for this entity."""
return COLOR_MODE_BRIGHTNESS
@property
def supported_color_modes(self):
"""Flag supported color_modes (in an array format)."""
return [COLOR_MODE_BRIGHTNESS]
class VeSyncTunableWhiteLightHA(VeSyncBaseLight, LightEntity):
"""Representation of a VeSync Tunable White Light device."""
@property
def color_temp(self):
"""Get device white temperature."""
# get value from pyvesync library api,
result = self.device.color_temp_pct
try:
# check for validity of brightness value received
color_temp_value = int(result)
except ValueError:
# deal if any unexpected/non numeric value
_LOGGER.debug(
"VeSync - received unexpected 'color_temp_pct' value from pyvesync api: %s",
result,
)
return 0
# flip cold/warm
color_temp_value = 100 - color_temp_value
# ensure value between 0-100
color_temp_value = max(0, min(color_temp_value, 100))
# convert percent value to Mireds
color_temp_value = round(
self.min_mireds
+ ((self.max_mireds - self.min_mireds) / 100 * color_temp_value)
)
# ensure value between minimum and maximum Mireds
return max(self.min_mireds, min(color_temp_value, self.max_mireds))
@property
def min_mireds(self):
"""Set device coldest white temperature."""
return 154 # 154 Mireds ( 1,000,000 divided by 6500 Kelvin = 154 Mireds)
@property
def max_mireds(self):
"""Set device warmest white temperature."""
return 370 # 370 Mireds ( 1,000,000 divided by 2700 Kelvin = 370 Mireds)
@property
def color_mode(self):
"""Set color mode for this entity."""
return COLOR_MODE_COLOR_TEMP
@property
def supported_color_modes(self):
"""Flag supported color_modes (in an array format)."""
return [COLOR_MODE_COLOR_TEMP]
class VeSyncHumidifierNightLightHA(VeSyncDimmableLightHA):
"""Representation of the night light on a VeSync humidifier."""
def __init__(self, humidifier):
"""Initialize the VeSync humidifier device."""
super().__init__(humidifier)
self.smarthumidifier = humidifier
@property
def unique_id(self):
"""Return the ID of this device."""
return f"{super().unique_id}-night-light"
@property
def name(self):
"""Return the name of the device."""
return f"{super().name} night light"
@property
def brightness(self):
"""Get night light brightness."""
# get value from pyvesync library api,
return _vesync_brightness_to_ha(
self.smarthumidifier.details["night_light_brightness"]
)
@property
def is_on(self):
"""Return True if night light is on."""
return self.smarthumidifier.details["night_light_brightness"] > 0
@property
def entity_category(self):
"""Return the configuration entity category."""
return EntityCategory.CONFIG
def turn_on(self, **kwargs):
"""Turn the night light on."""
if ATTR_BRIGHTNESS in kwargs:
brightness = _ha_brightness_to_vesync(kwargs[ATTR_BRIGHTNESS])
self.smarthumidifier.set_night_light_brightness(brightness)
else:
self.smarthumidifier.set_night_light_brightness(100)
def turn_off(self, **kwargs):
"""Turn the night light off."""
self.smarthumidifier.set_night_light_brightness(0)