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

View File

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

View File

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

View File

@ -1008,7 +1008,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"brightness": 95, "brightness": 95,
"hs_color": [100, 100], "hs_color": [100, 100],
"effect": "random", "effect": "random",
"color_temp": 100, "color_temp_kelvin": 100000,
"color_mode": "hs", "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("brightness") == 95
assert state.attributes.get("hs_color") == (100, 100) assert state.attributes.get("hs_color") == (100, 100)
assert state.attributes.get("effect") == "random" 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_COLOR_MODE) == "hs"
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
assert state.attributes.get(ATTR_ASSUMED_STATE) assert state.attributes.get(ATTR_ASSUMED_STATE)

View File

@ -1053,7 +1053,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"brightness": 95, "brightness": 95,
"hs_color": [100, 100], "hs_color": [100, 100],
"effect": "random", "effect": "random",
"color_temp": 100, "color_temp_kelvin": 10000,
}, },
) )
mock_restore_cache(hass, (fake_state,)) 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("brightness") == 95
assert state.attributes.get("hs_color") == (100, 100) assert state.attributes.get("hs_color") == (100, 100)
assert state.attributes.get("effect") == "random" 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] 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 = ( expected_features = (
@ -1205,7 +1205,7 @@ async def test_sending_mqtt_commands_and_optimistic2(
"on", "on",
{ {
"brightness": 95, "brightness": 95,
"color_temp": 100, "color_temp_kelvin": 10000,
"color_mode": "rgb", "color_mode": "rgb",
"effect": "random", "effect": "random",
"hs_color": [100, 100], "hs_color": [100, 100],

View File

@ -432,7 +432,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"brightness": 95, "brightness": 95,
"hs_color": [100, 100], "hs_color": [100, 100],
"effect": "random", "effect": "random",
"color_temp": 100, "color_temp_kelvin": 10000,
}, },
) )
mock_restore_cache(hass, (fake_state,)) 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.state == STATE_ON
assert state.attributes.get("hs_color") == (100, 100) assert state.attributes.get("hs_color") == (100, 100)
assert state.attributes.get("effect") == "random" 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) assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_turn_off(hass, "light.test") await common.async_turn_off(hass, "light.test")