mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-11 22:34:04 +02:00
feat: expose per-attribute manual-control state (#1469)
Adds two new read-only state attributes on the AdaptiveSwitch entity: - manual_control_brightness: list of light entity_ids whose brightness axis is currently in manual override (i.e. AL is paused for brightness on those lights). - manual_control_color: same, for the color axis. These mirror the existing 'manual_control' attribute (which is a union of both axes) but expose the LightControlAttributes bitfield that AL already tracks internally per-light. Why: the existing 'manual_control' state attribute and the adaptive_lighting.manual_control event are useful, but neither lets a template or dashboard see which axis is paused without subscribing to events. This is especially important with take_over_control_mode: pause_changed, where one axis can be manual while the other still adapts. Now a Lovelace card or template sensor can display brightness/color manual state directly via state_attr(). Test: extends test_manual_control to assert the new attributes reflect the bitfield correctly. No new platform, no breaking changes. Co-authored-by: Bas Nijholt <basnijholt@gmail.com>
This commit is contained in:
parent
61896eb86a
commit
e453541a78
4 changed files with 55 additions and 0 deletions
14
README.md
14
README.md
|
|
@ -48,6 +48,20 @@ This feature is available when `take_over_control` is enabled.
|
|||
Additionally, enabling `detect_non_ha_changes` allows Adaptive Lighting to detect all state changes, including those made outside of Home Assistant, by comparing the light's state to its previously used settings.
|
||||
The `adaptive_lighting.manual_control` event is fired when a light is marked as "manually controlled," allowing for integration with automations 🤖.
|
||||
|
||||
The Adaptive Lighting switch exposes these read-only attributes for its lights:
|
||||
|
||||
- `manual_control`: lights with any attribute marked as manually controlled.
|
||||
- `manual_control_brightness`: lights with brightness marked as manually controlled.
|
||||
- `manual_control_color`: lights with color marked as manually controlled.
|
||||
|
||||
These lists report manual-control flags. Actual adaptation also depends on `take_over_control_mode` and the brightness/color adaptation switches. For example, under the default `pause_all` mode, manually changing only brightness leaves `manual_control_color` empty while pausing both brightness and color adaptation. Under `pause_changed`, color can continue adapting.
|
||||
|
||||
The attributes are absent when the Adaptive Lighting switch is off. Use a fallback when checking them in templates:
|
||||
|
||||
```jinja
|
||||
{{ 'light.bedroom' in (state_attr('switch.adaptive_lighting_bedroom', 'manual_control_brightness') or []) }}
|
||||
```
|
||||
|
||||
> ⚠️ **_Caution: Some lights might falsely indicate an 'on' state, which could result in lights turning on unexpectedly. Disable `detect_non_ha_changes` if you encounter such issues._**
|
||||
<!-- SECTION:manual-control:END -->
|
||||
|
||||
|
|
|
|||
|
|
@ -1151,6 +1151,18 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
extra_state_attributes["manual_control"] = [
|
||||
light for light in self.lights if self.manager.manual_control.get(light)
|
||||
]
|
||||
extra_state_attributes["manual_control_brightness"] = [
|
||||
light
|
||||
for light in self.lights
|
||||
if self.manager.manual_control.get(light, LightControlAttributes.NONE)
|
||||
& LightControlAttributes.BRIGHTNESS
|
||||
]
|
||||
extra_state_attributes["manual_control_color"] = [
|
||||
light
|
||||
for light in self.lights
|
||||
if self.manager.manual_control.get(light, LightControlAttributes.NONE)
|
||||
& LightControlAttributes.COLOR
|
||||
]
|
||||
extra_state_attributes.update(self._settings)
|
||||
timers = self.manager.auto_reset_manual_control_timers
|
||||
extra_state_attributes["autoreset_time_remaining"] = {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,20 @@ This feature is available when `take_over_control` is enabled.
|
|||
Additionally, enabling `detect_non_ha_changes` allows Adaptive Lighting to detect all state changes, including those made outside of Home Assistant, by comparing the light's state to its previously used settings.
|
||||
The `adaptive_lighting.manual_control` event is fired when a light is marked as "manually controlled," allowing for integration with automations 🤖.
|
||||
|
||||
The Adaptive Lighting switch exposes these read-only attributes for its lights:
|
||||
|
||||
- `manual_control`: lights with any attribute marked as manually controlled.
|
||||
- `manual_control_brightness`: lights with brightness marked as manually controlled.
|
||||
- `manual_control_color`: lights with color marked as manually controlled.
|
||||
|
||||
These lists report manual-control flags. Actual adaptation also depends on `take_over_control_mode` and the brightness/color adaptation switches. For example, under the default `pause_all` mode, manually changing only brightness leaves `manual_control_color` empty while pausing both brightness and color adaptation. Under `pause_changed`, color can continue adapting.
|
||||
|
||||
The attributes are absent when the Adaptive Lighting switch is off. Use a fallback when checking them in templates:
|
||||
|
||||
```jinja
|
||||
{{ 'light.bedroom' in (state_attr('switch.adaptive_lighting_bedroom', 'manual_control_brightness') or []) }}
|
||||
```
|
||||
|
||||
> ⚠️ **_Caution: Some lights might falsely indicate an 'on' state, which could result in lights turning on unexpectedly. Disable `detect_non_ha_changes` if you encounter such issues._**
|
||||
|
||||
<!-- OUTPUT:END -->
|
||||
|
|
|
|||
|
|
@ -738,10 +738,19 @@ async def test_manual_control(
|
|||
await turn_light(True, brightness=increased_brightness())
|
||||
# Check that ENTITY_LIGHT_1 is manually controlled
|
||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
||||
# Per-attribute state attributes should reflect this
|
||||
state_attrs = hass.states.get(switch.entity_id).attributes
|
||||
assert ENTITY_LIGHT_1 in state_attrs["manual_control"]
|
||||
assert ENTITY_LIGHT_1 in state_attrs["manual_control_brightness"]
|
||||
assert ENTITY_LIGHT_1 not in state_attrs["manual_control_color"]
|
||||
# Test adaptive_lighting.set_manual_control
|
||||
await change_manual_control(False)
|
||||
# Check that ENTITY_LIGHT_1 is not manually controlled
|
||||
assert not manual_control[ENTITY_LIGHT_1]
|
||||
state_attrs = hass.states.get(switch.entity_id).attributes
|
||||
assert ENTITY_LIGHT_1 not in state_attrs["manual_control"]
|
||||
assert ENTITY_LIGHT_1 not in state_attrs["manual_control_brightness"]
|
||||
assert ENTITY_LIGHT_1 not in state_attrs["manual_control_color"]
|
||||
|
||||
# Check that toggling light off to on resets manual control
|
||||
await change_manual_control(True)
|
||||
|
|
@ -865,6 +874,9 @@ async def test_manual_control(
|
|||
assert not manual_control[ENTITY_LIGHT_1]
|
||||
await change_manual_control(True)
|
||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.ALL
|
||||
state_attrs = hass.states.get(switch.entity_id).attributes
|
||||
assert state_attrs["manual_control_brightness"] == [ENTITY_LIGHT_1]
|
||||
assert state_attrs["manual_control_color"] == [ENTITY_LIGHT_1]
|
||||
|
||||
# Check that manual control `False` unsets all attributes
|
||||
await change_manual_control(False)
|
||||
|
|
@ -875,6 +887,9 @@ async def test_manual_control(
|
|||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
||||
await change_manual_control("color")
|
||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.COLOR
|
||||
state_attrs = hass.states.get(switch.entity_id).attributes
|
||||
assert state_attrs["manual_control_brightness"] == []
|
||||
assert state_attrs["manual_control_color"] == [ENTITY_LIGHT_1]
|
||||
|
||||
|
||||
@flaky(max_runs=3, min_passes=1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue