adaptive-lighting/tests/test_native_targets.py

152 lines
4.8 KiB
Python

"""Native-group targets behavior at HA and device boundaries."""
# pylint: disable=protected-access
import asyncio
import pytest
from homeassistant.components.light import (
ATTR_COLOR_TEMP_KELVIN,
)
from homeassistant.components.light.const import DATA_COMPONENT
from homeassistant.const import ATTR_ENTITY_ID, CONF_LIGHTS, STATE_ON
from homeassistant.core import Context
from homeassistant.setup import async_setup_component
from .support.native_lights import (
GROUP,
RecordingGroup,
RecordingMember,
SceneSetup,
)
from .support.native_scenarios import (
prepare_reported_members,
setup_reported_group,
)
@pytest.mark.parametrize("newer_target", ["all", "members", "helper_group"])
@pytest.mark.parametrize("service", ["turn_on", "turn_off"])
async def test_expanded_targets_supersede_pending_adaptive_colour(
hass,
monkeypatch,
newer_target,
service,
):
"""An accepted newer request cancels colour for its actual light targets."""
setup = await setup_reported_group(hass)
# Keep aggregate power stable to isolate supersession of pending colour
# from the separate reactive path triggered by a new aggregate ON report.
await prepare_reported_members(hass, setup, on=(True, True, True))
planner = setup.switch.manager.native_groups
entered, release = asyncio.Event(), asyncio.Event()
original_flush = planner._flush
first = True
async def held_flush(batch):
nonlocal first
if first:
first = False
entered.set()
await release.wait()
await original_flush(batch)
monkeypatch.setattr(planner, "_flush", held_flush)
entities = [member.entity_id for member in setup.members]
hass.states.async_set("group.review_all", STATE_ON, {ATTR_ENTITY_ID: entities})
target = {
"all": "all",
"members": entities,
"helper_group": "group.review_all",
}[newer_target]
pending = asyncio.create_task(
hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: entities},
blocking=True,
context=Context(),
),
)
try:
await asyncio.wait_for(entered.wait(), 2)
await hass.services.async_call(
"light",
service,
{
ATTR_ENTITY_ID: target,
**({ATTR_COLOR_TEMP_KELVIN: 5000} if service == "turn_on" else {}),
},
blocking=True,
context=Context(),
)
finally:
release.set()
await pending
await hass.async_block_till_done()
if service == "turn_on":
assert [member.physical_kelvin for member in setup.members] == [
5000,
] * 3, setup.commands
else:
assert all(not member.is_on for member in setup.members), setup.commands
@pytest.mark.parametrize("brightness_adaptation", [False, True])
async def test_native_colour_call_combines_group_and_unrelated_member(
hass,
brightness_adaptation,
):
"""Mixed targets retain one original group command and one member command."""
assert await async_setup_component(hass, "light", {})
other_commands = []
other_members = [
RecordingMember(f"light.other_native_{index}", other_commands)
for index in range(3)
]
other_group = RecordingGroup(other_members, other_commands)
other_group.entity_id = "light.other_native_group"
await hass.data[DATA_COMPONENT].async_add_entities([*other_members, other_group])
setup = await setup_reported_group(
hass,
**{CONF_LIGHTS: [GROUP, other_group.entity_id]},
)
await prepare_reported_members(
hass,
setup,
on=(False, False, False),
brightness_adaptation=brightness_adaptation,
)
other_setup = SceneSetup(setup.switch, other_group, other_members, other_commands)
await prepare_reported_members(
hass,
other_setup,
on=(True, False, False),
brightness_adaptation=brightness_adaptation,
)
setup.commands.clear()
await hass.services.async_call(
"light",
"turn_on",
{
ATTR_ENTITY_ID: [GROUP, other_members[0].entity_id],
ATTR_COLOR_TEMP_KELVIN: 3500,
},
blocking=True,
context=Context(),
)
await hass.async_block_till_done()
assert setup.commands == [
{"target": GROUP, "service": "turn_on", ATTR_COLOR_TEMP_KELVIN: 3500},
]
assert other_commands == [
{
"target": other_members[0].entity_id,
"service": "turn_on",
ATTR_COLOR_TEMP_KELVIN: 3500,
},
]
assert other_members[0].physical_kelvin == 3500
assert all(not member.is_on for member in setup.members + other_members[1:])
assert all(
member.physical_kelvin == 4000 for member in setup.members + other_members[1:]
)