diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index 921a6b9c3a1d..189b05ef328c 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -6,11 +6,10 @@ import logging import math from typing import Any, final, override -import probatio from propcache.api import cached_property from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ( +from homeassistant.const import ( # noqa: F401 SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON, @@ -22,45 +21,41 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import ToggleEntity, ToggleEntityDescription from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.typing import ConfigType -from homeassistant.util.hass_dict import HassKey from homeassistant.util.percentage import ( percentage_to_ranged_value, ranged_value_to_percentage, ) -from .const import ( +from .const import ( # noqa: F401 + ATTR_DIRECTION, + ATTR_OSCILLATING, + ATTR_PERCENTAGE, + ATTR_PERCENTAGE_STEP, + ATTR_PRESET_MODE, + ATTR_PRESET_MODES, + DATA_COMPONENT, + DIRECTION_FORWARD, + DIRECTION_REVERSE, DOMAIN, + SERVICE_DECREASE_SPEED, + SERVICE_INCREASE_SPEED, + SERVICE_OSCILLATE, + SERVICE_SET_DIRECTION, + SERVICE_SET_PERCENTAGE, + SERVICE_SET_PRESET_MODE, FanEntityCapabilityAttribute, FanEntityFeature, FanEntityStateAttribute, ) +from .services import async_setup_services _LOGGER = logging.getLogger(__name__) -DATA_COMPONENT: HassKey[EntityComponent[FanEntity]] = HassKey(DOMAIN) ENTITY_ID_FORMAT = DOMAIN + ".{}" PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA PLATFORM_SCHEMA_BASE = cv.PLATFORM_SCHEMA_BASE SCAN_INTERVAL = timedelta(seconds=30) - -SERVICE_INCREASE_SPEED = "increase_speed" -SERVICE_DECREASE_SPEED = "decrease_speed" -SERVICE_OSCILLATE = "oscillate" -SERVICE_SET_DIRECTION = "set_direction" -SERVICE_SET_PERCENTAGE = "set_percentage" -SERVICE_SET_PRESET_MODE = "set_preset_mode" - -DIRECTION_FORWARD = "forward" -DIRECTION_REVERSE = "reverse" - -ATTR_PERCENTAGE = "percentage" -ATTR_PERCENTAGE_STEP = "percentage_step" -ATTR_OSCILLATING = "oscillating" -ATTR_DIRECTION = "direction" -ATTR_PRESET_MODE = "preset_mode" -ATTR_PRESET_MODES = "preset_modes" - # mypy: disallow-any-generics @@ -94,76 +89,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: await component.async_setup(config) - # After the transition to percentage and preset_modes concludes, - # switch this back to async_turn_on and remove async_turn_on_compat - component.async_register_entity_service( - SERVICE_TURN_ON, - { - probatio.Optional(ATTR_PERCENTAGE): probatio.All( - probatio.Coerce(int), probatio.Range(min=0, max=100) - ), - probatio.Optional(ATTR_PRESET_MODE): cv.string, - }, - "async_handle_turn_on_service", - [FanEntityFeature.TURN_ON], - ) - component.async_register_entity_service( - SERVICE_TURN_OFF, None, "async_turn_off", [FanEntityFeature.TURN_OFF] - ) - component.async_register_entity_service( - SERVICE_TOGGLE, - None, - "async_toggle", - [FanEntityFeature.TURN_OFF, FanEntityFeature.TURN_ON], - ) - component.async_register_entity_service( - SERVICE_INCREASE_SPEED, - { - probatio.Optional(ATTR_PERCENTAGE_STEP): probatio.All( - probatio.Coerce(int), probatio.Range(min=0, max=100) - ) - }, - "async_increase_speed", - [FanEntityFeature.SET_SPEED], - ) - component.async_register_entity_service( - SERVICE_DECREASE_SPEED, - { - probatio.Optional(ATTR_PERCENTAGE_STEP): probatio.All( - probatio.Coerce(int), probatio.Range(min=0, max=100) - ) - }, - "async_decrease_speed", - [FanEntityFeature.SET_SPEED], - ) - component.async_register_entity_service( - SERVICE_OSCILLATE, - {probatio.Required(ATTR_OSCILLATING): cv.boolean}, - "async_oscillate", - [FanEntityFeature.OSCILLATE], - ) - component.async_register_entity_service( - SERVICE_SET_DIRECTION, - {probatio.Optional(ATTR_DIRECTION): cv.string}, - "async_set_direction", - [FanEntityFeature.DIRECTION], - ) - component.async_register_entity_service( - SERVICE_SET_PERCENTAGE, - { - probatio.Required(ATTR_PERCENTAGE): probatio.All( - probatio.Coerce(int), probatio.Range(min=0, max=100) - ) - }, - "async_set_percentage", - [FanEntityFeature.SET_SPEED], - ) - component.async_register_entity_service( - SERVICE_SET_PRESET_MODE, - {probatio.Required(ATTR_PRESET_MODE): cv.string}, - "async_handle_set_preset_mode_service", - [FanEntityFeature.SET_SPEED, FanEntityFeature.PRESET_MODE], - ) + async_setup_services(hass) return True diff --git a/homeassistant/components/fan/const.py b/homeassistant/components/fan/const.py index 1d565787f214..97893dba4210 100644 --- a/homeassistant/components/fan/const.py +++ b/homeassistant/components/fan/const.py @@ -1,9 +1,34 @@ """Constants for the fan component.""" from enum import IntFlag, StrEnum -from typing import Final +from typing import TYPE_CHECKING, Final + +from homeassistant.util.hass_dict import HassKey + +if TYPE_CHECKING: + from homeassistant.helpers.entity_component import EntityComponent + + from . import FanEntity DOMAIN: Final = "fan" +DATA_COMPONENT: HassKey[EntityComponent[FanEntity]] = HassKey(DOMAIN) + +SERVICE_INCREASE_SPEED = "increase_speed" +SERVICE_DECREASE_SPEED = "decrease_speed" +SERVICE_OSCILLATE = "oscillate" +SERVICE_SET_DIRECTION = "set_direction" +SERVICE_SET_PERCENTAGE = "set_percentage" +SERVICE_SET_PRESET_MODE = "set_preset_mode" + +DIRECTION_FORWARD = "forward" +DIRECTION_REVERSE = "reverse" + +ATTR_PERCENTAGE = "percentage" +ATTR_PERCENTAGE_STEP = "percentage_step" +ATTR_OSCILLATING = "oscillating" +ATTR_DIRECTION = "direction" +ATTR_PRESET_MODE = "preset_mode" +ATTR_PRESET_MODES = "preset_modes" class FanEntityCapabilityAttribute(StrEnum): diff --git a/homeassistant/components/fan/services.py b/homeassistant/components/fan/services.py new file mode 100644 index 000000000000..63f0c0e00fec --- /dev/null +++ b/homeassistant/components/fan/services.py @@ -0,0 +1,100 @@ +"""Services for the Fan integration.""" + +import probatio + +from homeassistant.const import SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import config_validation as cv + +from .const import ( + ATTR_DIRECTION, + ATTR_OSCILLATING, + ATTR_PERCENTAGE, + ATTR_PERCENTAGE_STEP, + ATTR_PRESET_MODE, + DATA_COMPONENT, + SERVICE_DECREASE_SPEED, + SERVICE_INCREASE_SPEED, + SERVICE_OSCILLATE, + SERVICE_SET_DIRECTION, + SERVICE_SET_PERCENTAGE, + SERVICE_SET_PRESET_MODE, + FanEntityFeature, +) + + +@callback +def async_setup_services(hass: HomeAssistant) -> None: + """Register the fan services.""" + component = hass.data[DATA_COMPONENT] + + # After the transition to percentage and preset_modes concludes, + # switch this back to async_turn_on and remove async_turn_on_compat + component.async_register_entity_service( + SERVICE_TURN_ON, + { + probatio.Optional(ATTR_PERCENTAGE): probatio.All( + probatio.Coerce(int), probatio.Range(min=0, max=100) + ), + probatio.Optional(ATTR_PRESET_MODE): cv.string, + }, + "async_handle_turn_on_service", + [FanEntityFeature.TURN_ON], + ) + component.async_register_entity_service( + SERVICE_TURN_OFF, None, "async_turn_off", [FanEntityFeature.TURN_OFF] + ) + component.async_register_entity_service( + SERVICE_TOGGLE, + None, + "async_toggle", + [FanEntityFeature.TURN_OFF, FanEntityFeature.TURN_ON], + ) + component.async_register_entity_service( + SERVICE_INCREASE_SPEED, + { + probatio.Optional(ATTR_PERCENTAGE_STEP): probatio.All( + probatio.Coerce(int), probatio.Range(min=0, max=100) + ) + }, + "async_increase_speed", + [FanEntityFeature.SET_SPEED], + ) + component.async_register_entity_service( + SERVICE_DECREASE_SPEED, + { + probatio.Optional(ATTR_PERCENTAGE_STEP): probatio.All( + probatio.Coerce(int), probatio.Range(min=0, max=100) + ) + }, + "async_decrease_speed", + [FanEntityFeature.SET_SPEED], + ) + component.async_register_entity_service( + SERVICE_OSCILLATE, + {probatio.Required(ATTR_OSCILLATING): cv.boolean}, + "async_oscillate", + [FanEntityFeature.OSCILLATE], + ) + component.async_register_entity_service( + SERVICE_SET_DIRECTION, + {probatio.Optional(ATTR_DIRECTION): cv.string}, + "async_set_direction", + [FanEntityFeature.DIRECTION], + ) + component.async_register_entity_service( + SERVICE_SET_PERCENTAGE, + { + probatio.Required(ATTR_PERCENTAGE): probatio.All( + probatio.Coerce(int), probatio.Range(min=0, max=100) + ) + }, + "async_set_percentage", + [FanEntityFeature.SET_SPEED], + ) + component.async_register_entity_service( + SERVICE_SET_PRESET_MODE, + {probatio.Required(ATTR_PRESET_MODE): cv.string}, + "async_handle_set_preset_mode_service", + [FanEntityFeature.SET_SPEED, FanEntityFeature.PRESET_MODE], + )