From 28703698b2b6b9b86d4cf9622232b469b1a596d0 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 21 Sep 2026 18:42:04 +0200 Subject: [PATCH] Move remote service registration to services module (#182818) --- homeassistant/components/remote/__init__.py | 104 +++++--------------- homeassistant/components/remote/const.py | 30 +++++- homeassistant/components/remote/services.py | 88 +++++++++++++++++ 3 files changed, 143 insertions(+), 79 deletions(-) create mode 100644 homeassistant/components/remote/services.py diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index aab883a5961f..85c81fc4921c 100644 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -6,11 +6,10 @@ import functools as ft import logging 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 ATTR_COMMAND, SERVICE_TOGGLE, SERVICE_TURN_OFF, @@ -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 .const import DOMAIN, RemoteEntityFeature, RemoteEntityStateAttribute +from .const import ( # noqa: F401 + ATTR_ACTIVITY, + ATTR_ACTIVITY_LIST, + ATTR_ALTERNATIVE, + ATTR_COMMAND_TYPE, + ATTR_CURRENT_ACTIVITY, + ATTR_DELAY_SECS, + ATTR_DEVICE, + ATTR_HOLD_SECS, + ATTR_NUM_REPEATS, + ATTR_TIMEOUT, + DATA_COMPONENT, + DEFAULT_DELAY_SECS, + DEFAULT_HOLD_SECS, + DEFAULT_NUM_REPEATS, + DOMAIN, + SERVICE_DELETE_COMMAND, + SERVICE_LEARN_COMMAND, + SERVICE_SEND_COMMAND, + SERVICE_SYNC, + RemoteEntityFeature, + RemoteEntityStateAttribute, +) +from .services import async_setup_services _LOGGER = logging.getLogger(__name__) -DATA_COMPONENT: HassKey[EntityComponent[RemoteEntity]] = HassKey(DOMAIN) ENTITY_ID_FORMAT = DOMAIN + ".{}" PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA PLATFORM_SCHEMA_BASE = cv.PLATFORM_SCHEMA_BASE SCAN_INTERVAL = timedelta(seconds=30) -ATTR_ACTIVITY = "activity" -ATTR_ACTIVITY_LIST = "activity_list" -ATTR_CURRENT_ACTIVITY = "current_activity" -ATTR_COMMAND_TYPE = "command_type" -ATTR_DEVICE = "device" -ATTR_NUM_REPEATS = "num_repeats" -ATTR_DELAY_SECS = "delay_secs" -ATTR_HOLD_SECS = "hold_secs" -ATTR_ALTERNATIVE = "alternative" -ATTR_TIMEOUT = "timeout" - MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) -SERVICE_SEND_COMMAND = "send_command" -SERVICE_LEARN_COMMAND = "learn_command" -SERVICE_DELETE_COMMAND = "delete_command" -SERVICE_SYNC = "sync" - -DEFAULT_NUM_REPEATS = 1 -DEFAULT_DELAY_SECS = 0.4 -DEFAULT_HOLD_SECS = 0 - - -REMOTE_SERVICE_ACTIVITY_SCHEMA = cv.make_entity_service_schema( - {probatio.Optional(ATTR_ACTIVITY): cv.string} -) - def is_on(hass: HomeAssistant, entity_id: str) -> bool: """Return if the remote is on based on the statemachine.""" @@ -74,54 +69,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: ) await component.async_setup(config) - component.async_register_entity_service( - SERVICE_TURN_OFF, REMOTE_SERVICE_ACTIVITY_SCHEMA, "async_turn_off" - ) - - component.async_register_entity_service( - SERVICE_TURN_ON, REMOTE_SERVICE_ACTIVITY_SCHEMA, "async_turn_on" - ) - - component.async_register_entity_service( - SERVICE_TOGGLE, REMOTE_SERVICE_ACTIVITY_SCHEMA, "async_toggle" - ) - - component.async_register_entity_service( - SERVICE_SEND_COMMAND, - { - probatio.Required(ATTR_COMMAND): probatio.All(cv.ensure_list, [cv.string]), - probatio.Optional(ATTR_DEVICE): cv.string, - probatio.Optional( - ATTR_NUM_REPEATS, default=DEFAULT_NUM_REPEATS - ): cv.positive_int, - probatio.Optional(ATTR_DELAY_SECS): probatio.Coerce(float), - probatio.Optional( - ATTR_HOLD_SECS, default=DEFAULT_HOLD_SECS - ): probatio.Coerce(float), - }, - "async_send_command", - ) - - component.async_register_entity_service( - SERVICE_LEARN_COMMAND, - { - probatio.Optional(ATTR_DEVICE): cv.string, - probatio.Optional(ATTR_COMMAND): probatio.All(cv.ensure_list, [cv.string]), - probatio.Optional(ATTR_COMMAND_TYPE): cv.string, - probatio.Optional(ATTR_ALTERNATIVE): cv.boolean, - probatio.Optional(ATTR_TIMEOUT): cv.positive_int, - }, - "async_learn_command", - ) - - component.async_register_entity_service( - SERVICE_DELETE_COMMAND, - { - probatio.Required(ATTR_COMMAND): probatio.All(cv.ensure_list, [cv.string]), - probatio.Optional(ATTR_DEVICE): cv.string, - }, - "async_delete_command", - ) + async_setup_services(hass) return True diff --git a/homeassistant/components/remote/const.py b/homeassistant/components/remote/const.py index 72aa671df923..ac35c5d20112 100644 --- a/homeassistant/components/remote/const.py +++ b/homeassistant/components/remote/const.py @@ -1,9 +1,37 @@ """Constants for the remote 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 RemoteEntity DOMAIN: Final = "remote" +DATA_COMPONENT: HassKey[EntityComponent[RemoteEntity]] = HassKey(DOMAIN) + +ATTR_ACTIVITY = "activity" +ATTR_ACTIVITY_LIST = "activity_list" +ATTR_CURRENT_ACTIVITY = "current_activity" +ATTR_COMMAND_TYPE = "command_type" +ATTR_DEVICE = "device" +ATTR_NUM_REPEATS = "num_repeats" +ATTR_DELAY_SECS = "delay_secs" +ATTR_HOLD_SECS = "hold_secs" +ATTR_ALTERNATIVE = "alternative" +ATTR_TIMEOUT = "timeout" + +SERVICE_SEND_COMMAND = "send_command" +SERVICE_LEARN_COMMAND = "learn_command" +SERVICE_DELETE_COMMAND = "delete_command" +SERVICE_SYNC = "sync" + +DEFAULT_NUM_REPEATS = 1 +DEFAULT_DELAY_SECS = 0.4 +DEFAULT_HOLD_SECS = 0 class RemoteEntityStateAttribute(StrEnum): diff --git a/homeassistant/components/remote/services.py b/homeassistant/components/remote/services.py new file mode 100644 index 000000000000..c0b22553a119 --- /dev/null +++ b/homeassistant/components/remote/services.py @@ -0,0 +1,88 @@ +"""Services for the Remote integration.""" + +import probatio + +from homeassistant.const import ( + ATTR_COMMAND, + 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_ACTIVITY, + ATTR_ALTERNATIVE, + ATTR_COMMAND_TYPE, + ATTR_DELAY_SECS, + ATTR_DEVICE, + ATTR_HOLD_SECS, + ATTR_NUM_REPEATS, + ATTR_TIMEOUT, + DATA_COMPONENT, + DEFAULT_HOLD_SECS, + DEFAULT_NUM_REPEATS, + SERVICE_DELETE_COMMAND, + SERVICE_LEARN_COMMAND, + SERVICE_SEND_COMMAND, +) + +REMOTE_SERVICE_ACTIVITY_SCHEMA = cv.make_entity_service_schema( + {probatio.Optional(ATTR_ACTIVITY): cv.string} +) + + +@callback +def async_setup_services(hass: HomeAssistant) -> None: + """Register the remote services.""" + component = hass.data[DATA_COMPONENT] + + component.async_register_entity_service( + SERVICE_TURN_OFF, REMOTE_SERVICE_ACTIVITY_SCHEMA, "async_turn_off" + ) + + component.async_register_entity_service( + SERVICE_TURN_ON, REMOTE_SERVICE_ACTIVITY_SCHEMA, "async_turn_on" + ) + + component.async_register_entity_service( + SERVICE_TOGGLE, REMOTE_SERVICE_ACTIVITY_SCHEMA, "async_toggle" + ) + + component.async_register_entity_service( + SERVICE_SEND_COMMAND, + { + probatio.Required(ATTR_COMMAND): probatio.All(cv.ensure_list, [cv.string]), + probatio.Optional(ATTR_DEVICE): cv.string, + probatio.Optional( + ATTR_NUM_REPEATS, default=DEFAULT_NUM_REPEATS + ): cv.positive_int, + probatio.Optional(ATTR_DELAY_SECS): probatio.Coerce(float), + probatio.Optional( + ATTR_HOLD_SECS, default=DEFAULT_HOLD_SECS + ): probatio.Coerce(float), + }, + "async_send_command", + ) + + component.async_register_entity_service( + SERVICE_LEARN_COMMAND, + { + probatio.Optional(ATTR_DEVICE): cv.string, + probatio.Optional(ATTR_COMMAND): probatio.All(cv.ensure_list, [cv.string]), + probatio.Optional(ATTR_COMMAND_TYPE): cv.string, + probatio.Optional(ATTR_ALTERNATIVE): cv.boolean, + probatio.Optional(ATTR_TIMEOUT): cv.positive_int, + }, + "async_learn_command", + ) + + component.async_register_entity_service( + SERVICE_DELETE_COMMAND, + { + probatio.Required(ATTR_COMMAND): probatio.All(cv.ensure_list, [cv.string]), + probatio.Optional(ATTR_DEVICE): cv.string, + }, + "async_delete_command", + )