mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-12 14:54:04 +02:00
fix: publish manual-control state when it changes (#1538)
This commit is contained in:
parent
a04a533f45
commit
ecf2403422
2 changed files with 125 additions and 0 deletions
|
|
@ -2319,6 +2319,18 @@ class AdaptiveLightingManager:
|
|||
)
|
||||
|
||||
self._handle_timer(light, self.auto_reset_manual_control_timers, delay, reset)
|
||||
self._schedule_manual_control_state_update(light)
|
||||
|
||||
def _schedule_manual_control_state_update(self, *lights: str) -> None:
|
||||
"""Publish shared manual-control state on every affected switch."""
|
||||
# State publication must not expand groups or change tracked lights.
|
||||
for entry in self.hass.config_entries.async_entries(DOMAIN):
|
||||
entry_data = self.hass.data[DOMAIN].get(entry.entry_id)
|
||||
if entry_data is None:
|
||||
continue
|
||||
switch = entry_data.get(SWITCH_DOMAIN)
|
||||
if switch is not None and set(lights).intersection(switch.lights):
|
||||
switch.async_schedule_update_ha_state()
|
||||
|
||||
def add_manual_control_attributes(
|
||||
self,
|
||||
|
|
@ -2419,6 +2431,8 @@ class AdaptiveLightingManager:
|
|||
self.our_last_state_on_change.pop(light, None)
|
||||
self.last_service_data.pop(light, None)
|
||||
self.cancel_ongoing_adaptation_calls(light)
|
||||
if reset_manual_control:
|
||||
self._schedule_manual_control_state_update(*lights)
|
||||
|
||||
def _get_entity_list(self, service_data: ServiceData) -> list[str]:
|
||||
if ATTR_ENTITY_ID in service_data:
|
||||
|
|
|
|||
|
|
@ -1092,6 +1092,117 @@ async def test_mixed_turn_on_restarts_manual_control_timeout(
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("intercept", [True, False])
|
||||
@pytest.mark.parametrize(
|
||||
("service_data", "brightness", "color"),
|
||||
[
|
||||
({ATTR_BRIGHTNESS: 200}, True, False),
|
||||
({"brightness_step": 5}, True, False),
|
||||
({ATTR_COLOR_TEMP_KELVIN: 4000}, False, True),
|
||||
({ATTR_BRIGHTNESS: 200, ATTR_COLOR_TEMP_KELVIN: 4000}, True, True),
|
||||
],
|
||||
)
|
||||
async def test_manual_control_state_updates_without_adaptation(
|
||||
hass,
|
||||
intercept,
|
||||
service_data,
|
||||
brightness,
|
||||
color,
|
||||
):
|
||||
"""Publish manual state on service changes and resets, without an interval tick."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(
|
||||
hass,
|
||||
{
|
||||
CONF_INTERCEPT: intercept,
|
||||
CONF_MIN_BRIGHTNESS: 50,
|
||||
CONF_MAX_BRIGHTNESS: 50,
|
||||
},
|
||||
)
|
||||
events = []
|
||||
hass.bus.async_listen(f"{DOMAIN}.manual_control", events.append)
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: light.entity_id, **service_data},
|
||||
blocking=True,
|
||||
context=Context(),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
attrs = hass.states.get(switch.entity_id).attributes
|
||||
assert attrs["manual_control"] == [light.entity_id]
|
||||
assert attrs["manual_control_brightness"] == (
|
||||
[light.entity_id] if brightness else []
|
||||
)
|
||||
assert attrs["manual_control_color"] == ([light.entity_id] if color else [])
|
||||
assert len(events) == 1
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: light.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
attrs = hass.states.get(switch.entity_id).attributes
|
||||
assert attrs["manual_control"] == []
|
||||
assert attrs["manual_control_brightness"] == []
|
||||
assert attrs["manual_control_color"] == []
|
||||
|
||||
|
||||
async def test_manual_control_state_updates_shared_switches(hass):
|
||||
"""Publish shared state on both profiles when one receives a service call."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(hass)
|
||||
_, other = await setup_switch(
|
||||
hass,
|
||||
{CONF_NAME: "other", CONF_LIGHTS: [light.entity_id]},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SET_MANUAL_CONTROL,
|
||||
{
|
||||
ATTR_ENTITY_ID: switch.entity_id,
|
||||
CONF_LIGHTS: [light.entity_id],
|
||||
CONF_MANUAL_CONTROL: "brightness",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
for profile in (switch, other):
|
||||
attrs = hass.states.get(profile.entity_id).attributes
|
||||
assert attrs["manual_control"] == [light.entity_id]
|
||||
assert attrs["manual_control_brightness"] == [light.entity_id]
|
||||
assert attrs["manual_control_color"] == []
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SET_MANUAL_CONTROL,
|
||||
{ATTR_ENTITY_ID: other.entity_id, CONF_MANUAL_CONTROL: False},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
for profile in (switch, other):
|
||||
attrs = hass.states.get(profile.entity_id).attributes
|
||||
assert attrs["manual_control"] == []
|
||||
assert attrs["manual_control_brightness"] == []
|
||||
assert attrs["manual_control_color"] == []
|
||||
|
||||
|
||||
async def test_manual_control_state_ignores_incomplete_entries(hass):
|
||||
"""An entry awaiting platform setup must not break another profile's updates."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(hass)
|
||||
pending = MockConfigEntry(domain=DOMAIN, data={CONF_NAME: "pending"})
|
||||
pending.add_to_hass(hass)
|
||||
hass.data[DOMAIN][pending.entry_id] = {}
|
||||
|
||||
switch.manager.set_manual_control_attributes(light.entity_id)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(switch.entity_id).attributes["manual_control"] == [
|
||||
light.entity_id,
|
||||
]
|
||||
|
||||
|
||||
async def test_adaptation_attribute_selection(hass):
|
||||
"""Test the 'manual control' tracking."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(hass)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue