diff --git a/homeassistant/components/lyric/climate.py b/homeassistant/components/lyric/climate.py index e798aca5831..dfe88048ba4 100644 --- a/homeassistant/components/lyric/climate.py +++ b/homeassistant/components/lyric/climate.py @@ -1,6 +1,7 @@ """Support for Honeywell Lyric climate platform.""" from __future__ import annotations +import asyncio import logging from time import localtime, strftime, time @@ -22,6 +23,7 @@ from homeassistant.components.climate.const import ( HVAC_MODE_OFF, SUPPORT_PRESET_MODE, SUPPORT_TARGET_TEMPERATURE, + SUPPORT_TARGET_TEMPERATURE_RANGE, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE @@ -45,7 +47,11 @@ from .const import ( _LOGGER = logging.getLogger(__name__) -SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE +# Only LCC models support presets +SUPPORT_FLAGS_LCC = ( + SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE | SUPPORT_TARGET_TEMPERATURE_RANGE +) +SUPPORT_FLAGS_TCC = SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_TEMPERATURE_RANGE LYRIC_HVAC_ACTION_OFF = "EquipmentOff" LYRIC_HVAC_ACTION_HEAT = "Heat" @@ -166,7 +172,11 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity): @property def supported_features(self) -> int: """Return the list of supported features.""" - return SUPPORT_FLAGS + if self.device.changeableValues.thermostatSetpointStatus: + support_flags = SUPPORT_FLAGS_LCC + else: + support_flags = SUPPORT_FLAGS_TCC + return support_flags @property def temperature_unit(self) -> str: @@ -200,25 +210,28 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity): def target_temperature(self) -> float | None: """Return the temperature we try to reach.""" device = self.device - if not device.hasDualSetpointStatus: + if ( + not device.changeableValues.autoChangeoverActive + and HVAC_MODES[device.changeableValues.mode] != HVAC_MODE_OFF + ): if self.hvac_mode == HVAC_MODE_COOL: return device.changeableValues.coolSetpoint return device.changeableValues.heatSetpoint return None @property - def target_temperature_low(self) -> float | None: - """Return the upper bound temperature we try to reach.""" + def target_temperature_high(self) -> float | None: + """Return the highbound target temperature we try to reach.""" device = self.device - if device.hasDualSetpointStatus: + if device.changeableValues.autoChangeoverActive: return device.changeableValues.coolSetpoint return None @property - def target_temperature_high(self) -> float | None: - """Return the upper bound temperature we try to reach.""" + def target_temperature_low(self) -> float | None: + """Return the lowbound target temperature we try to reach.""" device = self.device - if device.hasDualSetpointStatus: + if device.changeableValues.autoChangeoverActive: return device.changeableValues.heatSetpoint return None @@ -256,11 +269,11 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity): async def async_set_temperature(self, **kwargs) -> None: """Set new target temperature.""" + device = self.device target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW) target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) - device = self.device - if device.hasDualSetpointStatus: + if device.changeableValues.autoChangeoverActive: if target_temp_low is None or target_temp_high is None: raise HomeAssistantError( "Could not find target_temp_low and/or target_temp_high in arguments" @@ -270,11 +283,13 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity): await self._update_thermostat( self.location, device, - coolSetpoint=target_temp_low, - heatSetpoint=target_temp_high, + coolSetpoint=target_temp_high, + heatSetpoint=target_temp_low, + mode=HVAC_MODES[device.changeableValues.heatCoolMode], ) except LYRIC_EXCEPTIONS as exception: _LOGGER.error(exception) + await self.coordinator.async_refresh() else: temp = kwargs.get(ATTR_TEMPERATURE) _LOGGER.debug("Set temperature: %s", temp) @@ -289,15 +304,58 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity): ) except LYRIC_EXCEPTIONS as exception: _LOGGER.error(exception) - await self.coordinator.async_refresh() + await self.coordinator.async_refresh() async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set hvac mode.""" - _LOGGER.debug("Set hvac mode: %s", hvac_mode) + _LOGGER.debug("HVAC mode: %s", hvac_mode) try: - await self._update_thermostat( - self.location, self.device, mode=LYRIC_HVAC_MODES[hvac_mode] - ) + if LYRIC_HVAC_MODES[hvac_mode] == LYRIC_HVAC_MODE_HEAT_COOL: + # If the system is off, turn it to Heat first then to Auto, otherwise it turns to + # Auto briefly and then reverts to Off (perhaps related to heatCoolMode). This is the + # behavior that happens with the native app as well, so likely a bug in the api itself + + if HVAC_MODES[self.device.changeableValues.mode] == HVAC_MODE_OFF: + _LOGGER.debug( + "HVAC mode passed to lyric: %s", + HVAC_MODES[LYRIC_HVAC_MODE_COOL], + ) + await self._update_thermostat( + self.location, + self.device, + mode=HVAC_MODES[LYRIC_HVAC_MODE_HEAT], + autoChangeoverActive=False, + ) + # Sleep 3 seconds before proceeding + await asyncio.sleep(3) + _LOGGER.debug( + "HVAC mode passed to lyric: %s", + HVAC_MODES[LYRIC_HVAC_MODE_HEAT], + ) + await self._update_thermostat( + self.location, + self.device, + mode=HVAC_MODES[LYRIC_HVAC_MODE_HEAT], + autoChangeoverActive=True, + ) + else: + _LOGGER.debug( + "HVAC mode passed to lyric: %s", + HVAC_MODES[self.device.changeableValues.mode], + ) + await self._update_thermostat( + self.location, self.device, autoChangeoverActive=True + ) + else: + _LOGGER.debug( + "HVAC mode passed to lyric: %s", LYRIC_HVAC_MODES[hvac_mode] + ) + await self._update_thermostat( + self.location, + self.device, + mode=LYRIC_HVAC_MODES[hvac_mode], + autoChangeoverActive=False, + ) except LYRIC_EXCEPTIONS as exception: _LOGGER.error(exception) await self.coordinator.async_refresh()