Allow to process kelvin as color_temp for mqtt json light (#133955)
parent
07482de4ab
commit
cabdae98e8
|
@ -56,12 +56,15 @@ CONF_SUPPORTED_FEATURES = "supported_features"
|
|||
|
||||
CONF_ACTION_TEMPLATE = "action_template"
|
||||
CONF_ACTION_TOPIC = "action_topic"
|
||||
CONF_COLOR_TEMP_KELVIN = "color_temp_kelvin"
|
||||
CONF_CURRENT_HUMIDITY_TEMPLATE = "current_humidity_template"
|
||||
CONF_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic"
|
||||
CONF_CURRENT_TEMP_TEMPLATE = "current_temperature_template"
|
||||
CONF_CURRENT_TEMP_TOPIC = "current_temperature_topic"
|
||||
CONF_ENABLED_BY_DEFAULT = "enabled_by_default"
|
||||
CONF_ENTITY_PICTURE = "entity_picture"
|
||||
CONF_MAX_KELVIN = "max_kelvin"
|
||||
CONF_MIN_KELVIN = "min_kelvin"
|
||||
CONF_MODE_COMMAND_TEMPLATE = "mode_command_template"
|
||||
CONF_MODE_COMMAND_TOPIC = "mode_command_topic"
|
||||
CONF_MODE_LIST = "modes"
|
||||
|
|
|
@ -51,7 +51,10 @@ import homeassistant.util.color as color_util
|
|||
from .. import subscription
|
||||
from ..config import MQTT_RW_SCHEMA
|
||||
from ..const import (
|
||||
CONF_COLOR_TEMP_KELVIN,
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_MAX_KELVIN,
|
||||
CONF_MIN_KELVIN,
|
||||
CONF_STATE_TOPIC,
|
||||
CONF_STATE_VALUE_TEMPLATE,
|
||||
PAYLOAD_NONE,
|
||||
|
@ -82,7 +85,6 @@ CONF_COLOR_TEMP_COMMAND_TEMPLATE = "color_temp_command_template"
|
|||
CONF_COLOR_TEMP_COMMAND_TOPIC = "color_temp_command_topic"
|
||||
CONF_COLOR_TEMP_STATE_TOPIC = "color_temp_state_topic"
|
||||
CONF_COLOR_TEMP_VALUE_TEMPLATE = "color_temp_value_template"
|
||||
CONF_COLOR_TEMP_KELVIN = "color_temp_kelvin"
|
||||
CONF_EFFECT_COMMAND_TEMPLATE = "effect_command_template"
|
||||
CONF_EFFECT_COMMAND_TOPIC = "effect_command_topic"
|
||||
CONF_EFFECT_LIST = "effect_list"
|
||||
|
@ -94,8 +96,6 @@ CONF_HS_STATE_TOPIC = "hs_state_topic"
|
|||
CONF_HS_VALUE_TEMPLATE = "hs_value_template"
|
||||
CONF_MAX_MIREDS = "max_mireds"
|
||||
CONF_MIN_MIREDS = "min_mireds"
|
||||
CONF_MAX_KELVIN = "max_kelvin"
|
||||
CONF_MIN_KELVIN = "min_kelvin"
|
||||
CONF_RGB_COMMAND_TEMPLATE = "rgb_command_template"
|
||||
CONF_RGB_COMMAND_TOPIC = "rgb_command_topic"
|
||||
CONF_RGB_STATE_TOPIC = "rgb_state_topic"
|
||||
|
|
|
@ -61,7 +61,10 @@ from homeassistant.util.yaml import dump as yaml_dump
|
|||
from .. import subscription
|
||||
from ..config import DEFAULT_QOS, DEFAULT_RETAIN, MQTT_RW_SCHEMA
|
||||
from ..const import (
|
||||
CONF_COLOR_TEMP_KELVIN,
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_MAX_KELVIN,
|
||||
CONF_MIN_KELVIN,
|
||||
CONF_QOS,
|
||||
CONF_RETAIN,
|
||||
CONF_STATE_TOPIC,
|
||||
|
@ -203,6 +206,7 @@ _PLATFORM_SCHEMA_BASE = (
|
|||
# CONF_COLOR_TEMP was deprecated with HA Core 2024.4 and will be
|
||||
# removed with HA Core 2025.3
|
||||
vol.Optional(CONF_COLOR_TEMP, default=DEFAULT_COLOR_TEMP): 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_LIST): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(
|
||||
|
@ -216,6 +220,8 @@ _PLATFORM_SCHEMA_BASE = (
|
|||
vol.Optional(CONF_HS, default=DEFAULT_HS): cv.boolean,
|
||||
vol.Optional(CONF_MAX_MIREDS): cv.positive_int,
|
||||
vol.Optional(CONF_MIN_MIREDS): cv.positive_int,
|
||||
vol.Optional(CONF_MAX_KELVIN): cv.positive_int,
|
||||
vol.Optional(CONF_MIN_KELVIN): cv.positive_int,
|
||||
vol.Optional(CONF_NAME): vol.Any(cv.string, None),
|
||||
vol.Optional(CONF_QOS, default=DEFAULT_QOS): vol.All(
|
||||
vol.Coerce(int), vol.In([0, 1, 2])
|
||||
|
@ -275,15 +281,16 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||
|
||||
def _setup_from_config(self, config: ConfigType) -> None:
|
||||
"""(Re)Setup the entity."""
|
||||
self._color_temp_kelvin = config[CONF_COLOR_TEMP_KELVIN]
|
||||
self._attr_min_color_temp_kelvin = (
|
||||
color_util.color_temperature_mired_to_kelvin(max_mireds)
|
||||
if (max_mireds := config.get(CONF_MAX_MIREDS))
|
||||
else DEFAULT_MIN_KELVIN
|
||||
else config.get(CONF_MIN_KELVIN, DEFAULT_MIN_KELVIN)
|
||||
)
|
||||
self._attr_max_color_temp_kelvin = (
|
||||
color_util.color_temperature_mired_to_kelvin(min_mireds)
|
||||
if (min_mireds := config.get(CONF_MIN_MIREDS))
|
||||
else DEFAULT_MAX_KELVIN
|
||||
else config.get(CONF_MAX_KELVIN, DEFAULT_MAX_KELVIN)
|
||||
)
|
||||
self._attr_effect_list = config.get(CONF_EFFECT_LIST)
|
||||
|
||||
|
@ -381,7 +388,9 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||
try:
|
||||
if color_mode == ColorMode.COLOR_TEMP:
|
||||
self._attr_color_temp_kelvin = (
|
||||
color_util.color_temperature_mired_to_kelvin(
|
||||
values["color_temp"]
|
||||
if self._color_temp_kelvin
|
||||
else color_util.color_temperature_mired_to_kelvin(
|
||||
values["color_temp"]
|
||||
)
|
||||
)
|
||||
|
@ -486,7 +495,9 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||
self._attr_color_temp_kelvin = None
|
||||
else:
|
||||
self._attr_color_temp_kelvin = (
|
||||
color_util.color_temperature_mired_to_kelvin(
|
||||
values["color_temp"] # type: ignore[assignment]
|
||||
if self._color_temp_kelvin
|
||||
else color_util.color_temperature_mired_to_kelvin(
|
||||
values["color_temp"] # type: ignore[arg-type]
|
||||
)
|
||||
)
|
||||
|
@ -709,10 +720,13 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
|||
should_update = True
|
||||
|
||||
if ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||
message["color_temp"] = color_util.color_temperature_kelvin_to_mired(
|
||||
message["color_temp"] = (
|
||||
kwargs[ATTR_COLOR_TEMP_KELVIN]
|
||||
if self._color_temp_kelvin
|
||||
else color_util.color_temperature_kelvin_to_mired(
|
||||
kwargs[ATTR_COLOR_TEMP_KELVIN]
|
||||
)
|
||||
)
|
||||
|
||||
if self._optimistic:
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
self._attr_color_temp_kelvin = kwargs[ATTR_COLOR_TEMP_KELVIN]
|
||||
|
|
|
@ -14,7 +14,7 @@ mqtt:
|
|||
rgb: true
|
||||
xy: true
|
||||
|
||||
Configuration with RGB, brightness, color temp and effect:
|
||||
Configuration with RGB, brightness, color temp (mireds) and effect:
|
||||
|
||||
mqtt:
|
||||
light:
|
||||
|
@ -24,10 +24,11 @@ mqtt:
|
|||
command_topic: "home/rgb1/set"
|
||||
brightness: true
|
||||
color_temp: true
|
||||
color_temp_kelvin: false
|
||||
effect: true
|
||||
rgb: true
|
||||
|
||||
Configuration with RGB, brightness and color temp:
|
||||
Configuration with RGB, brightness and color temp (Kelvin):
|
||||
|
||||
mqtt:
|
||||
light:
|
||||
|
@ -38,6 +39,7 @@ mqtt:
|
|||
brightness: true
|
||||
rgb: true
|
||||
color_temp: true
|
||||
color_temp_kelvin: true
|
||||
|
||||
Configuration with RGB, brightness:
|
||||
|
||||
|
@ -399,24 +401,50 @@ async def test_fail_setup_if_color_modes_invalid(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hass_config",
|
||||
("hass_config", "kelvin", "color_temp_payload_value"),
|
||||
[
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_light/set",
|
||||
"state_topic": "test_light",
|
||||
"color_mode": True,
|
||||
"supported_color_modes": "color_temp",
|
||||
(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_light/set",
|
||||
"state_topic": "test_light",
|
||||
"color_mode": True,
|
||||
"color_temp_kelvin": False,
|
||||
"supported_color_modes": "color_temp",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
5208,
|
||||
192,
|
||||
),
|
||||
(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_light/set",
|
||||
"state_topic": "test_light",
|
||||
"color_mode": True,
|
||||
"color_temp_kelvin": True,
|
||||
"supported_color_modes": "color_temp",
|
||||
}
|
||||
}
|
||||
},
|
||||
5208,
|
||||
5208,
|
||||
),
|
||||
],
|
||||
ids=["mireds", "kelvin"],
|
||||
)
|
||||
async def test_single_color_mode(
|
||||
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
kelvin: int,
|
||||
color_temp_payload_value: int,
|
||||
) -> None:
|
||||
"""Test setup with single color_mode."""
|
||||
await mqtt_mock_entry()
|
||||
|
@ -424,13 +452,19 @@ async def test_single_color_mode(
|
|||
assert state.state == STATE_UNKNOWN
|
||||
|
||||
await common.async_turn_on(
|
||||
hass, "light.test", brightness=50, color_temp_kelvin=5208
|
||||
hass, "light.test", brightness=50, color_temp_kelvin=kelvin
|
||||
)
|
||||
|
||||
payload = {
|
||||
"state": "ON",
|
||||
"brightness": 50,
|
||||
"color_mode": "color_temp",
|
||||
"color_temp": color_temp_payload_value,
|
||||
}
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"test_light",
|
||||
'{"state": "ON", "brightness": 50, "color_mode": "color_temp", "color_temp": 192}',
|
||||
json_dumps(payload),
|
||||
)
|
||||
color_modes = [light.ColorMode.COLOR_TEMP]
|
||||
state = hass.states.get("light.test")
|
||||
|
@ -788,6 +822,96 @@ async def test_controlling_state_via_topic(
|
|||
assert light_state.attributes.get("brightness") == 128
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hass_config",
|
||||
[
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"state_topic": "test_light_rgb",
|
||||
"command_topic": "test_light_rgb/set",
|
||||
"brightness": True,
|
||||
"color_temp": True,
|
||||
"color_temp_kelvin": True,
|
||||
"effect": True,
|
||||
"rgb": True,
|
||||
"xy": True,
|
||||
"hs": True,
|
||||
"qos": "0",
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
)
|
||||
async def test_controlling_state_color_temp_kelvin(
|
||||
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
|
||||
) -> None:
|
||||
"""Test the controlling of the state via topic in Kelvin mode."""
|
||||
await mqtt_mock_entry()
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_UNKNOWN
|
||||
color_modes = [light.ColorMode.COLOR_TEMP, light.ColorMode.HS]
|
||||
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
|
||||
expected_features = (
|
||||
light.SUPPORT_EFFECT | light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get("rgb_color") is None
|
||||
assert state.attributes.get("brightness") is None
|
||||
assert state.attributes.get("color_temp_kelvin") is None
|
||||
assert state.attributes.get("effect") is None
|
||||
assert state.attributes.get("xy_color") is None
|
||||
assert state.attributes.get("hs_color") is None
|
||||
assert not state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
# Turn on the light
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"test_light_rgb",
|
||||
'{"state":"ON",'
|
||||
'"color":{"r":255,"g":255,"b":255},'
|
||||
'"brightness":255,'
|
||||
'"color_temp":155,'
|
||||
'"effect":"colorloop"}',
|
||||
)
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get("rgb_color") == (255, 255, 255)
|
||||
assert state.attributes.get("brightness") == 255
|
||||
assert state.attributes.get("color_temp_kelvin") is None # rgb color has priority
|
||||
assert state.attributes.get("effect") == "colorloop"
|
||||
assert state.attributes.get("xy_color") == (0.323, 0.329)
|
||||
assert state.attributes.get("hs_color") == (0.0, 0.0)
|
||||
|
||||
# Turn on the light
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"test_light_rgb",
|
||||
'{"state":"ON",'
|
||||
'"brightness":255,'
|
||||
'"color":null,'
|
||||
'"color_temp":6451,' # Kelvin
|
||||
'"effect":"colorloop"}',
|
||||
)
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get("rgb_color") == (
|
||||
255,
|
||||
253,
|
||||
249,
|
||||
) # temp converted to color
|
||||
assert state.attributes.get("brightness") == 255
|
||||
assert state.attributes.get("color_temp_kelvin") == 6451
|
||||
assert state.attributes.get("effect") == "colorloop"
|
||||
assert state.attributes.get("xy_color") == (0.328, 0.333) # temp converted to color
|
||||
assert state.attributes.get("hs_color") == (44.098, 2.43) # temp converted to color
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hass_config",
|
||||
[
|
||||
|
@ -2591,30 +2715,82 @@ async def test_entity_debug_info_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hass_config",
|
||||
("hass_config", "min_kelvin", "max_kelvin"),
|
||||
[
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_max_mireds/set",
|
||||
"color_temp": True,
|
||||
"max_mireds": 370,
|
||||
(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_max_mireds/set",
|
||||
"supported_color_modes": ["color_temp"],
|
||||
"max_mireds": 370, # 2702 Kelvin
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
2702,
|
||||
light.DEFAULT_MAX_KELVIN,
|
||||
),
|
||||
(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_max_mireds/set",
|
||||
"supported_color_modes": ["color_temp"],
|
||||
"min_mireds": 150, # 6666 Kelvin
|
||||
}
|
||||
}
|
||||
},
|
||||
light.DEFAULT_MIN_KELVIN,
|
||||
6666,
|
||||
),
|
||||
(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_max_mireds/set",
|
||||
"supported_color_modes": ["color_temp"],
|
||||
"min_kelvin": 2702,
|
||||
}
|
||||
}
|
||||
},
|
||||
2702,
|
||||
light.DEFAULT_MAX_KELVIN,
|
||||
),
|
||||
(
|
||||
{
|
||||
mqtt.DOMAIN: {
|
||||
light.DOMAIN: {
|
||||
"schema": "json",
|
||||
"name": "test",
|
||||
"command_topic": "test_max_mireds/set",
|
||||
"supported_color_modes": ["color_temp"],
|
||||
"max_kelvin": 6666,
|
||||
}
|
||||
}
|
||||
},
|
||||
light.DEFAULT_MIN_KELVIN,
|
||||
6666,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_max_mireds(
|
||||
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
|
||||
async def test_min_max_kelvin(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
min_kelvin: int,
|
||||
max_kelvin: int,
|
||||
) -> None:
|
||||
"""Test setting min_mireds and max_mireds."""
|
||||
"""Test setting min_color_temp_kelvin and max_color_temp_kelvin."""
|
||||
await mqtt_mock_entry()
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.attributes.get("min_mireds") == 153
|
||||
assert state.attributes.get("max_mireds") == 370
|
||||
assert state.attributes.get("min_color_temp_kelvin") == min_kelvin
|
||||
assert state.attributes.get("max_color_temp_kelvin") == max_kelvin
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
Loading…
Reference in New Issue