From 8fc55b71c5153580508446d478adfb450c76ea41 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 1 Apr 2022 18:41:49 +0200 Subject: [PATCH] Add EntityFeature enum to Climate (#69077) --- homeassistant/components/climate/__init__.py | 58 ++++++++++--------- homeassistant/components/climate/const.py | 17 ++++++ homeassistant/components/demo/climate.py | 28 ++++----- .../components/climate/test_device_action.py | 14 ++++- .../climate/test_device_condition.py | 14 ++++- 5 files changed, 86 insertions(+), 45 deletions(-) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index b076e0db01a..91b4db1fc33 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -33,7 +33,7 @@ from homeassistant.helpers.temperature import display_temp as show_temp from homeassistant.helpers.typing import ConfigType from homeassistant.util.temperature import convert as convert_temperature -from .const import ( +from .const import ( # noqa: F401 ATTR_AUX_HEAT, ATTR_CURRENT_HUMIDITY, ATTR_CURRENT_TEMPERATURE, @@ -74,6 +74,7 @@ from .const import ( SUPPORT_TARGET_HUMIDITY, SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE_RANGE, + ClimateEntityFeature, ) DEFAULT_MIN_TEMP = 7 @@ -122,37 +123,40 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: SERVICE_SET_PRESET_MODE, {vol.Required(ATTR_PRESET_MODE): cv.string}, "async_set_preset_mode", - [SUPPORT_PRESET_MODE], + [ClimateEntityFeature.PRESET_MODE], ) component.async_register_entity_service( SERVICE_SET_AUX_HEAT, {vol.Required(ATTR_AUX_HEAT): cv.boolean}, async_service_aux_heat, - [SUPPORT_AUX_HEAT], + [ClimateEntityFeature.AUX_HEAT], ) component.async_register_entity_service( SERVICE_SET_TEMPERATURE, SET_TEMPERATURE_SCHEMA, async_service_temperature_set, - [SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE_RANGE], + [ + ClimateEntityFeature.TARGET_TEMPERATURE, + ClimateEntityFeature.TARGET_TEMPERATURE_RANGE, + ], ) component.async_register_entity_service( SERVICE_SET_HUMIDITY, {vol.Required(ATTR_HUMIDITY): vol.Coerce(int)}, "async_set_humidity", - [SUPPORT_TARGET_HUMIDITY], + [ClimateEntityFeature.TARGET_HUMIDITY], ) component.async_register_entity_service( SERVICE_SET_FAN_MODE, {vol.Required(ATTR_FAN_MODE): cv.string}, "async_set_fan_mode", - [SUPPORT_FAN_MODE], + [ClimateEntityFeature.FAN_MODE], ) component.async_register_entity_service( SERVICE_SET_SWING_MODE, {vol.Required(ATTR_SWING_MODE): cv.string}, "async_set_swing_mode", - [SUPPORT_SWING_MODE], + [ClimateEntityFeature.SWING_MODE], ) return True @@ -235,17 +239,17 @@ class ClimateEntity(Entity): if self.target_temperature_step: data[ATTR_TARGET_TEMP_STEP] = self.target_temperature_step - if supported_features & SUPPORT_TARGET_HUMIDITY: + if supported_features & ClimateEntityFeature.TARGET_HUMIDITY: data[ATTR_MIN_HUMIDITY] = self.min_humidity data[ATTR_MAX_HUMIDITY] = self.max_humidity - if supported_features & SUPPORT_FAN_MODE: + if supported_features & ClimateEntityFeature.FAN_MODE: data[ATTR_FAN_MODES] = self.fan_modes - if supported_features & SUPPORT_PRESET_MODE: + if supported_features & ClimateEntityFeature.PRESET_MODE: data[ATTR_PRESET_MODES] = self.preset_modes - if supported_features & SUPPORT_SWING_MODE: + if supported_features & ClimateEntityFeature.SWING_MODE: data[ATTR_SWING_MODES] = self.swing_modes return data @@ -264,7 +268,7 @@ class ClimateEntity(Entity): ), } - if supported_features & SUPPORT_TARGET_TEMPERATURE: + if supported_features & ClimateEntityFeature.TARGET_TEMPERATURE: data[ATTR_TEMPERATURE] = show_temp( self.hass, self.target_temperature, @@ -272,7 +276,7 @@ class ClimateEntity(Entity): self.precision, ) - if supported_features & SUPPORT_TARGET_TEMPERATURE_RANGE: + if supported_features & ClimateEntityFeature.TARGET_TEMPERATURE_RANGE: data[ATTR_TARGET_TEMP_HIGH] = show_temp( self.hass, self.target_temperature_high, @@ -289,22 +293,22 @@ class ClimateEntity(Entity): if self.current_humidity is not None: data[ATTR_CURRENT_HUMIDITY] = self.current_humidity - if supported_features & SUPPORT_TARGET_HUMIDITY: + if supported_features & ClimateEntityFeature.TARGET_HUMIDITY: data[ATTR_HUMIDITY] = self.target_humidity - if supported_features & SUPPORT_FAN_MODE: + if supported_features & ClimateEntityFeature.FAN_MODE: data[ATTR_FAN_MODE] = self.fan_mode if self.hvac_action: data[ATTR_HVAC_ACTION] = self.hvac_action - if supported_features & SUPPORT_PRESET_MODE: + if supported_features & ClimateEntityFeature.PRESET_MODE: data[ATTR_PRESET_MODE] = self.preset_mode - if supported_features & SUPPORT_SWING_MODE: + if supported_features & ClimateEntityFeature.SWING_MODE: data[ATTR_SWING_MODE] = self.swing_mode - if supported_features & SUPPORT_AUX_HEAT: + if supported_features & ClimateEntityFeature.AUX_HEAT: data[ATTR_AUX_HEAT] = STATE_ON if self.is_aux_heat else STATE_OFF return data @@ -367,7 +371,7 @@ class ClimateEntity(Entity): def target_temperature_high(self) -> float | None: """Return the highbound target temperature we try to reach. - Requires SUPPORT_TARGET_TEMPERATURE_RANGE. + Requires ClimateEntityFeature.TARGET_TEMPERATURE_RANGE. """ return self._attr_target_temperature_high @@ -375,7 +379,7 @@ class ClimateEntity(Entity): def target_temperature_low(self) -> float | None: """Return the lowbound target temperature we try to reach. - Requires SUPPORT_TARGET_TEMPERATURE_RANGE. + Requires ClimateEntityFeature.TARGET_TEMPERATURE_RANGE. """ return self._attr_target_temperature_low @@ -383,7 +387,7 @@ class ClimateEntity(Entity): def preset_mode(self) -> str | None: """Return the current preset mode, e.g., home, away, temp. - Requires SUPPORT_PRESET_MODE. + Requires ClimateEntityFeature.PRESET_MODE. """ return self._attr_preset_mode @@ -391,7 +395,7 @@ class ClimateEntity(Entity): def preset_modes(self) -> list[str] | None: """Return a list of available preset modes. - Requires SUPPORT_PRESET_MODE. + Requires ClimateEntityFeature.PRESET_MODE. """ return self._attr_preset_modes @@ -399,7 +403,7 @@ class ClimateEntity(Entity): def is_aux_heat(self) -> bool | None: """Return true if aux heater. - Requires SUPPORT_AUX_HEAT. + Requires ClimateEntityFeature.AUX_HEAT. """ return self._attr_is_aux_heat @@ -407,7 +411,7 @@ class ClimateEntity(Entity): def fan_mode(self) -> str | None: """Return the fan setting. - Requires SUPPORT_FAN_MODE. + Requires ClimateEntityFeature.FAN_MODE. """ return self._attr_fan_mode @@ -415,7 +419,7 @@ class ClimateEntity(Entity): def fan_modes(self) -> list[str] | None: """Return the list of available fan modes. - Requires SUPPORT_FAN_MODE. + Requires ClimateEntityFeature.FAN_MODE. """ return self._attr_fan_modes @@ -423,7 +427,7 @@ class ClimateEntity(Entity): def swing_mode(self) -> str | None: """Return the swing setting. - Requires SUPPORT_SWING_MODE. + Requires ClimateEntityFeature.SWING_MODE. """ return self._attr_swing_mode @@ -431,7 +435,7 @@ class ClimateEntity(Entity): def swing_modes(self) -> list[str] | None: """Return the list of available swing modes. - Requires SUPPORT_SWING_MODE. + Requires ClimateEntityFeature.SWING_MODE. """ return self._attr_swing_modes diff --git a/homeassistant/components/climate/const.py b/homeassistant/components/climate/const.py index 773ee5920da..5ee2424e7f7 100644 --- a/homeassistant/components/climate/const.py +++ b/homeassistant/components/climate/const.py @@ -1,5 +1,7 @@ """Provides the constants needed for component.""" +from enum import IntEnum + # All activity disabled / Device is off/standby HVAC_MODE_OFF = "off" @@ -133,6 +135,21 @@ SERVICE_SET_HVAC_MODE = "set_hvac_mode" SERVICE_SET_SWING_MODE = "set_swing_mode" SERVICE_SET_TEMPERATURE = "set_temperature" + +class ClimateEntityFeature(IntEnum): + """Supported features of the climate entity.""" + + TARGET_TEMPERATURE = 1 + TARGET_TEMPERATURE_RANGE = 2 + TARGET_HUMIDITY = 4 + FAN_MODE = 8 + PRESET_MODE = 16 + SWING_MODE = 32 + AUX_HEAT = 64 + + +# These SUPPORT_* constants are deprecated as of Home Assistant 2022.5. +# Pleease use the ClimateEntityFeature enum instead. SUPPORT_TARGET_TEMPERATURE = 1 SUPPORT_TARGET_TEMPERATURE_RANGE = 2 SUPPORT_TARGET_HUMIDITY = 4 diff --git a/homeassistant/components/demo/climate.py b/homeassistant/components/demo/climate.py index eb1c38d90bb..750354a567a 100644 --- a/homeassistant/components/demo/climate.py +++ b/homeassistant/components/demo/climate.py @@ -13,13 +13,7 @@ from homeassistant.components.climate.const import ( HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF, HVAC_MODES, - SUPPORT_AUX_HEAT, - SUPPORT_FAN_MODE, - SUPPORT_PRESET_MODE, - SUPPORT_SWING_MODE, - SUPPORT_TARGET_HUMIDITY, - SUPPORT_TARGET_TEMPERATURE, - SUPPORT_TARGET_TEMPERATURE_RANGE, + ClimateEntityFeature, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT @@ -138,19 +132,25 @@ class DemoClimate(ClimateEntity): self._name = name self._support_flags = SUPPORT_FLAGS if target_temperature is not None: - self._support_flags = self._support_flags | SUPPORT_TARGET_TEMPERATURE + self._support_flags = ( + self._support_flags | ClimateEntityFeature.TARGET_TEMPERATURE + ) if preset is not None: - self._support_flags = self._support_flags | SUPPORT_PRESET_MODE + self._support_flags = self._support_flags | ClimateEntityFeature.PRESET_MODE if fan_mode is not None: - self._support_flags = self._support_flags | SUPPORT_FAN_MODE + self._support_flags = self._support_flags | ClimateEntityFeature.FAN_MODE if target_humidity is not None: - self._support_flags = self._support_flags | SUPPORT_TARGET_HUMIDITY + self._support_flags = ( + self._support_flags | ClimateEntityFeature.TARGET_HUMIDITY + ) if swing_mode is not None: - self._support_flags = self._support_flags | SUPPORT_SWING_MODE + self._support_flags = self._support_flags | ClimateEntityFeature.SWING_MODE if aux is not None: - self._support_flags = self._support_flags | SUPPORT_AUX_HEAT + self._support_flags = self._support_flags | ClimateEntityFeature.AUX_HEAT if HVAC_MODE_HEAT_COOL in hvac_modes or HVAC_MODE_AUTO in hvac_modes: - self._support_flags = self._support_flags | SUPPORT_TARGET_TEMPERATURE_RANGE + self._support_flags = ( + self._support_flags | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE + ) self._target_temperature = target_temperature self._target_humidity = target_humidity self._unit_of_measurement = unit_of_measurement diff --git a/tests/components/climate/test_device_action.py b/tests/components/climate/test_device_action.py index 4f926e1b094..cd9bc0b1baf 100644 --- a/tests/components/climate/test_device_action.py +++ b/tests/components/climate/test_device_action.py @@ -35,9 +35,19 @@ def entity_reg(hass): "set_state,features_reg,features_state,expected_action_types", [ (False, 0, 0, ["set_hvac_mode"]), - (False, const.SUPPORT_PRESET_MODE, 0, ["set_hvac_mode", "set_preset_mode"]), + ( + False, + const.ClimateEntityFeature.PRESET_MODE, + 0, + ["set_hvac_mode", "set_preset_mode"], + ), (True, 0, 0, ["set_hvac_mode"]), - (True, 0, const.SUPPORT_PRESET_MODE, ["set_hvac_mode", "set_preset_mode"]), + ( + True, + 0, + const.ClimateEntityFeature.PRESET_MODE, + ["set_hvac_mode", "set_preset_mode"], + ), ], ) async def test_get_actions( diff --git a/tests/components/climate/test_device_condition.py b/tests/components/climate/test_device_condition.py index 65c1e17048b..e76073f1e25 100644 --- a/tests/components/climate/test_device_condition.py +++ b/tests/components/climate/test_device_condition.py @@ -41,9 +41,19 @@ def calls(hass): "set_state,features_reg,features_state,expected_condition_types", [ (False, 0, 0, ["is_hvac_mode"]), - (False, const.SUPPORT_PRESET_MODE, 0, ["is_hvac_mode", "is_preset_mode"]), + ( + False, + const.ClimateEntityFeature.PRESET_MODE, + 0, + ["is_hvac_mode", "is_preset_mode"], + ), (True, 0, 0, ["is_hvac_mode"]), - (True, 0, const.SUPPORT_PRESET_MODE, ["is_hvac_mode", "is_preset_mode"]), + ( + True, + 0, + const.ClimateEntityFeature.PRESET_MODE, + ["is_hvac_mode", "is_preset_mode"], + ), ], ) async def test_get_conditions(