mirror of
https://github.com/home-assistant/core.git
synced 2026-07-01 19:57:08 +01:00
282 lines
8.2 KiB
Python
282 lines
8.2 KiB
Python
"""Light platform tests for iAquaLink."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import AsyncMock
|
|
|
|
import httpx
|
|
from iaqualink.client import AqualinkClient
|
|
from iaqualink.exception import (
|
|
AqualinkServiceException,
|
|
AqualinkServiceUnauthorizedException,
|
|
)
|
|
from iaqualink.systems.iaqua.device import (
|
|
IaquaColorLightJC,
|
|
IaquaDimmableLight,
|
|
IaquaLightSwitch,
|
|
)
|
|
from iaqualink.systems.iaqua.system import IaquaSystem
|
|
import pytest
|
|
from syrupy.assertion import SnapshotAssertion
|
|
|
|
from homeassistant.components.light import (
|
|
ATTR_BRIGHTNESS,
|
|
ATTR_EFFECT,
|
|
DOMAIN as LIGHT_DOMAIN,
|
|
ColorMode,
|
|
LightEntityFeature,
|
|
)
|
|
from homeassistant.const import (
|
|
ATTR_ENTITY_ID,
|
|
SERVICE_TURN_OFF,
|
|
SERVICE_TURN_ON,
|
|
STATE_ON,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ConfigEntryAuthFailed, HomeAssistantError
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from .conftest import (
|
|
assert_platform_setup,
|
|
get_aqualink_device,
|
|
get_aqualink_system,
|
|
setup_entry,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
async def test_setup(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
entity_registry: er.EntityRegistry,
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test all light entities are created correctly."""
|
|
await assert_platform_setup(
|
|
hass, config_entry, client, entity_registry, snapshot, LIGHT_DOMAIN
|
|
)
|
|
|
|
|
|
async def _setup_light(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
cls: type,
|
|
data: dict[str, str],
|
|
) -> tuple[IaquaSystem, object, str, object]:
|
|
"""Set up the integration with a single light entity."""
|
|
system = get_aqualink_system(client, cls=IaquaSystem)
|
|
system.online = True
|
|
system.update = AsyncMock()
|
|
light = get_aqualink_device(system, name="aux_1", cls=cls, data=data)
|
|
system.get_devices = AsyncMock(return_value={light.name: light})
|
|
system.set_aux = AsyncMock()
|
|
system.set_light = AsyncMock()
|
|
|
|
await setup_entry(hass, config_entry, system)
|
|
|
|
entity_ids = hass.states.async_entity_ids(LIGHT_DOMAIN)
|
|
assert len(entity_ids) == 1
|
|
entity_id = entity_ids[0]
|
|
entity_state = hass.states.get(entity_id)
|
|
assert entity_state is not None
|
|
return system, light, entity_id, entity_state
|
|
|
|
|
|
async def test_effect_light_setup_exposes_effect_features(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
) -> None:
|
|
"""Test color lights expose effect-related state through Home Assistant."""
|
|
_, _, _, entity_state = await _setup_light(
|
|
hass,
|
|
config_entry,
|
|
client,
|
|
IaquaColorLightJC,
|
|
{"state": "1", "aux": "1", "subtype": "1", "label": "pool light"},
|
|
)
|
|
|
|
assert entity_state.state == STATE_ON
|
|
assert entity_state.attributes["color_mode"] == ColorMode.ONOFF.value
|
|
assert entity_state.attributes["supported_features"] == LightEntityFeature.EFFECT
|
|
assert "Alpine White" in entity_state.attributes["effect_list"]
|
|
|
|
|
|
async def test_dimmable_light_setup_exposes_brightness(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
) -> None:
|
|
"""Test dimmable lights expose brightness through Home Assistant."""
|
|
_, _, _, entity_state = await _setup_light(
|
|
hass,
|
|
config_entry,
|
|
client,
|
|
IaquaDimmableLight,
|
|
{"state": "1", "aux": "1", "subtype": "50", "label": "pool light"},
|
|
)
|
|
|
|
assert entity_state.state == STATE_ON
|
|
assert entity_state.attributes["color_mode"] == ColorMode.BRIGHTNESS.value
|
|
assert entity_state.attributes["brightness"] == 128
|
|
|
|
|
|
async def test_light_turn_on_with_effect_updates_state(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
) -> None:
|
|
"""Test turning on a color light with an effect uses the effect branch."""
|
|
system, light, entity_id, _ = await _setup_light(
|
|
hass,
|
|
config_entry,
|
|
client,
|
|
IaquaColorLightJC,
|
|
{"state": "0", "aux": "1", "subtype": "1", "label": "pool light"},
|
|
)
|
|
light_component = hass.data[LIGHT_DOMAIN]
|
|
entity = light_component.get_entity(entity_id)
|
|
assert entity is not None
|
|
|
|
async def set_light(data: dict[str, str]) -> None:
|
|
light.data["state"] = data["light"]
|
|
|
|
system.set_light = AsyncMock(side_effect=set_light)
|
|
|
|
await entity.async_turn_on(**{ATTR_EFFECT: "Alpine White"})
|
|
|
|
entity_state = hass.states.get(entity_id)
|
|
assert entity_state is not None
|
|
assert entity_state.state == STATE_ON
|
|
|
|
|
|
async def test_light_turn_on_with_brightness_updates_state(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
) -> None:
|
|
"""Test turning on a dimmable light updates Home Assistant state."""
|
|
system, light, entity_id, _ = await _setup_light(
|
|
hass,
|
|
config_entry,
|
|
client,
|
|
IaquaDimmableLight,
|
|
{"state": "0", "aux": "1", "subtype": "0", "label": "pool light"},
|
|
)
|
|
|
|
async def set_light(data: dict[str, str]) -> None:
|
|
light.data["state"] = "1" if data["light"] != "0" else "0"
|
|
light.data["subtype"] = data["light"]
|
|
|
|
system.set_light = AsyncMock(side_effect=set_light)
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
SERVICE_TURN_ON,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 128},
|
|
blocking=True,
|
|
)
|
|
|
|
entity_state = hass.states.get(entity_id)
|
|
assert entity_state is not None
|
|
assert entity_state.state == STATE_ON
|
|
assert entity_state.attributes["brightness"] == 128
|
|
|
|
|
|
async def test_light_turn_on_without_attributes_updates_state(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
) -> None:
|
|
"""Test turning on a basic light uses the default turn_on path."""
|
|
system, light, entity_id, _ = await _setup_light(
|
|
hass,
|
|
config_entry,
|
|
client,
|
|
IaquaLightSwitch,
|
|
{"state": "0", "aux": "1", "label": "pool light"},
|
|
)
|
|
|
|
async def set_aux(_: str) -> None:
|
|
light.data["state"] = "1"
|
|
|
|
system.set_aux = AsyncMock(side_effect=set_aux)
|
|
light_component = hass.data[LIGHT_DOMAIN]
|
|
entity = light_component.get_entity(entity_id)
|
|
assert entity is not None
|
|
|
|
await entity.async_turn_on()
|
|
|
|
entity_state = hass.states.get(entity_id)
|
|
assert entity_state is not None
|
|
assert entity_state.state == STATE_ON
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("raised_exception", "expected_exception", "match"),
|
|
[
|
|
pytest.param(
|
|
AqualinkServiceException,
|
|
HomeAssistantError,
|
|
"Aqualink error: AqualinkServiceException",
|
|
id="service",
|
|
),
|
|
pytest.param(
|
|
TimeoutError(),
|
|
HomeAssistantError,
|
|
"Aqualink error: TimeoutError",
|
|
id="timeout",
|
|
),
|
|
pytest.param(
|
|
httpx.HTTPError("boom"),
|
|
HomeAssistantError,
|
|
"Aqualink error: boom",
|
|
id="http",
|
|
),
|
|
pytest.param(
|
|
AqualinkServiceUnauthorizedException,
|
|
ConfigEntryAuthFailed,
|
|
"Invalid credentials for iAquaLink",
|
|
id="unauthorized",
|
|
),
|
|
pytest.param(
|
|
Exception("Test exception"),
|
|
Exception,
|
|
"Test exception",
|
|
id="unexpected",
|
|
),
|
|
],
|
|
)
|
|
async def test_light_turn_off_errors_leave_state_unchanged(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
client: AqualinkClient,
|
|
raised_exception: Exception | type[Exception],
|
|
expected_exception: type[Exception],
|
|
match: str,
|
|
) -> None:
|
|
"""Test turn-off errors are surfaced through the light service call."""
|
|
system, _, entity_id, _ = await _setup_light(
|
|
hass,
|
|
config_entry,
|
|
client,
|
|
IaquaLightSwitch,
|
|
{"state": "1", "aux": "1", "label": "pool light"},
|
|
)
|
|
system.set_aux = AsyncMock(side_effect=raised_exception)
|
|
|
|
with pytest.raises(expected_exception, match=match):
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
SERVICE_TURN_OFF,
|
|
{ATTR_ENTITY_ID: entity_id},
|
|
blocking=True,
|
|
)
|
|
|
|
entity_state = hass.states.get(entity_id)
|
|
assert entity_state is not None
|
|
assert entity_state.state == STATE_ON
|