hass-core/homeassistant/components/light/deconz.py
Leonardo Brondani Schenkel 10d1e81f10 deconz: fix light.turn_off with transition (#15222)
When light.turn_off is invoked with a transition, the following payload was
sent to deCONZ via PUT to /light/N/state:

{ "bri": 0, "transitiontime": transition }

However, on recent versions of deCONZ (latest is 2.05.31 at the time of
writing) this does not turn off the light, just sets it to minimum brightness
level (brightness is clamped to minimum level the light supports without
turning it off).

This commit makes the code send this payload instead:

{ "on": false, "transitiontime": transition }

This works as intended and the light does transition to the 'off' state.
This change was tested with Philips Hue colored lights, IKEA colored lights
and IKEA white spectrum lights: they were all able to be turned off
successfully with the new payload, and none of them could be turned off with
the old payload.
2018-06-30 00:59:10 +02:00

187 lines
5.8 KiB
Python

"""
Support for deCONZ light.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/light.deconz/
"""
from homeassistant.components.deconz import (
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID, DATA_DECONZ_UNSUB)
from homeassistant.components.deconz.const import CONF_ALLOW_DECONZ_GROUPS
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_HS_COLOR,
ATTR_TRANSITION, EFFECT_COLORLOOP, FLASH_LONG, FLASH_SHORT,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT,
SUPPORT_FLASH, SUPPORT_TRANSITION, Light)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
import homeassistant.util.color as color_util
DEPENDENCIES = ['deconz']
async def async_setup_platform(hass, config, async_add_devices,
discovery_info=None):
"""Old way of setting up deCONZ lights and group."""
pass
async def async_setup_entry(hass, config_entry, async_add_devices):
"""Set up the deCONZ lights and groups from a config entry."""
@callback
def async_add_light(lights):
"""Add light from deCONZ."""
entities = []
for light in lights:
entities.append(DeconzLight(light))
async_add_devices(entities, True)
hass.data[DATA_DECONZ_UNSUB].append(
async_dispatcher_connect(hass, 'deconz_new_light', async_add_light))
@callback
def async_add_group(groups):
"""Add group from deCONZ."""
entities = []
allow_group = config_entry.data.get(CONF_ALLOW_DECONZ_GROUPS, True)
for group in groups:
if group.lights and allow_group:
entities.append(DeconzLight(group))
async_add_devices(entities, True)
hass.data[DATA_DECONZ_UNSUB].append(
async_dispatcher_connect(hass, 'deconz_new_group', async_add_group))
async_add_light(hass.data[DATA_DECONZ].lights.values())
async_add_group(hass.data[DATA_DECONZ].groups.values())
class DeconzLight(Light):
"""Representation of a deCONZ light."""
def __init__(self, light):
"""Set up light and add update callback to get data from websocket."""
self._light = light
self._features = SUPPORT_BRIGHTNESS
self._features |= SUPPORT_FLASH
self._features |= SUPPORT_TRANSITION
if self._light.ct is not None:
self._features |= SUPPORT_COLOR_TEMP
if self._light.xy is not None:
self._features |= SUPPORT_COLOR
if self._light.effect is not None:
self._features |= SUPPORT_EFFECT
async def async_added_to_hass(self):
"""Subscribe to lights events."""
self._light.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._light.deconz_id
@callback
def async_update_callback(self, reason):
"""Update the light's state."""
self.async_schedule_update_ha_state()
@property
def brightness(self):
"""Return the brightness of this light between 0..255."""
return self._light.brightness
@property
def effect_list(self):
"""Return the list of supported effects."""
return [EFFECT_COLORLOOP]
@property
def color_temp(self):
"""Return the CT color value."""
return self._light.ct
@property
def hs_color(self):
"""Return the hs color value."""
if self._light.colormode in ('xy', 'hs') and self._light.xy:
return color_util.color_xy_to_hs(*self._light.xy)
return None
@property
def is_on(self):
"""Return true if light is on."""
return self._light.state
@property
def name(self):
"""Return the name of the light."""
return self._light.name
@property
def unique_id(self):
"""Return a unique identifier for this light."""
return self._light.uniqueid
@property
def supported_features(self):
"""Flag supported features."""
return self._features
@property
def available(self):
"""Return True if light is available."""
return self._light.reachable
@property
def should_poll(self):
"""No polling needed."""
return False
async def async_turn_on(self, **kwargs):
"""Turn on light."""
data = {'on': True}
if ATTR_COLOR_TEMP in kwargs:
data['ct'] = kwargs[ATTR_COLOR_TEMP]
if ATTR_HS_COLOR in kwargs:
data['xy'] = color_util.color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
if ATTR_BRIGHTNESS in kwargs:
data['bri'] = kwargs[ATTR_BRIGHTNESS]
if ATTR_TRANSITION in kwargs:
data['transitiontime'] = int(kwargs[ATTR_TRANSITION]) * 10
if ATTR_FLASH in kwargs:
if kwargs[ATTR_FLASH] == FLASH_SHORT:
data['alert'] = 'select'
del data['on']
elif kwargs[ATTR_FLASH] == FLASH_LONG:
data['alert'] = 'lselect'
del data['on']
if ATTR_EFFECT in kwargs:
if kwargs[ATTR_EFFECT] == EFFECT_COLORLOOP:
data['effect'] = 'colorloop'
else:
data['effect'] = 'none'
await self._light.async_set_state(data)
async def async_turn_off(self, **kwargs):
"""Turn off light."""
data = {'on': False}
if ATTR_TRANSITION in kwargs:
data['transitiontime'] = int(kwargs[ATTR_TRANSITION]) * 10
if ATTR_FLASH in kwargs:
if kwargs[ATTR_FLASH] == FLASH_SHORT:
data['alert'] = 'select'
del data['on']
elif kwargs[ATTR_FLASH] == FLASH_LONG:
data['alert'] = 'lselect'
del data['on']
await self._light.async_set_state(data)