mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-28 12:54:22 +02:00
Compare commits
3 commits
main
...
feat/fix-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4319a6a524 |
||
|
|
4c7786bbc6 |
||
|
|
b732eed970 |
2 changed files with 128 additions and 71 deletions
|
|
@ -1004,6 +1004,11 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
||||||
entry_type=DeviceEntryType.SERVICE,
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_adapt_only_on_bare_turn_on_enabled(self) -> bool:
|
||||||
|
"""Return whether adapt_only_on_bare_turn_on is enabled."""
|
||||||
|
return self._take_over_control and self._adapt_only_on_bare_turn_on
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Call when entity about to be added to hass."""
|
"""Call when entity about to be added to hass."""
|
||||||
if self.hass.is_running:
|
if self.hass.is_running:
|
||||||
|
|
@ -1122,7 +1127,9 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
||||||
extra_state_attributes[key] = None
|
extra_state_attributes[key] = None
|
||||||
return extra_state_attributes
|
return extra_state_attributes
|
||||||
extra_state_attributes["manual_control"] = [
|
extra_state_attributes["manual_control"] = [
|
||||||
light for light in self.lights if self.manager.manual_control.get(light)
|
light
|
||||||
|
for light in self.lights
|
||||||
|
if self.manager.get_manual_control_attributes(light).has_any()
|
||||||
]
|
]
|
||||||
extra_state_attributes.update(self._settings)
|
extra_state_attributes.update(self._settings)
|
||||||
timers = self.manager.auto_reset_manual_control_timers
|
timers = self.manager.auto_reset_manual_control_timers
|
||||||
|
|
@ -1533,8 +1540,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
||||||
return
|
return
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self._take_over_control
|
self.is_adapt_only_on_bare_turn_on_enabled
|
||||||
and self._adapt_only_on_bare_turn_on
|
|
||||||
and from_turn_on
|
and from_turn_on
|
||||||
# adaptive_lighting.apply can turn on light, so check this is not our context
|
# adaptive_lighting.apply can turn on light, so check this is not our context
|
||||||
and not is_our_context(event.context)
|
and not is_our_context(event.context)
|
||||||
|
|
@ -1709,7 +1715,7 @@ class AdaptiveLightingManager:
|
||||||
# Locks that prevent light adjusting when waiting for a light to 'turn_off'
|
# Locks that prevent light adjusting when waiting for a light to 'turn_off'
|
||||||
self.turn_off_locks: dict[str, asyncio.Lock] = {}
|
self.turn_off_locks: dict[str, asyncio.Lock] = {}
|
||||||
# Tracks which lights are manually controlled
|
# Tracks which lights are manually controlled
|
||||||
self.manual_control: dict[str, LightControlAttributes] = {}
|
self._manual_control: dict[str, LightControlAttributes] = {}
|
||||||
# Track 'state_changed' events of self.lights resulting from this integration
|
# Track 'state_changed' events of self.lights resulting from this integration
|
||||||
self.our_last_state_on_change: dict[str, list[State]] = {}
|
self.our_last_state_on_change: dict[str, list[State]] = {}
|
||||||
# Track last 'service_data' to 'light.turn_on' resulting from this integration
|
# Track last 'service_data' to 'light.turn_on' resulting from this integration
|
||||||
|
|
@ -1842,22 +1848,32 @@ class AdaptiveLightingManager:
|
||||||
skipped,
|
skipped,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
is_light_group = (
|
||||||
|
e := self.hass.states.get(entity_id)
|
||||||
|
) and _is_light_group(e)
|
||||||
|
is_already_on = self.hass.states.is_state(entity_id, STATE_ON)
|
||||||
|
is_manually_controlled = self.get_manual_control_attributes(
|
||||||
|
entity_id,
|
||||||
|
).has_all()
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not switch.is_on
|
not switch.is_on
|
||||||
or not switch._intercept
|
or not switch._intercept
|
||||||
# Never adapt on light groups, because HA will make a separate light.turn_on
|
# Never adapt on light groups, because HA will make a separate light.turn_on
|
||||||
or ((e := self.hass.states.get(entity_id)) and _is_light_group(e))
|
or is_light_group
|
||||||
# Prevent adaptation of TURN_ON calls when light is already on,
|
# Prevent adaptation of TURN_ON calls when light is already on,
|
||||||
# and of TOGGLE calls when toggling off.
|
# and of TOGGLE calls when toggling off.
|
||||||
or self.hass.states.is_state(entity_id, STATE_ON)
|
or is_already_on
|
||||||
or self.manual_control.get(entity_id, False)
|
or is_manually_controlled
|
||||||
or (
|
or (
|
||||||
switch._take_over_control
|
switch.is_adapt_only_on_bare_turn_on_enabled
|
||||||
and switch._adapt_only_on_bare_turn_on
|
|
||||||
and self._mark_manual_control_if_non_bare_turn_on(
|
and self._mark_manual_control_if_non_bare_turn_on(
|
||||||
entity_id,
|
entity_id,
|
||||||
data[CONF_PARAMS],
|
data[CONF_PARAMS],
|
||||||
)
|
)
|
||||||
|
# Skip adaptation only if all attributes are manually controlled, otherwise
|
||||||
|
# we have to assume that some attribute(s) need adaptation.
|
||||||
|
and self.get_manual_control_attributes(entity_id).has_all()
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
|
|
@ -1867,7 +1883,7 @@ class AdaptiveLightingManager:
|
||||||
skipped,
|
skipped,
|
||||||
switch.is_on,
|
switch.is_on,
|
||||||
self.hass.states.is_state(entity_id, STATE_ON),
|
self.hass.states.is_state(entity_id, STATE_ON),
|
||||||
self.manual_control.get(entity_id, False),
|
self.get_manual_control_attributes(entity_id),
|
||||||
switch._intercept,
|
switch._intercept,
|
||||||
)
|
)
|
||||||
skipped.append(entity_id)
|
skipped.append(entity_id)
|
||||||
|
|
@ -2069,7 +2085,8 @@ class AdaptiveLightingManager:
|
||||||
data: ServiceData,
|
data: ServiceData,
|
||||||
):
|
):
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Intercepted TURN_ON call with data %s (%s)",
|
"%s: Intercepted TURN_ON call with data %s (%s)",
|
||||||
|
entity_ids,
|
||||||
data,
|
data,
|
||||||
call.context.id,
|
call.context.id,
|
||||||
)
|
)
|
||||||
|
|
@ -2104,6 +2121,7 @@ class AdaptiveLightingManager:
|
||||||
# lack of a bijective mapping.)
|
# lack of a bijective mapping.)
|
||||||
preprocess_turn_on_alternatives(self.hass, first_service_data)
|
preprocess_turn_on_alternatives(self.hass, first_service_data)
|
||||||
data[CONF_PARAMS].update(first_service_data)
|
data[CONF_PARAMS].update(first_service_data)
|
||||||
|
switch.manager.last_service_data[entity_ids[0]] = first_service_data
|
||||||
|
|
||||||
# Schedule additional service calls for the remaining adaptation data.
|
# Schedule additional service calls for the remaining adaptation data.
|
||||||
# We cannot know here whether there is another call to follow (since the
|
# We cannot know here whether there is another call to follow (since the
|
||||||
|
|
@ -2204,7 +2222,7 @@ class AdaptiveLightingManager:
|
||||||
light: str,
|
light: str,
|
||||||
) -> LightControlAttributes:
|
) -> LightControlAttributes:
|
||||||
"""Get the attributes for a light that are manually controlled."""
|
"""Get the attributes for a light that are manually controlled."""
|
||||||
return self.manual_control.get(light, LightControlAttributes.NONE)
|
return self._manual_control.get(light, LightControlAttributes.NONE)
|
||||||
|
|
||||||
def set_manual_control_attributes(
|
def set_manual_control_attributes(
|
||||||
self,
|
self,
|
||||||
|
|
@ -2218,7 +2236,7 @@ class AdaptiveLightingManager:
|
||||||
attributes,
|
attributes,
|
||||||
self.get_manual_control_attributes(light),
|
self.get_manual_control_attributes(light),
|
||||||
)
|
)
|
||||||
self.manual_control[light] = attributes
|
self._manual_control[light] = attributes
|
||||||
delay = self.auto_reset_manual_control_times.get(light)
|
delay = self.auto_reset_manual_control_times.get(light)
|
||||||
|
|
||||||
async def reset() -> None:
|
async def reset() -> None:
|
||||||
|
|
@ -2239,7 +2257,7 @@ class AdaptiveLightingManager:
|
||||||
transition=switch.initial_transition,
|
transition=switch.initial_transition,
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
assert self.manual_control[light] == LightControlAttributes.NONE
|
assert self.get_manual_control_attributes(light).has_none()
|
||||||
|
|
||||||
self._handle_timer(light, self.auto_reset_manual_control_timers, delay, reset)
|
self._handle_timer(light, self.auto_reset_manual_control_timers, delay, reset)
|
||||||
|
|
||||||
|
|
@ -2336,7 +2354,7 @@ class AdaptiveLightingManager:
|
||||||
"Light %s: Clearing manual control attributes.",
|
"Light %s: Clearing manual control attributes.",
|
||||||
light,
|
light,
|
||||||
)
|
)
|
||||||
self.manual_control[light] = LightControlAttributes.NONE
|
self.set_manual_control_attributes(light, LightControlAttributes.NONE)
|
||||||
if timer := self.auto_reset_manual_control_timers.pop(light, None):
|
if timer := self.auto_reset_manual_control_timers.pop(light, None):
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
self.our_last_state_on_change.pop(light, None)
|
self.our_last_state_on_change.pop(light, None)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ from homeassistant.components.adaptive_lighting.adaptation_utils import (
|
||||||
AdaptationData,
|
AdaptationData,
|
||||||
LightControlAttributes,
|
LightControlAttributes,
|
||||||
_create_service_call_data_iterator,
|
_create_service_call_data_iterator,
|
||||||
|
has_color_attribute,
|
||||||
)
|
)
|
||||||
from homeassistant.components.adaptive_lighting.color_and_brightness import (
|
from homeassistant.components.adaptive_lighting.color_and_brightness import (
|
||||||
lerp_color_hsv,
|
lerp_color_hsv,
|
||||||
|
|
@ -632,7 +633,6 @@ async def test_manual_control(
|
||||||
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
||||||
|
|
||||||
context = switch.create_context("test") # needs to be passed to update method
|
context = switch.create_context("test") # needs to be passed to update method
|
||||||
manual_control = switch.manager.manual_control
|
|
||||||
|
|
||||||
async def update():
|
async def update():
|
||||||
await switch._update_attrs_and_maybe_adapt_lights(context=context, transition=0)
|
await switch._update_attrs_and_maybe_adapt_lights(context=context, transition=0)
|
||||||
|
|
@ -661,7 +661,7 @@ async def test_manual_control(
|
||||||
async def change_manual_control(set_to, extra_service_data=None):
|
async def change_manual_control(set_to, extra_service_data=None):
|
||||||
if extra_service_data is None:
|
if extra_service_data is None:
|
||||||
extra_service_data = {CONF_LIGHTS: [ENTITY_LIGHT_1]}
|
extra_service_data = {CONF_LIGHTS: [ENTITY_LIGHT_1]}
|
||||||
_LOGGER.debug(f"{switch.manager.manual_control=}")
|
_LOGGER.debug(f"{switch.manager._manual_control=}")
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_MANUAL_CONTROL,
|
SERVICE_SET_MANUAL_CONTROL,
|
||||||
|
|
@ -672,7 +672,7 @@ async def test_manual_control(
|
||||||
},
|
},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
_LOGGER.debug(f"{switch.manager.manual_control=}")
|
_LOGGER.debug(f"{switch.manager._manual_control=}")
|
||||||
_LOGGER.debug("Called set_manual_control with %s", set_to)
|
_LOGGER.debug("Called set_manual_control with %s", set_to)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await update()
|
await update()
|
||||||
|
|
@ -689,21 +689,24 @@ async def test_manual_control(
|
||||||
|
|
||||||
# Nothing is manually controlled
|
# Nothing is manually controlled
|
||||||
await update()
|
await update()
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
# Call light.turn_on for ENTITY_LIGHT_1
|
# Call light.turn_on for ENTITY_LIGHT_1
|
||||||
await turn_light(True, brightness=increased_brightness())
|
await turn_light(True, brightness=increased_brightness())
|
||||||
# Check that ENTITY_LIGHT_1 is manually controlled
|
# Check that ENTITY_LIGHT_1 is manually controlled
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.BRIGHTNESS
|
||||||
|
)
|
||||||
# Test adaptive_lighting.set_manual_control
|
# Test adaptive_lighting.set_manual_control
|
||||||
await change_manual_control(False)
|
await change_manual_control(False)
|
||||||
# Check that ENTITY_LIGHT_1 is not manually controlled
|
# Check that ENTITY_LIGHT_1 is not manually controlled
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
|
||||||
# Check that toggling light off to on resets manual control
|
# Check that toggling light off to on resets manual control
|
||||||
await change_manual_control(True)
|
await change_manual_control(True)
|
||||||
assert manual_control[ENTITY_LIGHT_1]
|
assert switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await turn_light(False)
|
await turn_light(False)
|
||||||
assert not manual_control[ENTITY_LIGHT_1], manual_control
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await turn_light(True, brightness=increased_brightness())
|
await turn_light(True, brightness=increased_brightness())
|
||||||
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
||||||
# Turning on from OFF with brightness:
|
# Turning on from OFF with brightness:
|
||||||
|
|
@ -711,44 +714,52 @@ async def test_manual_control(
|
||||||
# - With adapt_only_on_bare_turn_on=False: should NOT mark (fix for issue #1378)
|
# - With adapt_only_on_bare_turn_on=False: should NOT mark (fix for issue #1378)
|
||||||
if adapt_only_on_bare_turn_on:
|
if adapt_only_on_bare_turn_on:
|
||||||
assert (
|
assert (
|
||||||
manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
), manual_control
|
== LightControlAttributes.BRIGHTNESS
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
assert not manual_control[ENTITY_LIGHT_1], manual_control
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
# Reset for next test
|
# Reset for next test
|
||||||
await turn_light(False)
|
await turn_light(False)
|
||||||
await turn_light(True)
|
await turn_light(True)
|
||||||
assert not manual_control[ENTITY_LIGHT_1], manual_control
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
# Now change brightness while ON - this should always be manual control
|
# Now change brightness while ON - this should always be manual control
|
||||||
await turn_light(True, brightness=increased_brightness())
|
await turn_light(True, brightness=increased_brightness())
|
||||||
assert (
|
assert (
|
||||||
manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
), manual_control
|
== LightControlAttributes.BRIGHTNESS
|
||||||
|
)
|
||||||
|
|
||||||
# Check that toggling (sleep mode) switch resets manual control
|
# Check that toggling (sleep mode) switch resets manual control
|
||||||
for entity_id in [ENTITY_SWITCH, ENTITY_SLEEP_MODE_SWITCH]:
|
for entity_id in [ENTITY_SWITCH, ENTITY_SLEEP_MODE_SWITCH]:
|
||||||
await change_manual_control(True)
|
await change_manual_control(True)
|
||||||
assert manual_control[ENTITY_LIGHT_1]
|
assert switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await turn_switch(False, entity_id)
|
await turn_switch(False, entity_id)
|
||||||
await turn_switch(True, entity_id)
|
await turn_switch(True, entity_id)
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
|
||||||
# Check that manual control is still enabled if set while bulb is off.
|
# Check that manual control is still enabled if set while bulb is off.
|
||||||
# Test issue #37
|
# Test issue #37
|
||||||
await turn_light(False)
|
await turn_light(False)
|
||||||
await change_manual_control(True)
|
await change_manual_control(True)
|
||||||
await turn_light(True)
|
await turn_light(True)
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.ALL
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.ALL
|
||||||
|
)
|
||||||
|
|
||||||
# Check that when 'adapt_brightness' is off, changing the brightness
|
# Check that when 'adapt_brightness' is off, changing the brightness
|
||||||
# doesn't mark it as manually controlled but changing color_temp
|
# doesn't mark it as manually controlled but changing color_temp
|
||||||
# does
|
# does
|
||||||
await turn_light(False)
|
await turn_light(False)
|
||||||
await turn_light(True) # reset manually controlled status
|
await turn_light(True) # reset manually controlled status
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await switch.adapt_brightness_switch.async_turn_off()
|
await switch.adapt_brightness_switch.async_turn_off()
|
||||||
await turn_light(True, brightness=increased_brightness())
|
await turn_light(True, brightness=increased_brightness())
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.BRIGHTNESS
|
||||||
|
)
|
||||||
mired_range = (light.min_color_temp_kelvin, light.max_color_temp_kelvin)
|
mired_range = (light.min_color_temp_kelvin, light.max_color_temp_kelvin)
|
||||||
kelvin_range = (
|
kelvin_range = (
|
||||||
color_temperature_mired_to_kelvin(mired_range[1]),
|
color_temperature_mired_to_kelvin(mired_range[1]),
|
||||||
|
|
@ -759,7 +770,10 @@ async def test_manual_control(
|
||||||
True,
|
True,
|
||||||
color_temp_kelvin=(light._attr_color_temp + 100) % ptp_kelvin,
|
color_temp_kelvin=(light._attr_color_temp + 100) % ptp_kelvin,
|
||||||
)
|
)
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.ALL
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.ALL
|
||||||
|
)
|
||||||
await switch.adapt_brightness_switch.async_turn_on() # turn on again
|
await switch.adapt_brightness_switch.async_turn_on() # turn on again
|
||||||
|
|
||||||
# Check that when 'adapt_color' is off, changing the color
|
# Check that when 'adapt_color' is off, changing the color
|
||||||
|
|
@ -767,12 +781,18 @@ async def test_manual_control(
|
||||||
# does
|
# does
|
||||||
await turn_light(False) # reset manually controlled status
|
await turn_light(False) # reset manually controlled status
|
||||||
await turn_light(True)
|
await turn_light(True)
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await switch.adapt_color_switch.async_turn_off()
|
await switch.adapt_color_switch.async_turn_off()
|
||||||
await turn_light(True, color_temp_kelvin=increased_color_temp())
|
await turn_light(True, color_temp_kelvin=increased_color_temp())
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.COLOR
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.COLOR
|
||||||
|
)
|
||||||
await turn_light(True, brightness=increased_brightness())
|
await turn_light(True, brightness=increased_brightness())
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.ALL
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.ALL
|
||||||
|
)
|
||||||
|
|
||||||
# Check that when 'adapt_color' adapt_brightness are both off
|
# Check that when 'adapt_color' adapt_brightness are both off
|
||||||
# nothing marks it as manually controlled
|
# nothing marks it as manually controlled
|
||||||
|
|
@ -780,7 +800,7 @@ async def test_manual_control(
|
||||||
await turn_light(True)
|
await turn_light(True)
|
||||||
await switch.adapt_color_switch.async_turn_off()
|
await switch.adapt_color_switch.async_turn_off()
|
||||||
await switch.adapt_brightness_switch.async_turn_off()
|
await switch.adapt_brightness_switch.async_turn_off()
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await turn_light(True, color_temp_kelvin=increased_color_temp())
|
await turn_light(True, color_temp_kelvin=increased_color_temp())
|
||||||
await turn_light(True, brightness=increased_brightness())
|
await turn_light(True, brightness=increased_brightness())
|
||||||
await turn_light(
|
await turn_light(
|
||||||
|
|
@ -788,17 +808,26 @@ async def test_manual_control(
|
||||||
color_temp_kelvin=increased_color_temp(),
|
color_temp_kelvin=increased_color_temp(),
|
||||||
brightness=increased_brightness(),
|
brightness=increased_brightness(),
|
||||||
)
|
)
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.ALL
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.ALL
|
||||||
|
)
|
||||||
# Turn switches on again
|
# Turn switches on again
|
||||||
await switch.adapt_color_switch.async_turn_on()
|
await switch.adapt_color_switch.async_turn_on()
|
||||||
await switch.adapt_brightness_switch.async_turn_on()
|
await switch.adapt_brightness_switch.async_turn_on()
|
||||||
|
|
||||||
# Check that when no lights are specified, all are reset
|
# Check that when no lights are specified, all are reset
|
||||||
await change_manual_control(True, {CONF_LIGHTS: switch.lights})
|
await change_manual_control(True, {CONF_LIGHTS: switch.lights})
|
||||||
assert all(manual_control[eid] for eid in switch.lights)
|
assert all(
|
||||||
|
switch.manager.get_manual_control_attributes(eid).has_all()
|
||||||
|
for eid in switch.lights
|
||||||
|
)
|
||||||
# do not pass "lights" so reset all
|
# do not pass "lights" so reset all
|
||||||
await change_manual_control(False, {})
|
await change_manual_control(False, {})
|
||||||
assert all(not manual_control[eid] for eid in switch.lights)
|
assert all(
|
||||||
|
switch.manager.get_manual_control_attributes(eid).has_none()
|
||||||
|
for eid in switch.lights
|
||||||
|
)
|
||||||
|
|
||||||
# Turn off light and turn on using adaptive_lighting.apply
|
# Turn off light and turn on using adaptive_lighting.apply
|
||||||
await turn_light(False)
|
await turn_light(False)
|
||||||
|
|
@ -814,23 +843,32 @@ async def test_manual_control(
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
|
||||||
# Check that manual control `True` sets all attributes
|
# Check that manual control `True` sets all attributes
|
||||||
await change_manual_control(False)
|
await change_manual_control(False)
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await change_manual_control(True)
|
await change_manual_control(True)
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.ALL
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.ALL
|
||||||
|
)
|
||||||
|
|
||||||
# Check that manual control `False` unsets all attributes
|
# Check that manual control `False` unsets all attributes
|
||||||
await change_manual_control(False)
|
await change_manual_control(False)
|
||||||
assert not manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
|
||||||
# Check that manual control attributes can be selectively set
|
# Check that manual control attributes can be selectively set
|
||||||
await change_manual_control("brightness")
|
await change_manual_control("brightness")
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.BRIGHTNESS
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.BRIGHTNESS
|
||||||
|
)
|
||||||
await change_manual_control("color")
|
await change_manual_control("color")
|
||||||
assert manual_control[ENTITY_LIGHT_1] == LightControlAttributes.COLOR
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
== LightControlAttributes.COLOR
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@flaky(max_runs=3, min_passes=1)
|
@flaky(max_runs=3, min_passes=1)
|
||||||
|
|
@ -840,7 +878,6 @@ async def test_auto_reset_manual_control(hass):
|
||||||
{CONF_AUTORESET_CONTROL: 0.1},
|
{CONF_AUTORESET_CONTROL: 0.1},
|
||||||
)
|
)
|
||||||
context = switch.create_context("test") # needs to be passed to update method
|
context = switch.create_context("test") # needs to be passed to update method
|
||||||
manual_control = switch.manager.manual_control
|
|
||||||
|
|
||||||
async def update():
|
async def update():
|
||||||
await switch._update_attrs_and_maybe_adapt_lights(context=context, transition=0)
|
await switch._update_attrs_and_maybe_adapt_lights(context=context, transition=0)
|
||||||
|
|
@ -865,13 +902,16 @@ async def test_auto_reset_manual_control(hass):
|
||||||
_LOGGER.debug("Start test auto reset manual control")
|
_LOGGER.debug("Start test auto reset manual control")
|
||||||
await turn_light(True, brightness=1)
|
await turn_light(True, brightness=1)
|
||||||
await turn_light(True, brightness=10)
|
await turn_light(True, brightness=10)
|
||||||
assert manual_control[light.entity_id] == LightControlAttributes.BRIGHTNESS
|
assert (
|
||||||
|
switch.manager.get_manual_control_attributes(light.entity_id)
|
||||||
|
== LightControlAttributes.BRIGHTNESS
|
||||||
|
)
|
||||||
assert (
|
assert (
|
||||||
switch.extra_state_attributes["autoreset_time_remaining"][light.entity_id] > 0
|
switch.extra_state_attributes["autoreset_time_remaining"][light.entity_id] > 0
|
||||||
)
|
)
|
||||||
await update()
|
await update()
|
||||||
await asyncio.sleep(0.3) # Should be enough time for auto reset
|
await asyncio.sleep(0.3) # Should be enough time for auto reset
|
||||||
assert not manual_control[light.entity_id], (light, manual_control)
|
assert not switch.manager.get_manual_control_attributes(light.entity_id)
|
||||||
assert (
|
assert (
|
||||||
light.entity_id not in switch.extra_state_attributes["autoreset_time_remaining"]
|
light.entity_id not in switch.extra_state_attributes["autoreset_time_remaining"]
|
||||||
)
|
)
|
||||||
|
|
@ -881,11 +921,11 @@ async def test_auto_reset_manual_control(hass):
|
||||||
_LOGGER.debug("Quick change %s", i)
|
_LOGGER.debug("Quick change %s", i)
|
||||||
await turn_light(True, brightness=(i + 1) * 20)
|
await turn_light(True, brightness=(i + 1) * 20)
|
||||||
await asyncio.sleep(0.05) # Less than 0.1
|
await asyncio.sleep(0.05) # Less than 0.1
|
||||||
assert manual_control[light.entity_id]
|
assert switch.manager.get_manual_control_attributes(light.entity_id)
|
||||||
|
|
||||||
await update()
|
await update()
|
||||||
await asyncio.sleep(0.3) # Wait the auto reset time
|
await asyncio.sleep(0.3) # Wait the auto reset time
|
||||||
assert not manual_control[light.entity_id]
|
assert not switch.manager.get_manual_control_attributes(light.entity_id)
|
||||||
|
|
||||||
|
|
||||||
async def test_adaptation_attribute_selection(hass):
|
async def test_adaptation_attribute_selection(hass):
|
||||||
|
|
@ -1116,7 +1156,7 @@ async def test_switch_off_on_off(hass):
|
||||||
# Turn light off with transition
|
# Turn light off with transition
|
||||||
await turn_light(False, transition=1)
|
await turn_light(False, transition=1)
|
||||||
|
|
||||||
assert not switch.manager.manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
# Set state to on after a second (like happens IRL)
|
# Set state to on after a second (like happens IRL)
|
||||||
await asyncio.sleep(1e-3)
|
await asyncio.sleep(1e-3)
|
||||||
hass.states.async_set(ENTITY_LIGHT_1, STATE_ON)
|
hass.states.async_set(ENTITY_LIGHT_1, STATE_ON)
|
||||||
|
|
@ -1371,9 +1411,9 @@ async def test_state_change_handlers(hass):
|
||||||
assert timer.is_running()
|
assert timer.is_running()
|
||||||
last_service_data = deepcopy(current_service_data)
|
last_service_data = deepcopy(current_service_data)
|
||||||
await update()
|
await update()
|
||||||
assert not switch.manager.manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
await update()
|
await update()
|
||||||
assert not switch.manager.manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
timer = listener.transition_timers.get(ENTITY_LIGHT_1)
|
timer = listener.transition_timers.get(ENTITY_LIGHT_1)
|
||||||
assert timer
|
assert timer
|
||||||
assert timer.is_running()
|
assert timer.is_running()
|
||||||
|
|
@ -1397,19 +1437,19 @@ async def test_state_change_handlers(hass):
|
||||||
await turn_light(True, brightness=20)
|
await turn_light(True, brightness=20)
|
||||||
await update(force=False)
|
await update(force=False)
|
||||||
assert (
|
assert (
|
||||||
switch.manager.manual_control[ENTITY_LIGHT_1]
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
== LightControlAttributes.BRIGHTNESS
|
== LightControlAttributes.BRIGHTNESS
|
||||||
)
|
)
|
||||||
await update(force=True)
|
await update(force=True)
|
||||||
assert (
|
assert (
|
||||||
switch.manager.manual_control[ENTITY_LIGHT_1]
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
== LightControlAttributes.BRIGHTNESS
|
== LightControlAttributes.BRIGHTNESS
|
||||||
)
|
)
|
||||||
|
|
||||||
# turn light off then on should reset manual control.
|
# turn light off then on should reset manual control.
|
||||||
await turn_light(False)
|
await turn_light(False)
|
||||||
await turn_light(True)
|
await turn_light(True)
|
||||||
assert not switch.manager.manual_control[ENTITY_LIGHT_1]
|
assert not switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
|
|
||||||
await turn_light(True, brightness=50)
|
await turn_light(True, brightness=50)
|
||||||
_LOGGER.debug("Test: Brightness set to %s", 50)
|
_LOGGER.debug("Test: Brightness set to %s", 50)
|
||||||
|
|
@ -1419,7 +1459,7 @@ async def test_state_change_handlers(hass):
|
||||||
assert switch.manager.last_service_data.get(ENTITY_LIGHT_1) is not None
|
assert switch.manager.last_service_data.get(ENTITY_LIGHT_1) is not None
|
||||||
assert switch.manager.our_last_state_on_change.get(ENTITY_LIGHT_1) is not None
|
assert switch.manager.our_last_state_on_change.get(ENTITY_LIGHT_1) is not None
|
||||||
assert (
|
assert (
|
||||||
switch.manager.manual_control[ENTITY_LIGHT_1]
|
switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
== LightControlAttributes.BRIGHTNESS
|
== LightControlAttributes.BRIGHTNESS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2288,12 +2328,11 @@ async def test_light_group(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
if take_over_control:
|
if take_over_control:
|
||||||
assert switch.manager.manual_control["light.light_4"]
|
assert switch.manager.get_manual_control_attributes("light.light_4")
|
||||||
assert switch.manager.manual_control["light.light_5"]
|
assert switch.manager.get_manual_control_attributes("light.light_5")
|
||||||
else:
|
else:
|
||||||
assert not switch.manager.manual_control["light.light_4"]
|
assert not switch.manager.get_manual_control_attributes("light.light_4")
|
||||||
assert not switch.manager.manual_control["light.light_5"]
|
assert not switch.manager.get_manual_control_attributes("light.light_5")
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
LIGHT_DOMAIN,
|
LIGHT_DOMAIN,
|
||||||
SERVICE_TURN_OFF,
|
SERVICE_TURN_OFF,
|
||||||
|
|
@ -2302,8 +2341,8 @@ async def test_light_group(
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert not switch.manager.manual_control["light.light_4"]
|
assert not switch.manager.get_manual_control_attributes("light.light_4")
|
||||||
assert not switch.manager.manual_control["light.light_5"]
|
assert not switch.manager.get_manual_control_attributes("light.light_5")
|
||||||
events = await _turn_on_and_track_event_contexts(
|
events = await _turn_on_and_track_event_contexts(
|
||||||
hass,
|
hass,
|
||||||
"testing",
|
"testing",
|
||||||
|
|
@ -2796,7 +2835,7 @@ async def test_automation_turn_on_from_off_not_marked_as_manual_control(hass):
|
||||||
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_OFF
|
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_OFF
|
||||||
|
|
||||||
# Verify light is not manually controlled
|
# Verify light is not manually controlled
|
||||||
assert not switch.manager.manual_control.get(
|
assert not switch.manager.get_manual_control_attributes(
|
||||||
ENTITY_LIGHT_1,
|
ENTITY_LIGHT_1,
|
||||||
), "Light should not be manually controlled before test"
|
), "Light should not be manually controlled before test"
|
||||||
|
|
||||||
|
|
@ -2821,7 +2860,7 @@ async def test_automation_turn_on_from_off_not_marked_as_manual_control(hass):
|
||||||
# CRITICAL: The light should NOT be marked as manually controlled!
|
# CRITICAL: The light should NOT be marked as manually controlled!
|
||||||
# The bug in v1.30.0 would incorrectly mark this as manual control because
|
# The bug in v1.30.0 would incorrectly mark this as manual control because
|
||||||
# the turn_on had a brightness attribute.
|
# the turn_on had a brightness attribute.
|
||||||
manual_control_attrs = switch.manager.manual_control.get(ENTITY_LIGHT_1)
|
manual_control_attrs = switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
assert not manual_control_attrs, (
|
assert not manual_control_attrs, (
|
||||||
f"Bug confirmed: Light was incorrectly marked as manually controlled "
|
f"Bug confirmed: Light was incorrectly marked as manually controlled "
|
||||||
f"(attributes: {manual_control_attrs}) when turned on from OFF state. "
|
f"(attributes: {manual_control_attrs}) when turned on from OFF state. "
|
||||||
|
|
@ -2895,7 +2934,7 @@ async def test_adapt_only_on_bare_turn_on_respects_pause_changed_mode(hass, inte
|
||||||
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
assert hass.states.get(ENTITY_LIGHT_1).state == STATE_ON
|
||||||
|
|
||||||
# 1. Verify that ONLY brightness is marked as manually controlled
|
# 1. Verify that ONLY brightness is marked as manually controlled
|
||||||
manual_control_attrs = switch.manager.manual_control.get(ENTITY_LIGHT_1)
|
manual_control_attrs = switch.manager.get_manual_control_attributes(ENTITY_LIGHT_1)
|
||||||
assert manual_control_attrs == LightControlAttributes.BRIGHTNESS, (
|
assert manual_control_attrs == LightControlAttributes.BRIGHTNESS, (
|
||||||
f"Expected only BRIGHTNESS to be marked as manually controlled, "
|
f"Expected only BRIGHTNESS to be marked as manually controlled, "
|
||||||
f"but got: {manual_control_attrs}. With adapt_only_on_bare_turn_on=True, "
|
f"but got: {manual_control_attrs}. With adapt_only_on_bare_turn_on=True, "
|
||||||
|
|
@ -2909,7 +2948,7 @@ async def test_adapt_only_on_bare_turn_on_respects_pause_changed_mode(hass, inte
|
||||||
"With PAUSE_CHANGED mode, color should still be adapted since only brightness "
|
"With PAUSE_CHANGED mode, color should still be adapted since only brightness "
|
||||||
"was marked as manually controlled."
|
"was marked as manually controlled."
|
||||||
)
|
)
|
||||||
assert ATTR_COLOR_TEMP_KELVIN in last_service_data, (
|
assert has_color_attribute(last_service_data), (
|
||||||
f"Bug: Color was not adapted. last_service_data={last_service_data}. "
|
f"Bug: Color was not adapted. last_service_data={last_service_data}. "
|
||||||
f"With take_over_control_mode=PAUSE_CHANGED and only brightness marked "
|
f"With take_over_control_mode=PAUSE_CHANGED and only brightness marked "
|
||||||
f"as manually controlled, color_temp should still be adapted."
|
f"as manually controlled, color_temp should still be adapted."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue