Add TURN_OFF and TURN_ON to ClimateEntityFeature (#101673)
* Add ClimateEntityFeature.TURN_OFF * Fixes * Fixes * wording * Change to services * Fixing * Fixing * Last bits * Review comments * Add hvac_modes checks * Fixes * Add tests * Review comments * Update snapshots * balboa * coolmaster * ecobee * mqtt * nest * plugwise * smarttub * whirlpool * zwave_js * fix test climate * test climate * zwave * nexia * nuheat * venstar * tado * smartthings * self.hvac_modes not None * more tests * homekit_controller * homekit controller snapshotpull/108964/head
parent
cece117c93
commit
bc720b48b4
|
@ -1,6 +1,7 @@
|
|||
"""Provides functionality to interact with climate devices."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
import functools as ft
|
||||
import logging
|
||||
|
@ -34,6 +35,7 @@ from homeassistant.helpers.deprecation import (
|
|||
)
|
||||
from homeassistant.helpers.entity import Entity, EntityDescription
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity_platform import EntityPlatform
|
||||
from homeassistant.helpers.temperature import display_temp as show_temp
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||
|
@ -152,8 +154,18 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
)
|
||||
await component.async_setup(config)
|
||||
|
||||
component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on")
|
||||
component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off")
|
||||
component.async_register_entity_service(
|
||||
SERVICE_TURN_ON,
|
||||
{},
|
||||
"async_turn_on",
|
||||
[ClimateEntityFeature.TURN_ON],
|
||||
)
|
||||
component.async_register_entity_service(
|
||||
SERVICE_TURN_OFF,
|
||||
{},
|
||||
"async_turn_off",
|
||||
[ClimateEntityFeature.TURN_OFF],
|
||||
)
|
||||
component.async_register_entity_service(
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
{vol.Required(ATTR_HVAC_MODE): vol.Coerce(HVACMode)},
|
||||
|
@ -288,6 +300,102 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
_attr_target_temperature: float | None = None
|
||||
_attr_temperature_unit: str
|
||||
|
||||
__mod_supported_features: ClimateEntityFeature = ClimateEntityFeature(0)
|
||||
|
||||
def __getattribute__(self, __name: str) -> Any:
|
||||
"""Get attribute.
|
||||
|
||||
Modify return of `supported_features` to
|
||||
include `_mod_supported_features` if attribute is set.
|
||||
"""
|
||||
if __name != "supported_features":
|
||||
return super().__getattribute__(__name)
|
||||
|
||||
# Convert the supported features to ClimateEntityFeature.
|
||||
# Remove this compatibility shim in 2025.1 or later.
|
||||
_supported_features = super().__getattribute__(__name)
|
||||
if type(_supported_features) is int: # noqa: E721
|
||||
new_features = ClimateEntityFeature(_supported_features)
|
||||
self._report_deprecated_supported_features_values(new_features)
|
||||
|
||||
# Add automatically calculated ClimateEntityFeature.TURN_OFF/TURN_ON to
|
||||
# supported features and return it
|
||||
return _supported_features | super().__getattribute__(
|
||||
"_ClimateEntity__mod_supported_features"
|
||||
)
|
||||
|
||||
@callback
|
||||
def add_to_platform_start(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
platform: EntityPlatform,
|
||||
parallel_updates: asyncio.Semaphore | None,
|
||||
) -> None:
|
||||
"""Start adding an entity to a platform."""
|
||||
super().add_to_platform_start(hass, platform, parallel_updates)
|
||||
|
||||
def _report_turn_on_off(feature: str, method: str) -> None:
|
||||
"""Log warning not implemented turn on/off feature."""
|
||||
report_issue = self._suggest_report_issue()
|
||||
if feature.startswith("TURN"):
|
||||
message = (
|
||||
"Entity %s (%s) does not set ClimateEntityFeature.%s"
|
||||
" but implements the %s method. Please %s"
|
||||
)
|
||||
else:
|
||||
message = (
|
||||
"Entity %s (%s) implements HVACMode(s): %s and therefore implicitly"
|
||||
" supports the %s service without setting the proper"
|
||||
" ClimateEntityFeature. Please %s"
|
||||
)
|
||||
_LOGGER.warning(
|
||||
message,
|
||||
self.entity_id,
|
||||
type(self),
|
||||
feature,
|
||||
feature.lower(),
|
||||
report_issue,
|
||||
)
|
||||
|
||||
# Adds ClimateEntityFeature.TURN_OFF/TURN_ON depending on service calls implemented
|
||||
# This should be removed in 2025.1.
|
||||
if not self.supported_features & ClimateEntityFeature.TURN_OFF:
|
||||
if (
|
||||
type(self).async_turn_off is not ClimateEntity.async_turn_off
|
||||
or type(self).turn_off is not ClimateEntity.turn_off
|
||||
):
|
||||
# turn_off implicitly supported by implementing turn_off method
|
||||
_report_turn_on_off("TURN_OFF", "turn_off")
|
||||
self.__mod_supported_features |= ( # pylint: disable=unused-private-member
|
||||
ClimateEntityFeature.TURN_OFF
|
||||
)
|
||||
elif self.hvac_modes and HVACMode.OFF in self.hvac_modes:
|
||||
# turn_off implicitly supported by including HVACMode.OFF
|
||||
_report_turn_on_off("off", "turn_off")
|
||||
self.__mod_supported_features |= ( # pylint: disable=unused-private-member
|
||||
ClimateEntityFeature.TURN_OFF
|
||||
)
|
||||
|
||||
if not self.supported_features & ClimateEntityFeature.TURN_ON:
|
||||
if (
|
||||
type(self).async_turn_on is not ClimateEntity.async_turn_on
|
||||
or type(self).turn_on is not ClimateEntity.turn_on
|
||||
):
|
||||
# turn_on implicitly supported by implementing turn_on method
|
||||
_report_turn_on_off("TURN_ON", "turn_on")
|
||||
self.__mod_supported_features |= ( # pylint: disable=unused-private-member
|
||||
ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
elif self.hvac_modes and any(
|
||||
_mode != HVACMode.OFF and _mode is not None for _mode in self.hvac_modes
|
||||
):
|
||||
# turn_on implicitly supported by including any other HVACMode than HVACMode.OFF
|
||||
_modes = [_mode for _mode in self.hvac_modes if _mode != HVACMode.OFF]
|
||||
_report_turn_on_off(", ".join(_modes or []), "turn_on")
|
||||
self.__mod_supported_features |= ( # pylint: disable=unused-private-member
|
||||
ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
@final
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
|
@ -312,7 +420,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
@property
|
||||
def capability_attributes(self) -> dict[str, Any] | None:
|
||||
"""Return the capability attributes."""
|
||||
supported_features = self.supported_features_compat
|
||||
supported_features = self.supported_features
|
||||
temperature_unit = self.temperature_unit
|
||||
precision = self.precision
|
||||
hass = self.hass
|
||||
|
@ -345,7 +453,7 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
@property
|
||||
def state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the optional state attributes."""
|
||||
supported_features = self.supported_features_compat
|
||||
supported_features = self.supported_features
|
||||
temperature_unit = self.temperature_unit
|
||||
precision = self.precision
|
||||
hass = self.hass
|
||||
|
@ -625,9 +733,14 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
"""Turn auxiliary heater off."""
|
||||
await self.hass.async_add_executor_job(self.turn_aux_heat_off)
|
||||
|
||||
def turn_on(self) -> None:
|
||||
"""Turn the entity on."""
|
||||
raise NotImplementedError
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the entity on."""
|
||||
if hasattr(self, "turn_on"):
|
||||
# Forward to self.turn_on if it's been overridden.
|
||||
if type(self).turn_on is not ClimateEntity.turn_on:
|
||||
await self.hass.async_add_executor_job(self.turn_on)
|
||||
return
|
||||
|
||||
|
@ -646,9 +759,14 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
await self.async_set_hvac_mode(mode)
|
||||
break
|
||||
|
||||
def turn_off(self) -> None:
|
||||
"""Turn the entity off."""
|
||||
raise NotImplementedError
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the entity off."""
|
||||
if hasattr(self, "turn_off"):
|
||||
# Forward to self.turn_on if it's been overridden.
|
||||
if type(self).turn_off is not ClimateEntity.turn_off:
|
||||
await self.hass.async_add_executor_job(self.turn_off)
|
||||
return
|
||||
|
||||
|
@ -661,19 +779,6 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
"""Return the list of supported features."""
|
||||
return self._attr_supported_features
|
||||
|
||||
@property
|
||||
def supported_features_compat(self) -> ClimateEntityFeature:
|
||||
"""Return the supported features as ClimateEntityFeature.
|
||||
|
||||
Remove this compatibility shim in 2025.1 or later.
|
||||
"""
|
||||
features = self.supported_features
|
||||
if type(features) is int: # noqa: E721
|
||||
new_features = ClimateEntityFeature(features)
|
||||
self._report_deprecated_supported_features_values(new_features)
|
||||
return new_features
|
||||
return features
|
||||
|
||||
@cached_property
|
||||
def min_temp(self) -> float:
|
||||
"""Return the minimum temperature."""
|
||||
|
|
|
@ -163,6 +163,8 @@ class ClimateEntityFeature(IntFlag):
|
|||
PRESET_MODE = 16
|
||||
SWING_MODE = 32
|
||||
AUX_HEAT = 64
|
||||
TURN_OFF = 128
|
||||
TURN_ON = 256
|
||||
|
||||
|
||||
# These SUPPORT_* constants are deprecated as of Home Assistant 2022.5.
|
||||
|
|
|
@ -139,8 +139,12 @@ turn_on:
|
|||
target:
|
||||
entity:
|
||||
domain: climate
|
||||
supported_features:
|
||||
- climate.ClimateEntityFeature.TURN_ON
|
||||
|
||||
turn_off:
|
||||
target:
|
||||
entity:
|
||||
domain: climate
|
||||
supported_features:
|
||||
- climate.ClimateEntityFeature.TURN_OFF
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
]),
|
||||
'max_temp': 32,
|
||||
'min_temp': 16,
|
||||
'supported_features': <ClimateEntityFeature: 11>,
|
||||
'supported_features': <ClimateEntityFeature: 395>,
|
||||
'target_temp_high': 24,
|
||||
'target_temp_low': 20,
|
||||
'target_temp_step': 1,
|
||||
|
|
|
@ -51,7 +51,10 @@ async def test_spa_defaults(
|
|||
assert state
|
||||
assert (
|
||||
state.attributes["supported_features"]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
|
@ -71,7 +74,10 @@ async def test_spa_defaults_fake_tscale(
|
|||
assert state
|
||||
assert (
|
||||
state.attributes["supported_features"]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
|
@ -174,6 +180,8 @@ async def test_spa_with_blower(hass: HomeAssistant, client: MagicMock) -> None:
|
|||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 10.0
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'ccm15',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'translation_key': None,
|
||||
'unique_id': '1.1.1.1.0',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -97,7 +97,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'ccm15',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'translation_key': None,
|
||||
'unique_id': '1.1.1.1.1',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -125,7 +125,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'swing_mode': 'off',
|
||||
'swing_modes': list([
|
||||
'off',
|
||||
|
@ -163,7 +163,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'swing_mode': 'off',
|
||||
'swing_modes': list([
|
||||
'off',
|
||||
|
@ -225,7 +225,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'ccm15',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'translation_key': None,
|
||||
'unique_id': '1.1.1.1.0',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -277,7 +277,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'ccm15',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'translation_key': None,
|
||||
'unique_id': '1.1.1.1.1',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -302,7 +302,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'swing_modes': list([
|
||||
'off',
|
||||
'on',
|
||||
|
@ -335,7 +335,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'swing_modes': list([
|
||||
'off',
|
||||
'on',
|
||||
|
|
|
@ -25,7 +25,7 @@ from homeassistant.components.climate.const import (
|
|||
ClimateEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import UnitOfTemperature
|
||||
from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
@ -154,7 +154,8 @@ async def test_sync_turn_off(hass: HomeAssistant) -> None:
|
|||
def _create_tuples(enum: Enum, constant_prefix: str) -> list[tuple[Enum, str]]:
|
||||
result = []
|
||||
for enum in enum:
|
||||
result.append((enum, constant_prefix))
|
||||
if enum not in [ClimateEntityFeature.TURN_ON, ClimateEntityFeature.TURN_OFF]:
|
||||
result.append((enum, constant_prefix))
|
||||
return result
|
||||
|
||||
|
||||
|
@ -355,11 +356,262 @@ def test_deprecated_supported_features_ints(caplog: pytest.LogCaptureFixture) ->
|
|||
return 1
|
||||
|
||||
entity = MockClimateEntity()
|
||||
assert entity.supported_features_compat is ClimateEntityFeature(1)
|
||||
assert entity.supported_features is ClimateEntityFeature(1)
|
||||
assert "MockClimateEntity" in caplog.text
|
||||
assert "is using deprecated supported features values" in caplog.text
|
||||
assert "Instead it should use" in caplog.text
|
||||
assert "ClimateEntityFeature.TARGET_TEMPERATURE" in caplog.text
|
||||
caplog.clear()
|
||||
assert entity.supported_features_compat is ClimateEntityFeature(1)
|
||||
assert entity.supported_features is ClimateEntityFeature(1)
|
||||
assert "is using deprecated supported features values" not in caplog.text
|
||||
|
||||
|
||||
async def test_warning_not_implemented_turn_on_off_feature(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, config_flow_fixture: None
|
||||
) -> None:
|
||||
"""Test adding feature flag and warn if missing when methods are set."""
|
||||
|
||||
called = []
|
||||
|
||||
class MockClimateEntityTest(MockClimateEntity):
|
||||
"""Mock Climate device."""
|
||||
|
||||
def turn_on(self) -> None:
|
||||
"""Turn on."""
|
||||
called.append("turn_on")
|
||||
|
||||
def turn_off(self) -> None:
|
||||
"""Turn off."""
|
||||
called.append("turn_off")
|
||||
|
||||
async def async_setup_entry_init(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up test config entry."""
|
||||
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
|
||||
return True
|
||||
|
||||
async def async_setup_entry_climate_platform(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up test climate platform via config entry."""
|
||||
async_add_entities(
|
||||
[MockClimateEntityTest(name="test", entity_id="climate.test")]
|
||||
)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=async_setup_entry_init,
|
||||
),
|
||||
built_in=False,
|
||||
)
|
||||
mock_platform(
|
||||
hass,
|
||||
"test.climate",
|
||||
MockPlatform(async_setup_entry=async_setup_entry_climate_platform),
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("climate.test")
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"Entity climate.test (<class 'tests.components.climate.test_init."
|
||||
"test_warning_not_implemented_turn_on_off_feature.<locals>.MockClimateEntityTest'>)"
|
||||
" does not set ClimateEntityFeature.TURN_OFF but implements the turn_off method."
|
||||
" Please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
assert (
|
||||
"Entity climate.test (<class 'tests.components.climate.test_init."
|
||||
"test_warning_not_implemented_turn_on_off_feature.<locals>.MockClimateEntityTest'>)"
|
||||
" does not set ClimateEntityFeature.TURN_ON but implements the turn_on method."
|
||||
" Please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
"entity_id": "climate.test",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{
|
||||
"entity_id": "climate.test",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(called) == 2
|
||||
assert "turn_on" in called
|
||||
assert "turn_off" in called
|
||||
|
||||
|
||||
async def test_implicit_warning_not_implemented_turn_on_off_feature(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, config_flow_fixture: None
|
||||
) -> None:
|
||||
"""Test adding feature flag and warn if missing when methods are not set.
|
||||
|
||||
(implicit by hvac mode)
|
||||
"""
|
||||
|
||||
class MockClimateEntityTest(MockEntity, ClimateEntity):
|
||||
"""Mock Climate device."""
|
||||
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
"""Return hvac operation ie. heat, cool mode.
|
||||
|
||||
Need to be one of HVACMode.*.
|
||||
"""
|
||||
return HVACMode.HEAT
|
||||
|
||||
@property
|
||||
def hvac_modes(self) -> list[HVACMode]:
|
||||
"""Return the list of available hvac operation modes.
|
||||
|
||||
Need to be a subset of HVAC_MODES.
|
||||
"""
|
||||
return [HVACMode.OFF, HVACMode.HEAT]
|
||||
|
||||
async def async_setup_entry_init(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up test config entry."""
|
||||
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
|
||||
return True
|
||||
|
||||
async def async_setup_entry_climate_platform(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up test climate platform via config entry."""
|
||||
async_add_entities(
|
||||
[MockClimateEntityTest(name="test", entity_id="climate.test")]
|
||||
)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=async_setup_entry_init,
|
||||
),
|
||||
built_in=False,
|
||||
)
|
||||
mock_platform(
|
||||
hass,
|
||||
"test.climate",
|
||||
MockPlatform(async_setup_entry=async_setup_entry_climate_platform),
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("climate.test")
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"Entity climate.test (<class 'tests.components.climate.test_init."
|
||||
"test_implicit_warning_not_implemented_turn_on_off_feature.<locals>.MockClimateEntityTest'>)"
|
||||
" implements HVACMode(s): off and therefore implicitly supports the off service without setting"
|
||||
" the proper ClimateEntityFeature. Please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
assert (
|
||||
"Entity climate.test (<class 'tests.components.climate.test_init."
|
||||
"test_implicit_warning_not_implemented_turn_on_off_feature.<locals>.MockClimateEntityTest'>)"
|
||||
" implements HVACMode(s): heat and therefore implicitly supports the heat service without setting"
|
||||
" the proper ClimateEntityFeature. Please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
async def test_no_warning_implemented_turn_on_off_feature(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, config_flow_fixture: None
|
||||
) -> None:
|
||||
"""Test no warning when feature flags are set."""
|
||||
|
||||
class MockClimateEntityTest(MockClimateEntity):
|
||||
"""Mock Climate device."""
|
||||
|
||||
_attr_supported_features = (
|
||||
ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.SWING_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
async def async_setup_entry_init(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up test config entry."""
|
||||
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
|
||||
return True
|
||||
|
||||
async def async_setup_entry_climate_platform(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up test climate platform via config entry."""
|
||||
async_add_entities(
|
||||
[MockClimateEntityTest(name="test", entity_id="climate.test")]
|
||||
)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=async_setup_entry_init,
|
||||
),
|
||||
built_in=False,
|
||||
)
|
||||
mock_platform(
|
||||
hass,
|
||||
"test.climate",
|
||||
MockPlatform(async_setup_entry=async_setup_entry_climate_platform),
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("climate.test")
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"does not set ClimateEntityFeature.TURN_OFF but implements the turn_off method."
|
||||
not in caplog.text
|
||||
)
|
||||
assert (
|
||||
"does not set ClimateEntityFeature.TURN_ON but implements the turn_on method."
|
||||
not in caplog.text
|
||||
)
|
||||
assert (
|
||||
"implements HVACMode.off and therefore implicitly implements the off method without setting"
|
||||
not in caplog.text
|
||||
)
|
||||
assert (
|
||||
"implements HVACMode.heat and therefore implicitly implements the heat method without setting"
|
||||
not in caplog.text
|
||||
)
|
||||
|
|
|
@ -60,12 +60,17 @@ async def test_climate_supported_features(
|
|||
) -> None:
|
||||
"""Test the Coolmaster climate supported features."""
|
||||
assert hass.states.get("climate.l1_100").attributes[ATTR_SUPPORTED_FEATURES] == (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert hass.states.get("climate.l1_101").attributes[ATTR_SUPPORTED_FEATURES] == (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.SWING_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
]),
|
||||
'max_temp': 24,
|
||||
'min_temp': 4,
|
||||
'supported_features': <ClimateEntityFeature: 1>,
|
||||
'supported_features': <ClimateEntityFeature: 257>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 20,
|
||||
}),
|
||||
|
@ -52,7 +52,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'devolo_home_control',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 1>,
|
||||
'supported_features': <ClimateEntityFeature: 257>,
|
||||
'translation_key': None,
|
||||
'unique_id': 'Test',
|
||||
'unit_of_measurement': None,
|
||||
|
|
|
@ -98,6 +98,8 @@ async def test_aux_heat_not_supported_by_default(hass: HomeAssistant) -> None:
|
|||
| ClimateEntityFeature.TARGET_HUMIDITY
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
@ -115,6 +117,8 @@ async def test_aux_heat_supported_with_heat_pump(hass: HomeAssistant) -> None:
|
|||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.AUX_HEAT
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
'home',
|
||||
'boost',
|
||||
]),
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 22.0,
|
||||
}),
|
||||
|
@ -65,7 +65,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'flexit_bacnet',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': None,
|
||||
'unique_id': '0000-0001',
|
||||
'unit_of_measurement': None,
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
'none',
|
||||
'sleep',
|
||||
]),
|
||||
'supported_features': <ClimateEntityFeature: 57>,
|
||||
'supported_features': <ClimateEntityFeature: 441>,
|
||||
'swing_mode': 'off',
|
||||
'swing_modes': list([
|
||||
'off',
|
||||
|
@ -110,7 +110,7 @@
|
|||
'original_name': None,
|
||||
'platform': 'gree',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 57>,
|
||||
'supported_features': <ClimateEntityFeature: 441>,
|
||||
'translation_key': None,
|
||||
'unique_id': 'aabbcc112233',
|
||||
'unit_of_measurement': None,
|
||||
|
|
|
@ -3067,7 +3067,7 @@
|
|||
'original_name': 'HomeW',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 7>,
|
||||
'supported_features': <ClimateEntityFeature: 391>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_16',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -3089,7 +3089,7 @@
|
|||
'max_temp': 33.3,
|
||||
'min_humidity': 20,
|
||||
'min_temp': 7.2,
|
||||
'supported_features': <ClimateEntityFeature: 7>,
|
||||
'supported_features': <ClimateEntityFeature: 391>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'temperature': 22.2,
|
||||
|
@ -3775,7 +3775,7 @@
|
|||
'original_name': 'HomeW',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 7>,
|
||||
'supported_features': <ClimateEntityFeature: 391>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_16',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -3797,7 +3797,7 @@
|
|||
'max_temp': 33.3,
|
||||
'min_humidity': 20,
|
||||
'min_temp': 7.2,
|
||||
'supported_features': <ClimateEntityFeature: 7>,
|
||||
'supported_features': <ClimateEntityFeature: 391>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'temperature': 22.2,
|
||||
|
@ -4188,7 +4188,7 @@
|
|||
'original_name': 'HomeW',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 7>,
|
||||
'supported_features': <ClimateEntityFeature: 391>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_16',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -4210,7 +4210,7 @@
|
|||
'max_temp': 33.3,
|
||||
'min_humidity': 20,
|
||||
'min_temp': 7.2,
|
||||
'supported_features': <ClimateEntityFeature: 7>,
|
||||
'supported_features': <ClimateEntityFeature: 391>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'temperature': 22.2,
|
||||
|
@ -4853,7 +4853,7 @@
|
|||
'original_name': 'My ecobee',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 15>,
|
||||
'supported_features': <ClimateEntityFeature: 399>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_16',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -4880,7 +4880,7 @@
|
|||
'max_temp': 33.3,
|
||||
'min_humidity': 20,
|
||||
'min_temp': 7.2,
|
||||
'supported_features': <ClimateEntityFeature: 15>,
|
||||
'supported_features': <ClimateEntityFeature: 399>,
|
||||
'target_temp_high': 25.6,
|
||||
'target_temp_low': 7.2,
|
||||
'temperature': None,
|
||||
|
@ -7004,7 +7004,7 @@
|
|||
'original_name': '89 Living Room',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'supported_features': <ClimateEntityFeature: 384>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1233851541_169',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -7022,7 +7022,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 0>,
|
||||
'supported_features': <ClimateEntityFeature: 384>,
|
||||
'target_temp_step': 1.0,
|
||||
}),
|
||||
'entity_id': 'climate.89_living_room',
|
||||
|
@ -8431,7 +8431,7 @@
|
|||
'original_name': '89 Living Room',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 32>,
|
||||
'supported_features': <ClimateEntityFeature: 416>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1233851541_169',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -8449,7 +8449,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 32>,
|
||||
'supported_features': <ClimateEntityFeature: 416>,
|
||||
'swing_mode': 'vertical',
|
||||
'swing_modes': list([
|
||||
'off',
|
||||
|
@ -9509,7 +9509,7 @@
|
|||
'original_name': 'Air Conditioner SlaveID 1',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 9>,
|
||||
'supported_features': <ClimateEntityFeature: 393>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_9',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -9534,7 +9534,7 @@
|
|||
]),
|
||||
'max_temp': 32,
|
||||
'min_temp': 18,
|
||||
'supported_features': <ClimateEntityFeature: 9>,
|
||||
'supported_features': <ClimateEntityFeature: 393>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 24.5,
|
||||
}),
|
||||
|
@ -12059,7 +12059,7 @@
|
|||
'original_name': 'Lennox',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 387>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_100',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -12078,7 +12078,7 @@
|
|||
]),
|
||||
'max_temp': 37,
|
||||
'min_temp': 4.5,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 387>,
|
||||
'target_temp_high': 29.5,
|
||||
'target_temp_low': 21,
|
||||
'temperature': None,
|
||||
|
@ -13027,7 +13027,7 @@
|
|||
'original_name': 'Mysa-85dda9 Thermostat',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 1>,
|
||||
'supported_features': <ClimateEntityFeature: 385>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_20',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -13046,7 +13046,7 @@
|
|||
]),
|
||||
'max_temp': 35,
|
||||
'min_temp': 7,
|
||||
'supported_features': <ClimateEntityFeature: 1>,
|
||||
'supported_features': <ClimateEntityFeature: 385>,
|
||||
'temperature': None,
|
||||
}),
|
||||
'entity_id': 'climate.mysa_85dda9_thermostat',
|
||||
|
|
|
@ -107,6 +107,8 @@ async def test_ecobee3_setup(hass: HomeAssistant) -> None:
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.TARGET_HUMIDITY
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
),
|
||||
capabilities={
|
||||
"hvac_modes": ["off", "heat", "cool", "heat_cool"],
|
||||
|
|
|
@ -28,7 +28,10 @@ async def test_cover_add_feature_at_runtime(
|
|||
assert climate.unique_id == "00:00:00:00:00:00_1233851541_169"
|
||||
|
||||
climate_state = hass.states.get("climate.89_living_room")
|
||||
assert climate_state.attributes[ATTR_SUPPORTED_FEATURES] is ClimateEntityFeature(0)
|
||||
assert (
|
||||
climate_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert ATTR_SWING_MODES not in climate_state.attributes
|
||||
|
||||
climate = entity_registry.async_get("climate.89_living_room")
|
||||
|
@ -44,5 +47,7 @@ async def test_cover_add_feature_at_runtime(
|
|||
assert (
|
||||
climate_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is ClimateEntityFeature.SWING_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert climate_state.attributes[ATTR_SWING_MODES] == ["off", "vertical"]
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
'away',
|
||||
'hold',
|
||||
]),
|
||||
'supported_features': <ClimateEntityFeature: 95>,
|
||||
'supported_features': <ClimateEntityFeature: 479>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'temperature': None,
|
||||
|
|
|
@ -89,7 +89,10 @@ async def test_setup_thermostat(
|
|||
assert state.attributes.get(ATTR_PRESET_MODE) == PRESET_NONE
|
||||
assert (
|
||||
state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.attributes.get(ATTR_MAX_TEMP) == MAX_TEMPERATURE
|
||||
assert state.attributes.get(ATTR_MIN_TEMP) == 5.0
|
||||
|
|
|
@ -226,6 +226,8 @@ async def test_supported_features(
|
|||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.TARGET_HUMIDITY
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
assert state.attributes.get("supported_features") == support
|
||||
|
@ -1327,6 +1329,8 @@ async def test_set_aux(
|
|||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.TARGET_HUMIDITY
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
assert state.attributes.get("supported_features") == support
|
||||
|
|
|
@ -909,6 +909,8 @@ async def test_thermostat_fan_off(
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
@ -956,6 +958,8 @@ async def test_thermostat_fan_on(
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
@ -999,6 +1003,8 @@ async def test_thermostat_cool_with_fan(
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
@ -1036,6 +1042,8 @@ async def test_thermostat_set_fan(
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
# Turn off fan mode
|
||||
|
@ -1098,6 +1106,8 @@ async def test_thermostat_set_fan_when_off(
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
# Fan cannot be turned on when HVAC is off
|
||||
|
@ -1143,6 +1153,8 @@ async def test_thermostat_fan_empty(
|
|||
assert thermostat.attributes[ATTR_SUPPORTED_FEATURES] == (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
# Ignores set_fan_mode since it is lacking SUPPORT_FAN_MODE
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
'original_name': 'Bureau',
|
||||
'platform': 'netatmo',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': None,
|
||||
'unique_id': '222452125-DeviceType.OTM',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -61,7 +61,7 @@
|
|||
'Frost Guard',
|
||||
'Schedule',
|
||||
]),
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.5,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
@ -110,7 +110,7 @@
|
|||
'original_name': 'Cocina',
|
||||
'platform': 'netatmo',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': None,
|
||||
'unique_id': '2940411577-DeviceType.NRV',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -138,7 +138,7 @@
|
|||
'Schedule',
|
||||
]),
|
||||
'selected_schedule': 'Default',
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 7,
|
||||
}),
|
||||
|
@ -188,7 +188,7 @@
|
|||
'original_name': 'Corridor',
|
||||
'platform': 'netatmo',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': None,
|
||||
'unique_id': '1002003001-DeviceType.BNS',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -215,7 +215,7 @@
|
|||
'Schedule',
|
||||
]),
|
||||
'selected_schedule': 'Default',
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 22,
|
||||
}),
|
||||
|
@ -265,7 +265,7 @@
|
|||
'original_name': 'Entrada',
|
||||
'platform': 'netatmo',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': None,
|
||||
'unique_id': '2833524037-DeviceType.NRV',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -293,7 +293,7 @@
|
|||
'Schedule',
|
||||
]),
|
||||
'selected_schedule': 'Default',
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 7,
|
||||
}),
|
||||
|
@ -344,7 +344,7 @@
|
|||
'original_name': 'Livingroom',
|
||||
'platform': 'netatmo',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': None,
|
||||
'unique_id': '2746182631-DeviceType.NATherm1',
|
||||
'unit_of_measurement': None,
|
||||
|
@ -372,7 +372,7 @@
|
|||
'Schedule',
|
||||
]),
|
||||
'selected_schedule': 'Default',
|
||||
'supported_features': <ClimateEntityFeature: 17>,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.5,
|
||||
'temperature': 12,
|
||||
}),
|
||||
|
|
|
@ -29,7 +29,7 @@ async def test_climate_zones(hass: HomeAssistant) -> None:
|
|||
"min_temp": 12.8,
|
||||
"preset_mode": "None",
|
||||
"preset_modes": ["None", "Home", "Away", "Sleep"],
|
||||
"supported_features": 31,
|
||||
"supported_features": 415,
|
||||
"target_temp_high": 26.1,
|
||||
"target_temp_low": 17.2,
|
||||
"target_temp_step": 1.0,
|
||||
|
@ -61,7 +61,7 @@ async def test_climate_zones(hass: HomeAssistant) -> None:
|
|||
"min_temp": 12.8,
|
||||
"preset_mode": "None",
|
||||
"preset_modes": ["None", "Home", "Away", "Sleep"],
|
||||
"supported_features": 31,
|
||||
"supported_features": 415,
|
||||
"target_temp_high": 26.1,
|
||||
"target_temp_low": 17.2,
|
||||
"target_temp_step": 1.0,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -36,7 +36,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_step': 0.5,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
@ -59,7 +59,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -83,7 +83,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_step': 0.5,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
@ -112,7 +112,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -138,7 +138,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -164,7 +164,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -190,7 +190,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -216,7 +216,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -242,7 +242,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -268,7 +268,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -294,7 +294,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -320,7 +320,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -346,7 +346,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -372,7 +372,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -398,7 +398,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -424,7 +424,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -450,7 +450,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': 30.0,
|
||||
'target_temp_low': 21.0,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -476,7 +476,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
@ -502,7 +502,7 @@
|
|||
]),
|
||||
'max_temp': 35.0,
|
||||
'min_temp': 5.0,
|
||||
'supported_features': <ClimateEntityFeature: 3>,
|
||||
'supported_features': <ClimateEntityFeature: 259>,
|
||||
'target_temp_high': None,
|
||||
'target_temp_low': None,
|
||||
'target_temp_step': 0.5,
|
||||
|
|
|
@ -44,7 +44,7 @@ async def test_climate_thermostat_run(hass: HomeAssistant) -> None:
|
|||
"min_temp": 5.0,
|
||||
"preset_mode": "Run Schedule",
|
||||
"preset_modes": ["Run Schedule", "Temporary Hold", "Permanent Hold"],
|
||||
"supported_features": 17,
|
||||
"supported_features": 273,
|
||||
"temperature": 22.2,
|
||||
}
|
||||
# Only test for a subset of attributes in case
|
||||
|
@ -77,7 +77,7 @@ async def test_climate_thermostat_schedule_hold_unavailable(
|
|||
"max_temp": 180.6,
|
||||
"min_temp": -6.1,
|
||||
"preset_modes": ["Run Schedule", "Temporary Hold", "Permanent Hold"],
|
||||
"supported_features": 17,
|
||||
"supported_features": 273,
|
||||
}
|
||||
# Only test for a subset of attributes in case
|
||||
# HA changes the implementation and a new one appears
|
||||
|
@ -110,7 +110,7 @@ async def test_climate_thermostat_schedule_hold_available(hass: HomeAssistant) -
|
|||
"min_temp": -6.1,
|
||||
"preset_mode": "Run Schedule",
|
||||
"preset_modes": ["Run Schedule", "Temporary Hold", "Permanent Hold"],
|
||||
"supported_features": 17,
|
||||
"supported_features": 273,
|
||||
"temperature": 26.1,
|
||||
}
|
||||
# Only test for a subset of attributes in case
|
||||
|
@ -144,7 +144,7 @@ async def test_climate_thermostat_schedule_temporary_hold(hass: HomeAssistant) -
|
|||
"min_temp": -0.6,
|
||||
"preset_mode": "Run Schedule",
|
||||
"preset_modes": ["Run Schedule", "Temporary Hold", "Permanent Hold"],
|
||||
"supported_features": 17,
|
||||
"supported_features": 273,
|
||||
"temperature": 37.2,
|
||||
}
|
||||
# Only test for a subset of attributes in case
|
||||
|
|
|
@ -34,7 +34,7 @@ async def test_adam_climate_entity_attributes(
|
|||
|
||||
assert state.attributes["current_temperature"] == 20.9
|
||||
assert state.attributes["preset_mode"] == "home"
|
||||
assert state.attributes["supported_features"] == 17
|
||||
assert state.attributes["supported_features"] == 273
|
||||
assert state.attributes["temperature"] == 21.5
|
||||
assert state.attributes["min_temp"] == 0.0
|
||||
assert state.attributes["max_temp"] == 35.0
|
||||
|
@ -303,7 +303,7 @@ async def test_anna_climate_entity_attributes(
|
|||
|
||||
assert state.attributes["current_temperature"] == 19.3
|
||||
assert state.attributes["preset_mode"] == "home"
|
||||
assert state.attributes["supported_features"] == 18
|
||||
assert state.attributes["supported_features"] == 274
|
||||
assert state.attributes["target_temp_high"] == 30
|
||||
assert state.attributes["target_temp_low"] == 20.5
|
||||
assert state.attributes["min_temp"] == 4
|
||||
|
@ -325,7 +325,7 @@ async def test_anna_2_climate_entity_attributes(
|
|||
HVACMode.AUTO,
|
||||
HVACMode.HEAT_COOL,
|
||||
]
|
||||
assert state.attributes["supported_features"] == 18
|
||||
assert state.attributes["supported_features"] == 274
|
||||
assert state.attributes["target_temp_high"] == 30
|
||||
assert state.attributes["target_temp_low"] == 20.5
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
]),
|
||||
'max_temp': 20,
|
||||
'min_temp': 10,
|
||||
'supported_features': <ClimateEntityFeature: 41>,
|
||||
'supported_features': <ClimateEntityFeature: 425>,
|
||||
'swing_mode': 'stopped',
|
||||
'swing_modes': list([
|
||||
'stopped',
|
||||
|
|
|
@ -320,6 +320,8 @@ async def test_air_conditioner_entity_state(
|
|||
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.SWING_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert sorted(state.attributes[ATTR_HVAC_MODES]) == [
|
||||
HVACMode.COOL,
|
||||
|
|
|
@ -52,7 +52,9 @@ async def test_thermostat_update(
|
|||
assert state.state == HVACMode.HEAT
|
||||
assert (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
== ClimateEntityFeature.PRESET_MODE | ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
== ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 38
|
||||
assert state.attributes[ATTR_TEMPERATURE] == 39
|
||||
|
|
|
@ -24,7 +24,7 @@ async def test_air_con(hass: HomeAssistant) -> None:
|
|||
"min_temp": 16.0,
|
||||
"preset_mode": "auto",
|
||||
"preset_modes": ["away", "home", "auto"],
|
||||
"supported_features": 25,
|
||||
"supported_features": 409,
|
||||
"target_temp_step": 1,
|
||||
"temperature": 17.8,
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ async def test_heater(hass: HomeAssistant) -> None:
|
|||
"min_temp": 16.0,
|
||||
"preset_mode": "auto",
|
||||
"preset_modes": ["away", "home", "auto"],
|
||||
"supported_features": 17,
|
||||
"supported_features": 401,
|
||||
"target_temp_step": 1,
|
||||
"temperature": 20.5,
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ async def test_smartac_with_swing(hass: HomeAssistant) -> None:
|
|||
"preset_mode": "auto",
|
||||
"preset_modes": ["away", "home", "auto"],
|
||||
"swing_modes": ["on", "off"],
|
||||
"supported_features": 57,
|
||||
"supported_features": 441,
|
||||
"target_temp_step": 1.0,
|
||||
"temperature": 20.0,
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ EXPECTED_BASE_SUPPORTED_FEATURES = (
|
|||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -97,6 +97,8 @@ async def test_static_attributes(
|
|||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.SWING_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert attributes[ATTR_HVAC_MODES] == [
|
||||
HVACMode.COOL,
|
||||
|
|
|
@ -83,6 +83,8 @@ async def test_thermostat_v2(
|
|||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
| ClimateEntityFeature.FAN_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
client.async_send_command.reset_mock()
|
||||
|
@ -330,7 +332,7 @@ async def test_setpoint_thermostat(
|
|||
assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.HEAT]
|
||||
assert (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
client.async_send_command_no_wait.reset_mock()
|
||||
|
@ -432,7 +434,10 @@ async def test_thermostat_heatit_z_trm6(
|
|||
assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE
|
||||
assert (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 5
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 40
|
||||
|
@ -513,6 +518,8 @@ async def test_thermostat_heatit_z_trm3(
|
|||
assert (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 5
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 35
|
||||
|
@ -582,7 +589,10 @@ async def test_thermostat_heatit_z_trm2fx(
|
|||
assert state.attributes[ATTR_TEMPERATURE] == 29
|
||||
assert (
|
||||
state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
== ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
assert state.attributes[ATTR_MIN_TEMP] == 7
|
||||
assert state.attributes[ATTR_MAX_TEMP] == 35
|
||||
|
@ -627,7 +637,7 @@ async def test_thermostat_srt321_hrt4_zw(
|
|||
HVACMode.HEAT,
|
||||
]
|
||||
assert state.attributes[ATTR_CURRENT_TEMPERATURE] is None
|
||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 384
|
||||
|
||||
|
||||
async def test_preset_and_no_setpoint(
|
||||
|
|
Loading…
Reference in New Issue