Skip to content

Commit 630b4de

Browse files
committed
Fix missing color_mode initialization in MQTT JSON light schema
Initialize `_fixed_color_mode` and `_attr_color_mode` before the color mode branching logic in `_setup_from_config`, matching the pattern already used in `schema_template.py` (added in #162715). Without this, `_attr_color_mode` can remain `None` (the new default from #162715) in edge cases during entity (re)setup, causing "does not report a color mode" errors when the light is on. Also use `_fixed_color_mode` in `_update_color()` to skip color mode changes for single-mode lights, preventing the fixed mode from being overwritten by state updates. This matches the guard pattern used in `schema_template.py`.
1 parent b5480da commit 630b4de

2 files changed

Lines changed: 66 additions & 4 deletions

File tree

homeassistant/components/mqtt/light/schema_json.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,13 @@ def _setup_from_config(self, config: ConfigType) -> None:
190190
self._attr_supported_features |= (
191191
config[CONF_TRANSITION] and LightEntityFeature.TRANSITION
192192
)
193+
self._fixed_color_mode = None
194+
self._attr_color_mode = ColorMode.UNKNOWN
193195
if supported_color_modes := self._config.get(CONF_SUPPORTED_COLOR_MODES):
194196
self._attr_supported_color_modes = supported_color_modes
195197
if self.supported_color_modes and len(self.supported_color_modes) == 1:
196-
self._attr_color_mode = next(iter(self.supported_color_modes))
198+
self._fixed_color_mode = next(iter(self.supported_color_modes))
199+
self._attr_color_mode = self._fixed_color_mode
197200
else:
198201
self._attr_color_mode = ColorMode.UNKNOWN
199202
elif config.get(CONF_BRIGHTNESS):
@@ -206,7 +209,7 @@ def _setup_from_config(self, config: ConfigType) -> None:
206209
self._attr_color_mode = ColorMode.ONOFF
207210

208211
def _update_color(self, values: dict[str, Any]) -> None:
209-
color_mode: str = values["color_mode"]
212+
color_mode: str = self._fixed_color_mode or values["color_mode"]
210213
if not self._supports_color_mode(color_mode):
211214
_LOGGER.warning(
212215
"Invalid color mode '%s' received for entity %s",
@@ -337,8 +340,12 @@ async def _subscribe_topics(self) -> None:
337340
self._attr_brightness = last_attributes.get(
338341
ATTR_BRIGHTNESS, self.brightness
339342
)
340-
self._attr_color_mode = last_attributes.get(
341-
ATTR_COLOR_MODE, self.color_mode
343+
self._attr_color_mode = cast(
344+
ColorMode,
345+
self._fixed_color_mode
346+
if self._fixed_color_mode is not None
347+
else last_attributes.get(ATTR_COLOR_MODE, self.color_mode)
348+
or ColorMode.UNKNOWN,
342349
)
343350
self._attr_color_temp_kelvin = last_attributes.get(
344351
ATTR_COLOR_TEMP_KELVIN, self.color_temp_kelvin

tests/components/mqtt/test_light_json.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,61 @@ async def test_brightness_only(
513513
assert state.state == STATE_OFF
514514

515515

516+
@pytest.mark.parametrize(
517+
"hass_config",
518+
[
519+
{
520+
mqtt.DOMAIN: {
521+
light.DOMAIN: {
522+
"schema": "json",
523+
"name": "test",
524+
"state_topic": "test_light_rgb",
525+
"command_topic": "test_light_rgb/set",
526+
"supported_color_modes": ["brightness"],
527+
}
528+
}
529+
},
530+
{
531+
mqtt.DOMAIN: {
532+
light.DOMAIN: {
533+
"schema": "json",
534+
"name": "test",
535+
"state_topic": "test_light_rgb",
536+
"command_topic": "test_light_rgb/set",
537+
"supported_color_modes": ["color_temp"],
538+
}
539+
}
540+
},
541+
],
542+
)
543+
async def test_single_color_mode_turn_on(
544+
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
545+
) -> None:
546+
"""Test turning on a single color mode light does not raise.
547+
548+
Regression test: PR #162715 changed _attr_color_mode default to None
549+
and added a strict check. The JSON schema must initialize color_mode
550+
during setup so that turn_on does not raise "does not report a color mode".
551+
"""
552+
await mqtt_mock_entry()
553+
554+
state = hass.states.get("light.test")
555+
assert state.state == STATE_UNKNOWN
556+
557+
async_fire_mqtt_message(hass, "test_light_rgb", '{"state":"ON", "brightness": 50}')
558+
559+
state = hass.states.get("light.test")
560+
assert state.state == STATE_ON
561+
562+
# This should not raise "does not report a color mode"
563+
await common.async_turn_on(hass, "light.test")
564+
565+
state = hass.states.get("light.test")
566+
assert state.state == STATE_ON
567+
assert state.attributes.get(light.ATTR_COLOR_MODE) is not None
568+
assert state.attributes.get(light.ATTR_COLOR_MODE) != light.ColorMode.UNKNOWN
569+
570+
516571
@pytest.mark.parametrize(
517572
"hass_config",
518573
[

0 commit comments

Comments
 (0)