diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index c315765925f..889ff8cddbd 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -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.""" diff --git a/homeassistant/components/climate/const.py b/homeassistant/components/climate/const.py index 9c9153d9f63..c790b8596a9 100644 --- a/homeassistant/components/climate/const.py +++ b/homeassistant/components/climate/const.py @@ -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. diff --git a/homeassistant/components/climate/services.yaml b/homeassistant/components/climate/services.yaml index 405bb735b66..62952c5aae3 100644 --- a/homeassistant/components/climate/services.yaml +++ b/homeassistant/components/climate/services.yaml @@ -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 diff --git a/tests/components/advantage_air/snapshots/test_climate.ambr b/tests/components/advantage_air/snapshots/test_climate.ambr index 9e21d0ede17..28addf01ecd 100644 --- a/tests/components/advantage_air/snapshots/test_climate.ambr +++ b/tests/components/advantage_air/snapshots/test_climate.ambr @@ -40,7 +40,7 @@ ]), 'max_temp': 32, 'min_temp': 16, - 'supported_features': , + 'supported_features': , 'target_temp_high': 24, 'target_temp_low': 20, 'target_temp_step': 1, diff --git a/tests/components/balboa/test_climate.py b/tests/components/balboa/test_climate.py index 6ba0661ae55..1ec85f60b5d 100644 --- a/tests/components/balboa/test_climate.py +++ b/tests/components/balboa/test_climate.py @@ -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 diff --git a/tests/components/ccm15/snapshots/test_climate.ambr b/tests/components/ccm15/snapshots/test_climate.ambr index 0d4ce32fb8b..05ae0ef5f70 100644 --- a/tests/components/ccm15/snapshots/test_climate.ambr +++ b/tests/components/ccm15/snapshots/test_climate.ambr @@ -45,7 +45,7 @@ 'original_name': None, 'platform': 'ccm15', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , 'swing_mode': 'off', 'swing_modes': list([ 'off', @@ -163,7 +163,7 @@ ]), 'max_temp': 35, 'min_temp': 7, - 'supported_features': , + 'supported_features': , 'swing_mode': 'off', 'swing_modes': list([ 'off', @@ -225,7 +225,7 @@ 'original_name': None, 'platform': 'ccm15', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , 'swing_modes': list([ 'off', 'on', @@ -335,7 +335,7 @@ ]), 'max_temp': 35, 'min_temp': 7, - 'supported_features': , + 'supported_features': , 'swing_modes': list([ 'off', 'on', diff --git a/tests/components/climate/test_init.py b/tests/components/climate/test_init.py index 89826c98086..03d571f8529 100644 --- a/tests/components/climate/test_init.py +++ b/tests/components/climate/test_init.py @@ -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 (.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 (.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 (.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 (.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 + ) diff --git a/tests/components/coolmaster/test_climate.py b/tests/components/coolmaster/test_climate.py index 5f98082e822..0e306faa8ab 100644 --- a/tests/components/coolmaster/test_climate.py +++ b/tests/components/coolmaster/test_climate.py @@ -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 ) diff --git a/tests/components/devolo_home_control/snapshots/test_climate.ambr b/tests/components/devolo_home_control/snapshots/test_climate.ambr index 0e7c5ba547e..26effb7cac6 100644 --- a/tests/components/devolo_home_control/snapshots/test_climate.ambr +++ b/tests/components/devolo_home_control/snapshots/test_climate.ambr @@ -9,7 +9,7 @@ ]), 'max_temp': 24, 'min_temp': 4, - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 20, }), @@ -52,7 +52,7 @@ 'original_name': None, 'platform': 'devolo_home_control', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': 'Test', 'unit_of_measurement': None, diff --git a/tests/components/ecobee/test_climate.py b/tests/components/ecobee/test_climate.py index 8572764ce4d..642e4830016 100644 --- a/tests/components/ecobee/test_climate.py +++ b/tests/components/ecobee/test_climate.py @@ -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 ) diff --git a/tests/components/flexit_bacnet/snapshots/test_climate.ambr b/tests/components/flexit_bacnet/snapshots/test_climate.ambr index cc9c38e370c..f363c99f8f2 100644 --- a/tests/components/flexit_bacnet/snapshots/test_climate.ambr +++ b/tests/components/flexit_bacnet/snapshots/test_climate.ambr @@ -16,7 +16,7 @@ 'home', 'boost', ]), - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 22.0, }), @@ -65,7 +65,7 @@ 'original_name': None, 'platform': 'flexit_bacnet', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': '0000-0001', 'unit_of_measurement': None, diff --git a/tests/components/gree/snapshots/test_climate.ambr b/tests/components/gree/snapshots/test_climate.ambr index e28582ca2e9..fa35b5c1111 100644 --- a/tests/components/gree/snapshots/test_climate.ambr +++ b/tests/components/gree/snapshots/test_climate.ambr @@ -32,7 +32,7 @@ 'none', 'sleep', ]), - 'supported_features': , + 'supported_features': , 'swing_mode': 'off', 'swing_modes': list([ 'off', @@ -110,7 +110,7 @@ 'original_name': None, 'platform': 'gree', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': 'aabbcc112233', 'unit_of_measurement': None, diff --git a/tests/components/homekit_controller/snapshots/test_init.ambr b/tests/components/homekit_controller/snapshots/test_init.ambr index 476ab390217..29b71d18422 100644 --- a/tests/components/homekit_controller/snapshots/test_init.ambr +++ b/tests/components/homekit_controller/snapshots/test_init.ambr @@ -3067,7 +3067,7 @@ 'original_name': 'HomeW', 'platform': 'homekit_controller', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 24.5, }), @@ -12059,7 +12059,7 @@ 'original_name': 'Lennox', 'platform': 'homekit_controller', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , 'temperature': None, }), 'entity_id': 'climate.mysa_85dda9_thermostat', diff --git a/tests/components/homekit_controller/specific_devices/test_ecobee3.py b/tests/components/homekit_controller/specific_devices/test_ecobee3.py index 723881ac182..a4bcf7e962e 100644 --- a/tests/components/homekit_controller/specific_devices/test_ecobee3.py +++ b/tests/components/homekit_controller/specific_devices/test_ecobee3.py @@ -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"], diff --git a/tests/components/homekit_controller/specific_devices/test_heater_cooler_that_changes_features.py b/tests/components/homekit_controller/specific_devices/test_heater_cooler_that_changes_features.py index 79b07512c67..5d0f63b07ff 100644 --- a/tests/components/homekit_controller/specific_devices/test_heater_cooler_that_changes_features.py +++ b/tests/components/homekit_controller/specific_devices/test_heater_cooler_that_changes_features.py @@ -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"] diff --git a/tests/components/honeywell/snapshots/test_climate.ambr b/tests/components/honeywell/snapshots/test_climate.ambr index d589cbfbc9e..d1faf9af9a0 100644 --- a/tests/components/honeywell/snapshots/test_climate.ambr +++ b/tests/components/honeywell/snapshots/test_climate.ambr @@ -30,7 +30,7 @@ 'away', 'hold', ]), - 'supported_features': , + 'supported_features': , 'target_temp_high': None, 'target_temp_low': None, 'temperature': None, diff --git a/tests/components/maxcube/test_maxcube_climate.py b/tests/components/maxcube/test_maxcube_climate.py index 3f2b325330e..76ab214f3ac 100644 --- a/tests/components/maxcube/test_maxcube_climate.py +++ b/tests/components/maxcube/test_maxcube_climate.py @@ -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 diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index 9bb5c8b2585..b1c6cf5ddd8 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -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 diff --git a/tests/components/nest/test_climate.py b/tests/components/nest/test_climate.py index e1c3cc187db..a3698cf0e82 100644 --- a/tests/components/nest/test_climate.py +++ b/tests/components/nest/test_climate.py @@ -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 diff --git a/tests/components/netatmo/snapshots/test_climate.ambr b/tests/components/netatmo/snapshots/test_climate.ambr index 0e7d81a9edb..db02a4300cd 100644 --- a/tests/components/netatmo/snapshots/test_climate.ambr +++ b/tests/components/netatmo/snapshots/test_climate.ambr @@ -38,7 +38,7 @@ 'original_name': 'Bureau', 'platform': 'netatmo', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': '222452125-DeviceType.OTM', 'unit_of_measurement': None, @@ -61,7 +61,7 @@ 'Frost Guard', 'Schedule', ]), - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, }), 'context': , @@ -110,7 +110,7 @@ 'original_name': 'Cocina', 'platform': 'netatmo', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': '2940411577-DeviceType.NRV', 'unit_of_measurement': None, @@ -138,7 +138,7 @@ 'Schedule', ]), 'selected_schedule': 'Default', - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 7, }), @@ -188,7 +188,7 @@ 'original_name': 'Corridor', 'platform': 'netatmo', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': '1002003001-DeviceType.BNS', 'unit_of_measurement': None, @@ -215,7 +215,7 @@ 'Schedule', ]), 'selected_schedule': 'Default', - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 22, }), @@ -265,7 +265,7 @@ 'original_name': 'Entrada', 'platform': 'netatmo', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': '2833524037-DeviceType.NRV', 'unit_of_measurement': None, @@ -293,7 +293,7 @@ 'Schedule', ]), 'selected_schedule': 'Default', - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 7, }), @@ -344,7 +344,7 @@ 'original_name': 'Livingroom', 'platform': 'netatmo', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': '2746182631-DeviceType.NATherm1', 'unit_of_measurement': None, @@ -372,7 +372,7 @@ 'Schedule', ]), 'selected_schedule': 'Default', - 'supported_features': , + 'supported_features': , 'target_temp_step': 0.5, 'temperature': 12, }), diff --git a/tests/components/nexia/test_climate.py b/tests/components/nexia/test_climate.py index 6601e49f597..5553965b418 100644 --- a/tests/components/nexia/test_climate.py +++ b/tests/components/nexia/test_climate.py @@ -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, diff --git a/tests/components/nibe_heatpump/snapshots/test_climate.ambr b/tests/components/nibe_heatpump/snapshots/test_climate.ambr index f19fd69c47d..d7fced91e68 100644 --- a/tests/components/nibe_heatpump/snapshots/test_climate.ambr +++ b/tests/components/nibe_heatpump/snapshots/test_climate.ambr @@ -12,7 +12,7 @@ ]), 'max_temp': 35.0, 'min_temp': 5.0, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , 'target_temp_step': 0.5, }), 'context': , @@ -59,7 +59,7 @@ ]), 'max_temp': 35.0, 'min_temp': 5.0, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , 'target_temp_step': 0.5, }), 'context': , @@ -112,7 +112,7 @@ ]), 'max_temp': 35.0, 'min_temp': 5.0, - 'supported_features': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , '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': , + 'supported_features': , 'target_temp_high': None, 'target_temp_low': None, 'target_temp_step': 0.5, diff --git a/tests/components/nuheat/test_climate.py b/tests/components/nuheat/test_climate.py index 7a0e21485c8..73a07efcc3d 100644 --- a/tests/components/nuheat/test_climate.py +++ b/tests/components/nuheat/test_climate.py @@ -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 diff --git a/tests/components/plugwise/test_climate.py b/tests/components/plugwise/test_climate.py index c5ab3a209c2..1be4cc2a34f 100644 --- a/tests/components/plugwise/test_climate.py +++ b/tests/components/plugwise/test_climate.py @@ -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 diff --git a/tests/components/sensibo/snapshots/test_climate.ambr b/tests/components/sensibo/snapshots/test_climate.ambr index 0a5a9d78b1b..1e02ee63a9a 100644 --- a/tests/components/sensibo/snapshots/test_climate.ambr +++ b/tests/components/sensibo/snapshots/test_climate.ambr @@ -20,7 +20,7 @@ ]), 'max_temp': 20, 'min_temp': 10, - 'supported_features': , + 'supported_features': , 'swing_mode': 'stopped', 'swing_modes': list([ 'stopped', diff --git a/tests/components/smartthings/test_climate.py b/tests/components/smartthings/test_climate.py index e74d69f04c9..ae6e5734e75 100644 --- a/tests/components/smartthings/test_climate.py +++ b/tests/components/smartthings/test_climate.py @@ -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, diff --git a/tests/components/smarttub/test_climate.py b/tests/components/smarttub/test_climate.py index 40e3c05b509..cafb156d113 100644 --- a/tests/components/smarttub/test_climate.py +++ b/tests/components/smarttub/test_climate.py @@ -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 diff --git a/tests/components/tado/test_climate.py b/tests/components/tado/test_climate.py index fd4ae87ac64..91bc1af191e 100644 --- a/tests/components/tado/test_climate.py +++ b/tests/components/tado/test_climate.py @@ -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, } diff --git a/tests/components/venstar/test_climate.py b/tests/components/venstar/test_climate.py index 8aa3065e3c4..d7c28b953cc 100644 --- a/tests/components/venstar/test_climate.py +++ b/tests/components/venstar/test_climate.py @@ -10,6 +10,8 @@ EXPECTED_BASE_SUPPORTED_FEATURES = ( ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE | ClimateEntityFeature.PRESET_MODE + | ClimateEntityFeature.TURN_OFF + | ClimateEntityFeature.TURN_ON ) diff --git a/tests/components/whirlpool/test_climate.py b/tests/components/whirlpool/test_climate.py index 8607a49b42c..0cc58e80f0d 100644 --- a/tests/components/whirlpool/test_climate.py +++ b/tests/components/whirlpool/test_climate.py @@ -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, diff --git a/tests/components/zwave_js/test_climate.py b/tests/components/zwave_js/test_climate.py index b2e7c313916..5f75f7c8307 100644 --- a/tests/components/zwave_js/test_climate.py +++ b/tests/components/zwave_js/test_climate.py @@ -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(