mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-15 08:14:04 +02:00
fix: make zero brightness adaptation terminal
This commit is contained in:
parent
9ecffe5125
commit
c373e86043
9 changed files with 333 additions and 8 deletions
|
|
@ -134,7 +134,7 @@ The YAML and frontend configuration methods support all of the options listed be
|
|||
| `min_color_temp` | Warmest color temperature in Kelvin. 🔥 | `2000` | `int` 1000-10000 |
|
||||
| `max_color_temp` | Coldest color temperature in Kelvin. ❄️ | `5500` | `int` 1000-10000 |
|
||||
| `prefer_rgb_color` | Whether to prefer RGB color adjustment over light color temperature when possible. 🌈 | `False` | `bool` |
|
||||
| `sleep_brightness` | Brightness percentage of lights in sleep mode. 😴 | `1` | `int` 1-100 |
|
||||
| `sleep_brightness` | Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴 | `1` | `int` 0-100 |
|
||||
| `sleep_rgb_or_color_temp` | Use either `"rgb_color"` or `"color_temp"` in sleep mode. 🌙 | `color_temp` | one of `['color_temp', 'rgb_color']` |
|
||||
| `sleep_color_temp` | Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is `color_temp`) in Kelvin. 😴 | `1000` | `int` 1000-10000 |
|
||||
| `sleep_rgb_color` | RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is "rgb_color"). 🌈 | `[255, 56, 0]` | RGB color |
|
||||
|
|
|
|||
|
|
@ -130,6 +130,10 @@ def _is_attribute_satisfied(key: str, value: Any, attributes: dict[str, Any]) ->
|
|||
if not isinstance(current, (int, float)) or not isinstance(value, (int, float)):
|
||||
return value == current
|
||||
if key == ATTR_BRIGHTNESS:
|
||||
# Zero is an off command, so it must not be treated as equivalent to a
|
||||
# nearby nonzero brightness in either direction.
|
||||
if value == 0 or current == 0:
|
||||
return value == current
|
||||
return abs(value - current) <= BRIGHTNESS_TOLERANCE
|
||||
if key == ATTR_COLOR_TEMP_KELVIN and value > 0 and current > 0:
|
||||
# Compare in mired space: most integrations quantize color temperature
|
||||
|
|
@ -283,6 +287,14 @@ def prepare_adaptation_data(
|
|||
entity_id,
|
||||
service_data,
|
||||
)
|
||||
if service_data.get(ATTR_BRIGHTNESS) == 0:
|
||||
# Home Assistant treats brightness zero as turn-off. Make it terminal:
|
||||
# color is meaningless while off and must not become a later turn-on.
|
||||
service_data = {
|
||||
key: service_data[key]
|
||||
for key in (ATTR_ENTITY_ID, ATTR_BRIGHTNESS, ATTR_TRANSITION)
|
||||
if key in service_data
|
||||
}
|
||||
service_datas = _split_service_call_data(service_data) if split else [service_data]
|
||||
|
||||
service_datas_length = len(service_datas)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ DOCS[CONF_SEPARATE_TURN_ON_COMMANDS] = (
|
|||
|
||||
CONF_SLEEP_BRIGHTNESS, DEFAULT_SLEEP_BRIGHTNESS = "sleep_brightness", 1
|
||||
DOCS[CONF_SLEEP_BRIGHTNESS] = (
|
||||
"Brightness percentage of lights in sleep mode. Set to 0 to prevent lights from turning on. 😴"
|
||||
"Brightness percentage of lights in sleep mode. Set to 0 to turn lights off "
|
||||
"when brightness adaptation runs in sleep mode. 😴"
|
||||
)
|
||||
|
||||
CONF_SLEEP_COLOR_TEMP, DEFAULT_SLEEP_COLOR_TEMP = "sleep_color_temp", 1000
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ change_switch_settings:
|
|||
selector:
|
||||
boolean: null
|
||||
sleep_brightness:
|
||||
description: Brightness percentage of lights in sleep mode. Set to 0 to prevent lights from turning on. 😴
|
||||
description: Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴
|
||||
required: false
|
||||
example: 1
|
||||
selector:
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"data_description": {
|
||||
"interval": "Frequency to adapt the lights, in seconds. 🔄",
|
||||
"transition": "Duration of transition when lights change, in seconds. 🕑",
|
||||
"sleep_brightness": "Brightness percentage of lights in sleep mode. 😴",
|
||||
"sleep_brightness": "Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴",
|
||||
"sleep_color_temp": "Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is `color_temp`) in Kelvin. 😴"
|
||||
},
|
||||
"sections": {
|
||||
|
|
@ -219,7 +219,7 @@
|
|||
"name": "send_split_delay"
|
||||
},
|
||||
"sleep_brightness": {
|
||||
"description": "Brightness percentage of lights in sleep mode. 😴",
|
||||
"description": "Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴",
|
||||
"name": "sleep_brightness"
|
||||
},
|
||||
"sleep_rgb_or_color_temp": {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
"data_description": {
|
||||
"interval": "Frequency to adapt the lights, in seconds. 🔄",
|
||||
"transition": "Duration of transition when lights change, in seconds. 🕑",
|
||||
"sleep_brightness": "Brightness percentage of lights in sleep mode. 😴",
|
||||
"sleep_brightness": "Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴",
|
||||
"sleep_color_temp": "Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is `color_temp`) in Kelvin. 😴"
|
||||
},
|
||||
"sections": {
|
||||
|
|
@ -220,7 +220,7 @@
|
|||
"name": "send_split_delay"
|
||||
},
|
||||
"sleep_brightness": {
|
||||
"description": "Brightness percentage of lights in sleep mode. 😴",
|
||||
"description": "Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴",
|
||||
"name": "sleep_brightness"
|
||||
},
|
||||
"sleep_rgb_or_color_temp": {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ All configuration options are listed below with their default values. These opti
|
|||
| `min_color_temp` | Warmest color temperature in Kelvin. 🔥 | `2000` | `int` 1000-10000 |
|
||||
| `max_color_temp` | Coldest color temperature in Kelvin. ❄️ | `5500` | `int` 1000-10000 |
|
||||
| `prefer_rgb_color` | Whether to prefer RGB color adjustment over light color temperature when possible. 🌈 | `False` | `bool` |
|
||||
| `sleep_brightness` | Brightness percentage of lights in sleep mode. 😴 | `1` | `int` 1-100 |
|
||||
| `sleep_brightness` | Brightness percentage of lights in sleep mode. Set to 0 to turn lights off when brightness adaptation runs in sleep mode. 😴 | `1` | `int` 0-100 |
|
||||
| `sleep_rgb_or_color_temp` | Use either `"rgb_color"` or `"color_temp"` in sleep mode. 🌙 | `color_temp` | one of `['color_temp', 'rgb_color']` |
|
||||
| `sleep_color_temp` | Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is `color_temp`) in Kelvin. 😴 | `1000` | `int` 1000-10000 |
|
||||
| `sleep_rgb_color` | RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is "rgb_color"). 🌈 | `[255, 56, 0]` | RGB color |
|
||||
|
|
|
|||
|
|
@ -108,6 +108,26 @@ async def test_split_service_call_data(input_data, expected_data_list):
|
|||
State("light.test", STATE_ON, {ATTR_BRIGHTNESS: 227}),
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 230, ATTR_TRANSITION: 2},
|
||||
),
|
||||
(
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 0, ATTR_TRANSITION: 2},
|
||||
State("light.test", STATE_ON, {ATTR_BRIGHTNESS: 1}),
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 0, ATTR_TRANSITION: 2},
|
||||
),
|
||||
(
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 0, ATTR_TRANSITION: 2},
|
||||
State("light.test", STATE_ON, {ATTR_BRIGHTNESS: 2}),
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 0, ATTR_TRANSITION: 2},
|
||||
),
|
||||
(
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 1, ATTR_TRANSITION: 2},
|
||||
State("light.test", STATE_ON, {ATTR_BRIGHTNESS: 0}),
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 1, ATTR_TRANSITION: 2},
|
||||
),
|
||||
(
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_BRIGHTNESS: 0, ATTR_TRANSITION: 2},
|
||||
State("light.test", STATE_ON, {ATTR_BRIGHTNESS: 0}),
|
||||
{ATTR_ENTITY_ID: "light.test", ATTR_TRANSITION: 2},
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test",
|
||||
|
|
@ -165,6 +185,10 @@ async def test_split_service_call_data(input_data, expected_data_list):
|
|||
"keep attributes whose values differ from the state",
|
||||
"remove brightness within quantization tolerance (0-99 device scale)",
|
||||
"keep brightness outside quantization tolerance",
|
||||
"keep zero target across power boundary from brightness one",
|
||||
"keep zero target across power boundary from brightness two",
|
||||
"keep positive target across power boundary from zero",
|
||||
"remove zero target when brightness is already zero",
|
||||
"remove color temp within one mired (round-converting integration)",
|
||||
"remove color temp within one mired (floor-converting HA core helpers)",
|
||||
"remove color temp within one mired (6500 K)",
|
||||
|
|
@ -347,6 +371,24 @@ async def test_create_service_call_data_iterator(
|
|||
],
|
||||
0.7,
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test",
|
||||
ATTR_BRIGHTNESS: 0,
|
||||
ATTR_COLOR_TEMP_KELVIN: 4000,
|
||||
ATTR_TRANSITION: 10,
|
||||
},
|
||||
True,
|
||||
False,
|
||||
[
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test",
|
||||
ATTR_BRIGHTNESS: 0,
|
||||
ATTR_TRANSITION: 10,
|
||||
},
|
||||
],
|
||||
1.2,
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test",
|
||||
|
|
@ -383,6 +425,7 @@ async def test_create_service_call_data_iterator(
|
|||
ids=[
|
||||
"service data passed through",
|
||||
"service data split",
|
||||
"zero brightness is one terminal command",
|
||||
"service data filtered",
|
||||
"service data split and filtered",
|
||||
],
|
||||
|
|
@ -416,6 +459,31 @@ async def test_prepare_adaptation_data(
|
|||
assert generated_service_datas == service_datas_expected
|
||||
|
||||
|
||||
async def test_prepare_zero_after_shared_brightness_was_applied(hass_states_mock):
|
||||
"""A shared zero-brightness call leaves no per-light color follow-up."""
|
||||
data = prepare_adaptation_data(
|
||||
hass_states_mock,
|
||||
"light.test",
|
||||
Context(id="test-id"),
|
||||
10,
|
||||
0.2,
|
||||
{
|
||||
ATTR_ENTITY_ID: "light.test",
|
||||
ATTR_BRIGHTNESS: 0,
|
||||
ATTR_COLOR_TEMP_KELVIN: 4000,
|
||||
ATTR_TRANSITION: 10,
|
||||
},
|
||||
split=True,
|
||||
filter_by_state=False,
|
||||
force=False,
|
||||
already_applied=LightControlAttributes.BRIGHTNESS,
|
||||
)
|
||||
|
||||
assert [item async for item in data.service_call_datas] == []
|
||||
assert data.max_length == 0
|
||||
assert data.attributes is LightControlAttributes.NONE
|
||||
|
||||
|
||||
@pytest.fixture(name="hass_states_mock")
|
||||
def fixture_hass_states_mock():
|
||||
"""Mocks a HA state machine which returns a mock state."""
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ from homeassistant.components.adaptive_lighting.const import (
|
|||
CONF_RESET_MANUAL_CONTROL_ON_SLEEP_MODE_CHANGE,
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS,
|
||||
CONF_SKIP_REDUNDANT_COMMANDS,
|
||||
CONF_SLEEP_BRIGHTNESS,
|
||||
CONF_SLEEP_RGB_OR_COLOR_TEMP,
|
||||
CONF_SLEEP_TRANSITION,
|
||||
CONF_SUNRISE_OFFSET,
|
||||
|
|
@ -4969,3 +4970,246 @@ async def test_forced_split_apply_stays_off(hass, off_action, cleanup):
|
|||
assert ATTR_BRIGHTNESS in turn_on_events[0].data["service_data"]
|
||||
assert ATTR_COLOR_TEMP_KELVIN not in turn_on_events[0].data["service_data"]
|
||||
assert hass.states.get(ENTITY_LIGHT_3).state == STATE_OFF
|
||||
|
||||
|
||||
async def _finish_zero_sleep_adaptations(hass, switch):
|
||||
"""Wait until zero-sleep adaptation calls have settled."""
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
if switch.manager.adaptation_tasks:
|
||||
await asyncio.gather(*tuple(switch.manager.adaptation_tasks))
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
|
||||
def _light_turn_on_payloads(events, entity_id):
|
||||
"""Return turn-on payloads that target one light."""
|
||||
payloads = []
|
||||
for event in events:
|
||||
if (
|
||||
event.data["domain"] != LIGHT_DOMAIN
|
||||
or event.data["service"] != SERVICE_TURN_ON
|
||||
):
|
||||
continue
|
||||
service_data = event.data["service_data"]
|
||||
target = service_data[ATTR_ENTITY_ID]
|
||||
if target == entity_id or (not isinstance(target, str) and entity_id in target):
|
||||
payloads.append(service_data)
|
||||
return payloads
|
||||
|
||||
|
||||
@pytest.mark.parametrize("intercept", [False, True])
|
||||
@pytest.mark.parametrize("split", [False, True])
|
||||
async def test_zero_sleep_bare_turn_on_is_terminal(hass, intercept, split):
|
||||
"""A bare turn-on ends with one color-free zero-brightness command."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(
|
||||
hass,
|
||||
{
|
||||
CONF_INTERCEPT: intercept,
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS: split,
|
||||
CONF_SLEEP_BRIGHTNESS: 0,
|
||||
},
|
||||
)
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: light.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: switch.sleep_mode_switch.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
|
||||
events = []
|
||||
remove_listener = hass.bus.async_listen(EVENT_CALL_SERVICE, events.append)
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: light.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
remove_listener()
|
||||
|
||||
payloads = _light_turn_on_payloads(events, light.entity_id)
|
||||
zero_payloads = [data for data in payloads if data.get(ATTR_BRIGHTNESS) == 0]
|
||||
if intercept:
|
||||
assert payloads == [{ATTR_ENTITY_ID: light.entity_id}]
|
||||
else:
|
||||
assert payloads[0] == {ATTR_ENTITY_ID: light.entity_id}
|
||||
assert len(payloads) == 2
|
||||
assert zero_payloads == [
|
||||
{ATTR_ENTITY_ID: light.entity_id, ATTR_BRIGHTNESS: 0},
|
||||
]
|
||||
assert all(ATTR_COLOR_TEMP_KELVIN not in data for data in payloads)
|
||||
assert all(ATTR_RGB_COLOR not in data for data in payloads)
|
||||
assert hass.states.get(light.entity_id).state == STATE_OFF
|
||||
|
||||
|
||||
@pytest.mark.parametrize("split", [False, True])
|
||||
async def test_zero_sleep_enter_and_exit_does_not_restore_light(hass, split):
|
||||
"""Entering zero sleep turns a light off; exiting leaves it off."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(
|
||||
hass,
|
||||
{
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS: split,
|
||||
CONF_SLEEP_BRIGHTNESS: 0,
|
||||
},
|
||||
)
|
||||
assert hass.states.get(light.entity_id).state == STATE_ON
|
||||
|
||||
events = []
|
||||
remove_listener = hass.bus.async_listen(EVENT_CALL_SERVICE, events.append)
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: switch.sleep_mode_switch.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
enter_payloads = _light_turn_on_payloads(events, light.entity_id)
|
||||
assert len(enter_payloads) == 1
|
||||
assert enter_payloads[0][ATTR_BRIGHTNESS] == 0
|
||||
assert hass.states.get(light.entity_id).state == STATE_OFF
|
||||
|
||||
events.clear()
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: switch.sleep_mode_switch.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
remove_listener()
|
||||
assert _light_turn_on_payloads(events, light.entity_id) == []
|
||||
assert hass.states.get(light.entity_id).state == STATE_OFF
|
||||
|
||||
|
||||
@pytest.mark.parametrize("brightness", [1, 2])
|
||||
@pytest.mark.parametrize("split", [False, True])
|
||||
async def test_zero_sleep_is_not_redundant_with_dimmed_light(
|
||||
hass,
|
||||
brightness,
|
||||
split,
|
||||
):
|
||||
"""Brightness quantization tolerance does not suppress a required off."""
|
||||
switch, (light, *_) = await setup_lights_and_switch(
|
||||
hass,
|
||||
{
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS: split,
|
||||
CONF_SKIP_REDUNDANT_COMMANDS: True,
|
||||
CONF_SLEEP_BRIGHTNESS: 0,
|
||||
},
|
||||
)
|
||||
set_light_brightness(light, brightness)
|
||||
light.async_write_ha_state()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
events = []
|
||||
remove_listener = hass.bus.async_listen(EVENT_CALL_SERVICE, events.append)
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: switch.sleep_mode_switch.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
remove_listener()
|
||||
|
||||
payloads = _light_turn_on_payloads(events, light.entity_id)
|
||||
assert [data[ATTR_BRIGHTNESS] for data in payloads] == [0]
|
||||
assert hass.states.get(light.entity_id).state == STATE_OFF
|
||||
|
||||
|
||||
@pytest.mark.parametrize("split", [False, True])
|
||||
async def test_zero_sleep_command_keeps_full_transition(hass, split, cleanup):
|
||||
"""The terminal zero command keeps the configured sleep transition."""
|
||||
switch, lights = await setup_lights_and_switch(
|
||||
hass,
|
||||
{
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS: split,
|
||||
CONF_SLEEP_BRIGHTNESS: 0,
|
||||
CONF_SLEEP_TRANSITION: 1,
|
||||
},
|
||||
all_lights=True,
|
||||
)
|
||||
light = lights[2]
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: light.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
|
||||
events = []
|
||||
remove_listener = hass.bus.async_listen(EVENT_CALL_SERVICE, events.append)
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: switch.sleep_mode_switch.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
remove_listener()
|
||||
|
||||
payloads = _light_turn_on_payloads(events, light.entity_id)
|
||||
assert payloads == [
|
||||
{
|
||||
ATTR_ENTITY_ID: light.entity_id,
|
||||
ATTR_BRIGHTNESS: 0,
|
||||
ATTR_TRANSITION: 1,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
async def test_zero_sleep_multi_light_intercept_has_no_follow_up(hass):
|
||||
"""A shared intercepted zero command needs no per-light color call."""
|
||||
lights = await setup_lights(hass)
|
||||
managed = [lights[0].entity_id, lights[1].entity_id]
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: managed},
|
||||
blocking=True,
|
||||
)
|
||||
_, switch = await setup_switch(
|
||||
hass,
|
||||
{
|
||||
CONF_LIGHTS: managed,
|
||||
CONF_INTERCEPT: True,
|
||||
CONF_MULTI_LIGHT_INTERCEPT: True,
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS: True,
|
||||
CONF_INITIAL_TRANSITION: 0,
|
||||
CONF_SLEEP_BRIGHTNESS: 0,
|
||||
},
|
||||
)
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: switch.sleep_mode_switch.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
|
||||
events = []
|
||||
remove_listener = hass.bus.async_listen(EVENT_CALL_SERVICE, events.append)
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: managed},
|
||||
blocking=True,
|
||||
)
|
||||
await _finish_zero_sleep_adaptations(hass, switch)
|
||||
remove_listener()
|
||||
|
||||
payloads = [
|
||||
event.data["service_data"]
|
||||
for event in events
|
||||
if event.data["domain"] == LIGHT_DOMAIN
|
||||
and event.data["service"] == SERVICE_TURN_ON
|
||||
]
|
||||
assert payloads == [{ATTR_ENTITY_ID: managed}]
|
||||
assert all(hass.states.get(entity_id).state == STATE_OFF for entity_id in managed)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue