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.
This commit is contained in:
Adam DeMuri 2026-01-17 19:54:52 +00:00
commit 3952b4767a
3 changed files with 110 additions and 105 deletions

View file

@ -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(

View file

@ -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,

View file

@ -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: