KNX: Support for HS-color lights (#53538)

This commit is contained in:
Matthias Alphart 2021-07-27 19:36:46 +02:00 committed by GitHub
parent ce663f629c
commit 27d42e0cd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 10 deletions

View File

@ -10,11 +10,13 @@ from xknx.telegram.address import parse_device_group_address
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP, ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
ATTR_RGB_COLOR, ATTR_RGB_COLOR,
ATTR_RGBW_COLOR, ATTR_RGBW_COLOR,
ATTR_XY_COLOR, ATTR_XY_COLOR,
COLOR_MODE_BRIGHTNESS, COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP, COLOR_MODE_COLOR_TEMP,
COLOR_MODE_HS,
COLOR_MODE_ONOFF, COLOR_MODE_ONOFF,
COLOR_MODE_RGB, COLOR_MODE_RGB,
COLOR_MODE_RGBW, COLOR_MODE_RGBW,
@ -158,6 +160,12 @@ def _create_light(xknx: XKNX, config: ConfigType) -> XknxLight:
group_address_color_state=config.get(LightSchema.CONF_COLOR_STATE_ADDRESS), group_address_color_state=config.get(LightSchema.CONF_COLOR_STATE_ADDRESS),
group_address_rgbw=config.get(LightSchema.CONF_RGBW_ADDRESS), group_address_rgbw=config.get(LightSchema.CONF_RGBW_ADDRESS),
group_address_rgbw_state=config.get(LightSchema.CONF_RGBW_STATE_ADDRESS), group_address_rgbw_state=config.get(LightSchema.CONF_RGBW_STATE_ADDRESS),
group_address_hue=config.get(LightSchema.CONF_HUE_ADDRESS),
group_address_hue_state=config.get(LightSchema.CONF_HUE_STATE_ADDRESS),
group_address_saturation=config.get(LightSchema.CONF_SATURATION_ADDRESS),
group_address_saturation_state=config.get(
LightSchema.CONF_SATURATION_STATE_ADDRESS
),
group_address_xyy_color=config.get(LightSchema.CONF_XYY_ADDRESS), group_address_xyy_color=config.get(LightSchema.CONF_XYY_ADDRESS),
group_address_xyy_color_state=config.get(LightSchema.CONF_XYY_STATE_ADDRESS), group_address_xyy_color_state=config.get(LightSchema.CONF_XYY_STATE_ADDRESS),
group_address_tunable_white=group_address_tunable_white, group_address_tunable_white=group_address_tunable_white,
@ -283,6 +291,13 @@ class KNXLight(KnxEntity, LightEntity):
return (*rgb, white) return (*rgb, white)
return None return None
@property
def hs_color(self) -> tuple[float, float] | None:
"""Return the hue and saturation color value [float, float]."""
# Hue is scaled 0..360 int encoded in 1 byte in KNX (-> only 256 possible values)
# Saturation is scaled 0..100 int
return self._device.current_hs_color
@property @property
def xy_color(self) -> tuple[float, float] | None: def xy_color(self) -> tuple[float, float] | None:
"""Return the xy color value [float, float].""" """Return the xy color value [float, float]."""
@ -315,6 +330,8 @@ class KNXLight(KnxEntity, LightEntity):
"""Return the color mode of the light.""" """Return the color mode of the light."""
if self._device.supports_xyy_color: if self._device.supports_xyy_color:
return COLOR_MODE_XY return COLOR_MODE_XY
if self._device.supports_hs_color:
return COLOR_MODE_HS
if self._device.supports_rgbw: if self._device.supports_rgbw:
return COLOR_MODE_RGBW return COLOR_MODE_RGBW
if self._device.supports_color: if self._device.supports_color:
@ -339,6 +356,7 @@ class KNXLight(KnxEntity, LightEntity):
mireds = kwargs.get(ATTR_COLOR_TEMP) mireds = kwargs.get(ATTR_COLOR_TEMP)
rgb = kwargs.get(ATTR_RGB_COLOR) rgb = kwargs.get(ATTR_RGB_COLOR)
rgbw = kwargs.get(ATTR_RGBW_COLOR) rgbw = kwargs.get(ATTR_RGBW_COLOR)
hs_color = kwargs.get(ATTR_HS_COLOR)
xy_color = kwargs.get(ATTR_XY_COLOR) xy_color = kwargs.get(ATTR_XY_COLOR)
if ( if (
@ -347,6 +365,7 @@ class KNXLight(KnxEntity, LightEntity):
and mireds is None and mireds is None
and rgb is None and rgb is None
and rgbw is None and rgbw is None
and hs_color is None
and xy_color is None and xy_color is None
): ):
await self._device.set_on() await self._device.set_on()
@ -396,6 +415,12 @@ class KNXLight(KnxEntity, LightEntity):
) )
return return
if hs_color is not None:
# round so only one telegram will be sent if the other matches state
hue = round(hs_color[0])
sat = round(hs_color[1])
await self._device.set_hs_color((hue, sat))
if brightness is not None: if brightness is not None:
# brightness: 1..255; 0 brightness will call async_turn_off() # brightness: 1..255; 0 brightness will call async_turn_off()
if self._device.brightness.writable: if self._device.brightness.writable:

