diff --git a/homeassistant/components/actron_air/climate.py b/homeassistant/components/actron_air/climate.py index efa75212773..8d2e6811594 100644 --- a/homeassistant/components/actron_air/climate.py +++ b/homeassistant/components/actron_air/climate.py @@ -38,6 +38,7 @@ HVAC_MODE_MAPPING_ACTRONAIR_TO_HA = { "HEAT": HVACMode.HEAT, "FAN": HVACMode.FAN_ONLY, "AUTO": HVACMode.AUTO, + "DRY": HVACMode.DRY, "OFF": HVACMode.OFF, } HVAC_MODE_MAPPING_HA_TO_ACTRONAIR = { @@ -79,7 +80,6 @@ class ActronAirClimateEntity(ClimateEntity): ) _attr_name = None _attr_fan_modes = list(FAN_MODE_MAPPING_ACTRONAIR_TO_HA.values()) - _attr_hvac_modes = list(HVAC_MODE_MAPPING_ACTRONAIR_TO_HA.values()) class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity): @@ -93,6 +93,17 @@ class ActronSystemClimate(ActronAirAcEntity, ActronAirClimateEntity): super().__init__(coordinator) self._attr_unique_id = self._serial_number + @property + def hvac_modes(self) -> list[HVACMode]: + """Return the list of supported HVAC modes.""" + modes = [ + HVAC_MODE_MAPPING_ACTRONAIR_TO_HA[mode] + for mode in self._status.user_aircon_settings.supported_modes + if mode in HVAC_MODE_MAPPING_ACTRONAIR_TO_HA + ] + modes.append(HVACMode.OFF) + return modes + @property def min_temp(self) -> float: """Return the minimum temperature that can be set.""" @@ -179,6 +190,18 @@ class ActronZoneClimate(ActronAirZoneEntity, ActronAirClimateEntity): super().__init__(coordinator, zone) self._attr_unique_id: str = self._zone_identifier + @property + def hvac_modes(self) -> list[HVACMode]: + """Return the list of supported HVAC modes.""" + status = self.coordinator.data + modes = [ + HVAC_MODE_MAPPING_ACTRONAIR_TO_HA[mode] + for mode in status.user_aircon_settings.supported_modes + if mode in HVAC_MODE_MAPPING_ACTRONAIR_TO_HA + ] + modes.append(HVACMode.OFF) + return modes + @property def min_temp(self) -> float: """Return the minimum temperature that can be set.""" diff --git a/tests/components/actron_air/test_climate.py b/tests/components/actron_air/test_climate.py index 292513e03bd..5ac2b84c12d 100644 --- a/tests/components/actron_air/test_climate.py +++ b/tests/components/actron_air/test_climate.py @@ -3,6 +3,7 @@ from unittest.mock import MagicMock, patch from actron_neo_api import ActronAirAPIError +from actron_neo_api.models.settings import ActronAirModeSupport import pytest from syrupy.assertion import SnapshotAssertion @@ -362,3 +363,122 @@ async def test_zone_hvac_mode_inactive( state = hass.states.get("climate.living_room") assert state.state == "off" + + +async def test_system_hvac_modes_default( + hass: HomeAssistant, + mock_actron_api: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test system reports correct HVAC modes when DRY is not supported.""" + with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]): + await setup_integration(hass, mock_config_entry) + + state = hass.states.get("climate.test_system") + assert state.attributes["hvac_modes"] == [ + HVACMode.COOL, + HVACMode.HEAT, + HVACMode.FAN_ONLY, + HVACMode.AUTO, + HVACMode.OFF, + ] + + +async def test_system_hvac_modes_with_dry( + hass: HomeAssistant, + mock_actron_api: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test system reports DRY HVAC mode when hardware supports it.""" + + status = mock_actron_api.state_manager.get_status.return_value + status.user_aircon_settings.mode_support = ActronAirModeSupport( + Cool=True, Heat=True, Fan=True, Auto=True, Dry=True + ) + + with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]): + await setup_integration(hass, mock_config_entry) + + state = hass.states.get("climate.test_system") + assert state.attributes["hvac_modes"] == [ + HVACMode.COOL, + HVACMode.HEAT, + HVACMode.FAN_ONLY, + HVACMode.AUTO, + HVACMode.DRY, + HVACMode.OFF, + ] + + +async def test_system_hvac_modes_no_mode_support( + hass: HomeAssistant, + mock_actron_api: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test system falls back to default modes when ModeSupport is absent.""" + status = mock_actron_api.state_manager.get_status.return_value + status.user_aircon_settings.mode_support = None + + with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]): + await setup_integration(hass, mock_config_entry) + + state = hass.states.get("climate.test_system") + assert state.attributes["hvac_modes"] == [ + HVACMode.COOL, + HVACMode.HEAT, + HVACMode.FAN_ONLY, + HVACMode.AUTO, + HVACMode.OFF, + ] + + +async def test_zone_hvac_modes_with_dry( + hass: HomeAssistant, + mock_actron_api: MagicMock, + mock_config_entry: MockConfigEntry, + mock_zone: MagicMock, +) -> None: + """Test zone reports DRY HVAC mode when hardware supports it.""" + + status = mock_actron_api.state_manager.get_status.return_value + status.user_aircon_settings.mode_support = ActronAirModeSupport( + Cool=True, Heat=True, Fan=True, Auto=True, Dry=True + ) + status.remote_zone_info = [mock_zone] + + with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]): + await setup_integration(hass, mock_config_entry) + + state = hass.states.get("climate.living_room") + assert state.attributes["hvac_modes"] == [ + HVACMode.COOL, + HVACMode.HEAT, + HVACMode.FAN_ONLY, + HVACMode.AUTO, + HVACMode.DRY, + HVACMode.OFF, + ] + + +async def test_zone_hvac_modes_no_mode_support( + hass: HomeAssistant, + mock_actron_api: MagicMock, + mock_config_entry: MockConfigEntry, + mock_zone: MagicMock, +) -> None: + """Test zone falls back to default modes when ModeSupport is absent.""" + status = mock_actron_api.state_manager.get_status.return_value + status.user_aircon_settings.mode_support = None + status.remote_zone_info = [mock_zone] + + with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]): + await setup_integration(hass, mock_config_entry) + + state = hass.states.get("climate.living_room") + assert state.attributes["hvac_modes"] == [ + HVACMode.COOL, + HVACMode.HEAT, + HVACMode.FAN_ONLY, + HVACMode.AUTO, + HVACMode.OFF, + ]