Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 31 additions & 27 deletions homeassistant/components/climate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
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,
Expand Down Expand Up @@ -74,6 +74,7 @@
SUPPORT_TARGET_HUMIDITY,
SUPPORT_TARGET_TEMPERATURE,
SUPPORT_TARGET_TEMPERATURE_RANGE,
ClimateEntityFeature,
)

DEFAULT_MIN_TEMP = 7
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -235,17 +239,17 @@ def capability_attributes(self) -> dict[str, Any] | None:
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
Expand All @@ -264,15 +268,15 @@ def state_attributes(self) -> dict[str, Any]:
),
}

if supported_features & SUPPORT_TARGET_TEMPERATURE:
if supported_features & ClimateEntityFeature.TARGET_TEMPERATURE:
data[ATTR_TEMPERATURE] = show_temp(
self.hass,
self.target_temperature,
self.temperature_unit,
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,
Expand All @@ -289,22 +293,22 @@ def state_attributes(self) -> dict[str, Any]:
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
Expand Down Expand Up @@ -367,71 +371,71 @@ def target_temperature_step(self) -> float | None:
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

@property
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

@property
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

@property
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

@property
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

@property
def fan_mode(self) -> str | None:
"""Return the fan setting.

Requires SUPPORT_FAN_MODE.
Requires ClimateEntityFeature.FAN_MODE.
"""
return self._attr_fan_mode

@property
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

@property
def swing_mode(self) -> str | None:
"""Return the swing setting.

Requires SUPPORT_SWING_MODE.
Requires ClimateEntityFeature.SWING_MODE.
"""
return self._attr_swing_mode

@property
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

Expand Down
17 changes: 17 additions & 0 deletions homeassistant/components/climate/const.py
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -133,6 +135,21 @@
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
Expand Down
28 changes: 14 additions & 14 deletions homeassistant/components/demo/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,7 @@
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
Expand Down Expand Up @@ -138,19 +132,25 @@ def __init__(
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
Expand Down
14 changes: 12 additions & 2 deletions tests/components/climate/test_device_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
14 changes: 12 additions & 2 deletions tests/components/climate/test_device_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down