mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add transition and flash feature flags for MQTT JSON light (#142692)
This commit is contained in:
parent
0b02b43b11
commit
7cf63d1985
@ -56,6 +56,7 @@ ABBREVIATIONS = {
|
|||||||
"ent_pic": "entity_picture",
|
"ent_pic": "entity_picture",
|
||||||
"evt_typ": "event_types",
|
"evt_typ": "event_types",
|
||||||
"fanspd_lst": "fan_speed_list",
|
"fanspd_lst": "fan_speed_list",
|
||||||
|
"flsh": "flash",
|
||||||
"flsh_tlng": "flash_time_long",
|
"flsh_tlng": "flash_time_long",
|
||||||
"flsh_tsht": "flash_time_short",
|
"flsh_tsht": "flash_time_short",
|
||||||
"fx_cmd_tpl": "effect_command_template",
|
"fx_cmd_tpl": "effect_command_template",
|
||||||
@ -253,6 +254,7 @@ ABBREVIATIONS = {
|
|||||||
"tilt_status_tpl": "tilt_status_template",
|
"tilt_status_tpl": "tilt_status_template",
|
||||||
"tit": "title",
|
"tit": "title",
|
||||||
"t": "topic",
|
"t": "topic",
|
||||||
|
"trns": "transition",
|
||||||
"uniq_id": "unique_id",
|
"uniq_id": "unique_id",
|
||||||
"unit_of_meas": "unit_of_measurement",
|
"unit_of_meas": "unit_of_measurement",
|
||||||
"url_t": "url_topic",
|
"url_t": "url_topic",
|
||||||
|
@ -87,6 +87,7 @@ CONF_EFFECT_TEMPLATE = "effect_template"
|
|||||||
CONF_EFFECT_VALUE_TEMPLATE = "effect_value_template"
|
CONF_EFFECT_VALUE_TEMPLATE = "effect_value_template"
|
||||||
CONF_ENTITY_PICTURE = "entity_picture"
|
CONF_ENTITY_PICTURE = "entity_picture"
|
||||||
CONF_EXPIRE_AFTER = "expire_after"
|
CONF_EXPIRE_AFTER = "expire_after"
|
||||||
|
CONF_FLASH = "flash"
|
||||||
CONF_FLASH_TIME_LONG = "flash_time_long"
|
CONF_FLASH_TIME_LONG = "flash_time_long"
|
||||||
CONF_FLASH_TIME_SHORT = "flash_time_short"
|
CONF_FLASH_TIME_SHORT = "flash_time_short"
|
||||||
CONF_GREEN_TEMPLATE = "green_template"
|
CONF_GREEN_TEMPLATE = "green_template"
|
||||||
@ -139,6 +140,7 @@ CONF_TEMP_STATE_TOPIC = "temperature_state_topic"
|
|||||||
CONF_TEMP_INITIAL = "initial"
|
CONF_TEMP_INITIAL = "initial"
|
||||||
CONF_TEMP_MAX = "max_temp"
|
CONF_TEMP_MAX = "max_temp"
|
||||||
CONF_TEMP_MIN = "min_temp"
|
CONF_TEMP_MIN = "min_temp"
|
||||||
|
CONF_TRANSITION = "transition"
|
||||||
CONF_XY_COMMAND_TEMPLATE = "xy_command_template"
|
CONF_XY_COMMAND_TEMPLATE = "xy_command_template"
|
||||||
CONF_XY_COMMAND_TOPIC = "xy_command_topic"
|
CONF_XY_COMMAND_TOPIC = "xy_command_topic"
|
||||||
CONF_XY_STATE_TOPIC = "xy_state_topic"
|
CONF_XY_STATE_TOPIC = "xy_state_topic"
|
||||||
|
@ -59,6 +59,7 @@ from ..const import (
|
|||||||
CONF_COLOR_TEMP_KELVIN,
|
CONF_COLOR_TEMP_KELVIN,
|
||||||
CONF_COMMAND_TOPIC,
|
CONF_COMMAND_TOPIC,
|
||||||
CONF_EFFECT_LIST,
|
CONF_EFFECT_LIST,
|
||||||
|
CONF_FLASH,
|
||||||
CONF_FLASH_TIME_LONG,
|
CONF_FLASH_TIME_LONG,
|
||||||
CONF_FLASH_TIME_SHORT,
|
CONF_FLASH_TIME_SHORT,
|
||||||
CONF_MAX_KELVIN,
|
CONF_MAX_KELVIN,
|
||||||
@ -69,6 +70,7 @@ from ..const import (
|
|||||||
CONF_RETAIN,
|
CONF_RETAIN,
|
||||||
CONF_STATE_TOPIC,
|
CONF_STATE_TOPIC,
|
||||||
CONF_SUPPORTED_COLOR_MODES,
|
CONF_SUPPORTED_COLOR_MODES,
|
||||||
|
CONF_TRANSITION,
|
||||||
DEFAULT_BRIGHTNESS,
|
DEFAULT_BRIGHTNESS,
|
||||||
DEFAULT_BRIGHTNESS_SCALE,
|
DEFAULT_BRIGHTNESS_SCALE,
|
||||||
DEFAULT_EFFECT,
|
DEFAULT_EFFECT,
|
||||||
@ -93,6 +95,9 @@ DOMAIN = "mqtt_json"
|
|||||||
|
|
||||||
DEFAULT_NAME = "MQTT JSON Light"
|
DEFAULT_NAME = "MQTT JSON Light"
|
||||||
|
|
||||||
|
DEFAULT_FLASH = True
|
||||||
|
DEFAULT_TRANSITION = True
|
||||||
|
|
||||||
_PLATFORM_SCHEMA_BASE = (
|
_PLATFORM_SCHEMA_BASE = (
|
||||||
MQTT_RW_SCHEMA.extend(
|
MQTT_RW_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
@ -103,6 +108,7 @@ _PLATFORM_SCHEMA_BASE = (
|
|||||||
vol.Optional(CONF_COLOR_TEMP_KELVIN, default=False): cv.boolean,
|
vol.Optional(CONF_COLOR_TEMP_KELVIN, default=False): 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]),
|
||||||
|
vol.Optional(CONF_FLASH, default=DEFAULT_FLASH): cv.boolean,
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_FLASH_TIME_LONG, default=DEFAULT_FLASH_TIME_LONG
|
CONF_FLASH_TIME_LONG, default=DEFAULT_FLASH_TIME_LONG
|
||||||
): cv.positive_int,
|
): cv.positive_int,
|
||||||
@ -125,6 +131,7 @@ _PLATFORM_SCHEMA_BASE = (
|
|||||||
vol.Unique(),
|
vol.Unique(),
|
||||||
valid_supported_color_modes,
|
valid_supported_color_modes,
|
||||||
),
|
),
|
||||||
|
vol.Optional(CONF_TRANSITION, default=DEFAULT_TRANSITION): cv.boolean,
|
||||||
vol.Optional(CONF_WHITE_SCALE, default=DEFAULT_WHITE_SCALE): vol.All(
|
vol.Optional(CONF_WHITE_SCALE, default=DEFAULT_WHITE_SCALE): vol.All(
|
||||||
vol.Coerce(int), vol.Range(min=1)
|
vol.Coerce(int), vol.Range(min=1)
|
||||||
),
|
),
|
||||||
@ -199,12 +206,13 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||||||
for key in (CONF_FLASH_TIME_SHORT, CONF_FLASH_TIME_LONG)
|
for key in (CONF_FLASH_TIME_SHORT, CONF_FLASH_TIME_LONG)
|
||||||
}
|
}
|
||||||
|
|
||||||
self._attr_supported_features = (
|
|
||||||
LightEntityFeature.TRANSITION | LightEntityFeature.FLASH
|
|
||||||
)
|
|
||||||
self._attr_supported_features |= (
|
self._attr_supported_features |= (
|
||||||
config[CONF_EFFECT] and LightEntityFeature.EFFECT
|
config[CONF_EFFECT] and LightEntityFeature.EFFECT
|
||||||
)
|
)
|
||||||
|
self._attr_supported_features |= config[CONF_FLASH] and LightEntityFeature.FLASH
|
||||||
|
self._attr_supported_features |= (
|
||||||
|
config[CONF_TRANSITION] and LightEntityFeature.TRANSITION
|
||||||
|
)
|
||||||
if supported_color_modes := self._config.get(CONF_SUPPORTED_COLOR_MODES):
|
if supported_color_modes := self._config.get(CONF_SUPPORTED_COLOR_MODES):
|
||||||
self._attr_supported_color_modes = supported_color_modes
|
self._attr_supported_color_modes = supported_color_modes
|
||||||
if self.supported_color_modes and len(self.supported_color_modes) == 1:
|
if self.supported_color_modes and len(self.supported_color_modes) == 1:
|
||||||
|
@ -330,7 +330,9 @@ async def test_no_color_brightness_color_temp_if_no_topics(
|
|||||||
|
|
||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
expected_features = (
|
||||||
|
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION
|
||||||
|
)
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||||
assert state.attributes.get("rgb_color") is None
|
assert state.attributes.get("rgb_color") is None
|
||||||
assert state.attributes.get("brightness") is None
|
assert state.attributes.get("brightness") is None
|
||||||
@ -581,6 +583,104 @@ async def test_controlling_state_color_temp_kelvin(
|
|||||||
assert state.attributes.get("hs_color") == (44.098, 2.43) # temp converted to color
|
assert state.attributes.get("hs_color") == (44.098, 2.43) # temp converted to color
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("hass_config", "expected_features"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{
|
||||||
|
mqtt.DOMAIN: {
|
||||||
|
light.DOMAIN: {
|
||||||
|
"schema": "json",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "test_light_rgb",
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
mqtt.DOMAIN: {
|
||||||
|
light.DOMAIN: {
|
||||||
|
"schema": "json",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "test_light_rgb",
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"flash": True,
|
||||||
|
"transition": True,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
mqtt.DOMAIN: {
|
||||||
|
light.DOMAIN: {
|
||||||
|
"schema": "json",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "test_light_rgb",
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"flash": True,
|
||||||
|
"transition": False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
light.LightEntityFeature.FLASH,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
mqtt.DOMAIN: {
|
||||||
|
light.DOMAIN: {
|
||||||
|
"schema": "json",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "test_light_rgb",
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"flash": False,
|
||||||
|
"transition": True,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
light.LightEntityFeature.TRANSITION,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
mqtt.DOMAIN: {
|
||||||
|
light.DOMAIN: {
|
||||||
|
"schema": "json",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "test_light_rgb",
|
||||||
|
"command_topic": "test_light_rgb/set",
|
||||||
|
"flash": False,
|
||||||
|
"transition": False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
light.LightEntityFeature(0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ids=[
|
||||||
|
"default",
|
||||||
|
"explicit_on",
|
||||||
|
"flash_only",
|
||||||
|
"transition_only",
|
||||||
|
"no_flash_not_transition",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_flash_and_transition_feature_flags(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||||
|
expected_features: light.LightEntityFeature,
|
||||||
|
) -> None:
|
||||||
|
"""Test for no RGB, brightness, color temp, effector XY."""
|
||||||
|
await mqtt_mock_entry()
|
||||||
|
|
||||||
|
state = hass.states.get("light.test")
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"hass_config",
|
"hass_config",
|
||||||
[
|
[
|
||||||
@ -601,9 +701,11 @@ async def test_controlling_state_via_topic(
|
|||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
expected_features = (
|
expected_features = (
|
||||||
light.SUPPORT_EFFECT | light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
light.LightEntityFeature.EFFECT
|
||||||
|
| light.LightEntityFeature.FLASH
|
||||||
|
| light.LightEntityFeature.TRANSITION
|
||||||
)
|
)
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
assert state.attributes.get("brightness") is None
|
assert state.attributes.get("brightness") is None
|
||||||
assert state.attributes.get("color_mode") is None
|
assert state.attributes.get("color_mode") is None
|
||||||
assert state.attributes.get("color_temp_kelvin") is None
|
assert state.attributes.get("color_temp_kelvin") is None
|
||||||
@ -799,9 +901,11 @@ async def test_sending_mqtt_commands_and_optimistic(
|
|||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
expected_features = (
|
expected_features = (
|
||||||
light.SUPPORT_EFFECT | light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
light.LightEntityFeature.EFFECT
|
||||||
|
| light.LightEntityFeature.FLASH
|
||||||
|
| light.LightEntityFeature.TRANSITION
|
||||||
)
|
)
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
assert state.attributes.get("brightness") == 95
|
assert state.attributes.get("brightness") == 95
|
||||||
assert state.attributes.get("color_mode") == "rgb"
|
assert state.attributes.get("color_mode") == "rgb"
|
||||||
assert state.attributes.get("color_temp_kelvin") is None
|
assert state.attributes.get("color_temp_kelvin") is None
|
||||||
@ -1457,9 +1561,11 @@ async def test_effect(
|
|||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
expected_features = (
|
expected_features = (
|
||||||
light.SUPPORT_EFFECT | light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
light.LightEntityFeature.EFFECT
|
||||||
|
| light.LightEntityFeature.FLASH
|
||||||
|
| light.LightEntityFeature.TRANSITION
|
||||||
)
|
)
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
|
|
||||||
await common.async_turn_on(hass, "light.test")
|
await common.async_turn_on(hass, "light.test")
|
||||||
|
|
||||||
@ -1523,8 +1629,10 @@ async def test_flash_short_and_long(
|
|||||||
|
|
||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
expected_features = (
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION
|
||||||
|
)
|
||||||
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
|
|
||||||
await common.async_turn_on(hass, "light.test", flash="short")
|
await common.async_turn_on(hass, "light.test", flash="short")
|
||||||
|
|
||||||
@ -1586,8 +1694,10 @@ async def test_transition(
|
|||||||
|
|
||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
expected_features = (
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION
|
||||||
|
)
|
||||||
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
await common.async_turn_on(hass, "light.test", transition=15)
|
await common.async_turn_on(hass, "light.test", transition=15)
|
||||||
|
|
||||||
mqtt_mock.async_publish.assert_called_once_with(
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
@ -1766,8 +1876,10 @@ async def test_invalid_values(
|
|||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
color_modes = [light.ColorMode.COLOR_TEMP, light.ColorMode.HS]
|
color_modes = [light.ColorMode.COLOR_TEMP, light.ColorMode.HS]
|
||||||
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
|
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
|
||||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
expected_features = (
|
||||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
light.LightEntityFeature.FLASH | light.LightEntityFeature.TRANSITION
|
||||||
|
)
|
||||||
|
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) is expected_features
|
||||||
assert state.attributes.get("rgb_color") is None
|
assert state.attributes.get("rgb_color") is None
|
||||||
assert state.attributes.get("brightness") is None
|
assert state.attributes.get("brightness") is None
|
||||||
assert state.attributes.get("color_temp_kelvin") is None
|
assert state.attributes.get("color_temp_kelvin") is None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user