View File

@ -496,8 +496,12 @@ class LightSchema(KNXPlatformSchema):
CONF_COLOR_TEMP_ADDRESS = "color_temperature_address" CONF_COLOR_TEMP_ADDRESS = "color_temperature_address"
CONF_COLOR_TEMP_STATE_ADDRESS = "color_temperature_state_address" CONF_COLOR_TEMP_STATE_ADDRESS = "color_temperature_state_address"
CONF_COLOR_TEMP_MODE = "color_temperature_mode" CONF_COLOR_TEMP_MODE = "color_temperature_mode"
CONF_HUE_ADDRESS = "hue_address"
CONF_HUE_STATE_ADDRESS = "hue_state_address"
CONF_RGBW_ADDRESS = "rgbw_address" CONF_RGBW_ADDRESS = "rgbw_address"
CONF_RGBW_STATE_ADDRESS = "rgbw_state_address" CONF_RGBW_STATE_ADDRESS = "rgbw_state_address"
CONF_SATURATION_ADDRESS = "saturation_address"
CONF_SATURATION_STATE_ADDRESS = "saturation_state_address"
CONF_XYY_ADDRESS = "xyy_address" CONF_XYY_ADDRESS = "xyy_address"
CONF_XYY_STATE_ADDRESS = "xyy_state_address" CONF_XYY_STATE_ADDRESS = "xyy_state_address"
CONF_MIN_KELVIN = "min_kelvin" CONF_MIN_KELVIN = "min_kelvin"
@ -514,7 +518,18 @@ class LightSchema(KNXPlatformSchema):
CONF_BLUE = "blue" CONF_BLUE = "blue"
CONF_WHITE = "white" CONF_WHITE = "white"
COLOR_SCHEMA = vol.Schema( _hs_color_inclusion_msg = (
"'hue_address', 'saturation_address' and 'brightness_address'"
" are required for hs_color configuration"
)
HS_COLOR_SCHEMA = {
vol.Optional(CONF_HUE_ADDRESS): ga_list_validator,
vol.Optional(CONF_HUE_STATE_ADDRESS): ga_list_validator,
vol.Optional(CONF_SATURATION_ADDRESS): ga_list_validator,
vol.Optional(CONF_SATURATION_STATE_ADDRESS): ga_list_validator,
}
INDIVIDUAL_COLOR_SCHEMA = vol.Schema(
{ {
vol.Optional(KNX_ADDRESS): ga_list_validator, vol.Optional(KNX_ADDRESS): ga_list_validator,
vol.Optional(CONF_STATE_ADDRESS): ga_list_validator, vol.Optional(CONF_STATE_ADDRESS): ga_list_validator,
@ -536,18 +551,18 @@ class LightSchema(KNXPlatformSchema):
CONF_RED, CONF_RED,
"individual_colors", "individual_colors",
msg="'red', 'green' and 'blue' are required for individual colors configuration", msg="'red', 'green' and 'blue' are required for individual colors configuration",
): COLOR_SCHEMA, ): INDIVIDUAL_COLOR_SCHEMA,
vol.Inclusive( vol.Inclusive(
CONF_GREEN, CONF_GREEN,
"individual_colors", "individual_colors",
msg="'red', 'green' and 'blue' are required for individual colors configuration", msg="'red', 'green' and 'blue' are required for individual colors configuration",
): COLOR_SCHEMA, ): INDIVIDUAL_COLOR_SCHEMA,
vol.Inclusive( vol.Inclusive(
CONF_BLUE, CONF_BLUE,
"individual_colors", "individual_colors",
msg="'red', 'green' and 'blue' are required for individual colors configuration", msg="'red', 'green' and 'blue' are required for individual colors configuration",
): COLOR_SCHEMA, ): INDIVIDUAL_COLOR_SCHEMA,
vol.Optional(CONF_WHITE): COLOR_SCHEMA, vol.Optional(CONF_WHITE): INDIVIDUAL_COLOR_SCHEMA,
}, },
vol.Exclusive(CONF_COLOR_ADDRESS, "color"): ga_list_validator, vol.Exclusive(CONF_COLOR_ADDRESS, "color"): ga_list_validator,
vol.Optional(CONF_COLOR_STATE_ADDRESS): ga_list_validator, vol.Optional(CONF_COLOR_STATE_ADDRESS): ga_list_validator,
@ -556,6 +571,7 @@ class LightSchema(KNXPlatformSchema):
vol.Optional( vol.Optional(
CONF_COLOR_TEMP_MODE, default=DEFAULT_COLOR_TEMP_MODE CONF_COLOR_TEMP_MODE, default=DEFAULT_COLOR_TEMP_MODE
): vol.All(vol.Upper, cv.enum(ColorTempModes)), ): vol.All(vol.Upper, cv.enum(ColorTempModes)),
**HS_COLOR_SCHEMA,
vol.Exclusive(CONF_RGBW_ADDRESS, "color"): ga_list_validator, vol.Exclusive(CONF_RGBW_ADDRESS, "color"): ga_list_validator,
vol.Optional(CONF_RGBW_STATE_ADDRESS): ga_list_validator, vol.Optional(CONF_RGBW_STATE_ADDRESS): ga_list_validator,
vol.Exclusive(CONF_XYY_ADDRESS, "color"): ga_list_validator, vol.Exclusive(CONF_XYY_ADDRESS, "color"): ga_list_validator,
@ -569,20 +585,39 @@ class LightSchema(KNXPlatformSchema):
} }
), ),
vol.Any( vol.Any(
# either global "address" or "individual_colors" is required
vol.Schema( vol.Schema(
{vol.Required(KNX_ADDRESS): object},
extra=vol.ALLOW_EXTRA,
),
vol.Schema( # brightness addresses are required in INDIVIDUAL_COLOR_SCHEMA
{vol.Required(CONF_INDIVIDUAL_COLORS): object},
extra=vol.ALLOW_EXTRA,
),
msg="either 'address' or 'individual_colors' is required",
),
vol.Any(
vol.Schema( # 'brightness' is non-optional for hs-color
{ {
# brightness addresses are required in COLOR_SCHEMA vol.Inclusive(
vol.Required(CONF_INDIVIDUAL_COLORS): object, CONF_BRIGHTNESS_ADDRESS, "hs_color", msg=_hs_color_inclusion_msg
): object,
vol.Inclusive(
CONF_HUE_ADDRESS, "hs_color", msg=_hs_color_inclusion_msg
): object,
vol.Inclusive(
CONF_SATURATION_ADDRESS, "hs_color", msg=_hs_color_inclusion_msg
): object,
}, },
extra=vol.ALLOW_EXTRA, extra=vol.ALLOW_EXTRA,
), ),
vol.Schema( vol.Schema( # hs-colors not used
{ {
vol.Required(KNX_ADDRESS): object, vol.Optional(CONF_HUE_ADDRESS): None,
vol.Optional(CONF_SATURATION_ADDRESS): None,
}, },
extra=vol.ALLOW_EXTRA, extra=vol.ALLOW_EXTRA,
), ),
msg=_hs_color_inclusion_msg,
), ),
) )