diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index 633300af591..1f365b07099 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -32,6 +32,11 @@ from homeassistant.helpers.config_validation import ( # noqa: F401 PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, ) +from homeassistant.helpers.deprecation import ( + DeprecatedConstantEnum, + check_if_deprecated_constant, + dir_with_deprecated_constants, +) from homeassistant.helpers.entity import Entity, EntityDescription from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.typing import ConfigType @@ -69,16 +74,32 @@ DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.Coerce(CoverDeviceClass)) # DEVICE_CLASS* below are deprecated as of 2021.12 # use the CoverDeviceClass enum instead. DEVICE_CLASSES = [cls.value for cls in CoverDeviceClass] -DEVICE_CLASS_AWNING = CoverDeviceClass.AWNING.value -DEVICE_CLASS_BLIND = CoverDeviceClass.BLIND.value -DEVICE_CLASS_CURTAIN = CoverDeviceClass.CURTAIN.value -DEVICE_CLASS_DAMPER = CoverDeviceClass.DAMPER.value -DEVICE_CLASS_DOOR = CoverDeviceClass.DOOR.value -DEVICE_CLASS_GARAGE = CoverDeviceClass.GARAGE.value -DEVICE_CLASS_GATE = CoverDeviceClass.GATE.value -DEVICE_CLASS_SHADE = CoverDeviceClass.SHADE.value -DEVICE_CLASS_SHUTTER = CoverDeviceClass.SHUTTER.value -DEVICE_CLASS_WINDOW = CoverDeviceClass.WINDOW.value +_DEPRECATED_DEVICE_CLASS_AWNING = DeprecatedConstantEnum( + CoverDeviceClass.AWNING, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_BLIND = DeprecatedConstantEnum( + CoverDeviceClass.BLIND, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_CURTAIN = DeprecatedConstantEnum( + CoverDeviceClass.CURTAIN, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_DAMPER = DeprecatedConstantEnum( + CoverDeviceClass.DAMPER, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_DOOR = DeprecatedConstantEnum(CoverDeviceClass.DOOR, "2025.1") +_DEPRECATED_DEVICE_CLASS_GARAGE = DeprecatedConstantEnum( + CoverDeviceClass.GARAGE, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_GATE = DeprecatedConstantEnum(CoverDeviceClass.GATE, "2025.1") +_DEPRECATED_DEVICE_CLASS_SHADE = DeprecatedConstantEnum( + CoverDeviceClass.SHADE, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_SHUTTER = DeprecatedConstantEnum( + CoverDeviceClass.SHUTTER, "2025.1" +) +_DEPRECATED_DEVICE_CLASS_WINDOW = DeprecatedConstantEnum( + CoverDeviceClass.WINDOW, "2025.1" +) # mypy: disallow-any-generics @@ -98,14 +119,28 @@ class CoverEntityFeature(IntFlag): # These SUPPORT_* constants are deprecated as of Home Assistant 2022.5. # Please use the CoverEntityFeature enum instead. -SUPPORT_OPEN = 1 -SUPPORT_CLOSE = 2 -SUPPORT_SET_POSITION = 4 -SUPPORT_STOP = 8 -SUPPORT_OPEN_TILT = 16 -SUPPORT_CLOSE_TILT = 32 -SUPPORT_STOP_TILT = 64 -SUPPORT_SET_TILT_POSITION = 128 +_DEPRECATED_SUPPORT_OPEN = DeprecatedConstantEnum(CoverEntityFeature.OPEN, "2025.1") +_DEPRECATED_SUPPORT_CLOSE = DeprecatedConstantEnum(CoverEntityFeature.CLOSE, "2025.1") +_DEPRECATED_SUPPORT_SET_POSITION = DeprecatedConstantEnum( + CoverEntityFeature.SET_POSITION, "2025.1" +) +_DEPRECATED_SUPPORT_STOP = DeprecatedConstantEnum(CoverEntityFeature.STOP, "2025.1") +_DEPRECATED_SUPPORT_OPEN_TILT = DeprecatedConstantEnum( + CoverEntityFeature.OPEN_TILT, "2025.1" +) +_DEPRECATED_SUPPORT_CLOSE_TILT = DeprecatedConstantEnum( + CoverEntityFeature.CLOSE_TILT, "2025.1" +) +_DEPRECATED_SUPPORT_STOP_TILT = DeprecatedConstantEnum( + CoverEntityFeature.STOP_TILT, "2025.1" +) +_DEPRECATED_SUPPORT_SET_TILT_POSITION = DeprecatedConstantEnum( + CoverEntityFeature.SET_TILT_POSITION, "2025.1" +) + +# Both can be removed if no deprecated constant are in this module anymore +__getattr__ = ft.partial(check_if_deprecated_constant, module_globals=globals()) +__dir__ = ft.partial(dir_with_deprecated_constants, module_globals=globals()) ATTR_CURRENT_POSITION = "current_position" ATTR_CURRENT_TILT_POSITION = "current_tilt_position" diff --git a/homeassistant/components/cover/device_action.py b/homeassistant/components/cover/device_action.py index e34a623be93..2224e5bab1c 100644 --- a/homeassistant/components/cover/device_action.py +++ b/homeassistant/components/cover/device_action.py @@ -24,18 +24,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import get_supported_features from homeassistant.helpers.typing import ConfigType, TemplateVarsType -from . import ( - ATTR_POSITION, - ATTR_TILT_POSITION, - DOMAIN, - SUPPORT_CLOSE, - SUPPORT_CLOSE_TILT, - SUPPORT_OPEN, - SUPPORT_OPEN_TILT, - SUPPORT_SET_POSITION, - SUPPORT_SET_TILT_POSITION, - SUPPORT_STOP, -) +from . import ATTR_POSITION, ATTR_TILT_POSITION, DOMAIN, CoverEntityFeature CMD_ACTION_TYPES = {"open", "close", "stop", "open_tilt", "close_tilt"} POSITION_ACTION_TYPES = {"set_position", "set_tilt_position"} @@ -88,20 +77,20 @@ async def async_get_actions( CONF_ENTITY_ID: entry.id, } - if supported_features & SUPPORT_SET_POSITION: + if supported_features & CoverEntityFeature.SET_POSITION: actions.append({**base_action, CONF_TYPE: "set_position"}) - if supported_features & SUPPORT_OPEN: + if supported_features & CoverEntityFeature.OPEN: actions.append({**base_action, CONF_TYPE: "open"}) - if supported_features & SUPPORT_CLOSE: + if supported_features & CoverEntityFeature.CLOSE: actions.append({**base_action, CONF_TYPE: "close"}) - if supported_features & SUPPORT_STOP: + if supported_features & CoverEntityFeature.STOP: actions.append({**base_action, CONF_TYPE: "stop"}) - if supported_features & SUPPORT_SET_TILT_POSITION: + if supported_features & CoverEntityFeature.SET_TILT_POSITION: actions.append({**base_action, CONF_TYPE: "set_tilt_position"}) - if supported_features & SUPPORT_OPEN_TILT: + if supported_features & CoverEntityFeature.OPEN_TILT: actions.append({**base_action, CONF_TYPE: "open_tilt"}) - if supported_features & SUPPORT_CLOSE_TILT: + if supported_features & CoverEntityFeature.CLOSE_TILT: actions.append({**base_action, CONF_TYPE: "close_tilt"}) return actions diff --git a/homeassistant/components/cover/device_condition.py b/homeassistant/components/cover/device_condition.py index 2aa0a1dd2fb..23ec7d75650 100644 --- a/homeassistant/components/cover/device_condition.py +++ b/homeassistant/components/cover/device_condition.py @@ -26,13 +26,7 @@ from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA from homeassistant.helpers.entity import get_supported_features from homeassistant.helpers.typing import ConfigType, TemplateVarsType -from . import ( - DOMAIN, - SUPPORT_CLOSE, - SUPPORT_OPEN, - SUPPORT_SET_POSITION, - SUPPORT_SET_TILT_POSITION, -) +from . import DOMAIN, CoverEntityFeature # mypy: disallow-any-generics @@ -78,7 +72,9 @@ async def async_get_conditions( continue supported_features = get_supported_features(hass, entry.entity_id) - supports_open_close = supported_features & (SUPPORT_OPEN | SUPPORT_CLOSE) + supports_open_close = supported_features & ( + CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE + ) # Add conditions for each entity that belongs to this integration base_condition = { @@ -92,9 +88,9 @@ async def async_get_conditions( conditions += [ {**base_condition, CONF_TYPE: cond} for cond in STATE_CONDITION_TYPES ] - if supported_features & SUPPORT_SET_POSITION: + if supported_features & CoverEntityFeature.SET_POSITION: conditions.append({**base_condition, CONF_TYPE: "is_position"}) - if supported_features & SUPPORT_SET_TILT_POSITION: + if supported_features & CoverEntityFeature.SET_TILT_POSITION: conditions.append({**base_condition, CONF_TYPE: "is_tilt_position"}) return conditions diff --git a/homeassistant/components/cover/device_trigger.py b/homeassistant/components/cover/device_trigger.py index 2fb456d726d..8225348619d 100644 --- a/homeassistant/components/cover/device_trigger.py +++ b/homeassistant/components/cover/device_trigger.py @@ -29,13 +29,7 @@ from homeassistant.helpers.entity import get_supported_features from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo from homeassistant.helpers.typing import ConfigType -from . import ( - DOMAIN, - SUPPORT_CLOSE, - SUPPORT_OPEN, - SUPPORT_SET_POSITION, - SUPPORT_SET_TILT_POSITION, -) +from . import DOMAIN, CoverEntityFeature POSITION_TRIGGER_TYPES = {"position", "tilt_position"} STATE_TRIGGER_TYPES = {"opened", "closed", "opening", "closing"} @@ -80,7 +74,9 @@ async def async_get_triggers( continue supported_features = get_supported_features(hass, entry.entity_id) - supports_open_close = supported_features & (SUPPORT_OPEN | SUPPORT_CLOSE) + supports_open_close = supported_features & ( + CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE + ) # Add triggers for each entity that belongs to this integration base_trigger = { @@ -98,14 +94,14 @@ async def async_get_triggers( } for trigger in STATE_TRIGGER_TYPES ] - if supported_features & SUPPORT_SET_POSITION: + if supported_features & CoverEntityFeature.SET_POSITION: triggers.append( { **base_trigger, CONF_TYPE: "position", } ) - if supported_features & SUPPORT_SET_TILT_POSITION: + if supported_features & CoverEntityFeature.SET_TILT_POSITION: triggers.append( { **base_trigger, diff --git a/tests/components/cover/test_init.py b/tests/components/cover/test_init.py index 802bf759d81..062440e6b39 100644 --- a/tests/components/cover/test_init.py +++ b/tests/components/cover/test_init.py @@ -1,4 +1,8 @@ """The tests for Cover.""" +from enum import Enum + +import pytest + import homeassistant.components.cover as cover from homeassistant.const import ( ATTR_ENTITY_ID, @@ -12,6 +16,8 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component +from tests.common import import_and_test_deprecated_constant_enum + async def test_services(hass: HomeAssistant, enable_custom_integrations: None) -> None: """Test the provided services.""" @@ -112,3 +118,26 @@ def is_closed(hass, ent): def is_closing(hass, ent): """Return if the cover is closed based on the statemachine.""" return hass.states.is_state(ent.entity_id, STATE_CLOSING) + + +def _create_tuples(enum: Enum, constant_prefix: str) -> list[tuple[Enum, str]]: + result = [] + for enum in enum: + result.append((enum, constant_prefix)) + return result + + +@pytest.mark.parametrize( + ("enum", "constant_prefix"), + _create_tuples(cover.CoverEntityFeature, "SUPPORT_") + + _create_tuples(cover.CoverDeviceClass, "DEVICE_CLASS_"), +) +def test_deprecated_constants( + caplog: pytest.LogCaptureFixture, + enum: Enum, + constant_prefix: str, +) -> None: + """Test deprecated constants.""" + import_and_test_deprecated_constant_enum( + caplog, cover, enum, constant_prefix, "2025.1" + ) diff --git a/tests/components/tasmota/test_cover.py b/tests/components/tasmota/test_cover.py index cae65521e21..26f8dee4a9d 100644 --- a/tests/components/tasmota/test_cover.py +++ b/tests/components/tasmota/test_cover.py @@ -35,16 +35,16 @@ from tests.common import async_fire_mqtt_message from tests.typing import MqttMockHAClient, MqttMockPahoClient COVER_SUPPORT = ( - cover.SUPPORT_OPEN - | cover.SUPPORT_CLOSE - | cover.SUPPORT_STOP - | cover.SUPPORT_SET_POSITION + cover.CoverEntityFeature.OPEN + | cover.CoverEntityFeature.CLOSE + | cover.CoverEntityFeature.STOP + | cover.CoverEntityFeature.SET_POSITION ) TILT_SUPPORT = ( - cover.SUPPORT_OPEN_TILT - | cover.SUPPORT_CLOSE_TILT - | cover.SUPPORT_STOP_TILT - | cover.SUPPORT_SET_TILT_POSITION + cover.CoverEntityFeature.OPEN_TILT + | cover.CoverEntityFeature.CLOSE_TILT + | cover.CoverEntityFeature.STOP_TILT + | cover.CoverEntityFeature.SET_TILT_POSITION ) diff --git a/tests/testing_config/custom_components/test/cover.py b/tests/testing_config/custom_components/test/cover.py index 51a4a9dc83b..2a57412ea9e 100644 --- a/tests/testing_config/custom_components/test/cover.py +++ b/tests/testing_config/custom_components/test/cover.py @@ -2,17 +2,7 @@ Call init before using it in your tests to ensure clean test data. """ -from homeassistant.components.cover import ( - SUPPORT_CLOSE, - SUPPORT_CLOSE_TILT, - SUPPORT_OPEN, - SUPPORT_OPEN_TILT, - SUPPORT_SET_POSITION, - SUPPORT_SET_TILT_POSITION, - SUPPORT_STOP, - SUPPORT_STOP_TILT, - CoverEntity, -) +from homeassistant.components.cover import CoverEntity, CoverEntityFeature from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING from tests.common import MockEntity @@ -32,38 +22,38 @@ def init(empty=False): name="Simple cover", is_on=True, unique_id="unique_cover", - supported_features=SUPPORT_OPEN | SUPPORT_CLOSE, + supported_features=CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE, ), MockCover( name="Set position cover", is_on=True, unique_id="unique_set_pos_cover", current_cover_position=50, - supported_features=SUPPORT_OPEN - | SUPPORT_CLOSE - | SUPPORT_STOP - | SUPPORT_SET_POSITION, + supported_features=CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.STOP + | CoverEntityFeature.SET_POSITION, ), MockCover( name="Simple tilt cover", is_on=True, unique_id="unique_tilt_cover", - supported_features=SUPPORT_OPEN - | SUPPORT_CLOSE - | SUPPORT_OPEN_TILT - | SUPPORT_CLOSE_TILT, + supported_features=CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.OPEN_TILT + | CoverEntityFeature.CLOSE_TILT, ), MockCover( name="Set tilt position cover", is_on=True, unique_id="unique_set_pos_tilt_cover", current_cover_tilt_position=50, - supported_features=SUPPORT_OPEN - | SUPPORT_CLOSE - | SUPPORT_OPEN_TILT - | SUPPORT_CLOSE_TILT - | SUPPORT_STOP_TILT - | SUPPORT_SET_TILT_POSITION, + supported_features=CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.OPEN_TILT + | CoverEntityFeature.CLOSE_TILT + | CoverEntityFeature.STOP_TILT + | CoverEntityFeature.SET_TILT_POSITION, ), MockCover( name="All functions cover", @@ -71,14 +61,14 @@ def init(empty=False): unique_id="unique_all_functions_cover", current_cover_position=50, current_cover_tilt_position=50, - supported_features=SUPPORT_OPEN - | SUPPORT_CLOSE - | SUPPORT_STOP - | SUPPORT_SET_POSITION - | SUPPORT_OPEN_TILT - | SUPPORT_CLOSE_TILT - | SUPPORT_STOP_TILT - | SUPPORT_SET_TILT_POSITION, + supported_features=CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.STOP + | CoverEntityFeature.SET_POSITION + | CoverEntityFeature.OPEN_TILT + | CoverEntityFeature.CLOSE_TILT + | CoverEntityFeature.STOP_TILT + | CoverEntityFeature.SET_TILT_POSITION, ), ] ) @@ -97,7 +87,7 @@ class MockCover(MockEntity, CoverEntity): @property def is_closed(self): """Return if the cover is closed or not.""" - if self.supported_features & SUPPORT_STOP: + if self.supported_features & CoverEntityFeature.STOP: return self.current_cover_position == 0 if "state" in self._values: @@ -107,7 +97,7 @@ class MockCover(MockEntity, CoverEntity): @property def is_opening(self): """Return if the cover is opening or not.""" - if self.supported_features & SUPPORT_STOP: + if self.supported_features & CoverEntityFeature.STOP: if "state" in self._values: return self._values["state"] == STATE_OPENING @@ -116,7 +106,7 @@ class MockCover(MockEntity, CoverEntity): @property def is_closing(self): """Return if the cover is closing or not.""" - if self.supported_features & SUPPORT_STOP: + if self.supported_features & CoverEntityFeature.STOP: if "state" in self._values: return self._values["state"] == STATE_CLOSING @@ -124,14 +114,14 @@ class MockCover(MockEntity, CoverEntity): def open_cover(self, **kwargs) -> None: """Open cover.""" - if self.supported_features & SUPPORT_STOP: + if self.supported_features & CoverEntityFeature.STOP: self._values["state"] = STATE_OPENING else: self._values["state"] = STATE_OPEN def close_cover(self, **kwargs) -> None: """Close cover.""" - if self.supported_features & SUPPORT_STOP: + if self.supported_features & CoverEntityFeature.STOP: self._values["state"] = STATE_CLOSING else: self._values["state"] = STATE_CLOSED