Skip to content

Commit

Permalink
Fix mqtt light rgbww update without state topic (#100707)
Browse files Browse the repository at this point in the history
* Fix mqtt light rgbww update without state topic

* Add @callback decprator and correct mired conv
  • Loading branch information
jbouwh authored and frenck committed Sep 23, 2023
1 parent 161e9d1 commit 556e40a
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 1 deletion.
18 changes: 17 additions & 1 deletion homeassistant/components/mqtt/light/schema_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ def brightness_received(msg: ReceiveMessage) -> None:

add_topic(CONF_BRIGHTNESS_STATE_TOPIC, brightness_received)

@callback
def _rgbx_received(
msg: ReceiveMessage,
template: str,
Expand Down Expand Up @@ -532,11 +533,26 @@ def rgbw_received(msg: ReceiveMessage) -> None:
@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
Expand Down
171 changes: 171 additions & 0 deletions tests/components/mqtt/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
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,
Expand Down Expand Up @@ -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",
[
Expand Down

0 comments on commit 556e40a

Please sign in to comment.