From 1fa6972a665052cc5f7c7dbb3d7fc5b32a8209fd Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Tue, 2 Jul 2024 21:02:29 +0200 Subject: [PATCH] Handle mains power for Matter appliances (#121023) --- homeassistant/components/matter/climate.py | 7 +++++++ homeassistant/components/matter/fan.py | 16 +++++++++++++++- tests/components/matter/test_climate.py | 9 +++++++-- tests/components/matter/test_fan.py | 6 ++++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/matter/climate.py b/homeassistant/components/matter/climate.py index 2c05fd3373ee4..192cb6b3bb4d4 100644 --- a/homeassistant/components/matter/climate.py +++ b/homeassistant/components/matter/climate.py @@ -227,6 +227,13 @@ def _update_from_device(self) -> None: self._attr_current_temperature = self._get_temperature_in_degrees( clusters.Thermostat.Attributes.LocalTemperature ) + if self.get_matter_attribute_value(clusters.OnOff.Attributes.OnOff) is False: + # special case: the appliance has a dedicated Power switch on the OnOff cluster + # if the mains power is off - treat it as if the HVAC mode is off + self._attr_hvac_mode = HVACMode.OFF + self._attr_hvac_action = None + return + # update hvac_mode from SystemMode system_mode_value = int( self.get_matter_attribute_value(clusters.Thermostat.Attributes.SystemMode) diff --git a/homeassistant/components/matter/fan.py b/homeassistant/components/matter/fan.py index 0ce42f14d3913..86f03dc7a03fe 100644 --- a/homeassistant/components/matter/fan.py +++ b/homeassistant/components/matter/fan.py @@ -170,6 +170,14 @@ def _update_from_device(self) -> None: """Update from device.""" if not hasattr(self, "_attr_preset_modes"): self._calculate_features() + + if self.get_matter_attribute_value(clusters.OnOff.Attributes.OnOff) is False: + # special case: the appliance has a dedicated Power switch on the OnOff cluster + # if the mains power is off - treat it as if the fan mode is off + self._attr_preset_mode = None + self._attr_percentage = 0 + return + if self._attr_supported_features & FanEntityFeature.DIRECTION: direction_value = self.get_matter_attribute_value( clusters.FanControl.Attributes.AirflowDirection @@ -200,7 +208,13 @@ def _update_from_device(self) -> None: wind_setting = self.get_matter_attribute_value( clusters.FanControl.Attributes.WindSetting ) - if ( + fan_mode = self.get_matter_attribute_value( + clusters.FanControl.Attributes.FanMode + ) + if fan_mode == clusters.FanControl.Enums.FanModeEnum.kOff: + self._attr_preset_mode = None + self._attr_percentage = 0 + elif ( self._attr_preset_modes and PRESET_NATURAL_WIND in self._attr_preset_modes and wind_setting & WindBitmap.kNaturalWind diff --git a/tests/components/matter/test_climate.py b/tests/components/matter/test_climate.py index 6a4cf34a64077..e0015e8b4454c 100644 --- a/tests/components/matter/test_climate.py +++ b/tests/components/matter/test_climate.py @@ -315,14 +315,19 @@ async def test_room_airconditioner( state = hass.states.get("climate.room_airconditioner_thermostat") assert state assert state.attributes["current_temperature"] == 20 - assert state.attributes["min_temp"] == 16 - assert state.attributes["max_temp"] == 32 + # room airconditioner has mains power on OnOff cluster with value set to False + assert state.state == HVACMode.OFF # test supported features correctly parsed # WITHOUT temperature_range support mask = ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TURN_OFF assert state.attributes["supported_features"] & mask == mask + # set mains power to ON (OnOff cluster) + set_node_attribute(room_airconditioner, 1, 6, 0, True) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get("climate.room_airconditioner_thermostat") + # test supported HVAC modes include fan and dry modes assert state.attributes["hvac_modes"] == [ HVACMode.OFF, diff --git a/tests/components/matter/test_fan.py b/tests/components/matter/test_fan.py index 30bd7f4a00967..7e964d672ca3d 100644 --- a/tests/components/matter/test_fan.py +++ b/tests/components/matter/test_fan.py @@ -92,6 +92,12 @@ async def test_fan_base( await trigger_subscription_callback(hass, matter_client) state = hass.states.get(entity_id) assert state.attributes["preset_mode"] == "sleep_wind" + # set mains power to OFF (OnOff cluster) + set_node_attribute(air_purifier, 1, 6, 0, False) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get(entity_id) + assert state.attributes["preset_mode"] is None + assert state.attributes["percentage"] == 0 async def test_fan_turn_on_with_percentage(