mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-27 20:34:20 +02:00
feat: add adapt_only_on_ha_turn_on to skip adapting externally turned-on lights
When a light turns on from `off` via a source outside Home Assistant — a physical wall switch or a hub/manufacturer scene (e.g. Lutron) — and `detect_non_ha_changes` is enabled, Adaptive Lighting adapts the light on the resulting `off` → `on` event, overriding the brightness/color the external source just set. Disabling `detect_non_ha_changes` avoids this but also stops detection of manual changes to already-on lights; the two behaviors were coupled to a single flag. Add `adapt_only_on_ha_turn_on` (default `false`, requires `take_over_control`). When enabled, an `off` → `on` transition with no matching HA `light.turn_on` context is marked `manual_control` and left untouched, independent of `detect_non_ha_changes`, decoupling the two behaviors. The off→on guard reduces to the previous expression when the option is `false`, so existing configurations are unaffected. Includes a parametrized regression test, docs, and regenerated strings/services/README via scripts/update-generated-content. Refs #435 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7afdf5bc5c
commit
cb0e552ec5
9 changed files with 148 additions and 6 deletions
|
|
@ -100,6 +100,17 @@ DOCS[CONF_ADAPT_ONLY_ON_BARE_TURN_ON] = (
|
|||
"Needs `take_over_control` enabled. 🕵️"
|
||||
)
|
||||
|
||||
CONF_ADAPT_ONLY_ON_HA_TURN_ON, DEFAULT_ADAPT_ONLY_ON_HA_TURN_ON = (
|
||||
"adapt_only_on_ha_turn_on",
|
||||
False,
|
||||
)
|
||||
DOCS[CONF_ADAPT_ONLY_ON_HA_TURN_ON] = (
|
||||
"When a light turns on from `off`, only adapt it if Home Assistant issued the "
|
||||
"`light.turn_on`; lights turned on by a physical switch or an external scene "
|
||||
"(e.g. Lutron) are left untouched. Unlike disabling `detect_non_ha_changes`, this "
|
||||
"still detects manual changes to already-on lights. Needs `take_over_control` enabled. 🕵️"
|
||||
)
|
||||
|
||||
CONF_PREFER_RGB_COLOR, DEFAULT_PREFER_RGB_COLOR = "prefer_rgb_color", False
|
||||
DOCS[CONF_PREFER_RGB_COLOR] = (
|
||||
"Whether to prefer RGB color adjustment over "
|
||||
|
|
@ -394,6 +405,7 @@ VALIDATION_TUPLES: list[tuple[str, Any, Any]] = [
|
|||
),
|
||||
(CONF_ONLY_ONCE, DEFAULT_ONLY_ONCE, bool),
|
||||
(CONF_ADAPT_ONLY_ON_BARE_TURN_ON, DEFAULT_ADAPT_ONLY_ON_BARE_TURN_ON, bool),
|
||||
(CONF_ADAPT_ONLY_ON_HA_TURN_ON, DEFAULT_ADAPT_ONLY_ON_HA_TURN_ON, bool),
|
||||
(CONF_SEPARATE_TURN_ON_COMMANDS, DEFAULT_SEPARATE_TURN_ON_COMMANDS, bool),
|
||||
(CONF_SEND_SPLIT_DELAY, DEFAULT_SEND_SPLIT_DELAY, int_between(0, 10000)),
|
||||
(CONF_ADAPT_DELAY, DEFAULT_ADAPT_DELAY, cv.positive_float),
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
"autoreset_control_seconds": "autoreset_control_seconds",
|
||||
"only_once": "only_once: Adapt lights only when they are turned on (`true`) or keep adapting them (`false`). 🔄",
|
||||
"adapt_only_on_bare_turn_on": "adapt_only_on_bare_turn_on: When turning lights on initially. If set to `true`, AL adapts only if `light.turn_on` is invoked without specifying color or brightness. ❌🌈 This e.g., prevents adaptation when activating a scene and marks the light as manually controlled. If `false`, AL adapts regardless of the presence of color or brightness in the initial `service_data`. Needs `take_over_control` enabled. 🕵️",
|
||||
"adapt_only_on_ha_turn_on": "adapt_only_on_ha_turn_on: When a light turns on from `off`, only adapt it if Home Assistant issued the `light.turn_on`; lights turned on by a physical switch or an external scene (e.g. Lutron) are left untouched. Unlike disabling `detect_non_ha_changes`, this still detects manual changes to already-on lights. Needs `take_over_control` enabled. 🕵️",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands: Use separate `light.turn_on` calls for color and brightness, needed for some light types. 🔀",
|
||||
"send_split_delay": "send_split_delay",
|
||||
"adapt_delay": "adapt_delay",
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ from .const import (
|
|||
ATTR_ADAPTIVE_LIGHTING_MANAGER,
|
||||
CONF_ADAPT_DELAY,
|
||||
CONF_ADAPT_ONLY_ON_BARE_TURN_ON,
|
||||
CONF_ADAPT_ONLY_ON_HA_TURN_ON,
|
||||
CONF_ADAPT_UNTIL_SLEEP,
|
||||
CONF_AUTORESET_CONTROL,
|
||||
CONF_BRIGHTNESS_MODE,
|
||||
|
|
@ -929,12 +930,14 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
self._send_split_delay = data[CONF_SEND_SPLIT_DELAY]
|
||||
self._take_over_control = data[CONF_TAKE_OVER_CONTROL]
|
||||
if not data[CONF_TAKE_OVER_CONTROL] and (
|
||||
data[CONF_DETECT_NON_HA_CHANGES] or data[CONF_ADAPT_ONLY_ON_BARE_TURN_ON]
|
||||
data[CONF_DETECT_NON_HA_CHANGES]
|
||||
or data[CONF_ADAPT_ONLY_ON_BARE_TURN_ON]
|
||||
or data[CONF_ADAPT_ONLY_ON_HA_TURN_ON]
|
||||
):
|
||||
_LOGGER.warning(
|
||||
"%s: Config mismatch: `detect_non_ha_changes` or `adapt_only_on_bare_turn_on` "
|
||||
"set to `true` requires `take_over_control` to be enabled. Adjusting config "
|
||||
"and continuing setup with `take_over_control: true`.",
|
||||
"%s: Config mismatch: `detect_non_ha_changes`, `adapt_only_on_bare_turn_on`, "
|
||||
"or `adapt_only_on_ha_turn_on` set to `true` requires `take_over_control` to be "
|
||||
"enabled. Adjusting config and continuing setup with `take_over_control: true`.",
|
||||
self._name,
|
||||
)
|
||||
self._take_over_control = True
|
||||
|
|
@ -943,6 +946,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
)
|
||||
self._detect_non_ha_changes = data[CONF_DETECT_NON_HA_CHANGES]
|
||||
self._adapt_only_on_bare_turn_on = data[CONF_ADAPT_ONLY_ON_BARE_TURN_ON]
|
||||
self._adapt_only_on_ha_turn_on = data[CONF_ADAPT_ONLY_ON_HA_TURN_ON]
|
||||
self._auto_reset_manual_control_time = data[CONF_AUTORESET_CONTROL]
|
||||
self._skip_redundant_commands = data[CONF_SKIP_REDUNDANT_COMMANDS]
|
||||
self._intercept = data[CONF_INTERCEPT]
|
||||
|
|
@ -1530,16 +1534,24 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
)
|
||||
if (
|
||||
self._take_over_control
|
||||
and not self._detect_non_ha_changes
|
||||
and (not self._detect_non_ha_changes or self._adapt_only_on_ha_turn_on)
|
||||
and not from_turn_on
|
||||
):
|
||||
# There is an edge case where 2 switches control the same light, e.g.,
|
||||
# one for brightness and one for color. Now we will mark both switches
|
||||
# as manually controlled, which is not 100% correct.
|
||||
#
|
||||
# This 'off' → 'on' event was not caused by an HA `light.turn_on` call, so
|
||||
# it comes from an external source (a physical switch or a hub/manufacturer
|
||||
# scene like Lutron). We hand control over and skip adaptation when either:
|
||||
# - `detect_non_ha_changes` is False (we can't reliably track manual changes
|
||||
# to already-on lights anyway), or
|
||||
# - `adapt_only_on_ha_turn_on` is True (the user explicitly wants external
|
||||
# turn-ons left untouched, even while `detect_non_ha_changes` is enabled).
|
||||
_LOGGER.debug(
|
||||
"%s: Ignoring 'off' → 'on' event for '%s' with context.id='%s'"
|
||||
" because 'light.turn_on' was not called by HA and"
|
||||
" 'detect_non_ha_changes' is False",
|
||||
" ('detect_non_ha_changes' is False or 'adapt_only_on_ha_turn_on' is True)",
|
||||
self._name,
|
||||
entity_id,
|
||||
event.context.id,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
"autoreset_control_seconds": "autoreset_control_seconds",
|
||||
"only_once": "only_once: Adapt lights only when they are turned on (`true`) or keep adapting them (`false`). 🔄",
|
||||
"adapt_only_on_bare_turn_on": "adapt_only_on_bare_turn_on: When turning lights on initially. If set to `true`, AL adapts only if `light.turn_on` is invoked without specifying color or brightness. ❌🌈 This e.g., prevents adaptation when activating a scene and marks the light as manually controlled. If `false`, AL adapts regardless of the presence of color or brightness in the initial `service_data`. Needs `take_over_control` enabled. 🕵️",
|
||||
"adapt_only_on_ha_turn_on": "adapt_only_on_ha_turn_on: When a light turns on from `off`, only adapt it if Home Assistant issued the `light.turn_on`; lights turned on by a physical switch or an external scene (e.g. Lutron) are left untouched. Unlike disabling `detect_non_ha_changes`, this still detects manual changes to already-on lights. Needs `take_over_control` enabled. 🕵️",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands: Use separate `light.turn_on` calls for color and brightness, needed for some light types. 🔀",
|
||||
"send_split_delay": "send_split_delay",
|
||||
"adapt_delay": "adapt_delay",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue