diff --git a/homeassistant/components/mqtt/light/schema_basic.py b/homeassistant/components/mqtt/light/schema_basic.py index 03f78b8c43fa4b698db7fcb6c2f4c9d80d61ebbb..c12d8719d7a4db2f53626d9f34c02cab9b4205aa 100644 --- a/homeassistant/components/mqtt/light/schema_basic.py +++ b/homeassistant/components/mqtt/light/schema_basic.py @@ -463,6 +463,7 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity): add_topic(CONF_BRIGHTNESS_STATE_TOPIC, brightness_received) + @callback def _rgbx_received( msg: ReceiveMessage, template: str, @@ -533,11 +534,26 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity): @log_messages(self.hass, self.entity_id) def rgbww_received(msg: ReceiveMessage) -> None: """Handle new MQTT messages for RGBWW.""" + + @callback + def _converter( + r: int, g: int, b: int, cw: int, ww: int + ) -> tuple[int, int, int]: + min_kelvin = color_util.color_temperature_mired_to_kelvin( + self.max_mireds + ) + max_kelvin = color_util.color_temperature_mired_to_kelvin( + self.min_mireds + ) + return color_util.color_rgbww_to_rgb( + r, g, b, cw, ww, min_kelvin, max_kelvin + ) + rgbww = _rgbx_received( msg, CONF_RGBWW_VALUE_TEMPLATE, ColorMode.RGBWW, - color_util.color_rgbww_to_rgb, + _converter, ) if rgbww is None: return diff --git a/tests/components/mqtt/test_light.py b/tests/components/mqtt/test_light.py index ba0b21b5ceba807792629313fb0a5a1dbbeb8bc8..0199ee19772be4b66c58cc152377046a5f054ecf 100644 --- a/tests/components/mqtt/test_light.py +++ b/tests/components/mqtt/test_light.py @@ -198,6 +198,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, State from .test_common import ( + help_custom_config, help_test_availability_when_connection_lost, help_test_availability_without_topic, help_test_custom_availability_payload, @@ -441,6 +442,176 @@ async def test_controlling_state_via_topic( assert light_state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes +@pytest.mark.parametrize( + "hass_config", + [ + help_custom_config( + light.DOMAIN, + DEFAULT_CONFIG, + ( + { + "state_topic": "test-topic", + "optimistic": True, + "brightness_command_topic": "test_light_rgb/brightness/set", + "color_mode_state_topic": "color-mode-state-topic", + "rgb_command_topic": "test_light_rgb/rgb/set", + "rgb_state_topic": "rgb-state-topic", + "rgbw_command_topic": "test_light_rgb/rgbw/set", + "rgbw_state_topic": "rgbw-state-topic", + "rgbww_command_topic": "test_light_rgb/rgbww/set", + "rgbww_state_topic": "rgbww-state-topic", + }, + ), + ) + ], +) +async def test_received_rgbx_values_set_state_optimistic( + hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator +) -> None: + """Test the state is set correctly when an rgbx update is received.""" + await mqtt_mock_entry() + state = hass.states.get("light.test") + assert state and state.state is not None + async_fire_mqtt_message(hass, "test-topic", "ON") + ## Test rgb processing + async_fire_mqtt_message(hass, "rgb-state-topic", "255,255,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgb" + assert state.attributes["rgb_color"] == (255, 255, 255) + + # Only update color mode + async_fire_mqtt_message(hass, "color-mode-state-topic", "rgbww") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbww" + + # Resending same rgb value should restore color mode + async_fire_mqtt_message(hass, "rgb-state-topic", "255,255,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgb" + assert state.attributes["rgb_color"] == (255, 255, 255) + + # Only update brightness + await common.async_turn_on(hass, "light.test", brightness=128) + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 128 + assert state.attributes["color_mode"] == "rgb" + assert state.attributes["rgb_color"] == (255, 255, 255) + + # Resending same rgb value should restore brightness + async_fire_mqtt_message(hass, "rgb-state-topic", "255,255,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgb" + assert state.attributes["rgb_color"] == (255, 255, 255) + + # Only change rgb value + async_fire_mqtt_message(hass, "rgb-state-topic", "255,255,0") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgb" + assert state.attributes["rgb_color"] == (255, 255, 0) + + ## Test rgbw processing + async_fire_mqtt_message(hass, "rgbw-state-topic", "255,255,255,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbw" + assert state.attributes["rgbw_color"] == (255, 255, 255, 255) + + # Only update color mode + async_fire_mqtt_message(hass, "color-mode-state-topic", "rgb") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgb" + + # Resending same rgbw value should restore color mode + async_fire_mqtt_message(hass, "rgbw-state-topic", "255,255,255,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbw" + assert state.attributes["rgbw_color"] == (255, 255, 255, 255) + + # Only update brightness + await common.async_turn_on(hass, "light.test", brightness=128) + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 128 + assert state.attributes["color_mode"] == "rgbw" + assert state.attributes["rgbw_color"] == (255, 255, 255, 255) + + # Resending same rgbw value should restore brightness + async_fire_mqtt_message(hass, "rgbw-state-topic", "255,255,255,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbw" + assert state.attributes["rgbw_color"] == (255, 255, 255, 255) + + # Only change rgbw value + async_fire_mqtt_message(hass, "rgbw-state-topic", "255,255,128,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbw" + assert state.attributes["rgbw_color"] == (255, 255, 128, 255) + + ## Test rgbww processing + async_fire_mqtt_message(hass, "rgbww-state-topic", "255,255,255,32,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbww" + assert state.attributes["rgbww_color"] == (255, 255, 255, 32, 255) + + # Only update color mode + async_fire_mqtt_message(hass, "color-mode-state-topic", "rgb") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgb" + + # Resending same rgbw value should restore color mode + async_fire_mqtt_message(hass, "rgbww-state-topic", "255,255,255,32,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbww" + assert state.attributes["rgbww_color"] == (255, 255, 255, 32, 255) + + # Only update brightness + await common.async_turn_on(hass, "light.test", brightness=128) + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 128 + assert state.attributes["color_mode"] == "rgbww" + assert state.attributes["rgbww_color"] == (255, 255, 255, 32, 255) + + # Resending same rgbww value should restore brightness + async_fire_mqtt_message(hass, "rgbww-state-topic", "255,255,255,32,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbww" + assert state.attributes["rgbww_color"] == (255, 255, 255, 32, 255) + + # Only change rgbww value + async_fire_mqtt_message(hass, "rgbww-state-topic", "255,255,128,32,255") + await hass.async_block_till_done() + state = hass.states.get("light.test") + assert state.attributes["brightness"] == 255 + assert state.attributes["color_mode"] == "rgbww" + assert state.attributes["rgbww_color"] == (255, 255, 128, 32, 255) + + @pytest.mark.parametrize( "hass_config", [