From c4340f6f5f76021752db41537ad52752feef4fba Mon Sep 17 00:00:00 2001 From: Gage Benne Date: Wed, 24 Apr 2024 04:16:35 -0400 Subject: [PATCH] Ecobee preset mode icon translations (#116072) --- homeassistant/components/ecobee/climate.py | 72 ++++++++++++---------- tests/components/ecobee/test_climate.py | 2 +- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/homeassistant/components/ecobee/climate.py b/homeassistant/components/ecobee/climate.py index e341f4176ad..11675c0bf61 100644 --- a/homeassistant/components/ecobee/climate.py +++ b/homeassistant/components/ecobee/climate.py @@ -12,7 +12,10 @@ from homeassistant.components.climate import ( ATTR_TARGET_TEMP_LOW, FAN_AUTO, FAN_ON, + PRESET_AWAY, + PRESET_HOME, PRESET_NONE, + PRESET_SLEEP, ClimateEntity, ClimateEntityFeature, HVACAction, @@ -60,9 +63,6 @@ PRESET_TEMPERATURE = "temp" PRESET_VACATION = "vacation" PRESET_HOLD_NEXT_TRANSITION = "next_transition" PRESET_HOLD_INDEFINITE = "indefinite" -AWAY_MODE = "awayMode" -PRESET_HOME = "home" -PRESET_SLEEP = "sleep" HAS_HEAT_PUMP = "hasHeatPump" DEFAULT_MIN_HUMIDITY = 15 @@ -103,6 +103,13 @@ ECOBEE_HVAC_ACTION_TO_HASS = { "compWaterHeater": None, } +ECOBEE_TO_HASS_PRESET = { + "Away": PRESET_AWAY, + "Home": PRESET_HOME, + "Sleep": PRESET_SLEEP, +} +HASS_TO_ECOBEE_PRESET = {v: k for k, v in ECOBEE_TO_HASS_PRESET.items()} + PRESET_TO_ECOBEE_HOLD = { PRESET_HOLD_NEXT_TRANSITION: "nextTransition", PRESET_HOLD_INDEFINITE: "indefinite", @@ -348,10 +355,6 @@ class Thermostat(ClimateEntity): self._attr_hvac_modes.insert(0, HVACMode.HEAT_COOL) self._attr_hvac_modes.append(HVACMode.OFF) - self._preset_modes = { - comfort["climateRef"]: comfort["name"] - for comfort in self.thermostat["program"]["climates"] - } self.update_without_throttle = False async def async_update(self) -> None: @@ -474,7 +477,7 @@ class Thermostat(ClimateEntity): return self.thermostat["runtime"]["desiredFanMode"] @property - def preset_mode(self): + def preset_mode(self) -> str | None: """Return current preset mode.""" events = self.thermostat["events"] for event in events: @@ -487,8 +490,8 @@ class Thermostat(ClimateEntity): ): return PRESET_AWAY_INDEFINITELY - if event["holdClimateRef"] in self._preset_modes: - return self._preset_modes[event["holdClimateRef"]] + if name := self.comfort_settings.get(event["holdClimateRef"]): + return ECOBEE_TO_HASS_PRESET.get(name, name) # Any hold not based on a climate is a temp hold return PRESET_TEMPERATURE @@ -499,7 +502,12 @@ class Thermostat(ClimateEntity): self.vacation = event["name"] return PRESET_VACATION - return self._preset_modes[self.thermostat["program"]["currentClimateRef"]] + if name := self.comfort_settings.get( + self.thermostat["program"]["currentClimateRef"] + ): + return ECOBEE_TO_HASS_PRESET.get(name, name) + + return None @property def hvac_mode(self): @@ -545,14 +553,14 @@ class Thermostat(ClimateEntity): return HVACAction.IDLE @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any] | None: """Return device specific state attributes.""" status = self.thermostat["equipmentStatus"] return { "fan": self.fan, - "climate_mode": self._preset_modes[ + "climate_mode": self.comfort_settings.get( self.thermostat["program"]["currentClimateRef"] - ], + ), "equipment_running": status, "fan_min_on_time": self.settings["fanMinOnTime"], } @@ -577,6 +585,8 @@ class Thermostat(ClimateEntity): def set_preset_mode(self, preset_mode: str) -> None: """Activate a preset.""" + preset_mode = HASS_TO_ECOBEE_PRESET.get(preset_mode, preset_mode) + if preset_mode == self.preset_mode: return @@ -605,25 +615,14 @@ class Thermostat(ClimateEntity): elif preset_mode == PRESET_NONE: self.data.ecobee.resume_program(self.thermostat_index) - elif preset_mode in self.preset_modes: - climate_ref = None - - for comfort in self.thermostat["program"]["climates"]: - if comfort["name"] == preset_mode: - climate_ref = comfort["climateRef"] + else: + for climate_ref, name in self.comfort_settings.items(): + if name == preset_mode: + preset_mode = climate_ref break - - if climate_ref is not None: - self.data.ecobee.set_climate_hold( - self.thermostat_index, - climate_ref, - self.hold_preference(), - self.hold_hours(), - ) else: _LOGGER.warning("Received unknown preset mode: %s", preset_mode) - else: self.data.ecobee.set_climate_hold( self.thermostat_index, preset_mode, @@ -632,11 +631,22 @@ class Thermostat(ClimateEntity): ) @property - def preset_modes(self): + def preset_modes(self) -> list[str] | None: """Return available preset modes.""" # Return presets provided by the ecobee API, and an indefinite away # preset which we handle separately in set_preset_mode(). - return [*self._preset_modes.values(), PRESET_AWAY_INDEFINITELY] + return [ + ECOBEE_TO_HASS_PRESET.get(name, name) + for name in self.comfort_settings.values() + ] + [PRESET_AWAY_INDEFINITELY] + + @property + def comfort_settings(self) -> dict[str, str]: + """Return ecobee API comfort settings.""" + return { + comfort["climateRef"]: comfort["name"] + for comfort in self.thermostat["program"]["climates"] + } def set_auto_temp_hold(self, heat_temp, cool_temp): """Set temperature hold in auto mode.""" diff --git a/tests/components/ecobee/test_climate.py b/tests/components/ecobee/test_climate.py index 7ea9950e2d4..46ca77025cc 100644 --- a/tests/components/ecobee/test_climate.py +++ b/tests/components/ecobee/test_climate.py @@ -441,7 +441,7 @@ async def test_preset_indefinite_away(ecobee_fixture, thermostat) -> None: """Test indefinite away showing correctly, and not as temporary away.""" ecobee_fixture["program"]["currentClimateRef"] = "away" ecobee_fixture["events"][0]["holdClimateRef"] = "away" - assert thermostat.preset_mode == "Away" + assert thermostat.preset_mode == "away" ecobee_fixture["events"][0]["endDate"] = "2999-01-01" assert thermostat.preset_mode == PRESET_AWAY_INDEFINITELY