Add support for yeelight ceiling ambilight (#22346)

pull/22463/head
zewelor 2019-03-27 13:39:55 +01:00 committed by Sebastian Muszynski
parent 6540114ec5
commit 4de2efd07f
2 changed files with 120 additions and 30 deletions

View File

@ -91,6 +91,7 @@ YEELIGHT_SERVICE_SCHEMA = vol.Schema({
UPDATE_REQUEST_PROPERTIES = [
"power",
"main_power",
"bright",
"ct",
"rgb",
@ -98,6 +99,13 @@ UPDATE_REQUEST_PROPERTIES = [
"sat",
"color_mode",
"bg_power",
"bg_lmode",
"bg_flowing",
"bg_ct",
"bg_bright",
"bg_hue",
"bg_sat",
"bg_rgb",
"nl_br",
"active_mode",
]
@ -249,22 +257,34 @@ class YeelightDevice:
"""Return true / false if nightlight is supported."""
return self.bulb.get_model_specs().get('night_light', False)
def turn_on(self, duration=DEFAULT_TRANSITION):
@property
def is_ambilight_supported(self) -> bool:
"""Return true / false if ambilight is supported."""
return self.bulb.get_model_specs().get('background_light', False)
def turn_on(self, duration=DEFAULT_TRANSITION, light_type=None):
"""Turn on device."""
import yeelight
if not light_type:
light_type = yeelight.enums.LightType.Main
try:
self._bulb_device.turn_on(duration=duration)
self._bulb_device.turn_on(duration=duration, light_type=light_type)
except yeelight.BulbException as ex:
_LOGGER.error("Unable to turn the bulb on: %s", ex)
return
def turn_off(self, duration=DEFAULT_TRANSITION):
def turn_off(self, duration=DEFAULT_TRANSITION, light_type=None):
"""Turn off device."""
import yeelight
if not light_type:
light_type = yeelight.enums.LightType.Main
try:
self._bulb_device.turn_off(duration=duration)
self._bulb_device.turn_off(duration=duration,
light_type=light_type)
except yeelight.BulbException as ex:
_LOGGER.error("Unable to turn the bulb on: %s", ex)
return

View File

@ -110,10 +110,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
_LOGGER.debug("Adding %s", device.name)
custom_effects = discovery_info[CONF_CUSTOM_EFFECTS]
light = YeelightLight(device, custom_effects=custom_effects)
hass.data[data_key].append(light)
add_entities([light], True)
lights = [YeelightLight(device, custom_effects=custom_effects)]
if device.is_ambilight_supported:
lights.append(
YeelightAmbientLight(device, custom_effects=custom_effects))
hass.data[data_key] += lights
add_entities(lights, True)
def service_handler(service):
"""Dispatch service calls to target entities."""
@ -243,9 +248,16 @@ class YeelightLight(Light):
"""Return list with custom effects names."""
return list(self.custom_effects.keys())
@property
def light_type(self):
"""Return light type."""
import yeelight
return yeelight.enums.LightType.Main
def _get_hs_from_properties(self):
rgb = self._properties.get('rgb', None)
color_mode = self._properties.get('color_mode', None)
rgb = self._get_property('rgb')
color_mode = self._get_property('color_mode')
if not rgb or not color_mode:
return None
@ -254,8 +266,9 @@ class YeelightLight(Light):
temp_in_k = mired_to_kelvin(self._color_temp)
return color_util.color_temperature_to_hs(temp_in_k)
if color_mode == 3: # hsv
hue = int(self._properties.get('hue'))
sat = int(self._properties.get('sat'))
hue = int(self._get_property('hue'))
sat = int(self._get_property('sat'))
return (hue / 360 * 65536, sat / 100 * 255)
rgb = int(rgb)
@ -276,11 +289,18 @@ class YeelightLight(Light):
return {}
return self._bulb.last_properties
def _get_property(self, prop, default=None):
return self._properties.get(prop, default)
@property
def device(self):
"""Return yeelight device."""
return self._device
@property
def _is_nightlight_enabled(self):
return self.device.is_nightlight_enabled
# F821: https://github.com/PyCQA/pyflakes/issues/373
@property
def _bulb(self) -> 'yeelight.Bulb': # noqa: F821
@ -304,32 +324,41 @@ class YeelightLight(Light):
"""Update properties from the bulb."""
import yeelight
try:
if self._bulb.bulb_type == yeelight.BulbType.Color:
bulb_type = self._bulb.bulb_type
if bulb_type == yeelight.BulbType.Color:
self._supported_features = SUPPORT_YEELIGHT_RGB
elif self._bulb.bulb_type == yeelight.BulbType.WhiteTemp:
if self._device.is_nightlight_enabled:
elif self.light_type == yeelight.enums.LightType.Ambient:
self._supported_features = SUPPORT_YEELIGHT_RGB
elif bulb_type in (yeelight.BulbType.WhiteTemp,
yeelight.BulbType.WhiteTempMood):
if self._is_nightlight_enabled:
self._supported_features = SUPPORT_YEELIGHT
else:
self._supported_features = SUPPORT_YEELIGHT_WHITE_TEMP
if self._min_mireds is None:
if self.min_mireds is None:
model_specs = self._bulb.get_model_specs()
self._min_mireds = \
kelvin_to_mired(model_specs['color_temp']['max'])
self._max_mireds = \
kelvin_to_mired(model_specs['color_temp']['min'])
self._is_on = self._properties.get('power') == 'on'
if self._device.is_nightlight_enabled:
bright = self._properties.get('nl_br', None)
if bulb_type == yeelight.BulbType.WhiteTempMood:
self._is_on = self._get_property('main_power') == 'on'
else:
bright = self._properties.get('bright', None)
self._is_on = self._get_property('power') == 'on'
if self._is_nightlight_enabled:
bright = self._get_property('nl_br', None)
else:
bright = self._get_property('bright', None)
if bright:
self._brightness = round(255 * (int(bright) / 100))
temp_in_k = self._properties.get('ct', None)
temp_in_k = self._get_property('ct')
if temp_in_k:
self._color_temp = kelvin_to_mired(int(temp_in_k))
@ -347,14 +376,16 @@ class YeelightLight(Light):
if brightness:
_LOGGER.debug("Setting brightness: %s", brightness)
self._bulb.set_brightness(brightness / 255 * 100,
duration=duration)
duration=duration,
light_type=self.light_type)
@_cmd
def set_rgb(self, rgb, duration) -> None:
"""Set bulb's color."""
if rgb and self.supported_features & SUPPORT_COLOR:
_LOGGER.debug("Setting RGB: %s", rgb)
self._bulb.set_rgb(rgb[0], rgb[1], rgb[2], duration=duration)
self._bulb.set_rgb(rgb[0], rgb[1], rgb[2], duration=duration,
light_type=self.light_type)
@_cmd
def set_colortemp(self, colortemp, duration) -> None:
@ -363,7 +394,8 @@ class YeelightLight(Light):
temp_in_k = mired_to_kelvin(colortemp)
_LOGGER.debug("Setting color temp: %s K", temp_in_k)
self._bulb.set_color_temp(temp_in_k, duration=duration)
self._bulb.set_color_temp(temp_in_k, duration=duration,
light_type=self.light_type)
@_cmd
def set_default(self) -> None:
@ -401,7 +433,7 @@ class YeelightLight(Light):
flow = Flow(count=count, transitions=transitions)
try:
self._bulb.start_flow(flow)
self._bulb.start_flow(flow, light_type=self.light_type)
except BulbException as ex:
_LOGGER.error("Unable to set flash: %s", ex)
@ -415,7 +447,7 @@ class YeelightLight(Light):
police2, christmas, rgb,
randomloop, lsd, slowdown)
if effect == EFFECT_STOP:
self._bulb.stop_flow()
self._bulb.stop_flow(light_type=self.light_type)
return
effects_map = {
@ -447,7 +479,7 @@ class YeelightLight(Light):
flow = Flow(count=2, transitions=pulse(0, 172, 237))
try:
self._bulb.start_flow(flow)
self._bulb.start_flow(flow, light_type=self.light_type)
except BulbException as ex:
_LOGGER.error("Unable to set effect: %s", ex)
@ -465,7 +497,7 @@ class YeelightLight(Light):
if ATTR_TRANSITION in kwargs: # passed kwarg overrides config
duration = int(kwargs.get(ATTR_TRANSITION) * 1000) # kwarg in s
self.device.turn_on(duration=duration)
self.device.turn_on(duration=duration, light_type=self.light_type)
if self.config[CONF_MODE_MUSIC] and not self._bulb.music_mode:
try:
@ -502,7 +534,7 @@ class YeelightLight(Light):
if ATTR_TRANSITION in kwargs: # passed kwarg overrides config
duration = int(kwargs.get(ATTR_TRANSITION) * 1000) # kwarg in s
self.device.turn_off(duration=duration)
self.device.turn_off(duration=duration, light_type=self.light_type)
self.device.update()
def set_mode(self, mode: str):
@ -525,7 +557,45 @@ class YeelightLight(Light):
action=yeelight.Flow.actions[action],
transitions=transitions)
self._bulb.start_flow(flow)
self._bulb.start_flow(flow, light_type=self.light_type)
self.device.update()
except yeelight.BulbException as ex:
_LOGGER.error("Unable to set effect: %s", ex)
class YeelightAmbientLight(YeelightLight):
"""Representation of a Yeelight ambient light."""
PROPERTIES_MAPPING = {
"color_mode": "bg_lmode",
"main_power": "bg_power",
}
def __init__(self, *args, **kwargs):
"""Initialize the Yeelight Ambient light."""
super().__init__(*args, **kwargs)
self._min_mireds = kelvin_to_mired(6500)
self._max_mireds = kelvin_to_mired(1700)
@property
def name(self) -> str:
"""Return the name of the device if any."""
return "{} ambilight".format(self.device.name)
@property
def light_type(self):
"""Return light type."""
import yeelight
return yeelight.enums.LightType.Ambient
@property
def _is_nightlight_enabled(self):
return False
def _get_property(self, prop, default=None):
bg_prop = self.PROPERTIES_MAPPING.get(prop)
if not bg_prop:
bg_prop = "bg_" + prop
return self._properties.get(bg_prop, default)