From afe3b38ce38b6c9d7c8811ad97ba60057cb3c179 Mon Sep 17 00:00:00 2001 From: rqi14 <26152437+rqi14@users.noreply.github.com> Date: Thu, 10 Sep 2026 20:09:00 +0800 Subject: [PATCH] Nest climate: recompute supported_features from live device traits (#181660) --- homeassistant/components/nest/climate.py | 7 +++- tests/components/nest/test_climate.py | 49 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/nest/climate.py b/homeassistant/components/nest/climate.py index 444c70fc0f20..da3489ac74b8 100644 --- a/homeassistant/components/nest/climate.py +++ b/homeassistant/components/nest/climate.py @@ -126,7 +126,6 @@ class ThermostatEntity(ClimateEntity): @override async def async_added_to_hass(self) -> None: """Run when entity is added to register update signal handler.""" - self._attr_supported_features = self._get_supported_features() self.async_on_remove( self._device.add_update_listener(self.async_write_ha_state) ) @@ -264,6 +263,12 @@ class ThermostatEntity(ClimateEntity): return FAN_INV_MODES return [] + @property + @override + def supported_features(self) -> ClimateEntityFeature: + """Return the bitmap of supported features, computed from current traits.""" + return self._get_supported_features() + def _get_supported_features(self) -> ClimateEntityFeature: """Compute the bitmap of supported features from the current state.""" features = ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON diff --git a/tests/components/nest/test_climate.py b/tests/components/nest/test_climate.py index e45fc5752d72..09afe6ee814b 100644 --- a/tests/components/nest/test_climate.py +++ b/tests/components/nest/test_climate.py @@ -1372,6 +1372,55 @@ async def test_thermostat_fan_empty( assert ATTR_FAN_MODES not in thermostat.attributes +async def test_thermostat_fan_becomes_supported_after_update( + hass: HomeAssistant, + setup_platform: PlatformSetup, + create_device: CreateDevice, + create_event: CreateEvent, +) -> None: + """Test that supported_features is recomputed once the fan trait reports a mode. + + The fan trait can be present at startup without a timer_mode value yet + populated (e.g. before the initial full state has propagated). Regression + test for supported_features being frozen at entity setup rather than + reflecting the live device state. + """ + create_device.create( + { + "sdm.devices.traits.Fan": {}, + "sdm.devices.traits.ThermostatHvac": {"status": "OFF"}, + "sdm.devices.traits.ThermostatMode": { + "availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"], + "mode": "OFF", + }, + } + ) + await setup_platform() + + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert ATTR_FAN_MODE not in thermostat.attributes + assert ATTR_FAN_MODES not in thermostat.attributes + assert not ( + thermostat.attributes[ATTR_SUPPORTED_FEATURES] & ClimateEntityFeature.FAN_MODE + ) + + # The fan trait later reports a real timer_mode value + await create_event( + { + "sdm.devices.traits.Fan": {"timerMode": "OFF"}, + } + ) + + thermostat = hass.states.get("climate.my_thermostat") + assert thermostat is not None + assert ( + thermostat.attributes[ATTR_SUPPORTED_FEATURES] & ClimateEntityFeature.FAN_MODE + ) + assert thermostat.attributes[ATTR_FAN_MODE] == FAN_OFF + assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF] + + async def test_thermostat_invalid_fan_mode( hass: HomeAssistant, setup_platform: PlatformSetup,