Skip to content

Commit

Permalink
Allow to process kelvin as color_temp for mqtt template light (#133957)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbouwh authored Jan 10, 2025
1 parent b5971ec commit eba090c
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 53 deletions.
27 changes: 22 additions & 5 deletions homeassistant/components/mqtt/light/schema_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@

from .. import subscription
from ..config import MQTT_RW_SCHEMA
from ..const import CONF_COMMAND_TOPIC, CONF_STATE_TOPIC, PAYLOAD_NONE
from ..const import (
CONF_COLOR_TEMP_KELVIN,
CONF_COMMAND_TOPIC,
CONF_MAX_KELVIN,
CONF_MIN_KELVIN,
CONF_STATE_TOPIC,
PAYLOAD_NONE,
)
from ..entity import MqttEntity
from ..models import (
MqttCommandTemplate,
Expand Down Expand Up @@ -85,12 +92,15 @@
{
vol.Optional(CONF_BLUE_TEMPLATE): cv.template,
vol.Optional(CONF_BRIGHTNESS_TEMPLATE): cv.template,
vol.Optional(CONF_COLOR_TEMP_KELVIN, default=False): cv.boolean,
vol.Optional(CONF_COLOR_TEMP_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_OFF_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_ON_TEMPLATE): cv.template,
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_EFFECT_TEMPLATE): cv.template,
vol.Optional(CONF_GREEN_TEMPLATE): cv.template,
vol.Optional(CONF_MAX_KELVIN): cv.positive_int,
vol.Optional(CONF_MIN_KELVIN): cv.positive_int,
vol.Optional(CONF_MAX_MIREDS): cv.positive_int,
vol.Optional(CONF_MIN_MIREDS): cv.positive_int,
vol.Optional(CONF_NAME): vol.Any(cv.string, None),
Expand Down Expand Up @@ -128,15 +138,16 @@ def config_schema() -> VolSchemaType:

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)

Expand Down Expand Up @@ -224,7 +235,9 @@ def _state_received(self, msg: ReceiveMessage) -> None:
msg.payload
)
self._attr_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(int(color_temp))
int(color_temp)
if self._color_temp_kelvin
else color_util.color_temperature_mired_to_kelvin(int(color_temp))
if color_temp != "None"
else None
)
Expand Down Expand Up @@ -310,8 +323,12 @@ async def async_turn_on(self, **kwargs: Any) -> None:
self._attr_brightness = kwargs[ATTR_BRIGHTNESS]

if ATTR_COLOR_TEMP_KELVIN in kwargs:
values["color_temp"] = color_util.color_temperature_kelvin_to_mired(
values["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:
Expand Down
163 changes: 115 additions & 48 deletions tests/components/mqtt/test_light_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,25 +179,50 @@ async def test_rgb_light(


@pytest.mark.parametrize(
"hass_config",
("hass_config", "kelvin", "payload"),
[
{
mqtt.DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
"command_topic": "test_light/set",
"command_on_template": "on,{{ brightness|d }},{{ color_temp|d }}",
"command_off_template": "off",
"brightness_template": "{{ value.split(',')[1] }}",
"color_temp_template": "{{ value.split(',')[2] }}",
(
{
mqtt.DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
"command_topic": "test_light/set",
"command_on_template": "on,{{ brightness|d }},{{ color_temp|d }}",
"command_off_template": "off",
"brightness_template": "{{ value.split(',')[1] }}",
"color_temp_template": "{{ value.split(',')[2] }}",
}
}
}
}
},
5208,
"192",
),
(
{
mqtt.DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
"command_topic": "test_light/set",
"command_on_template": "on,{{ brightness|d }},{{ color_temp|d }}",
"command_off_template": "off",
"brightness_template": "{{ value.split(',')[1] }}",
"color_temp_template": "{{ value.split(',')[2] }}",
}
}
},
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,
payload: str,
) -> None:
"""Test the color mode when we only have one supported color_mode."""
await mqtt_mock_entry()
Expand All @@ -206,15 +231,15 @@ 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
)
async_fire_mqtt_message(hass, "test_light", "on,50,192")
async_fire_mqtt_message(hass, "test_light", f"on,50,{payload}")
color_modes = [light.ColorMode.COLOR_TEMP]
state = hass.states.get("light.test")
assert state.state == STATE_ON

assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
assert state.attributes.get(light.ATTR_COLOR_TEMP_KELVIN) == 5208
assert state.attributes.get(light.ATTR_COLOR_TEMP_KELVIN) == kelvin
assert state.attributes.get(light.ATTR_BRIGHTNESS) == 50
assert state.attributes.get(light.ATTR_COLOR_MODE) == color_modes[0]

Expand Down Expand Up @@ -392,39 +417,80 @@ async def test_state_brightness_color_effect_temp_change_via_topic(


@pytest.mark.parametrize(
"hass_config",
("hass_config", "kelvin", "payload"),
[
{
mqtt.DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
"command_topic": "test_light_rgb/set",
"command_on_template": "on,"
"{{ brightness|d }},"
"{{ color_temp|d }},"
"{{ red|d }}-"
"{{ green|d }}-"
"{{ blue|d }},"
"{{ hue|d }}-"
"{{ sat|d }}",
"command_off_template": "off",
"effect_list": ["colorloop", "random"],
"optimistic": True,
"state_template": '{{ value.split(",")[0] }}',
"color_temp_template": '{{ value.split(",")[2] }}',
"red_template": '{{ value.split(",")[3].split("-")[0] }}',
"green_template": '{{ value.split(",")[3].split("-")[1] }}',
"blue_template": '{{ value.split(",")[3].split("-")[2] }}',
"effect_template": '{{ value.split(",")[4] }}',
"qos": 2,
(
{
mqtt.DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
"command_topic": "test_light_rgb/set",
"command_on_template": "on,"
"{{ brightness|d }},"
"{{ color_temp|d }},"
"{{ red|d }}-"
"{{ green|d }}-"
"{{ blue|d }},"
"{{ hue|d }}-"
"{{ sat|d }}",
"command_off_template": "off",
"effect_list": ["colorloop", "random"],
"optimistic": True,
"state_template": '{{ value.split(",")[0] }}',
"color_temp_kelvin": False,
"color_temp_template": '{{ value.split(",")[2] }}',
"red_template": '{{ value.split(",")[3].split("-")[0] }}',
"green_template": '{{ value.split(",")[3].split("-")[1] }}',
"blue_template": '{{ value.split(",")[3].split("-")[2] }}',
"effect_template": '{{ value.split(",")[4] }}',
"qos": 2,
}
}
}
}
},
14285,
"on,,70,--,-",
),
(
{
mqtt.DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
"command_topic": "test_light_rgb/set",
"command_on_template": "on,"
"{{ brightness|d }},"
"{{ color_temp|d }},"
"{{ red|d }}-"
"{{ green|d }}-"
"{{ blue|d }},"
"{{ hue|d }}-"
"{{ sat|d }}",
"command_off_template": "off",
"effect_list": ["colorloop", "random"],
"optimistic": True,
"state_template": '{{ value.split(",")[0] }}',
"color_temp_kelvin": True,
"color_temp_template": '{{ value.split(",")[2] }}',
"red_template": '{{ value.split(",")[3].split("-")[0] }}',
"green_template": '{{ value.split(",")[3].split("-")[1] }}',
"blue_template": '{{ value.split(",")[3].split("-")[2] }}',
"effect_template": '{{ value.split(",")[4] }}',
"qos": 2,
}
},
},
14285,
"on,,14285,--,-",
),
],
ids=["mireds", "kelvin"],
)
async def test_sending_mqtt_commands_and_optimistic(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
kelvin: int,
payload: str,
) -> None:
"""Test the sending of command in optimistic mode."""
fake_state = State(
Expand Down Expand Up @@ -465,14 +531,15 @@ async def test_sending_mqtt_commands_and_optimistic(
assert state.state == STATE_ON

# Set color_temp
await common.async_turn_on(hass, "light.test", color_temp_kelvin=14285)
await common.async_turn_on(hass, "light.test", color_temp_kelvin=kelvin)
# Assert mireds or Kelvin as payload
mqtt_mock.async_publish.assert_called_once_with(
"test_light_rgb/set", "on,,70,--,-", 2, False
"test_light_rgb/set", payload, 2, False
)
mqtt_mock.async_publish.reset_mock()
state = hass.states.get("light.test")
assert state.state == STATE_ON
assert state.attributes.get("color_temp_kelvin") == 14285
assert state.attributes.get("color_temp_kelvin") == kelvin

# Set full brightness
await common.async_turn_on(hass, "light.test", brightness=255)
Expand Down

0 comments on commit eba090c

Please sign in to comment.