Migrate mqtt lights to use Kelvin (#132828)

* Migrate mqtt lights to use Kelvin

* Adjust restore_cache tests

* Adjust tests
This commit is contained in:
epenet 2024-12-11 16:11:14 +01:00 committed by GitHub
parent ee4db13c2a
commit 0d71828def
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 80 additions and 39 deletions

View File

@ -246,7 +246,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
_optimistic: bool
_optimistic_brightness: bool
_optimistic_color_mode: bool
_optimistic_color_temp: bool
_optimistic_color_temp_kelvin: bool
_optimistic_effect: bool
_optimistic_hs_color: bool
_optimistic_rgb_color: bool
@ -327,7 +327,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
and topic[CONF_RGB_STATE_TOPIC] is None
)
)
self._optimistic_color_temp = (
self._optimistic_color_temp_kelvin = (
optimistic or topic[CONF_COLOR_TEMP_STATE_TOPIC] is None
)
self._optimistic_effect = optimistic or topic[CONF_EFFECT_STATE_TOPIC] is None
@ -518,7 +518,9 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
if self._optimistic_color_mode:
self._attr_color_mode = ColorMode.COLOR_TEMP
self._attr_color_temp = int(payload)
self._attr_color_temp_kelvin = color_util.color_temperature_mired_to_kelvin(
int(payload)
)
@callback
def _effect_received(self, msg: ReceiveMessage) -> None:
@ -592,7 +594,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
self.add_subscription(
CONF_COLOR_TEMP_STATE_TOPIC,
self._color_temp_received,
{"_attr_color_mode", "_attr_color_temp"},
{"_attr_color_mode", "_attr_color_temp_kelvin"},
)
self.add_subscription(
CONF_EFFECT_STATE_TOPIC, self._effect_received, {"_attr_effect"}
@ -631,7 +633,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
restore_state(ATTR_RGBW_COLOR)
restore_state(ATTR_RGBWW_COLOR)
restore_state(ATTR_COLOR_MODE)
restore_state(ATTR_COLOR_TEMP)
restore_state(ATTR_COLOR_TEMP_KELVIN)
restore_state(ATTR_EFFECT)
restore_state(ATTR_HS_COLOR)
restore_state(ATTR_XY_COLOR)
@ -803,14 +805,21 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
await publish(CONF_RGBWW_COMMAND_TOPIC, rgbww_s)
should_update |= set_optimistic(ATTR_BRIGHTNESS, kwargs[ATTR_BRIGHTNESS])
if (
ATTR_COLOR_TEMP in kwargs
ATTR_COLOR_TEMP_KELVIN in kwargs
and self._topic[CONF_COLOR_TEMP_COMMAND_TOPIC] is not None
):
ct_command_tpl = self._command_templates[CONF_COLOR_TEMP_COMMAND_TEMPLATE]
color_temp = ct_command_tpl(int(kwargs[ATTR_COLOR_TEMP]), None)
color_temp = ct_command_tpl(
color_util.color_temperature_kelvin_to_mired(
kwargs[ATTR_COLOR_TEMP_KELVIN]
),
None,
)
await publish(CONF_COLOR_TEMP_COMMAND_TOPIC, color_temp)
should_update |= set_optimistic(
ATTR_COLOR_TEMP, kwargs[ATTR_COLOR_TEMP], ColorMode.COLOR_TEMP
ATTR_COLOR_TEMP_KELVIN,
kwargs[ATTR_COLOR_TEMP_KELVIN],
ColorMode.COLOR_TEMP,
)
if (

View File

@ -12,7 +12,7 @@ import voluptuous as vol
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_MODE,
ATTR_COLOR_TEMP,
ATTR_COLOR_TEMP_KELVIN,
ATTR_EFFECT,
ATTR_FLASH,
ATTR_HS_COLOR,
@ -273,8 +273,16 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
def _setup_from_config(self, config: ConfigType) -> None:
"""(Re)Setup the entity."""
self._attr_max_mireds = config.get(CONF_MAX_MIREDS, super().max_mireds)
self._attr_min_mireds = config.get(CONF_MIN_MIREDS, super().min_mireds)
self._attr_min_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(max_mireds)
if (max_mireds := config.get(CONF_MAX_MIREDS))
else super().min_color_temp_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 super().max_color_temp_kelvin
)
self._attr_effect_list = config.get(CONF_EFFECT_LIST)
self._topic = {
@ -370,7 +378,11 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
return
try:
if color_mode == ColorMode.COLOR_TEMP:
self._attr_color_temp = int(values["color_temp"])
self._attr_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(
values["color_temp"]
)
)
self._attr_color_mode = ColorMode.COLOR_TEMP
elif color_mode == ColorMode.HS:
hue = float(values["color"]["h"])
@ -469,9 +481,13 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
# Deprecated color handling
try:
if values["color_temp"] is None:
self._attr_color_temp = None
self._attr_color_temp_kelvin = None
else:
self._attr_color_temp = int(values["color_temp"]) # type: ignore[arg-type]
self._attr_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(
values["color_temp"] # type: ignore[arg-type]
)
)
except KeyError:
pass
except ValueError:
@ -496,7 +512,7 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
self._state_received,
{
"_attr_brightness",
"_attr_color_temp",
"_attr_color_temp_kelvin",
"_attr_effect",
"_attr_hs_color",
"_attr_is_on",
@ -522,8 +538,8 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
self._attr_color_mode = last_attributes.get(
ATTR_COLOR_MODE, self.color_mode
)
self._attr_color_temp = last_attributes.get(
ATTR_COLOR_TEMP, self.color_temp
self._attr_color_temp_kelvin = last_attributes.get(
ATTR_COLOR_TEMP_KELVIN, self.color_temp_kelvin
)
self._attr_effect = last_attributes.get(ATTR_EFFECT, self.effect)
self._attr_hs_color = last_attributes.get(ATTR_HS_COLOR, self.hs_color)
@ -690,12 +706,14 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
self._attr_brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
if ATTR_COLOR_TEMP in kwargs:
message["color_temp"] = int(kwargs[ATTR_COLOR_TEMP])
if ATTR_COLOR_TEMP_KELVIN in kwargs:
message["color_temp"] = 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 = kwargs[ATTR_COLOR_TEMP]
self._attr_color_temp_kelvin = kwargs[ATTR_COLOR_TEMP_KELVIN]
self._attr_hs_color = None
should_update = True

View File

@ -10,7 +10,7 @@ import voluptuous as vol
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_COLOR_TEMP_KELVIN,
ATTR_EFFECT,
ATTR_FLASH,
ATTR_HS_COLOR,
@ -126,8 +126,16 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
def _setup_from_config(self, config: ConfigType) -> None:
"""(Re)Setup the entity."""
self._attr_max_mireds = config.get(CONF_MAX_MIREDS, super().max_mireds)
self._attr_min_mireds = config.get(CONF_MIN_MIREDS, super().min_mireds)
self._attr_min_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(max_mireds)
if (max_mireds := config.get(CONF_MAX_MIREDS))
else super().min_color_temp_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 super().max_color_temp_kelvin
)
self._attr_effect_list = config.get(CONF_EFFECT_LIST)
self._topics = {
@ -213,8 +221,10 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
color_temp = self._value_templates[CONF_COLOR_TEMP_TEMPLATE](
msg.payload
)
self._attr_color_temp = (
int(color_temp) if color_temp != "None" else None
self._attr_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(int(color_temp))
if color_temp != "None"
else None
)
except ValueError:
_LOGGER.warning("Invalid color temperature value received")
@ -256,7 +266,7 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
{
"_attr_brightness",
"_attr_color_mode",
"_attr_color_temp",
"_attr_color_temp_kelvin",
"_attr_effect",
"_attr_hs_color",
"_attr_is_on",
@ -275,8 +285,10 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
if last_state.attributes.get(ATTR_HS_COLOR):
self._attr_hs_color = last_state.attributes.get(ATTR_HS_COLOR)
self._update_color_mode()
if last_state.attributes.get(ATTR_COLOR_TEMP):
self._attr_color_temp = last_state.attributes.get(ATTR_COLOR_TEMP)
if last_state.attributes.get(ATTR_COLOR_TEMP_KELVIN):
self._attr_color_temp_kelvin = last_state.attributes.get(
ATTR_COLOR_TEMP_KELVIN
)
if last_state.attributes.get(ATTR_EFFECT):
self._attr_effect = last_state.attributes.get(ATTR_EFFECT)
@ -295,11 +307,13 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
if self._optimistic:
self._attr_brightness = kwargs[ATTR_BRIGHTNESS]
if ATTR_COLOR_TEMP in kwargs:
values["color_temp"] = int(kwargs[ATTR_COLOR_TEMP])
if ATTR_COLOR_TEMP_KELVIN in kwargs:
values["color_temp"] = color_util.color_temperature_kelvin_to_mired(
kwargs[ATTR_COLOR_TEMP_KELVIN]
)
if self._optimistic:
self._attr_color_temp = kwargs[ATTR_COLOR_TEMP]
self._attr_color_temp_kelvin = kwargs[ATTR_COLOR_TEMP_KELVIN]
self._attr_hs_color = None
self._update_color_mode()
@ -325,7 +339,7 @@ class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity):
values["sat"] = hs_color[1]
if self._optimistic:
self._attr_color_temp = None
self._attr_color_temp_kelvin = None
self._attr_hs_color = kwargs[ATTR_HS_COLOR]
self._update_color_mode()

View File

@ -1008,7 +1008,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"brightness": 95,
"hs_color": [100, 100],
"effect": "random",
"color_temp": 100,
"color_temp_kelvin": 100000,
"color_mode": "hs",
},
)
@ -1021,7 +1021,7 @@ async def test_sending_mqtt_commands_and_optimistic(
assert state.attributes.get("brightness") == 95
assert state.attributes.get("hs_color") == (100, 100)
assert state.attributes.get("effect") == "random"
assert state.attributes.get("color_temp") is None
assert state.attributes.get("color_temp_kelvin") is None
assert state.attributes.get(light.ATTR_COLOR_MODE) == "hs"
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
assert state.attributes.get(ATTR_ASSUMED_STATE)

View File

@ -1053,7 +1053,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"brightness": 95,
"hs_color": [100, 100],
"effect": "random",
"color_temp": 100,
"color_temp_kelvin": 10000,
},
)
mock_restore_cache(hass, (fake_state,))
@ -1065,7 +1065,7 @@ async def test_sending_mqtt_commands_and_optimistic(
assert state.attributes.get("brightness") == 95
assert state.attributes.get("hs_color") == (100, 100)
assert state.attributes.get("effect") == "random"
assert state.attributes.get("color_temp") is None # hs_color has priority
assert state.attributes.get("color_temp_kelvin") is None # hs_color has priority
color_modes = [light.ColorMode.COLOR_TEMP, light.ColorMode.HS]
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
expected_features = (
@ -1205,7 +1205,7 @@ async def test_sending_mqtt_commands_and_optimistic2(
"on",
{
"brightness": 95,
"color_temp": 100,
"color_temp_kelvin": 10000,
"color_mode": "rgb",
"effect": "random",
"hs_color": [100, 100],

View File

@ -432,7 +432,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"brightness": 95,
"hs_color": [100, 100],
"effect": "random",
"color_temp": 100,
"color_temp_kelvin": 10000,
},
)
mock_restore_cache(hass, (fake_state,))
@ -443,7 +443,7 @@ async def test_sending_mqtt_commands_and_optimistic(
assert state.state == STATE_ON
assert state.attributes.get("hs_color") == (100, 100)
assert state.attributes.get("effect") == "random"
assert state.attributes.get("color_temp") is None # hs_color has priority
assert state.attributes.get("color_temp_kelvin") is None # hs_color has priority
assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_turn_off(hass, "light.test")