Use climate enums in nest (#70723)

This commit is contained in:
epenet 2022-04-26 09:19:02 +02:00 committed by GitHub
parent 7cbe56dcdf
commit 76dd82f8e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 71 deletions

View File

@ -14,25 +14,18 @@ from google_nest_sdm.thermostat_traits import (
ThermostatTemperatureSetpointTrait, ThermostatTemperatureSetpointTrait,
) )
from homeassistant.components.climate import ClimateEntity, ClimateEntityFeature from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import ( from homeassistant.components.climate.const import (
ATTR_HVAC_MODE, ATTR_HVAC_MODE,
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_COOL,
CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE,
CURRENT_HVAC_OFF,
FAN_OFF, FAN_OFF,
FAN_ON, FAN_ON,
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL,
HVAC_MODE_OFF,
PRESET_ECO, PRESET_ECO,
PRESET_NONE, PRESET_NONE,
ClimateEntityFeature,
HVACAction,
HVACMode,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
@ -45,11 +38,11 @@ from .const import DATA_SUBSCRIBER, DOMAIN
from .device_info import NestDeviceInfo from .device_info import NestDeviceInfo
# Mapping for sdm.devices.traits.ThermostatMode mode field # Mapping for sdm.devices.traits.ThermostatMode mode field
THERMOSTAT_MODE_MAP: dict[str, str] = { THERMOSTAT_MODE_MAP: dict[str, HVACMode] = {
"OFF": HVAC_MODE_OFF, "OFF": HVACMode.OFF,
"HEAT": HVAC_MODE_HEAT, "HEAT": HVACMode.HEAT,
"COOL": HVAC_MODE_COOL, "COOL": HVACMode.COOL,
"HEATCOOL": HVAC_MODE_HEAT_COOL, "HEATCOOL": HVACMode.HEAT_COOL,
} }
THERMOSTAT_INV_MODE_MAP = {v: k for k, v in THERMOSTAT_MODE_MAP.items()} THERMOSTAT_INV_MODE_MAP = {v: k for k, v in THERMOSTAT_MODE_MAP.items()}
@ -58,12 +51,12 @@ THERMOSTAT_ECO_MODE = "MANUAL_ECO"
# Mapping for sdm.devices.traits.ThermostatHvac status field # Mapping for sdm.devices.traits.ThermostatHvac status field
THERMOSTAT_HVAC_STATUS_MAP = { THERMOSTAT_HVAC_STATUS_MAP = {
"OFF": CURRENT_HVAC_OFF, "OFF": HVACAction.OFF,
"HEATING": CURRENT_HVAC_HEAT, "HEATING": HVACAction.HEATING,
"COOLING": CURRENT_HVAC_COOL, "COOLING": HVACAction.COOLING,
} }
THERMOSTAT_RANGE_MODES = [HVAC_MODE_HEAT_COOL, HVAC_MODE_AUTO] THERMOSTAT_RANGE_MODES = [HVACMode.HEAT_COOL, HVACMode.AUTO]
PRESET_MODE_MAP = { PRESET_MODE_MAP = {
"MANUAL_ECO": PRESET_ECO, "MANUAL_ECO": PRESET_ECO,
@ -153,16 +146,16 @@ class ThermostatEntity(ClimateEntity):
"""Return the temperature currently set to be reached.""" """Return the temperature currently set to be reached."""
if not (trait := self._target_temperature_trait): if not (trait := self._target_temperature_trait):
return None return None
if self.hvac_mode == HVAC_MODE_HEAT: if self.hvac_mode == HVACMode.HEAT:
return trait.heat_celsius return trait.heat_celsius
if self.hvac_mode == HVAC_MODE_COOL: if self.hvac_mode == HVACMode.COOL:
return trait.cool_celsius return trait.cool_celsius
return None return None
@property @property
def target_temperature_high(self) -> float | None: def target_temperature_high(self) -> float | None:
"""Return the upper bound target temperature.""" """Return the upper bound target temperature."""
if self.hvac_mode != HVAC_MODE_HEAT_COOL: if self.hvac_mode != HVACMode.HEAT_COOL:
return None return None
if not (trait := self._target_temperature_trait): if not (trait := self._target_temperature_trait):
return None return None
@ -171,7 +164,7 @@ class ThermostatEntity(ClimateEntity):
@property @property
def target_temperature_low(self) -> float | None: def target_temperature_low(self) -> float | None:
"""Return the lower bound target temperature.""" """Return the lower bound target temperature."""
if self.hvac_mode != HVAC_MODE_HEAT_COOL: if self.hvac_mode != HVACMode.HEAT_COOL:
return None return None
if not (trait := self._target_temperature_trait): if not (trait := self._target_temperature_trait):
return None return None
@ -197,26 +190,26 @@ class ThermostatEntity(ClimateEntity):
return None return None
@property @property
def hvac_mode(self) -> str: def hvac_mode(self) -> HVACMode:
"""Return the current operation (e.g. heat, cool, idle).""" """Return the current operation (e.g. heat, cool, idle)."""
hvac_mode = HVAC_MODE_OFF hvac_mode = HVACMode.OFF
if ThermostatModeTrait.NAME in self._device.traits: if ThermostatModeTrait.NAME in self._device.traits:
trait = self._device.traits[ThermostatModeTrait.NAME] trait = self._device.traits[ThermostatModeTrait.NAME]
if trait.mode in THERMOSTAT_MODE_MAP: if trait.mode in THERMOSTAT_MODE_MAP:
hvac_mode = THERMOSTAT_MODE_MAP[trait.mode] hvac_mode = THERMOSTAT_MODE_MAP[trait.mode]
if hvac_mode == HVAC_MODE_OFF and self.fan_mode == FAN_ON: if hvac_mode == HVACMode.OFF and self.fan_mode == FAN_ON:
hvac_mode = HVAC_MODE_FAN_ONLY hvac_mode = HVACMode.FAN_ONLY
return hvac_mode return hvac_mode
@property @property
def hvac_modes(self) -> list[str]: def hvac_modes(self) -> list[HVACMode]:
"""List of available operation modes.""" """List of available operation modes."""
supported_modes = [] supported_modes = []
for mode in self._get_device_hvac_modes: for mode in self._get_device_hvac_modes:
if mode in THERMOSTAT_MODE_MAP: if mode in THERMOSTAT_MODE_MAP:
supported_modes.append(THERMOSTAT_MODE_MAP[mode]) supported_modes.append(THERMOSTAT_MODE_MAP[mode])
if self.supported_features & ClimateEntityFeature.FAN_MODE: if self.supported_features & ClimateEntityFeature.FAN_MODE:
supported_modes.append(HVAC_MODE_FAN_ONLY) supported_modes.append(HVACMode.FAN_ONLY)
return supported_modes return supported_modes
@property @property
@ -229,14 +222,12 @@ class ThermostatEntity(ClimateEntity):
return set(modes) return set(modes)
@property @property
def hvac_action(self) -> str | None: def hvac_action(self) -> HVACAction | None:
"""Return the current HVAC action (heating, cooling).""" """Return the current HVAC action (heating, cooling)."""
trait = self._device.traits[ThermostatHvacTrait.NAME] trait = self._device.traits[ThermostatHvacTrait.NAME]
if trait.status == "OFF" and self.hvac_mode != HVAC_MODE_OFF: if trait.status == "OFF" and self.hvac_mode != HVACMode.OFF:
return CURRENT_HVAC_IDLE return HVACAction.IDLE
if trait.status in THERMOSTAT_HVAC_STATUS_MAP: return THERMOSTAT_HVAC_STATUS_MAP.get(trait.status)
return THERMOSTAT_HVAC_STATUS_MAP[trait.status]
return None
@property @property
def preset_mode(self) -> str: def preset_mode(self) -> str:
@ -281,9 +272,9 @@ class ThermostatEntity(ClimateEntity):
def _get_supported_features(self) -> int: def _get_supported_features(self) -> int:
"""Compute the bitmap of supported features from the current state.""" """Compute the bitmap of supported features from the current state."""
features = 0 features = 0
if HVAC_MODE_HEAT_COOL in self.hvac_modes: if HVACMode.HEAT_COOL in self.hvac_modes:
features |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE features |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
if HVAC_MODE_HEAT in self.hvac_modes or HVAC_MODE_COOL in self.hvac_modes: if HVACMode.HEAT in self.hvac_modes or HVACMode.COOL in self.hvac_modes:
features |= ClimateEntityFeature.TARGET_TEMPERATURE features |= ClimateEntityFeature.TARGET_TEMPERATURE
if ThermostatEcoTrait.NAME in self._device.traits: if ThermostatEcoTrait.NAME in self._device.traits:
features |= ClimateEntityFeature.PRESET_MODE features |= ClimateEntityFeature.PRESET_MODE
@ -294,14 +285,14 @@ class ThermostatEntity(ClimateEntity):
features |= ClimateEntityFeature.FAN_MODE features |= ClimateEntityFeature.FAN_MODE
return features return features
async def async_set_hvac_mode(self, hvac_mode: str) -> None: async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode.""" """Set new target hvac mode."""
if hvac_mode not in self.hvac_modes: if hvac_mode not in self.hvac_modes:
raise ValueError(f"Unsupported hvac_mode '{hvac_mode}'") raise ValueError(f"Unsupported hvac_mode '{hvac_mode}'")
if hvac_mode == HVAC_MODE_FAN_ONLY: if hvac_mode == HVACMode.FAN_ONLY:
# Turn the fan on but also turn off the hvac if it is on # Turn the fan on but also turn off the hvac if it is on
await self.async_set_fan_mode(FAN_ON) await self.async_set_fan_mode(FAN_ON)
hvac_mode = HVAC_MODE_OFF hvac_mode = HVACMode.OFF
api_mode = THERMOSTAT_INV_MODE_MAP[hvac_mode] api_mode = THERMOSTAT_INV_MODE_MAP[hvac_mode]
trait = self._device.traits[ThermostatModeTrait.NAME] trait = self._device.traits[ThermostatModeTrait.NAME]
await trait.set_mode(api_mode) await trait.set_mode(api_mode)
@ -318,12 +309,12 @@ class ThermostatEntity(ClimateEntity):
if ThermostatTemperatureSetpointTrait.NAME not in self._device.traits: if ThermostatTemperatureSetpointTrait.NAME not in self._device.traits:
return return
trait = self._device.traits[ThermostatTemperatureSetpointTrait.NAME] trait = self._device.traits[ThermostatTemperatureSetpointTrait.NAME]
if self.preset_mode == PRESET_ECO or hvac_mode == HVAC_MODE_HEAT_COOL: if self.preset_mode == PRESET_ECO or hvac_mode == HVACMode.HEAT_COOL:
if low_temp and high_temp: if low_temp and high_temp:
await trait.set_range(low_temp, high_temp) await trait.set_range(low_temp, high_temp)
elif hvac_mode == HVAC_MODE_COOL and temp: elif hvac_mode == HVACMode.COOL and temp:
await trait.set_cool(temp) await trait.set_cool(temp)
elif hvac_mode == HVAC_MODE_HEAT and temp: elif hvac_mode == HVACMode.HEAT and temp:
await trait.set_heat(temp) await trait.set_heat(temp)
async def async_set_preset_mode(self, preset_mode: str) -> None: async def async_set_preset_mode(self, preset_mode: str) -> None:

View File

@ -6,26 +6,18 @@ import logging
from nest.nest import APIError from nest.nest import APIError
import voluptuous as vol import voluptuous as vol
from homeassistant.components.climate import ( from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity
PLATFORM_SCHEMA,
ClimateEntity,
ClimateEntityFeature,
)
from homeassistant.components.climate.const import ( from homeassistant.components.climate.const import (
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_LOW,
CURRENT_HVAC_COOL,
CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE,
FAN_AUTO, FAN_AUTO,
FAN_ON, FAN_ON,
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_HEAT,
HVAC_MODE_OFF,
PRESET_AWAY, PRESET_AWAY,
PRESET_ECO, PRESET_ECO,
PRESET_NONE, PRESET_NONE,
ClimateEntityFeature,
HVACAction,
HVACMode,
) )
from homeassistant.const import ( from homeassistant.const import (
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
@ -51,18 +43,18 @@ NEST_MODE_COOL = "cool"
NEST_MODE_OFF = "off" NEST_MODE_OFF = "off"
MODE_HASS_TO_NEST = { MODE_HASS_TO_NEST = {
HVAC_MODE_AUTO: NEST_MODE_HEAT_COOL, HVACMode.AUTO: NEST_MODE_HEAT_COOL,
HVAC_MODE_HEAT: NEST_MODE_HEAT, HVACMode.HEAT: NEST_MODE_HEAT,
HVAC_MODE_COOL: NEST_MODE_COOL, HVACMode.COOL: NEST_MODE_COOL,
HVAC_MODE_OFF: NEST_MODE_OFF, HVACMode.OFF: NEST_MODE_OFF,
} }
MODE_NEST_TO_HASS = {v: k for k, v in MODE_HASS_TO_NEST.items()} MODE_NEST_TO_HASS = {v: k for k, v in MODE_HASS_TO_NEST.items()}
ACTION_NEST_TO_HASS = { ACTION_NEST_TO_HASS = {
"off": CURRENT_HVAC_IDLE, "off": HVACAction.IDLE,
"heating": CURRENT_HVAC_HEAT, "heating": HVACAction.HEATING,
"cooling": CURRENT_HVAC_COOL, "cooling": HVACAction.COOLING,
} }
PRESET_AWAY_AND_ECO = "Away and Eco" PRESET_AWAY_AND_ECO = "Away and Eco"
@ -110,17 +102,17 @@ class NestThermostat(ClimateEntity):
self._operation_list = [] self._operation_list = []
if self.device.can_heat and self.device.can_cool: if self.device.can_heat and self.device.can_cool:
self._operation_list.append(HVAC_MODE_AUTO) self._operation_list.append(HVACMode.AUTO)
self._support_flags |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE self._support_flags |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
# Add supported nest thermostat features # Add supported nest thermostat features
if self.device.can_heat: if self.device.can_heat:
self._operation_list.append(HVAC_MODE_HEAT) self._operation_list.append(HVACMode.HEAT)
if self.device.can_cool: if self.device.can_cool:
self._operation_list.append(HVAC_MODE_COOL) self._operation_list.append(HVACMode.COOL)
self._operation_list.append(HVAC_MODE_OFF) self._operation_list.append(HVACMode.OFF)
# feature of device # feature of device
self._has_fan = self.device.has_fan self._has_fan = self.device.has_fan
@ -197,7 +189,7 @@ class NestThermostat(ClimateEntity):
return self._temperature return self._temperature
@property @property
def hvac_mode(self): def hvac_mode(self) -> HVACMode:
"""Return current operation ie. heat, cool, idle.""" """Return current operation ie. heat, cool, idle."""
if self._mode == NEST_MODE_ECO: if self._mode == NEST_MODE_ECO:
if self.device.previous_mode in MODE_NEST_TO_HASS: if self.device.previous_mode in MODE_NEST_TO_HASS:
@ -209,7 +201,7 @@ class NestThermostat(ClimateEntity):
return MODE_NEST_TO_HASS[self._mode] return MODE_NEST_TO_HASS[self._mode]
@property @property
def hvac_action(self): def hvac_action(self) -> HVACAction:
"""Return the current hvac action.""" """Return the current hvac action."""
return ACTION_NEST_TO_HASS[self._action] return ACTION_NEST_TO_HASS[self._action]
@ -259,12 +251,12 @@ class NestThermostat(ClimateEntity):
# restore target temperature # restore target temperature
self.schedule_update_ha_state(True) self.schedule_update_ha_state(True)
def set_hvac_mode(self, hvac_mode): def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set operation mode.""" """Set operation mode."""
self.device.mode = MODE_HASS_TO_NEST[hvac_mode] self.device.mode = MODE_HASS_TO_NEST[hvac_mode]
@property @property
def hvac_modes(self): def hvac_modes(self) -> list[HVACMode]:
"""List of available operation modes.""" """List of available operation modes."""
return self._operation_list return self._operation_list