diff --git a/homeassistant/components/honeywell/climate.py b/homeassistant/components/honeywell/climate.py index 934d41b238e..98cbae4eb7e 100644 --- a/homeassistant/components/honeywell/climate.py +++ b/homeassistant/components/honeywell/climate.py @@ -49,6 +49,10 @@ from .const import ( RETRY, ) +MODE_PERMANENT_HOLD = 2 +MODE_TEMPORARY_HOLD = 1 +MODE_HOLD = {MODE_PERMANENT_HOLD, MODE_TEMPORARY_HOLD} + ATTR_FAN_ACTION = "fan_action" ATTR_PERMANENT_HOLD = "permanent_hold" @@ -175,6 +179,7 @@ class HoneywellUSThermostat(ClimateEntity): self._cool_away_temp = cool_away_temp self._heat_away_temp = heat_away_temp self._away = False + self._away_hold = False self._retry = 0 self._attr_unique_id = str(device.deviceid) @@ -323,11 +328,15 @@ class HoneywellUSThermostat(ClimateEntity): @property def preset_mode(self) -> str | None: """Return the current preset mode, e.g., home, away, temp.""" - if self._away: + if self._away and self._is_hold(): + self._away_hold = True return PRESET_AWAY - if self._is_permanent_hold(): + if self._is_hold(): return PRESET_HOLD - + # Someone has changed the stat manually out of hold in away mode + if self._away and self._away_hold: + self._away = False + self._away_hold = False return PRESET_NONE @property @@ -335,10 +344,15 @@ class HoneywellUSThermostat(ClimateEntity): """Return the fan setting.""" return HW_FAN_MODE_TO_HA.get(self._device.fan_mode) + def _is_hold(self) -> bool: + heat_status = self._device.raw_ui_data.get("StatusHeat", 0) + cool_status = self._device.raw_ui_data.get("StatusCool", 0) + return heat_status in MODE_HOLD or cool_status in MODE_HOLD + def _is_permanent_hold(self) -> bool: heat_status = self._device.raw_ui_data.get("StatusHeat", 0) cool_status = self._device.raw_ui_data.get("StatusCool", 0) - return heat_status == 2 or cool_status == 2 + return MODE_PERMANENT_HOLD in (heat_status, cool_status) async def _set_temperature(self, **kwargs) -> None: """Set new target temperature.""" diff --git a/tests/components/honeywell/test_climate.py b/tests/components/honeywell/test_climate.py index 9485f2f4302..73c5ff33dbc 100644 --- a/tests/components/honeywell/test_climate.py +++ b/tests/components/honeywell/test_climate.py @@ -5,6 +5,7 @@ from unittest.mock import MagicMock from aiohttp import ClientConnectionError import aiosomecomfort +from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion from syrupy.filters import props @@ -29,6 +30,8 @@ from homeassistant.components.climate import ( ) from homeassistant.components.honeywell.climate import ( DOMAIN, + MODE_PERMANENT_HOLD, + MODE_TEMPORARY_HOLD, PRESET_HOLD, RETRY, SCAN_INTERVAL, @@ -1207,3 +1210,59 @@ async def test_unique_id( await init_integration(hass, config_entry) entity_entry = entity_registry.async_get(f"climate.{device.name}") assert entity_entry.unique_id == str(device.deviceid) + + +async def test_preset_mode( + hass: HomeAssistant, + device: MagicMock, + config_entry: er.EntityRegistry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test mode settings properly reflected.""" + await init_integration(hass, config_entry) + entity_id = f"climate.{device.name}" + + device.raw_ui_data["StatusHeat"] = 3 + device.raw_ui_data["StatusCool"] = 3 + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE + + device.raw_ui_data["StatusHeat"] = MODE_TEMPORARY_HOLD + device.raw_ui_data["StatusCool"] = MODE_TEMPORARY_HOLD + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes[ATTR_PRESET_MODE] == PRESET_HOLD + + device.raw_ui_data["StatusHeat"] = MODE_PERMANENT_HOLD + device.raw_ui_data["StatusCool"] = MODE_PERMANENT_HOLD + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes[ATTR_PRESET_MODE] == PRESET_HOLD + + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_PRESET_MODE, + {ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: PRESET_AWAY}, + blocking=True, + ) + + state = hass.states.get(entity_id) + assert state.attributes[ATTR_PRESET_MODE] == PRESET_AWAY + + device.raw_ui_data["StatusHeat"] = 3 + device.raw_ui_data["StatusCool"] = 3 + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE