forked from angadsingh/wiz_light
-
Notifications
You must be signed in to change notification settings - Fork 0
/
light.py
307 lines (262 loc) · 8.45 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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
'''
ToDO:
- Change ATTR_BRIGHTNESS to ATTR_BRIGHTNESS_PCT ??
- ATTR_EFFECT_LIST - List of possible effects
'''
"""Platform for light integration."""
''' Stephan Traub @sbidy '''
import logging
import voluptuous as vol
from .wizlight import wizlight, PilotBuilder, PilotParser
from .scenes import SCENES
from homeassistant.exceptions import InvalidStateError
from homeassistant.core import callback
from homeassistant.const import STATE_OFF, STATE_ON
import homeassistant.util.color as color_utils
import homeassistant.helpers.config_validation as cv
# Import the device class from the component that you want to support
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
PLATFORM_SCHEMA,
Light,
ATTR_RGB_COLOR,
SUPPORT_COLOR,
SUPPORT_BRIGHTNESS,
ATTR_COLOR_TEMP,
SUPPORT_COLOR_TEMP,
ATTR_HS_COLOR,
SUPPORT_EFFECT,
ATTR_EFFECT,
)
from homeassistant.const import CONF_HOST, CONF_NAME
_LOGGER = logging.getLogger(__name__)
# Validation of the user's configuration
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_NAME): cv.string
})
SUPPORT_FEATURES = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR | SUPPORT_COLOR_TEMP | SUPPORT_EFFECT )
def setup_platform(hass, config, add_entities, discovery_info=None):
"""
Set up the WiZ Light platform.
"""
# Assign configuration variables.
# The configuration check takes care they are present.
ip = config[CONF_HOST]
bulb = wizlight(ip)
# Add devices
add_entities([WizBulb(bulb, config[CONF_NAME])])
class WizBulb(Light):
"""
Representation of WiZ Light bulb
"""
def __init__(self, light, name):
"""
Initialize an WiZLight.
"""
self._light = light
self._state = None
self._brightness = None
self._name = name
self._rgb_color = None
self._temperature = None
self._hscolor = None
self._available = None
self._effect = None
self._scenes = []
@property
def brightness(self):
"""
Return the brightness of the light.
"""
return self._brightness
@property
def rgb_color(self):
"""
Return the color property.
"""
return self._rgb_color
@property
def hs_color(self):
"""Return the hs color value."""
return self._hscolor
@property
def name(self):
"""
Return the ip as name of the device if any.
"""
return self._name
@property
def is_on(self):
"""
Return true if light is on.
"""
return self._state
async def async_turn_on(self, **kwargs):
"""
Instruct the light to turn on.
"""
# TODO: change this to set state using a single UDP call
#
rgb = None
if ATTR_RGB_COLOR in kwargs:
rgb = kwargs[ATTR_RGB_COLOR]
if ATTR_HS_COLOR in kwargs:
rgb = color_utils.color_hs_to_RGB(kwargs[ATTR_HS_COLOR][0], kwargs[ATTR_HS_COLOR][1])
brightness = None
if ATTR_BRIGHTNESS in kwargs:
brightness = kwargs[ATTR_BRIGHTNESS]
colortemp = None
if ATTR_COLOR_TEMP in kwargs:
kelvin = color_utils.color_temperature_mired_to_kelvin(kwargs[ATTR_COLOR_TEMP])
colortemp = kelvin
sceneid = None
if ATTR_EFFECT in kwargs:
sceneid = self._light.get_id_from_scene_name(kwargs[ATTR_EFFECT])
if sceneid == 1000: #rhythm
pilot = PilotBuilder()
else:
pilot = PilotBuilder(
rgb = rgb,
brightness = brightness,
colortemp = colortemp,
scene = sceneid
)
await self._light.turn_on(pilot)
async def async_turn_off(self, **kwargs):
"""
Instruct the light to turn off.
"""
await self._light.turn_off()
@property
def color_temp(self):
"""
Return the CT color value in mireds.
"""
return self._temperature
@property
def min_mireds(self):
"""
Return the coldest color_temp that this light supports.
"""
return color_utils.color_temperature_kelvin_to_mired(6500)
@property
def max_mireds(self):
"""
Return the warmest color_temp that this light supports.
"""
return color_utils.color_temperature_kelvin_to_mired(2500)
@property
def supported_features(self) -> int:
"""
Flag supported features.
"""
return SUPPORT_FEATURES
@property
def effect(self):
"""Return the current effect."""
return self._effect
@property
def effect_list(self):
"""Return the list of supported effects."""
return self._scenes
@property
def available(self):
"""Return if light is available."""
return self._available
async def async_update(self):
"""
Fetch new state data for this light.
This is the only method that should fetch new data for Home Assistant.
"""
await self.update_state()
if self._state != None and self._state != False:
self.update_brightness()
self.update_temperature()
self.update_color()
self.update_effect()
self.update_scene_list()
async def update_state_available(self):
self._state = self._light.status
self._available = True
async def update_state_unavailable(self):
self._state = False
self._available = False
async def update_state(self):
"""
Update the state
"""
try:
_LOGGER.debug("[wizlight {}] updating state".format(self._light.ip))
await self._light.updateState()
if self._light.state == None:
await self.update_state_unavailable()
else:
await self.update_state_available()
except Exception as ex:
_LOGGER.error(ex)
await self.update_state_unavailable()
_LOGGER.debug("[wizlight {}] updated state: {}".format(self._light.ip, self._state))
def update_brightness(self):
"""
Update the brightness.
"""
if self._light.state.get_brightness() is None:
return
try:
brightness = self._light.state.get_brightness()
if 0 <= int(brightness) <= 255:
self._brightness = int(brightness)
else:
_LOGGER.error(
"Received invalid brightness : %s. Expected: 0-255", brightness
)
self._brightness = None
except Exception as ex:
_LOGGER.error(ex)
self._state = None
def update_temperature(self):
"""
Update the temperature
"""
if self._light.state.get_colortemp() is None:
return
try:
temperature = color_utils.color_temperature_kelvin_to_mired(self._light.state.get_colortemp())
self._temperature = temperature
except Exception:
_LOGGER.error("Cannot evaluate temperature", exc_info=True)
self._temperature = None
def update_color(self):
"""
Update the hs color
"""
if self._light.state.get_rgb() is None:
return
try:
r, g, b = self._light.state.get_rgb()
if r is None:
# this is the case if the temperature was changed - no infomation was return form the lamp.
# do nothing until the RGB color was changed
return
color = color_utils.color_RGB_to_hs(r,g,b)
if color is not None:
self._hscolor = color
else:
_LOGGER.error(
"Received invalid HS color : %s", color
)
self._hscolor = None
except Exception:
_LOGGER.error("Cannot evaluate color", exc_info=True)
self._hscolor = None
def update_effect(self):
'''
update the bulb scene
'''
self._effect = self._light.state.get_scene()
# TODO: this should be improved :-)
def update_scene_list(self):
self._scenes = []
for id in SCENES:
self._scenes.append(SCENES[id])