From 3952b4767aecf637de1673ed3214fdf8874f6c6c Mon Sep 17 00:00:00 2001 From: Adam DeMuri Date: Sat, 17 Jan 2026 19:54:52 +0000 Subject: [PATCH] Register service actions in async_setup for Bronze tier compliance - Move 'apply' and 'set_manual_control' service registration from async_setup_entry to async_setup. - Move service handlers to module-level functions in switch.py. - Update apply_service_schema to support dynamic defaults for transition duration. - Clean up related unused imports and fix Python 3.10 syntax compatibility. --- .../adaptive_lighting/__init__.py | 20 ++ custom_components/adaptive_lighting/const.py | 7 +- custom_components/adaptive_lighting/switch.py | 188 ++++++++---------- 3 files changed, 110 insertions(+), 105 deletions(-) diff --git a/custom_components/adaptive_lighting/__init__.py b/custom_components/adaptive_lighting/__init__.py index 8e61e93b..65b4145b 100644 --- a/custom_components/adaptive_lighting/__init__.py +++ b/custom_components/adaptive_lighting/__init__.py @@ -1,6 +1,7 @@ """Adaptive Lighting integration in Home-Assistant.""" import logging +from functools import partial from typing import Any import homeassistant.helpers.config_validation as cv @@ -14,8 +15,13 @@ from .const import ( ATTR_ADAPTIVE_LIGHTING_MANAGER, CONF_NAME, DOMAIN, + SERVICE_APPLY, + SERVICE_SET_MANUAL_CONTROL, + SET_MANUAL_CONTROL_SCHEMA, UNDO_UPDATE_LISTENER, + apply_service_schema, ) +from .switch import handle_apply_service, handle_set_manual_control_service _LOGGER = logging.getLogger(__name__) @@ -47,6 +53,20 @@ async def reload_configuration_yaml(event: Event) -> None: async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool: """Import integration from config.""" + hass.services.async_register( + DOMAIN, + SERVICE_APPLY, + partial(handle_apply_service, hass), + schema=apply_service_schema(), + ) + + hass.services.async_register( + DOMAIN, + SERVICE_SET_MANUAL_CONTROL, + partial(handle_set_manual_control_service, hass), + schema=SET_MANUAL_CONTROL_SCHEMA, + ) + if DOMAIN in config: for entry in config[DOMAIN]: hass.async_create_task( diff --git a/custom_components/adaptive_lighting/const.py b/custom_components/adaptive_lighting/const.py index 502318f0..650374a0 100644 --- a/custom_components/adaptive_lighting/const.py +++ b/custom_components/adaptive_lighting/const.py @@ -459,16 +459,13 @@ _DOMAIN_SCHEMA = vol.Schema( ) -def apply_service_schema(initial_transition: int = 1) -> vol.Schema: +def apply_service_schema() -> vol.Schema: """Return the schema for the apply service.""" return vol.Schema( { vol.Optional(CONF_ENTITY_ID): cv.entity_ids, # type: ignore[arg-type] vol.Optional(CONF_LIGHTS, default=[]): cv.entity_ids, # type: ignore[arg-type] - vol.Optional( - CONF_TRANSITION, - default=initial_transition, - ): VALID_TRANSITION, + vol.Optional(CONF_TRANSITION): VALID_TRANSITION, vol.Optional(ATTR_ADAPT_BRIGHTNESS, default=True): cv.boolean, vol.Optional(ATTR_ADAPT_COLOR, default=True): cv.boolean, vol.Optional(CONF_PREFER_RGB_COLOR, default=False): cv.boolean, diff --git a/custom_components/adaptive_lighting/switch.py b/custom_components/adaptive_lighting/switch.py index 3923e056..839359d1 100644 --- a/custom_components/adaptive_lighting/switch.py +++ b/custom_components/adaptive_lighting/switch.py @@ -137,15 +137,11 @@ from .const import ( ICON_COLOR_TEMP, ICON_MAIN, ICON_SLEEP, - SERVICE_APPLY, SERVICE_CHANGE_SWITCH_SETTINGS, - SERVICE_SET_MANUAL_CONTROL, - SET_MANUAL_CONTROL_SCHEMA, SLEEP_MODE_SWITCH, TURNING_OFF_DELAY, VALIDATION_TUPLES, TakeOverControlMode, - apply_service_schema, replace_none_str, ) from .hass_utils import area_entities, setup_service_call_interceptor @@ -361,7 +357,92 @@ async def handle_change_switch_settings( ) -async def async_setup_entry( # noqa: PLR0915 +@callback +async def handle_apply_service(hass: HomeAssistant, service_call: ServiceCall) -> None: + """Handle the entity service apply.""" + data = service_call.data + _LOGGER.debug( + "Called 'adaptive_lighting.apply' service with '%s'", + data, + ) + switches = _switches_from_service_call(hass, service_call) + lights = data[CONF_LIGHTS] + for switch in switches: + all_lights = ( + switch.lights if not lights else _expand_light_groups(hass, lights) + ) + switch.manager.lights.update(all_lights) + for light in all_lights: + if data[CONF_TURN_ON_LIGHTS] or is_on(hass, light): + context = switch.create_context( + "service", + parent=service_call.context, + ) + # Handle optional transition + transition = data.get(CONF_TRANSITION) + if transition is None: + transition = switch.initial_transition + + await switch._adapt_light( # pylint: disable=protected-access + light, + context=context, + transition=transition, + adapt_brightness=data[ATTR_ADAPT_BRIGHTNESS], + adapt_color=data[ATTR_ADAPT_COLOR], + prefer_rgb_color=data[CONF_PREFER_RGB_COLOR], + force=True, + ) + + +@callback +async def handle_set_manual_control_service( + hass: HomeAssistant, + service_call: ServiceCall, +) -> None: + """Set or unset lights as 'manually controlled'.""" + data = service_call.data + _LOGGER.debug( + "Called 'adaptive_lighting.set_manual_control' service with '%s'", + data, + ) + switches = _switches_from_service_call(hass, service_call) + lights = data[CONF_LIGHTS] + for switch in switches: + all_lights = ( + switch.lights if not lights else _expand_light_groups(hass, lights) + ) + + manual_attributes = manual_control_event_attribute_to_flags( + service_call.data[CONF_MANUAL_CONTROL], + ) + + if manual_attributes: + for light in all_lights: + switch.manager.set_manual_control_attributes( + light, + manual_attributes, + ) + switch.fire_manual_control_event( + light, + service_call.context, + ) + else: + switch.manager.reset(*all_lights) + if switch.is_on: + context = switch.create_context( + "service", + parent=service_call.context, + ) + # pylint: disable=protected-access + await switch._update_attrs_and_maybe_adapt_lights( + context=context, + lights=all_lights, + transition=switch.initial_transition, + force=True, + ) + + +async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, @@ -431,99 +512,6 @@ async def async_setup_entry( # noqa: PLR0915 update_before_add=True, ) - @callback - async def handle_apply(service_call: ServiceCall) -> None: - """Handle the entity service apply.""" - data = service_call.data - _LOGGER.debug( - "Called 'adaptive_lighting.apply' service with '%s'", - data, - ) - switches = _switches_from_service_call(hass, service_call) - lights = data[CONF_LIGHTS] - for switch in switches: - if not lights: - all_lights = switch.lights - else: - all_lights = _expand_light_groups(hass, lights) - switch.manager.lights.update(all_lights) - for light in all_lights: - if data[CONF_TURN_ON_LIGHTS] or is_on(hass, light): - context = switch.create_context( - "service", - parent=service_call.context, - ) - await switch._adapt_light( # pylint: disable=protected-access - light, - context=context, - transition=data[CONF_TRANSITION], - adapt_brightness=data[ATTR_ADAPT_BRIGHTNESS], - adapt_color=data[ATTR_ADAPT_COLOR], - prefer_rgb_color=data[CONF_PREFER_RGB_COLOR], - force=True, - ) - - @callback - async def handle_set_manual_control(service_call: ServiceCall) -> None: - """Set or unset lights as 'manually controlled'.""" - data = service_call.data - _LOGGER.debug( - "Called 'adaptive_lighting.set_manual_control' service with '%s'", - data, - ) - switches = _switches_from_service_call(hass, service_call) - lights = data[CONF_LIGHTS] - for switch in switches: - if not lights: - all_lights = switch.lights - else: - all_lights = _expand_light_groups(hass, lights) - - manual_attributes = manual_control_event_attribute_to_flags( - service_call.data[CONF_MANUAL_CONTROL], - ) - - if manual_attributes: - for light in all_lights: - switch.manager.set_manual_control_attributes( - light, - manual_attributes, - ) - switch.fire_manual_control_event( - light, - service_call.context, - ) - else: - switch.manager.reset(*all_lights) - if switch.is_on: - context = switch.create_context( - "service", - parent=service_call.context, - ) - # pylint: disable=protected-access - await switch._update_attrs_and_maybe_adapt_lights( - context=context, - lights=all_lights, - transition=switch.initial_transition, - force=True, - ) - - # Register `apply` service - hass.services.async_register( - domain=DOMAIN, - service=SERVICE_APPLY, - service_func=handle_apply, - schema=apply_service_schema(switch.initial_transition), - ) - - # Register `set_manual_control` service - hass.services.async_register( - domain=DOMAIN, - service=SERVICE_SET_MANUAL_CONTROL, - service_func=handle_set_manual_control, - schema=SET_MANUAL_CONTROL_SCHEMA, - ) - args: VolDictType = {vol.Optional(CONF_USE_DEFAULTS, default="current"): cv.string} # Modifying these after init isn't possible skip = (CONF_INTERVAL, CONF_NAME, CONF_LIGHTS) @@ -1681,8 +1669,8 @@ class SimpleSwitch(SwitchEntity, RestoreEntity): self._state = False -type AdaptiveSwitches = list[AdaptiveSwitch] -type AdaptiveSwitchMap = dict[AdaptiveSwitch, list[str]] +AdaptiveSwitches = list[AdaptiveSwitch] +AdaptiveSwitchMap = dict[AdaptiveSwitch, list[str]] class AdaptiveLightingManager: