mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 02:37:08 +00:00
Add color_mode support to MQTT JSON light (#47993)
This commit is contained in:
parent
64d5dd1f6b
commit
c7584a1f92
@ -24,6 +24,7 @@ ABBREVIATIONS = {
|
|||||||
"bat_lev_tpl": "battery_level_template",
|
"bat_lev_tpl": "battery_level_template",
|
||||||
"chrg_t": "charging_topic",
|
"chrg_t": "charging_topic",
|
||||||
"chrg_tpl": "charging_template",
|
"chrg_tpl": "charging_template",
|
||||||
|
"clrm": "color_mode",
|
||||||
"clr_temp_cmd_t": "color_temp_command_topic",
|
"clr_temp_cmd_t": "color_temp_command_topic",
|
||||||
"clr_temp_stat_t": "color_temp_state_topic",
|
"clr_temp_stat_t": "color_temp_state_topic",
|
||||||
"clr_temp_tpl": "color_temp_template",
|
"clr_temp_tpl": "color_temp_template",
|
||||||
@ -169,6 +170,7 @@ ABBREVIATIONS = {
|
|||||||
"stat_val_tpl": "state_value_template",
|
"stat_val_tpl": "state_value_template",
|
||||||
"stype": "subtype",
|
"stype": "subtype",
|
||||||
"sup_feat": "supported_features",
|
"sup_feat": "supported_features",
|
||||||
|
"sup_clrm": "supported_color_modes",
|
||||||
"swing_mode_cmd_tpl": "swing_mode_command_template",
|
"swing_mode_cmd_tpl": "swing_mode_command_template",
|
||||||
"swing_mode_cmd_t": "swing_mode_command_topic",
|
"swing_mode_cmd_t": "swing_mode_command_topic",
|
||||||
"swing_mode_stat_tpl": "swing_mode_state_template",
|
"swing_mode_stat_tpl": "swing_mode_state_template",
|
||||||
|
@ -7,12 +7,23 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
|
ATTR_COLOR_MODE,
|
||||||
ATTR_COLOR_TEMP,
|
ATTR_COLOR_TEMP,
|
||||||
ATTR_EFFECT,
|
ATTR_EFFECT,
|
||||||
ATTR_FLASH,
|
ATTR_FLASH,
|
||||||
ATTR_HS_COLOR,
|
ATTR_HS_COLOR,
|
||||||
|
ATTR_RGB_COLOR,
|
||||||
|
ATTR_RGBW_COLOR,
|
||||||
|
ATTR_RGBWW_COLOR,
|
||||||
ATTR_TRANSITION,
|
ATTR_TRANSITION,
|
||||||
ATTR_WHITE_VALUE,
|
ATTR_WHITE_VALUE,
|
||||||
|
ATTR_XY_COLOR,
|
||||||
|
COLOR_MODE_COLOR_TEMP,
|
||||||
|
COLOR_MODE_HS,
|
||||||
|
COLOR_MODE_RGB,
|
||||||
|
COLOR_MODE_RGBW,
|
||||||
|
COLOR_MODE_RGBWW,
|
||||||
|
COLOR_MODE_XY,
|
||||||
FLASH_LONG,
|
FLASH_LONG,
|
||||||
FLASH_SHORT,
|
FLASH_SHORT,
|
||||||
SUPPORT_BRIGHTNESS,
|
SUPPORT_BRIGHTNESS,
|
||||||
@ -22,6 +33,7 @@ from homeassistant.components.light import (
|
|||||||
SUPPORT_FLASH,
|
SUPPORT_FLASH,
|
||||||
SUPPORT_TRANSITION,
|
SUPPORT_TRANSITION,
|
||||||
SUPPORT_WHITE_VALUE,
|
SUPPORT_WHITE_VALUE,
|
||||||
|
VALID_COLOR_MODES,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -54,6 +66,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
DOMAIN = "mqtt_json"
|
DOMAIN = "mqtt_json"
|
||||||
|
|
||||||
DEFAULT_BRIGHTNESS = False
|
DEFAULT_BRIGHTNESS = False
|
||||||
|
DEFAULT_COLOR_MODE = False
|
||||||
DEFAULT_COLOR_TEMP = False
|
DEFAULT_COLOR_TEMP = False
|
||||||
DEFAULT_EFFECT = False
|
DEFAULT_EFFECT = False
|
||||||
DEFAULT_FLASH_TIME_LONG = 10
|
DEFAULT_FLASH_TIME_LONG = 10
|
||||||
@ -66,6 +79,9 @@ DEFAULT_XY = False
|
|||||||
DEFAULT_HS = False
|
DEFAULT_HS = False
|
||||||
DEFAULT_BRIGHTNESS_SCALE = 255
|
DEFAULT_BRIGHTNESS_SCALE = 255
|
||||||
|
|
||||||
|
CONF_COLOR_MODE = "color_mode"
|
||||||
|
CONF_SUPPORTED_COLOR_MODES = "supported_color_modes"
|
||||||
|
|
||||||
CONF_EFFECT_LIST = "effect_list"
|
CONF_EFFECT_LIST = "effect_list"
|
||||||
|
|
||||||
CONF_FLASH_TIME_LONG = "flash_time_long"
|
CONF_FLASH_TIME_LONG = "flash_time_long"
|
||||||
@ -74,14 +90,25 @@ CONF_FLASH_TIME_SHORT = "flash_time_short"
|
|||||||
CONF_MAX_MIREDS = "max_mireds"
|
CONF_MAX_MIREDS = "max_mireds"
|
||||||
CONF_MIN_MIREDS = "min_mireds"
|
CONF_MIN_MIREDS = "min_mireds"
|
||||||
|
|
||||||
# Stealing some of these from the base MQTT configs.
|
|
||||||
PLATFORM_SCHEMA_JSON = (
|
def valid_color_configuration(config):
|
||||||
|
"""Test color_mode is not combined with deprecated config."""
|
||||||
|
deprecated = {CONF_COLOR_TEMP, CONF_HS, CONF_RGB, CONF_WHITE_VALUE, CONF_XY}
|
||||||
|
if config[CONF_COLOR_MODE] and any(config.get(key) for key in deprecated):
|
||||||
|
raise vol.Invalid(f"color_mode must not be combined with any of {deprecated}")
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA_JSON = vol.All(
|
||||||
mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean,
|
vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean,
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_BRIGHTNESS_SCALE, default=DEFAULT_BRIGHTNESS_SCALE
|
CONF_BRIGHTNESS_SCALE, default=DEFAULT_BRIGHTNESS_SCALE
|
||||||
): vol.All(vol.Coerce(int), vol.Range(min=1)),
|
): vol.All(vol.Coerce(int), vol.Range(min=1)),
|
||||||
|
vol.Inclusive(
|
||||||
|
CONF_COLOR_MODE, "color_mode", default=DEFAULT_COLOR_MODE
|
||||||
|
): cv.boolean,
|
||||||
vol.Optional(CONF_COLOR_TEMP, default=DEFAULT_COLOR_TEMP): cv.boolean,
|
vol.Optional(CONF_COLOR_TEMP, default=DEFAULT_COLOR_TEMP): cv.boolean,
|
||||||
vol.Optional(CONF_EFFECT, default=DEFAULT_EFFECT): cv.boolean,
|
vol.Optional(CONF_EFFECT, default=DEFAULT_EFFECT): cv.boolean,
|
||||||
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
|
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
|
||||||
@ -102,12 +129,16 @@ PLATFORM_SCHEMA_JSON = (
|
|||||||
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
|
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
|
||||||
vol.Optional(CONF_RGB, default=DEFAULT_RGB): cv.boolean,
|
vol.Optional(CONF_RGB, default=DEFAULT_RGB): cv.boolean,
|
||||||
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
|
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
|
||||||
|
vol.Inclusive(CONF_SUPPORTED_COLOR_MODES, "color_mode"): vol.All(
|
||||||
|
cv.ensure_list, [vol.In(VALID_COLOR_MODES)], vol.Unique()
|
||||||
|
),
|
||||||
vol.Optional(CONF_WHITE_VALUE, default=DEFAULT_WHITE_VALUE): cv.boolean,
|
vol.Optional(CONF_WHITE_VALUE, default=DEFAULT_WHITE_VALUE): cv.boolean,
|
||||||
vol.Optional(CONF_XY, default=DEFAULT_XY): cv.boolean,
|
vol.Optional(CONF_XY, default=DEFAULT_XY): cv.boolean,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
.extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
.extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
||||||
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema),
|
||||||
|
valid_color_configuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -129,11 +160,16 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
self._topic = None
|
self._topic = None
|
||||||
self._optimistic = False
|
self._optimistic = False
|
||||||
self._brightness = None
|
self._brightness = None
|
||||||
|
self._color_mode = None
|
||||||
self._color_temp = None
|
self._color_temp = None
|
||||||
self._effect = None
|
self._effect = None
|
||||||
self._hs = None
|
|
||||||
self._white_value = None
|
|
||||||
self._flash_times = None
|
self._flash_times = None
|
||||||
|
self._hs = None
|
||||||
|
self._rgb = None
|
||||||
|
self._rgbw = None
|
||||||
|
self._rgbww = None
|
||||||
|
self._white_value = None
|
||||||
|
self._xy = None
|
||||||
|
|
||||||
MqttEntity.__init__(self, None, config, config_entry, discovery_data)
|
MqttEntity.__init__(self, None, config, config_entry, discovery_data)
|
||||||
|
|
||||||
@ -156,50 +192,90 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
}
|
}
|
||||||
|
|
||||||
self._supported_features = SUPPORT_TRANSITION | SUPPORT_FLASH
|
self._supported_features = SUPPORT_TRANSITION | SUPPORT_FLASH
|
||||||
self._supported_features |= config[CONF_RGB] and SUPPORT_COLOR
|
|
||||||
self._supported_features |= config[CONF_BRIGHTNESS] and SUPPORT_BRIGHTNESS
|
|
||||||
self._supported_features |= config[CONF_COLOR_TEMP] and SUPPORT_COLOR_TEMP
|
|
||||||
self._supported_features |= config[CONF_EFFECT] and SUPPORT_EFFECT
|
self._supported_features |= config[CONF_EFFECT] and SUPPORT_EFFECT
|
||||||
self._supported_features |= config[CONF_WHITE_VALUE] and SUPPORT_WHITE_VALUE
|
if not self._config[CONF_COLOR_MODE]:
|
||||||
self._supported_features |= config[CONF_XY] and SUPPORT_COLOR
|
self._supported_features |= config[CONF_BRIGHTNESS] and SUPPORT_BRIGHTNESS
|
||||||
self._supported_features |= config[CONF_HS] and SUPPORT_COLOR
|
self._supported_features |= config[CONF_COLOR_TEMP] and SUPPORT_COLOR_TEMP
|
||||||
|
self._supported_features |= config[CONF_HS] and SUPPORT_COLOR
|
||||||
|
self._supported_features |= config[CONF_RGB] and SUPPORT_COLOR
|
||||||
|
self._supported_features |= config[CONF_WHITE_VALUE] and SUPPORT_WHITE_VALUE
|
||||||
|
self._supported_features |= config[CONF_XY] and SUPPORT_COLOR
|
||||||
|
|
||||||
def _parse_color(self, values):
|
def _update_color(self, values):
|
||||||
try:
|
if not self._config[CONF_COLOR_MODE]:
|
||||||
red = int(values["color"]["r"])
|
# Deprecated color handling
|
||||||
green = int(values["color"]["g"])
|
try:
|
||||||
blue = int(values["color"]["b"])
|
red = int(values["color"]["r"])
|
||||||
|
green = int(values["color"]["g"])
|
||||||
|
blue = int(values["color"]["b"])
|
||||||
|
self._hs = color_util.color_RGB_to_hs(red, green, blue)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
except ValueError:
|
||||||
|
_LOGGER.warning("Invalid RGB color value received")
|
||||||
|
return
|
||||||
|
|
||||||
return color_util.color_RGB_to_hs(red, green, blue)
|
try:
|
||||||
except KeyError:
|
x_color = float(values["color"]["x"])
|
||||||
pass
|
y_color = float(values["color"]["y"])
|
||||||
except ValueError:
|
self._hs = color_util.color_xy_to_hs(x_color, y_color)
|
||||||
_LOGGER.warning("Invalid RGB color value received")
|
except KeyError:
|
||||||
return self._hs
|
pass
|
||||||
|
except ValueError:
|
||||||
|
_LOGGER.warning("Invalid XY color value received")
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
x_color = float(values["color"]["x"])
|
hue = float(values["color"]["h"])
|
||||||
y_color = float(values["color"]["y"])
|
saturation = float(values["color"]["s"])
|
||||||
|
self._hs = (hue, saturation)
|
||||||
return color_util.color_xy_to_hs(x_color, y_color)
|
except KeyError:
|
||||||
except KeyError:
|
pass
|
||||||
pass
|
except ValueError:
|
||||||
except ValueError:
|
_LOGGER.warning("Invalid HS color value received")
|
||||||
_LOGGER.warning("Invalid XY color value received")
|
return
|
||||||
return self._hs
|
else:
|
||||||
|
color_mode = values["color_mode"]
|
||||||
try:
|
if not self._supports_color_mode(color_mode):
|
||||||
hue = float(values["color"]["h"])
|
_LOGGER.warning("Invalid color mode received")
|
||||||
saturation = float(values["color"]["s"])
|
return
|
||||||
|
try:
|
||||||
return (hue, saturation)
|
if color_mode == COLOR_MODE_COLOR_TEMP:
|
||||||
except KeyError:
|
self._color_temp = int(values["color_temp"])
|
||||||
pass
|
self._color_mode = COLOR_MODE_COLOR_TEMP
|
||||||
except ValueError:
|
elif color_mode == COLOR_MODE_HS:
|
||||||
_LOGGER.warning("Invalid HS color value received")
|
hue = float(values["color"]["h"])
|
||||||
return self._hs
|
saturation = float(values["color"]["s"])
|
||||||
|
self._color_mode = COLOR_MODE_HS
|
||||||
return self._hs
|
self._hs = (hue, saturation)
|
||||||
|
elif color_mode == COLOR_MODE_RGB:
|
||||||
|
r = int(values["color"]["r"]) # pylint: disable=invalid-name
|
||||||
|
g = int(values["color"]["g"]) # pylint: disable=invalid-name
|
||||||
|
b = int(values["color"]["b"]) # pylint: disable=invalid-name
|
||||||
|
self._color_mode = COLOR_MODE_RGB
|
||||||
|
self._rgb = (r, g, b)
|
||||||
|
elif color_mode == COLOR_MODE_RGBW:
|
||||||
|
r = int(values["color"]["r"]) # pylint: disable=invalid-name
|
||||||
|
g = int(values["color"]["g"]) # pylint: disable=invalid-name
|
||||||
|
b = int(values["color"]["b"]) # pylint: disable=invalid-name
|
||||||
|
w = int(values["color"]["w"]) # pylint: disable=invalid-name
|
||||||
|
self._color_mode = COLOR_MODE_RGBW
|
||||||
|
self._rgbw = (r, g, b, w)
|
||||||
|
elif color_mode == COLOR_MODE_RGBWW:
|
||||||
|
r = int(values["color"]["r"]) # pylint: disable=invalid-name
|
||||||
|
g = int(values["color"]["g"]) # pylint: disable=invalid-name
|
||||||
|
b = int(values["color"]["b"]) # pylint: disable=invalid-name
|
||||||
|
c = int(values["color"]["c"]) # pylint: disable=invalid-name
|
||||||
|
w = int(values["color"]["w"]) # pylint: disable=invalid-name
|
||||||
|
self._color_mode = COLOR_MODE_RGBWW
|
||||||
|
self._rgbww = (r, g, b, c, w)
|
||||||
|
elif color_mode == COLOR_MODE_XY:
|
||||||
|
x = float(values["color"]["x"]) # pylint: disable=invalid-name
|
||||||
|
y = float(values["color"]["y"]) # pylint: disable=invalid-name
|
||||||
|
self._color_mode = COLOR_MODE_XY
|
||||||
|
self._xy = (x, y)
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
_LOGGER.warning("Invalid or incomplete color value received")
|
||||||
|
|
||||||
async def _subscribe_topics(self):
|
async def _subscribe_topics(self):
|
||||||
"""(Re)Subscribe to topics."""
|
"""(Re)Subscribe to topics."""
|
||||||
@ -220,7 +296,10 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
if values["color"] is None:
|
if values["color"] is None:
|
||||||
self._hs = None
|
self._hs = None
|
||||||
else:
|
else:
|
||||||
self._hs = self._parse_color(values)
|
self._update_color(values)
|
||||||
|
|
||||||
|
if self._config[CONF_COLOR_MODE] and "color_mode" in values:
|
||||||
|
self._update_color(values)
|
||||||
|
|
||||||
if self._supported_features and SUPPORT_BRIGHTNESS:
|
if self._supported_features and SUPPORT_BRIGHTNESS:
|
||||||
try:
|
try:
|
||||||
@ -234,7 +313,11 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
_LOGGER.warning("Invalid brightness value received")
|
_LOGGER.warning("Invalid brightness value received")
|
||||||
|
|
||||||
if self._supported_features and SUPPORT_COLOR_TEMP:
|
if (
|
||||||
|
self._supported_features
|
||||||
|
and SUPPORT_COLOR_TEMP
|
||||||
|
and not self._config[CONF_COLOR_MODE]
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
if values["color_temp"] is None:
|
if values["color_temp"] is None:
|
||||||
self._color_temp = None
|
self._color_temp = None
|
||||||
@ -274,16 +357,17 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
|
|
||||||
if self._optimistic and last_state:
|
if self._optimistic and last_state:
|
||||||
self._state = last_state.state == STATE_ON
|
self._state = last_state.state == STATE_ON
|
||||||
if last_state.attributes.get(ATTR_BRIGHTNESS):
|
last_attributes = last_state.attributes
|
||||||
self._brightness = last_state.attributes.get(ATTR_BRIGHTNESS)
|
self._brightness = last_attributes.get(ATTR_BRIGHTNESS, self._brightness)
|
||||||
if last_state.attributes.get(ATTR_HS_COLOR):
|
self._color_mode = last_attributes.get(ATTR_COLOR_MODE, self._color_mode)
|
||||||
self._hs = last_state.attributes.get(ATTR_HS_COLOR)
|
self._color_temp = last_attributes.get(ATTR_COLOR_TEMP, self._color_temp)
|
||||||
if last_state.attributes.get(ATTR_COLOR_TEMP):
|
self._effect = last_attributes.get(ATTR_EFFECT, self._effect)
|
||||||
self._color_temp = last_state.attributes.get(ATTR_COLOR_TEMP)
|
self._hs = last_attributes.get(ATTR_HS_COLOR, self._hs)
|
||||||
if last_state.attributes.get(ATTR_EFFECT):
|
self._rgb = last_attributes.get(ATTR_RGB_COLOR, self._rgb)
|
||||||
self._effect = last_state.attributes.get(ATTR_EFFECT)
|
self._rgbw = last_attributes.get(ATTR_RGBW_COLOR, self._rgbw)
|
||||||
if last_state.attributes.get(ATTR_WHITE_VALUE):
|
self._rgbww = last_attributes.get(ATTR_RGBWW_COLOR, self._rgbww)
|
||||||
self._white_value = last_state.attributes.get(ATTR_WHITE_VALUE)
|
self._white_value = last_attributes.get(ATTR_WHITE_VALUE, self._white_value)
|
||||||
|
self._xy = last_attributes.get(ATTR_XY_COLOR, self._xy)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self):
|
def brightness(self):
|
||||||
@ -320,6 +404,26 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
"""Return the hs color value."""
|
"""Return the hs color value."""
|
||||||
return self._hs
|
return self._hs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rgb_color(self):
|
||||||
|
"""Return the hs color value."""
|
||||||
|
return self._rgb
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rgbw_color(self):
|
||||||
|
"""Return the hs color value."""
|
||||||
|
return self._rgbw
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rgbww_color(self):
|
||||||
|
"""Return the hs color value."""
|
||||||
|
return self._rgbww
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xy_color(self):
|
||||||
|
"""Return the hs color value."""
|
||||||
|
return self._xy
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def white_value(self):
|
def white_value(self):
|
||||||
"""Return the white property."""
|
"""Return the white property."""
|
||||||
@ -335,6 +439,16 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
"""Return true if we do optimistic updates."""
|
"""Return true if we do optimistic updates."""
|
||||||
return self._optimistic
|
return self._optimistic
|
||||||
|
|
||||||
|
@property
|
||||||
|
def color_mode(self):
|
||||||
|
"""Return current color mode."""
|
||||||
|
return self._color_mode
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_color_modes(self):
|
||||||
|
"""Flag supported color modes."""
|
||||||
|
return self._config.get(CONF_SUPPORTED_COLOR_MODES)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
@ -352,6 +466,18 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
elif flash == FLASH_SHORT:
|
elif flash == FLASH_SHORT:
|
||||||
message["flash"] = self._flash_times[CONF_FLASH_TIME_SHORT]
|
message["flash"] = self._flash_times[CONF_FLASH_TIME_SHORT]
|
||||||
|
|
||||||
|
def _scale_rgbxx(self, rgbxx, kwargs):
|
||||||
|
# If there's a brightness topic set, we don't want to scale the
|
||||||
|
# RGBxx values given using the brightness.
|
||||||
|
if self._config[CONF_BRIGHTNESS]:
|
||||||
|
brightness = 255
|
||||||
|
else:
|
||||||
|
brightness = kwargs.get(ATTR_BRIGHTNESS, 255)
|
||||||
|
return tuple(round(i / 255 * brightness) for i in rgbxx)
|
||||||
|
|
||||||
|
def _supports_color_mode(self, color_mode):
|
||||||
|
return self.supported_color_modes and color_mode in self.supported_color_modes
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the device on.
|
"""Turn the device on.
|
||||||
|
|
||||||
@ -391,6 +517,52 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
self._hs = kwargs[ATTR_HS_COLOR]
|
self._hs = kwargs[ATTR_HS_COLOR]
|
||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
|
if ATTR_HS_COLOR in kwargs and self._supports_color_mode(COLOR_MODE_HS):
|
||||||
|
hs_color = kwargs[ATTR_HS_COLOR]
|
||||||
|
message["color"] = {"h": hs_color[0], "s": hs_color[1]}
|
||||||
|
if self._optimistic:
|
||||||
|
self._color_mode = COLOR_MODE_HS
|
||||||
|
self._hs = hs_color
|
||||||
|
should_update = True
|
||||||
|
|
||||||
|
if ATTR_RGB_COLOR in kwargs and self._supports_color_mode(COLOR_MODE_RGB):
|
||||||
|
rgb = self._scale_rgbxx(kwargs[ATTR_RGB_COLOR], kwargs)
|
||||||
|
message["color"] = {"r": rgb[0], "g": rgb[1], "b": rgb[2]}
|
||||||
|
if self._optimistic:
|
||||||
|
self._color_mode = COLOR_MODE_RGB
|
||||||
|
self._rgb = rgb
|
||||||
|
should_update = True
|
||||||
|
|
||||||
|
if ATTR_RGBW_COLOR in kwargs and self._supports_color_mode(COLOR_MODE_RGBW):
|
||||||
|
rgb = self._scale_rgbxx(kwargs[ATTR_RGBW_COLOR], kwargs)
|
||||||
|
message["color"] = {"r": rgb[0], "g": rgb[1], "b": rgb[2], "w": rgb[3]}
|
||||||
|
if self._optimistic:
|
||||||
|
self._color_mode = COLOR_MODE_RGBW
|
||||||
|
self._rgbw = rgb
|
||||||
|
should_update = True
|
||||||
|
|
||||||
|
if ATTR_RGBWW_COLOR in kwargs and self._supports_color_mode(COLOR_MODE_RGBWW):
|
||||||
|
rgb = self._scale_rgbxx(kwargs[ATTR_RGBWW_COLOR], kwargs)
|
||||||
|
message["color"] = {
|
||||||
|
"r": rgb[0],
|
||||||
|
"g": rgb[1],
|
||||||
|
"b": rgb[2],
|
||||||
|
"c": rgb[3],
|
||||||
|
"w": rgb[4],
|
||||||
|
}
|
||||||
|
if self._optimistic:
|
||||||
|
self._color_mode = COLOR_MODE_RGBWW
|
||||||
|
self._rgbww = rgb
|
||||||
|
should_update = True
|
||||||
|
|
||||||
|
if ATTR_XY_COLOR in kwargs and self._supports_color_mode(COLOR_MODE_XY):
|
||||||
|
xy = kwargs[ATTR_XY_COLOR] # pylint: disable=invalid-name
|
||||||
|
message["color"] = {"x": xy[0], "y": xy[1]}
|
||||||
|
if self._optimistic:
|
||||||
|
self._color_mode = COLOR_MODE_XY
|
||||||
|
self._xy = xy
|
||||||
|
should_update = True
|
||||||
|
|
||||||
self._set_flash_and_transition(message, **kwargs)
|
self._set_flash_and_transition(message, **kwargs)
|
||||||
|
|
||||||
if ATTR_BRIGHTNESS in kwargs and self._config[CONF_BRIGHTNESS]:
|
if ATTR_BRIGHTNESS in kwargs and self._config[CONF_BRIGHTNESS]:
|
||||||
|
@ -14,6 +14,8 @@ from homeassistant.components.light import (
|
|||||||
ATTR_KELVIN,
|
ATTR_KELVIN,
|
||||||
ATTR_PROFILE,
|
ATTR_PROFILE,
|
||||||
ATTR_RGB_COLOR,
|
ATTR_RGB_COLOR,
|
||||||
|
ATTR_RGBW_COLOR,
|
||||||
|
ATTR_RGBWW_COLOR,
|
||||||
ATTR_TRANSITION,
|
ATTR_TRANSITION,
|
||||||
ATTR_WHITE_VALUE,
|
ATTR_WHITE_VALUE,
|
||||||
ATTR_XY_COLOR,
|
ATTR_XY_COLOR,
|
||||||
@ -37,6 +39,8 @@ def turn_on(
|
|||||||
brightness=None,
|
brightness=None,
|
||||||
brightness_pct=None,
|
brightness_pct=None,
|
||||||
rgb_color=None,
|
rgb_color=None,
|
||||||
|
rgbw_color=None,
|
||||||
|
rgbww_color=None,
|
||||||
xy_color=None,
|
xy_color=None,
|
||||||
hs_color=None,
|
hs_color=None,
|
||||||
color_temp=None,
|
color_temp=None,
|
||||||
@ -56,6 +60,8 @@ def turn_on(
|
|||||||
brightness,
|
brightness,
|
||||||
brightness_pct,
|
brightness_pct,
|
||||||
rgb_color,
|
rgb_color,
|
||||||
|
rgbw_color,
|
||||||
|
rgbww_color,
|
||||||
xy_color,
|
xy_color,
|
||||||
hs_color,
|
hs_color,
|
||||||
color_temp,
|
color_temp,
|
||||||
@ -75,6 +81,8 @@ async def async_turn_on(
|
|||||||
brightness=None,
|
brightness=None,
|
||||||
brightness_pct=None,
|
brightness_pct=None,
|
||||||
rgb_color=None,
|
rgb_color=None,
|
||||||
|
rgbw_color=None,
|
||||||
|
rgbww_color=None,
|
||||||
xy_color=None,
|
xy_color=None,
|
||||||
hs_color=None,
|
hs_color=None,
|
||||||
color_temp=None,
|
color_temp=None,
|
||||||
@ -95,6 +103,8 @@ async def async_turn_on(
|
|||||||
(ATTR_BRIGHTNESS, brightness),
|
(ATTR_BRIGHTNESS, brightness),
|
||||||
(ATTR_BRIGHTNESS_PCT, brightness_pct),
|
(ATTR_BRIGHTNESS_PCT, brightness_pct),
|
||||||
(ATTR_RGB_COLOR, rgb_color),
|
(ATTR_RGB_COLOR, rgb_color),
|
||||||
|
(ATTR_RGBW_COLOR, rgbw_color),
|
||||||
|
(ATTR_RGBWW_COLOR, rgbww_color),
|
||||||
(ATTR_XY_COLOR, xy_color),
|
(ATTR_XY_COLOR, xy_color),
|
||||||
(ATTR_HS_COLOR, hs_color),
|
(ATTR_HS_COLOR, hs_color),
|
||||||
(ATTR_COLOR_TEMP, color_temp),
|
(ATTR_COLOR_TEMP, color_temp),
|
||||||
|
@ -162,6 +162,32 @@ async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
|
|||||||
assert hass.states.get("light.test") is None
|
assert hass.states.get("light.test") is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("deprecated", ("color_temp", "hs", "rgb", "white_value", "xy"))
|
||||||
|
async def test_fail_setup_if_color_mode_deprecated(hass, mqtt_mock, deprecated):
|
||||||
|
"""Test if setup fails if color mode is combined with deprecated config keys."""
|
||||||
|
supported_color_modes = ["color_temp", "hs", "rgb", "rgbw", "rgbww", "xy"]
|
||||||
|
|
||||||
|
config = {
|
||||||
|
light.DOMAIN: {
|
||||||
|
"brightness": True,
|
||||||
|
"color_mode": True,
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"name": "test",
|
||||||
|
"platform": "mqtt",
|
||||||
|
"schema": "json",
|
||||||
|
"supported_color_modes": supported_color_modes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config[light.DOMAIN][deprecated] = True
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
light.DOMAIN,
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("light.test") is None
|
||||||
|
|
||||||
|
|
||||||
async def test_no_color_brightness_color_temp_white_val_if_no_topics(hass, mqtt_mock):
|
async def test_no_color_brightness_color_temp_white_val_if_no_topics(hass, mqtt_mock):
|
||||||
"""Test for no RGB, brightness, color temp, effect, white val or XY."""
|
"""Test for no RGB, brightness, color temp, effect, white val or XY."""
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
@ -323,6 +349,166 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
|
|||||||
assert light_state.attributes.get("white_value") == 155
|
assert light_state.attributes.get("white_value") == 155
|
||||||
|
|
||||||
|
|
||||||
|
async def test_controlling_state_via_topic2(hass, mqtt_mock, caplog):
|
||||||
|
"""Test the controlling of the state via topic for a light supporting color mode."""
|
||||||
|
supported_color_modes = ["color_temp", "hs", "rgb", "rgbw", "rgbww", "xy"]
|
||||||
|
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
light.DOMAIN,
|
||||||
|
{
|
||||||
|
light.DOMAIN: {
|
||||||
|
"brightness": True,
|
||||||
|
"color_mode": True,
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"effect": True,
|
||||||
|
"name": "test",
|
||||||
|
"platform": "mqtt",
|
||||||
|
"qos": "0",
|
||||||
|
"schema": "json",
|
||||||
|
"state_topic": "test_light_rgb",
|
||||||
|
"supported_color_modes": supported_color_modes,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 44
|
||||||
|
assert state.attributes.get("brightness") is None
|
||||||
|
assert state.attributes.get("color_mode") is None
|
||||||
|
assert state.attributes.get("color_temp") is None
|
||||||
|
assert state.attributes.get("effect") is None
|
||||||
|
assert state.attributes.get("hs_color") is None
|
||||||
|
assert state.attributes.get("rgb_color") is None
|
||||||
|
assert state.attributes.get("rgbw_color") is None
|
||||||
|
assert state.attributes.get("rgbww_color") is None
|
||||||
|
assert state.attributes.get("supported_color_modes") == supported_color_modes
|
||||||
|
assert state.attributes.get("white_value") is None
|
||||||
|
assert state.attributes.get("xy_color") is None
|
||||||
|
assert not state.attributes.get(ATTR_ASSUMED_STATE)
|
||||||
|
|
||||||
|
# Turn on the light, rgbww mode, additional values in the update
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON",'
|
||||||
|
'"color_mode":"rgbww",'
|
||||||
|
'"color":{"r":255,"g":128,"b":64, "c": 32, "w": 16, "x": 1, "y": 1},'
|
||||||
|
'"brightness":255,'
|
||||||
|
'"color_temp":155,'
|
||||||
|
'"effect":"colorloop",'
|
||||||
|
'"white_value":150}',
|
||||||
|
)
|
||||||
|
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes.get("brightness") == 255
|
||||||
|
assert state.attributes.get("color_mode") == "rgbww"
|
||||||
|
assert state.attributes.get("color_temp") is None
|
||||||
|
assert state.attributes.get("effect") == "colorloop"
|
||||||
|
assert state.attributes.get("hs_color") is None
|
||||||
|
assert state.attributes.get("rgb_color") is None
|
||||||
|
assert state.attributes.get("rgbw_color") is None
|
||||||
|
assert state.attributes.get("rgbww_color") == (255, 128, 64, 32, 16)
|
||||||
|
assert state.attributes.get("white_value") is None
|
||||||
|
assert state.attributes.get("xy_color") is None
|
||||||
|
|
||||||
|
# Light turned off
|
||||||
|
async_fire_mqtt_message(hass, "test_light_rgb", '{"state":"OFF"}')
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
# Light turned on, brightness 100
|
||||||
|
async_fire_mqtt_message(hass, "test_light_rgb", '{"state":"ON", "brightness":100}')
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes["brightness"] == 100
|
||||||
|
|
||||||
|
# RGB color
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON", "color_mode":"rgb", "color":{"r":64,"g":128,"b":255}}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("color_mode") == "rgb"
|
||||||
|
assert state.attributes.get("rgb_color") == (64, 128, 255)
|
||||||
|
|
||||||
|
# RGBW color
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON", "color_mode":"rgbw", "color":{"r":64,"g":128,"b":255,"w":32}}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("color_mode") == "rgbw"
|
||||||
|
assert state.attributes.get("rgbw_color") == (64, 128, 255, 32)
|
||||||
|
|
||||||
|
# XY color
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON", "color_mode":"xy", "color":{"x":0.135,"y":0.235}}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("color_mode") == "xy"
|
||||||
|
assert state.attributes.get("xy_color") == (0.135, 0.235)
|
||||||
|
|
||||||
|
# HS color
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON", "color_mode":"hs", "color":{"h":180,"s":50}}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("color_mode") == "hs"
|
||||||
|
assert state.attributes.get("hs_color") == (180.0, 50.0)
|
||||||
|
|
||||||
|
# Color temp
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON", "color_mode":"color_temp", "color_temp":155}',
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("color_mode") == "color_temp"
|
||||||
|
assert state.attributes.get("color_temp") == 155
|
||||||
|
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass, "test_light_rgb", '{"state":"ON", "effect":"other_effect"}'
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("effect") == "other_effect"
|
||||||
|
|
||||||
|
# White value should be ignored
|
||||||
|
async_fire_mqtt_message(hass, "test_light_rgb", '{"state":"ON", "white_value":155}')
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.attributes.get("white_value") is None
|
||||||
|
|
||||||
|
# Invalid color mode
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass, "test_light_rgb", '{"state":"ON", "color_mode":"col_temp"}'
|
||||||
|
)
|
||||||
|
assert "Invalid color mode received" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
# Incomplete color
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass, "test_light_rgb", '{"state":"ON", "color_mode":"rgb"}'
|
||||||
|
)
|
||||||
|
assert "Invalid or incomplete color value received" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
# Invalid color
|
||||||
|
async_fire_mqtt_message(
|
||||||
|
hass,
|
||||||
|
"test_light_rgb",
|
||||||
|
'{"state":"ON", "color_mode":"rgb", "color":{"r":64,"g":128,"b":"cow"}}',
|
||||||
|
)
|
||||||
|
assert "Invalid or incomplete color value received" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||||
"""Test the sending of command in optimistic mode."""
|
"""Test the sending of command in optimistic mode."""
|
||||||
fake_state = ha.State(
|
fake_state = ha.State(
|
||||||
@ -457,6 +643,206 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
|||||||
assert state.attributes["xy_color"] == (0.611, 0.375)
|
assert state.attributes["xy_color"] == (0.611, 0.375)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sending_mqtt_commands_and_optimistic2(hass, mqtt_mock):
|
||||||
|
"""Test the sending of command in optimistic mode for a light supporting color mode."""
|
||||||
|
supported_color_modes = ["color_temp", "hs", "rgb", "rgbw", "rgbww", "xy"]
|
||||||
|
fake_state = ha.State(
|
||||||
|
"light.test",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"brightness": 95,
|
||||||
|
"color_temp": 100,
|
||||||
|
"color_mode": "rgb",
|
||||||
|
"effect": "random",
|
||||||
|
"hs_color": [100, 100],
|
||||||
|
"white_value": 50,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.helpers.restore_state.RestoreEntity.async_get_last_state",
|
||||||
|
return_value=fake_state,
|
||||||
|
):
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
light.DOMAIN,
|
||||||
|
{
|
||||||
|
light.DOMAIN: {
|
||||||
|
"brightness": True,
|
||||||
|
"color_mode": True,
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"effect": True,
|
||||||
|
"name": "test",
|
||||||
|
"platform": "mqtt",
|
||||||
|
"qos": 2,
|
||||||
|
"schema": "json",
|
||||||
|
"supported_color_modes": supported_color_modes,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 44
|
||||||
|
assert state.attributes.get("brightness") == 95
|
||||||
|
assert state.attributes.get("color_mode") == "rgb"
|
||||||
|
assert state.attributes.get("color_temp") is None
|
||||||
|
assert state.attributes.get("effect") == "random"
|
||||||
|
assert state.attributes.get("hs_color") is None
|
||||||
|
assert state.attributes.get("rgb_color") is None
|
||||||
|
assert state.attributes.get("rgbw_color") is None
|
||||||
|
assert state.attributes.get("rgbww_color") is None
|
||||||
|
assert state.attributes.get("supported_color_modes") == supported_color_modes
|
||||||
|
assert state.attributes.get("white_value") is None
|
||||||
|
assert state.attributes.get("xy_color") is None
|
||||||
|
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||||
|
|
||||||
|
# Turn the light on
|
||||||
|
await common.async_turn_on(hass, "light.test")
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set", '{"state": "ON"}', 2, False
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
# Turn the light on with color temperature
|
||||||
|
await common.async_turn_on(hass, "light.test", color_temp=90)
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator('{"state": "ON", "color_temp": 90}'),
|
||||||
|
2,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
# Turn the light off
|
||||||
|
await common.async_turn_off(hass, "light.test")
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set", '{"state": "OFF"}', 2, False
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
# Set hs color
|
||||||
|
await common.async_turn_on(hass, "light.test", brightness=75, hs_color=[359, 78])
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes["brightness"] == 75
|
||||||
|
assert state.attributes["color_mode"] == "hs"
|
||||||
|
assert state.attributes["hs_color"] == (359, 78)
|
||||||
|
assert state.attributes["rgb_color"] == (255, 56, 59)
|
||||||
|
assert state.attributes["xy_color"] == (0.654, 0.301)
|
||||||
|
assert "rgbw_color" not in state.attributes
|
||||||
|
assert "rgbww_color" not in state.attributes
|
||||||
|
assert "white_value" not in state.attributes
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator(
|
||||||
|
'{"state": "ON", "color": {"h": 359.0, "s": 78.0},' ' "brightness": 75}'
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
|
||||||
|
# Set rgb color, white value should be discarded
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", rgb_color=[255, 128, 0], white_value=80
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes["brightness"] == 75
|
||||||
|
assert state.attributes["color_mode"] == "rgb"
|
||||||
|
assert state.attributes["hs_color"] == (30.118, 100.0)
|
||||||
|
assert state.attributes["rgb_color"] == (255, 128, 0)
|
||||||
|
assert state.attributes["xy_color"] == (0.611, 0.375)
|
||||||
|
assert "rgbw_color" not in state.attributes
|
||||||
|
assert "rgbww_color" not in state.attributes
|
||||||
|
assert "white_value" not in state.attributes
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator('{"state": "ON", "color": {"r": 255, "g": 128, "b": 0} }'),
|
||||||
|
2,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
|
||||||
|
# Set rgbw color
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", rgbw_color=[255, 128, 0, 123], white_value=80
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes["brightness"] == 75
|
||||||
|
assert state.attributes["color_mode"] == "rgbw"
|
||||||
|
assert state.attributes["rgbw_color"] == (255, 128, 0, 123)
|
||||||
|
assert "hs_color" not in state.attributes
|
||||||
|
assert "rgb_color" not in state.attributes
|
||||||
|
assert "rgbww_color" not in state.attributes
|
||||||
|
assert "white_value" not in state.attributes
|
||||||
|
assert "xy_color" not in state.attributes
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator(
|
||||||
|
'{"state": "ON", "color": {"r": 255, "g": 128, "b": 0, "w": 123} }'
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
|
||||||
|
# Set rgbww color
|
||||||
|
await common.async_turn_on(hass, "light.test", rgbww_color=[255, 128, 0, 45, 32])
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes["brightness"] == 75
|
||||||
|
assert state.attributes["color_mode"] == "rgbww"
|
||||||
|
assert state.attributes["rgbww_color"] == (255, 128, 0, 45, 32)
|
||||||
|
assert "hs_color" not in state.attributes
|
||||||
|
assert "rgb_color" not in state.attributes
|
||||||
|
assert "rgbw_color" not in state.attributes
|
||||||
|
assert "white_value" not in state.attributes
|
||||||
|
assert "xy_color" not in state.attributes
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator(
|
||||||
|
'{"state": "ON", "color": {"r": 255, "g": 128, "b": 0, "c": 45, "w": 32} }'
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
|
||||||
|
# Set xy color
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", brightness=50, xy_color=[0.123, 0.223]
|
||||||
|
)
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes["brightness"] == 50
|
||||||
|
assert state.attributes["color_mode"] == "xy"
|
||||||
|
assert state.attributes["hs_color"] == (196.471, 100.0)
|
||||||
|
assert state.attributes["rgb_color"] == (0, 185, 255)
|
||||||
|
assert state.attributes["xy_color"] == (0.123, 0.223)
|
||||||
|
assert "rgbw_color" not in state.attributes
|
||||||
|
assert "rgbww_color" not in state.attributes
|
||||||
|
assert "white_value" not in state.attributes
|
||||||
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator(
|
||||||
|
'{"state": "ON", "color": {"x": 0.123, "y": 0.223},' ' "brightness": 50}'
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
mqtt_mock.async_publish.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
async def test_sending_hs_color(hass, mqtt_mock):
|
async def test_sending_hs_color(hass, mqtt_mock):
|
||||||
"""Test light.turn_on with hs color sends hs color parameters."""
|
"""Test light.turn_on with hs color sends hs color parameters."""
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
@ -574,6 +960,83 @@ async def test_sending_rgb_color_no_brightness(hass, mqtt_mock):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sending_rgb_color_no_brightness2(hass, mqtt_mock):
|
||||||
|
"""Test light.turn_on with hs color sends rgb color parameters."""
|
||||||
|
supported_color_modes = ["rgb", "rgbw", "rgbww"]
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
light.DOMAIN,
|
||||||
|
{
|
||||||
|
light.DOMAIN: {
|
||||||
|
"color_mode": True,
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"name": "test",
|
||||||
|
"platform": "mqtt",
|
||||||
|
"schema": "json",
|
||||||
|
"supported_color_modes": supported_color_modes,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", brightness=50, xy_color=[0.123, 0.123]
|
||||||
|
)
|
||||||
|
await common.async_turn_on(hass, "light.test", brightness=50, hs_color=[359, 78])
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", rgb_color=[255, 128, 0], brightness=255
|
||||||
|
)
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", rgbw_color=[128, 64, 32, 16], brightness=128
|
||||||
|
)
|
||||||
|
await common.async_turn_on(
|
||||||
|
hass, "light.test", rgbww_color=[128, 64, 32, 16, 8], brightness=64
|
||||||
|
)
|
||||||
|
|
||||||
|
mqtt_mock.async_publish.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator('{"state": "ON", "color": {"r": 0, "g": 24, "b": 50}}'),
|
||||||
|
0,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator('{"state": "ON", "color": {"r": 50, "g": 11, "b": 12}}'),
|
||||||
|
0,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator('{"state": "ON", "color": {"r": 255, "g": 128, "b": 0}}'),
|
||||||
|
0,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator(
|
||||||
|
'{"state": "ON", "color": {"r": 64, "g": 32, "b": 16, "w": 8}}'
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
"test_light_rgb/set",
|
||||||
|
JsonValidator(
|
||||||
|
'{"state": "ON", "color": {"r": 32, "g": 16, "b": 8, "c": 4, "w": 2}}'
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
any_order=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_sending_rgb_color_with_brightness(hass, mqtt_mock):
|
async def test_sending_rgb_color_with_brightness(hass, mqtt_mock):
|
||||||
"""Test light.turn_on with hs color sends rgb color parameters."""
|
"""Test light.turn_on with hs color sends rgb color parameters."""
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user