Use supported color modes in deCONZ integration (#51656)
* Initial commit everything is working, need to reevaluate tests * Fix supported color modes and hs_color * Attest color mode
This commit is contained in:
parent
9097f41219
commit
b1022ce84e
2 changed files with 93 additions and 36 deletions
|
@ -1,5 +1,8 @@
|
|||
"""Support for deCONZ lights."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydeconz.group import DeconzGroup as Group
|
||||
from pydeconz.light import Light
|
||||
|
||||
from homeassistant.components.light import (
|
||||
|
@ -9,13 +12,16 @@ from homeassistant.components.light import (
|
|||
ATTR_FLASH,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_XY_COLOR,
|
||||
COLOR_MODE_BRIGHTNESS,
|
||||
COLOR_MODE_COLOR_TEMP,
|
||||
COLOR_MODE_HS,
|
||||
COLOR_MODE_ONOFF,
|
||||
COLOR_MODE_XY,
|
||||
DOMAIN,
|
||||
EFFECT_COLORLOOP,
|
||||
FLASH_LONG,
|
||||
FLASH_SHORT,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
SUPPORT_COLOR_TEMP,
|
||||
SUPPORT_EFFECT,
|
||||
SUPPORT_FLASH,
|
||||
SUPPORT_TRANSITION,
|
||||
|
@ -23,7 +29,6 @@ from homeassistant.components.light import (
|
|||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
import homeassistant.util.color as color_util
|
||||
|
||||
from .const import (
|
||||
COVER_TYPES,
|
||||
|
@ -106,24 +111,50 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
"""Set up light."""
|
||||
super().__init__(device, gateway)
|
||||
|
||||
self._attr_supported_color_modes = set()
|
||||
self.update_features(self._device)
|
||||
|
||||
def update_features(self, device):
|
||||
def update_features(self, device: Light | Group) -> None:
|
||||
"""Calculate supported features of device."""
|
||||
supported_color_modes = self._attr_supported_color_modes
|
||||
|
||||
if device.ct is not None:
|
||||
supported_color_modes.add(COLOR_MODE_COLOR_TEMP)
|
||||
|
||||
if device.hue is not None and device.sat is not None:
|
||||
supported_color_modes.add(COLOR_MODE_HS)
|
||||
|
||||
if device.xy is not None:
|
||||
supported_color_modes.add(COLOR_MODE_XY)
|
||||
|
||||
if not supported_color_modes and device.brightness is not None:
|
||||
supported_color_modes.add(COLOR_MODE_BRIGHTNESS)
|
||||
|
||||
if not supported_color_modes:
|
||||
supported_color_modes.add(COLOR_MODE_ONOFF)
|
||||
|
||||
if device.brightness is not None:
|
||||
self._attr_supported_features |= SUPPORT_BRIGHTNESS
|
||||
self._attr_supported_features |= SUPPORT_FLASH
|
||||
self._attr_supported_features |= SUPPORT_TRANSITION
|
||||
|
||||
if device.ct is not None:
|
||||
self._attr_supported_features |= SUPPORT_COLOR_TEMP
|
||||
|
||||
if device.xy is not None or (device.hue is not None and device.sat is not None):
|
||||
self._attr_supported_features |= SUPPORT_COLOR
|
||||
|
||||
if device.effect is not None:
|
||||
self._attr_supported_features |= SUPPORT_EFFECT
|
||||
|
||||
@property
|
||||
def color_mode(self) -> str:
|
||||
"""Return the color mode of the light."""
|
||||
if self._device.colormode == "ct":
|
||||
color_mode = COLOR_MODE_COLOR_TEMP
|
||||
elif self._device.colormode == "hs":
|
||||
color_mode = COLOR_MODE_HS
|
||||
elif self._device.colormode == "xy":
|
||||
color_mode = COLOR_MODE_XY
|
||||
elif self._device.brightness is not None:
|
||||
color_mode = COLOR_MODE_BRIGHTNESS
|
||||
else:
|
||||
color_mode = COLOR_MODE_ONOFF
|
||||
return color_mode
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
|
@ -137,20 +168,17 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
@property
|
||||
def color_temp(self):
|
||||
"""Return the CT color value."""
|
||||
if self._device.colormode != "ct":
|
||||
return None
|
||||
|
||||
return self._device.ct
|
||||
|
||||
@property
|
||||
def hs_color(self):
|
||||
def hs_color(self) -> tuple:
|
||||
"""Return the hs color value."""
|
||||
if self._device.colormode in ("xy", "hs"):
|
||||
if self._device.xy:
|
||||
return color_util.color_xy_to_hs(*self._device.xy)
|
||||
if self._device.hue and self._device.sat:
|
||||
return (self._device.hue / 65535 * 360, self._device.sat / 255 * 100)
|
||||
return None
|
||||
return (self._device.hue / 65535 * 360, self._device.sat / 255 * 100)
|
||||
|
||||
@property
|
||||
def xy_color(self) -> tuple | None:
|
||||
"""Return the XY color value."""
|
||||
return self._device.xy
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
|
@ -161,18 +189,18 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
|
|||
"""Turn on light."""
|
||||
data = {"on": True}
|
||||
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
data["bri"] = kwargs[ATTR_BRIGHTNESS]
|
||||
|
||||
if ATTR_COLOR_TEMP in kwargs:
|
||||
data["ct"] = kwargs[ATTR_COLOR_TEMP]
|
||||
|
||||
if ATTR_HS_COLOR in kwargs:
|
||||
if self._device.xy is not None:
|
||||
data["xy"] = color_util.color_hs_to_xy(*kwargs[ATTR_HS_COLOR])
|
||||
else:
|
||||
data["hue"] = int(kwargs[ATTR_HS_COLOR][0] / 360 * 65535)
|
||||
data["sat"] = int(kwargs[ATTR_HS_COLOR][1] / 100 * 255)
|
||||
data["hue"] = int(kwargs[ATTR_HS_COLOR][0] / 360 * 65535)
|
||||
data["sat"] = int(kwargs[ATTR_HS_COLOR][1] / 100 * 255)
|
||||
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
data["bri"] = kwargs[ATTR_BRIGHTNESS]
|
||||
if ATTR_XY_COLOR in kwargs:
|
||||
data["xy"] = kwargs[ATTR_XY_COLOR]
|
||||
|
||||
if ATTR_TRANSITION in kwargs:
|
||||
data["transitiontime"] = int(kwargs[ATTR_TRANSITION] * 10)
|
||||
|
@ -250,6 +278,21 @@ class DeconzGroup(DeconzBaseLight):
|
|||
if light.ZHATYPE == Light.ZHATYPE:
|
||||
self.update_features(light)
|
||||
|
||||
for exclusive_color_mode in [COLOR_MODE_ONOFF, COLOR_MODE_BRIGHTNESS]:
|
||||
if (
|
||||
exclusive_color_mode in self._attr_supported_color_modes
|
||||
and len(self._attr_supported_color_modes) > 1
|
||||
):
|
||||
self._attr_supported_color_modes.remove(exclusive_color_mode)
|
||||
|
||||
@property
|
||||
def hs_color(self) -> tuple | None:
|
||||
"""Return the hs color value."""
|
||||
try:
|
||||
return super().hs_color
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return a unique identifier for this device."""
|
||||
|
|
|
@ -7,13 +7,19 @@ import pytest
|
|||
from homeassistant.components.deconz.const import CONF_ALLOW_DECONZ_GROUPS
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_MODE,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_FLASH,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_MAX_MIREDS,
|
||||
ATTR_MIN_MIREDS,
|
||||
ATTR_SUPPORTED_COLOR_MODES,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_XY_COLOR,
|
||||
COLOR_MODE_COLOR_TEMP,
|
||||
COLOR_MODE_ONOFF,
|
||||
COLOR_MODE_XY,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
EFFECT_COLORLOOP,
|
||||
FLASH_LONG,
|
||||
|
@ -73,7 +79,7 @@ async def test_lights_and_groups(hass, aioclient_mock, mock_deconz_websocket):
|
|||
"bri": 255,
|
||||
"colormode": "xy",
|
||||
"effect": "colorloop",
|
||||
"xy": (500, 500),
|
||||
"xy": (0.5, 0.5),
|
||||
"reachable": True,
|
||||
},
|
||||
"type": "Extended color light",
|
||||
|
@ -117,16 +123,22 @@ async def test_lights_and_groups(hass, aioclient_mock, mock_deconz_websocket):
|
|||
rgb_light = hass.states.get("light.rgb_light")
|
||||
assert rgb_light.state == STATE_ON
|
||||
assert rgb_light.attributes[ATTR_BRIGHTNESS] == 255
|
||||
assert rgb_light.attributes[ATTR_HS_COLOR] == (224.235, 100.0)
|
||||
assert rgb_light.attributes[ATTR_XY_COLOR] == (0.5, 0.5)
|
||||
assert rgb_light.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_XY]
|
||||
assert rgb_light.attributes[ATTR_COLOR_MODE] == COLOR_MODE_XY
|
||||
assert rgb_light.attributes[ATTR_SUPPORTED_FEATURES] == 44
|
||||
assert rgb_light.attributes["is_deconz_group"] is False
|
||||
assert rgb_light.attributes[ATTR_SUPPORTED_FEATURES] == 61
|
||||
|
||||
tunable_white_light = hass.states.get("light.tunable_white_light")
|
||||
assert tunable_white_light.state == STATE_ON
|
||||
assert tunable_white_light.attributes[ATTR_COLOR_TEMP] == 2500
|
||||
assert tunable_white_light.attributes[ATTR_MAX_MIREDS] == 454
|
||||
assert tunable_white_light.attributes[ATTR_MIN_MIREDS] == 155
|
||||
assert tunable_white_light.attributes[ATTR_SUPPORTED_FEATURES] == 2
|
||||
assert tunable_white_light.attributes[ATTR_SUPPORTED_COLOR_MODES] == [
|
||||
COLOR_MODE_COLOR_TEMP
|
||||
]
|
||||
assert tunable_white_light.attributes[ATTR_COLOR_MODE] == COLOR_MODE_COLOR_TEMP
|
||||
assert tunable_white_light.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
tunable_white_light_bad_maxmin = hass.states.get(
|
||||
"light.tunable_white_light_with_bad_maxmin_values"
|
||||
|
@ -135,10 +147,12 @@ async def test_lights_and_groups(hass, aioclient_mock, mock_deconz_websocket):
|
|||
assert tunable_white_light_bad_maxmin.attributes[ATTR_COLOR_TEMP] == 2500
|
||||
assert tunable_white_light_bad_maxmin.attributes[ATTR_MAX_MIREDS] == 650
|
||||
assert tunable_white_light_bad_maxmin.attributes[ATTR_MIN_MIREDS] == 140
|
||||
assert tunable_white_light_bad_maxmin.attributes[ATTR_SUPPORTED_FEATURES] == 2
|
||||
assert tunable_white_light_bad_maxmin.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
on_off_light = hass.states.get("light.on_off_light")
|
||||
assert on_off_light.state == STATE_ON
|
||||
assert on_off_light.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_ONOFF]
|
||||
assert on_off_light.attributes[ATTR_COLOR_MODE] == COLOR_MODE_ONOFF
|
||||
assert on_off_light.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
|
||||
assert hass.states.get("light.light_group").state == STATE_ON
|
||||
|
@ -191,7 +205,7 @@ async def test_lights_and_groups(hass, aioclient_mock, mock_deconz_websocket):
|
|||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.rgb_light",
|
||||
ATTR_HS_COLOR: (20, 30),
|
||||
ATTR_XY_COLOR: (0.411, 0.351),
|
||||
ATTR_FLASH: FLASH_LONG,
|
||||
ATTR_EFFECT: "None",
|
||||
},
|
||||
|
@ -598,4 +612,4 @@ async def test_verify_group_supported_features(hass, aioclient_mock):
|
|||
assert len(hass.states.async_all()) == 4
|
||||
|
||||
assert hass.states.get("light.group").state == STATE_ON
|
||||
assert hass.states.get("light.group").attributes[ATTR_SUPPORTED_FEATURES] == 63
|
||||
assert hass.states.get("light.group").attributes[ATTR_SUPPORTED_FEATURES] == 44
|
||||
|
|
Loading…
Add table
Reference in a new issue