Handle unknown preset mode in generic thermostat (#55588)

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
pull/55750/head
Brian Egge 2021-09-04 16:17:57 -04:00 committed by GitHub
parent f5a543b220
commit c81a319346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 17 deletions

View File

@ -182,14 +182,17 @@ class GenericThermostat(ClimateEntity, RestoreEntity):
self._temp_lock = asyncio.Lock()
self._min_temp = min_temp
self._max_temp = max_temp
self._attr_preset_mode = PRESET_NONE
self._target_temp = target_temp
self._unit = unit
self._unique_id = unique_id
self._support_flags = SUPPORT_FLAGS
if away_temp:
self._support_flags = SUPPORT_FLAGS | SUPPORT_PRESET_MODE
self._attr_preset_modes = [PRESET_NONE, PRESET_AWAY]
else:
self._attr_preset_modes = [PRESET_NONE]
self._away_temp = away_temp
self._is_away = False
async def async_added_to_hass(self):
"""Run when entity about to be added."""
@ -247,8 +250,8 @@ class GenericThermostat(ClimateEntity, RestoreEntity):
)
else:
self._target_temp = float(old_state.attributes[ATTR_TEMPERATURE])
if old_state.attributes.get(ATTR_PRESET_MODE) == PRESET_AWAY:
self._is_away = True
if old_state.attributes.get(ATTR_PRESET_MODE) in self._attr_preset_modes:
self._attr_preset_mode = old_state.attributes.get(ATTR_PRESET_MODE)
if not self._hvac_mode and old_state.state:
self._hvac_mode = old_state.state
@ -343,16 +346,6 @@ class GenericThermostat(ClimateEntity, RestoreEntity):
"""List of available operation modes."""
return self._hvac_list
@property
def preset_mode(self):
"""Return the current preset mode, e.g., home, away, temp."""
return PRESET_AWAY if self._is_away else PRESET_NONE
@property
def preset_modes(self):
"""Return a list of available preset modes or PRESET_NONE if _away_temp is undefined."""
return [PRESET_NONE, PRESET_AWAY] if self._away_temp else PRESET_NONE
async def async_set_hvac_mode(self, hvac_mode):
"""Set hvac mode."""
if hvac_mode == HVAC_MODE_HEAT:
@ -521,13 +514,20 @@ class GenericThermostat(ClimateEntity, RestoreEntity):
async def async_set_preset_mode(self, preset_mode: str):
"""Set new preset mode."""
if preset_mode == PRESET_AWAY and not self._is_away:
self._is_away = True
if preset_mode not in (self._attr_preset_modes or []):
raise ValueError(
f"Got unsupported preset_mode {preset_mode}. Must be one of {self._attr_preset_modes}"
)
if preset_mode == self._attr_preset_mode:
# I don't think we need to call async_write_ha_state if we didn't change the state
return
if preset_mode == PRESET_AWAY:
self._attr_preset_mode = PRESET_AWAY
self._saved_target_temp = self._target_temp
self._target_temp = self._away_temp
await self._async_control_heating(force=True)
elif preset_mode == PRESET_NONE and self._is_away:
self._is_away = False
elif preset_mode == PRESET_NONE:
self._attr_preset_mode = PRESET_NONE
self._target_temp = self._saved_target_temp
await self._async_control_heating(force=True)

View File

@ -324,6 +324,21 @@ async def test_set_away_mode_twice_and_restore_prev_temp(hass, setup_comp_2):
assert state.attributes.get("temperature") == 23
async def test_set_preset_mode_invalid(hass, setup_comp_2):
"""Test an invalid mode raises an error and ignore case when checking modes."""
await common.async_set_temperature(hass, 23)
await common.async_set_preset_mode(hass, "away")
state = hass.states.get(ENTITY)
assert state.attributes.get("preset_mode") == "away"
await common.async_set_preset_mode(hass, "none")
state = hass.states.get(ENTITY)
assert state.attributes.get("preset_mode") == "none"
with pytest.raises(ValueError):
await common.async_set_preset_mode(hass, "Sleep")
state = hass.states.get(ENTITY)
assert state.attributes.get("preset_mode") == "none"
async def test_sensor_bad_value(hass, setup_comp_2):
"""Test sensor that have None as state."""
state = hass.states.get(ENTITY)