mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 02:48:57 +00:00
[esphome] Implement feature_flags for climate (#153507)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
@@ -9,6 +9,7 @@ from typing import Any, cast
|
|||||||
from aioesphomeapi import (
|
from aioesphomeapi import (
|
||||||
ClimateAction,
|
ClimateAction,
|
||||||
ClimateFanMode,
|
ClimateFanMode,
|
||||||
|
ClimateFeature,
|
||||||
ClimateInfo,
|
ClimateInfo,
|
||||||
ClimateMode,
|
ClimateMode,
|
||||||
ClimatePreset,
|
ClimatePreset,
|
||||||
@@ -134,12 +135,16 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
|
|
||||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||||
_attr_translation_key = "climate"
|
_attr_translation_key = "climate"
|
||||||
|
_feature_flags = ClimateFeature(0)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _on_static_info_update(self, static_info: EntityInfo) -> None:
|
def _on_static_info_update(self, static_info: EntityInfo) -> None:
|
||||||
"""Set attrs from static info."""
|
"""Set attrs from static info."""
|
||||||
super()._on_static_info_update(static_info)
|
super()._on_static_info_update(static_info)
|
||||||
static_info = self._static_info
|
static_info = self._static_info
|
||||||
|
self._feature_flags = ClimateFeature(
|
||||||
|
static_info.supported_feature_flags_compat(self._api_version)
|
||||||
|
)
|
||||||
self._attr_precision = self._get_precision()
|
self._attr_precision = self._get_precision()
|
||||||
self._attr_hvac_modes = [
|
self._attr_hvac_modes = [
|
||||||
_CLIMATE_MODES.from_esphome(mode) for mode in static_info.supported_modes
|
_CLIMATE_MODES.from_esphome(mode) for mode in static_info.supported_modes
|
||||||
@@ -163,11 +168,18 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
self._attr_max_temp = static_info.visual_max_temperature
|
self._attr_max_temp = static_info.visual_max_temperature
|
||||||
self._attr_min_humidity = round(static_info.visual_min_humidity)
|
self._attr_min_humidity = round(static_info.visual_min_humidity)
|
||||||
self._attr_max_humidity = round(static_info.visual_max_humidity)
|
self._attr_max_humidity = round(static_info.visual_max_humidity)
|
||||||
features = ClimateEntityFeature.TARGET_TEMPERATURE
|
features = ClimateEntityFeature(0)
|
||||||
if static_info.supports_two_point_target_temperature:
|
if self._feature_flags & ClimateFeature.SUPPORTS_TARGET_HUMIDITY:
|
||||||
features |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
|
||||||
if static_info.supports_target_humidity:
|
|
||||||
features |= ClimateEntityFeature.TARGET_HUMIDITY
|
features |= ClimateEntityFeature.TARGET_HUMIDITY
|
||||||
|
if self._feature_flags & ClimateFeature.REQUIRES_TWO_POINT_TARGET_TEMPERATURE:
|
||||||
|
features |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
|
else:
|
||||||
|
features |= ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
|
if (
|
||||||
|
self._feature_flags
|
||||||
|
& ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
|
):
|
||||||
|
features |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
if self.preset_modes:
|
if self.preset_modes:
|
||||||
features |= ClimateEntityFeature.PRESET_MODE
|
features |= ClimateEntityFeature.PRESET_MODE
|
||||||
if self.fan_modes:
|
if self.fan_modes:
|
||||||
@@ -203,7 +215,7 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
def hvac_action(self) -> HVACAction | None:
|
def hvac_action(self) -> HVACAction | None:
|
||||||
"""Return current action."""
|
"""Return current action."""
|
||||||
# HA has no support feature field for hvac_action
|
# HA has no support feature field for hvac_action
|
||||||
if not self._static_info.supports_action:
|
if not self._feature_flags & ClimateFeature.SUPPORTS_ACTION:
|
||||||
return None
|
return None
|
||||||
return _CLIMATE_ACTIONS.from_esphome(self._state.action)
|
return _CLIMATE_ACTIONS.from_esphome(self._state.action)
|
||||||
|
|
||||||
@@ -233,7 +245,7 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
@esphome_float_state_property
|
@esphome_float_state_property
|
||||||
def current_temperature(self) -> float | None:
|
def current_temperature(self) -> float | None:
|
||||||
"""Return the current temperature."""
|
"""Return the current temperature."""
|
||||||
if not self._static_info.supports_current_temperature:
|
if not self._feature_flags & ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE:
|
||||||
return None
|
return None
|
||||||
return self._state.current_temperature
|
return self._state.current_temperature
|
||||||
|
|
||||||
@@ -242,7 +254,7 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
def current_humidity(self) -> int | None:
|
def current_humidity(self) -> int | None:
|
||||||
"""Return the current humidity."""
|
"""Return the current humidity."""
|
||||||
if (
|
if (
|
||||||
not self._static_info.supports_current_humidity
|
(not self._feature_flags & ClimateFeature.SUPPORTS_CURRENT_HUMIDITY)
|
||||||
or (val := self._state.current_humidity) is None
|
or (val := self._state.current_humidity) is None
|
||||||
or not isfinite(val)
|
or not isfinite(val)
|
||||||
):
|
):
|
||||||
@@ -254,7 +266,11 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
def target_temperature(self) -> float | None:
|
def target_temperature(self) -> float | None:
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
if (
|
if (
|
||||||
not self._static_info.supports_two_point_target_temperature
|
not self._feature_flags
|
||||||
|
& (
|
||||||
|
ClimateFeature.REQUIRES_TWO_POINT_TARGET_TEMPERATURE
|
||||||
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
|
)
|
||||||
and self.hvac_mode != HVACMode.AUTO
|
and self.hvac_mode != HVACMode.AUTO
|
||||||
):
|
):
|
||||||
return self._state.target_temperature
|
return self._state.target_temperature
|
||||||
@@ -295,7 +311,10 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
|||||||
cast(HVACMode, kwargs[ATTR_HVAC_MODE])
|
cast(HVACMode, kwargs[ATTR_HVAC_MODE])
|
||||||
)
|
)
|
||||||
if ATTR_TEMPERATURE in kwargs:
|
if ATTR_TEMPERATURE in kwargs:
|
||||||
if not self._static_info.supports_two_point_target_temperature:
|
if not self._feature_flags & (
|
||||||
|
ClimateFeature.REQUIRES_TWO_POINT_TARGET_TEMPERATURE
|
||||||
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
|
):
|
||||||
data["target_temperature"] = kwargs[ATTR_TEMPERATURE]
|
data["target_temperature"] = kwargs[ATTR_TEMPERATURE]
|
||||||
else:
|
else:
|
||||||
hvac_mode = kwargs.get(ATTR_HVAC_MODE) or self.hvac_mode
|
hvac_mode = kwargs.get(ATTR_HVAC_MODE) or self.hvac_mode
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from aioesphomeapi import (
|
|||||||
APIClient,
|
APIClient,
|
||||||
ClimateAction,
|
ClimateAction,
|
||||||
ClimateFanMode,
|
ClimateFanMode,
|
||||||
|
ClimateFeature,
|
||||||
ClimateInfo,
|
ClimateInfo,
|
||||||
ClimateMode,
|
ClimateMode,
|
||||||
ClimatePreset,
|
ClimatePreset,
|
||||||
@@ -107,11 +108,10 @@ async def test_climate_entity_with_step_and_two_point(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_current_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
|
||||||
supports_two_point_target_temperature=True,
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE,
|
||||||
visual_target_temperature_step=2,
|
visual_target_temperature_step=2,
|
||||||
visual_current_temperature_step=2,
|
visual_current_temperature_step=2,
|
||||||
supports_action=False,
|
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
supported_modes=[ClimateMode.COOL, ClimateMode.HEAT, ClimateMode.AUTO],
|
supported_modes=[ClimateMode.COOL, ClimateMode.HEAT, ClimateMode.AUTO],
|
||||||
@@ -346,13 +346,13 @@ async def test_climate_entity_with_humidity(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_current_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
|
||||||
supports_two_point_target_temperature=True,
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
supports_action=True,
|
| ClimateFeature.SUPPORTS_CURRENT_HUMIDITY
|
||||||
|
| ClimateFeature.SUPPORTS_TARGET_HUMIDITY
|
||||||
|
| ClimateFeature.SUPPORTS_ACTION,
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
supports_current_humidity=True,
|
|
||||||
supports_target_humidity=True,
|
|
||||||
visual_min_humidity=10.1,
|
visual_min_humidity=10.1,
|
||||||
visual_max_humidity=29.7,
|
visual_max_humidity=29.7,
|
||||||
)
|
)
|
||||||
@@ -407,9 +407,9 @@ async def test_climate_entity_with_heat(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_current_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
|
||||||
supports_two_point_target_temperature=True,
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
supports_action=True,
|
| ClimateFeature.SUPPORTS_ACTION,
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
supported_modes=[ClimateMode.COOL, ClimateMode.HEAT, ClimateMode.AUTO],
|
supported_modes=[ClimateMode.COOL, ClimateMode.HEAT, ClimateMode.AUTO],
|
||||||
@@ -456,9 +456,9 @@ async def test_climate_entity_with_heat_cool(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_current_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
|
||||||
supports_two_point_target_temperature=True,
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
supports_action=True,
|
| ClimateFeature.SUPPORTS_ACTION,
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
supported_modes=[ClimateMode.COOL, ClimateMode.HEAT, ClimateMode.HEAT_COOL],
|
supported_modes=[ClimateMode.COOL, ClimateMode.HEAT, ClimateMode.HEAT_COOL],
|
||||||
@@ -516,7 +516,7 @@ async def test_climate_set_temperature_unsupported_mode(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_two_point_target_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE,
|
||||||
supported_modes=[ClimateMode.HEAT, ClimateMode.COOL, ClimateMode.AUTO],
|
supported_modes=[ClimateMode.HEAT, ClimateMode.COOL, ClimateMode.AUTO],
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
@@ -563,13 +563,13 @@ async def test_climate_entity_with_inf_value(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_current_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
|
||||||
supports_two_point_target_temperature=True,
|
| ClimateFeature.SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
|
||||||
supports_action=True,
|
| ClimateFeature.SUPPORTS_CURRENT_HUMIDITY
|
||||||
|
| ClimateFeature.SUPPORTS_TARGET_HUMIDITY
|
||||||
|
| ClimateFeature.SUPPORTS_ACTION,
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
supports_current_humidity=True,
|
|
||||||
supports_target_humidity=True,
|
|
||||||
visual_min_humidity=10.1,
|
visual_min_humidity=10.1,
|
||||||
visual_max_humidity=29.7,
|
visual_max_humidity=29.7,
|
||||||
)
|
)
|
||||||
@@ -616,10 +616,10 @@ async def test_climate_entity_attributes(
|
|||||||
object_id="myclimate",
|
object_id="myclimate",
|
||||||
key=1,
|
key=1,
|
||||||
name="my climate",
|
name="my climate",
|
||||||
supports_current_temperature=True,
|
feature_flags=ClimateFeature.SUPPORTS_CURRENT_TEMPERATURE
|
||||||
|
| ClimateFeature.SUPPORTS_ACTION,
|
||||||
visual_target_temperature_step=2,
|
visual_target_temperature_step=2,
|
||||||
visual_current_temperature_step=2,
|
visual_current_temperature_step=2,
|
||||||
supports_action=True,
|
|
||||||
visual_min_temperature=10.0,
|
visual_min_temperature=10.0,
|
||||||
visual_max_temperature=30.0,
|
visual_max_temperature=30.0,
|
||||||
supported_fan_modes=[ClimateFanMode.LOW, ClimateFanMode.HIGH],
|
supported_fan_modes=[ClimateFanMode.LOW, ClimateFanMode.HIGH],
|
||||||
|
|||||||
Reference in New Issue
Block a user