mirror of
https://github.com/home-assistant/core.git
synced 2026-04-02 16:36:08 +01:00
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Joostlek <joostlek@outlook.com>
645 lines
18 KiB
Python
645 lines
18 KiB
Python
"""Test for the SmartThings light platform."""
|
|
|
|
from typing import Any
|
|
from unittest.mock import AsyncMock, call
|
|
|
|
from pysmartthings import Attribute, Capability, Command
|
|
from pysmartthings.models import HealthStatus
|
|
import pytest
|
|
from syrupy.assertion import SnapshotAssertion
|
|
|
|
from homeassistant.components.light import (
|
|
ATTR_BRIGHTNESS,
|
|
ATTR_COLOR_MODE,
|
|
ATTR_COLOR_TEMP_KELVIN,
|
|
ATTR_HS_COLOR,
|
|
ATTR_MAX_COLOR_TEMP_KELVIN,
|
|
ATTR_MIN_COLOR_TEMP_KELVIN,
|
|
ATTR_RGB_COLOR,
|
|
ATTR_SUPPORTED_COLOR_MODES,
|
|
ATTR_TRANSITION,
|
|
ATTR_XY_COLOR,
|
|
DOMAIN as LIGHT_DOMAIN,
|
|
ColorMode,
|
|
)
|
|
from homeassistant.components.smartthings.const import MAIN
|
|
from homeassistant.const import (
|
|
ATTR_ENTITY_ID,
|
|
SERVICE_TURN_OFF,
|
|
SERVICE_TURN_ON,
|
|
STATE_OFF,
|
|
STATE_ON,
|
|
STATE_UNAVAILABLE,
|
|
STATE_UNKNOWN,
|
|
Platform,
|
|
)
|
|
from homeassistant.core import HomeAssistant, State
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from . import (
|
|
set_attribute_value,
|
|
setup_integration,
|
|
snapshot_smartthings_entities,
|
|
trigger_health_update,
|
|
trigger_update,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry, mock_restore_cache_with_extra_data
|
|
|
|
|
|
async def test_all_entities(
|
|
hass: HomeAssistant,
|
|
snapshot: SnapshotAssertion,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test all entities."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
snapshot_smartthings_entities(hass, entity_registry, snapshot, Platform.LIGHT)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
@pytest.mark.parametrize(
|
|
("data", "calls"),
|
|
[
|
|
(
|
|
{},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH,
|
|
Command.ON,
|
|
MAIN,
|
|
)
|
|
],
|
|
),
|
|
(
|
|
{ATTR_COLOR_TEMP_KELVIN: 4000},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_TEMPERATURE,
|
|
Command.SET_COLOR_TEMPERATURE,
|
|
MAIN,
|
|
argument=4000,
|
|
),
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH,
|
|
Command.ON,
|
|
MAIN,
|
|
),
|
|
],
|
|
),
|
|
(
|
|
{ATTR_HS_COLOR: [350, 90]},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_CONTROL,
|
|
Command.SET_COLOR,
|
|
MAIN,
|
|
argument={"hue": 97.2222, "saturation": 90.0},
|
|
),
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH,
|
|
Command.ON,
|
|
MAIN,
|
|
),
|
|
],
|
|
),
|
|
(
|
|
{ATTR_BRIGHTNESS: 50},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH_LEVEL,
|
|
Command.SET_LEVEL,
|
|
MAIN,
|
|
argument=[20, 0],
|
|
)
|
|
],
|
|
),
|
|
(
|
|
{ATTR_BRIGHTNESS: 50, ATTR_TRANSITION: 3},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH_LEVEL,
|
|
Command.SET_LEVEL,
|
|
MAIN,
|
|
argument=[20, 3],
|
|
)
|
|
],
|
|
),
|
|
],
|
|
)
|
|
async def test_turn_on_light(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
data: dict[str, Any],
|
|
calls: list[call],
|
|
) -> None:
|
|
"""Test light turn on command."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
SERVICE_TURN_ON,
|
|
{ATTR_ENTITY_ID: "light.standing_light"} | data,
|
|
blocking=True,
|
|
)
|
|
assert devices.execute_device_command.mock_calls == calls
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
@pytest.mark.parametrize(
|
|
("data", "calls"),
|
|
[
|
|
(
|
|
{},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH,
|
|
Command.OFF,
|
|
MAIN,
|
|
)
|
|
],
|
|
),
|
|
(
|
|
{ATTR_TRANSITION: 3},
|
|
[
|
|
call(
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH_LEVEL,
|
|
Command.SET_LEVEL,
|
|
MAIN,
|
|
argument=[0, 3],
|
|
)
|
|
],
|
|
),
|
|
],
|
|
)
|
|
async def test_turn_off_light(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
data: dict[str, Any],
|
|
calls: list[call],
|
|
) -> None:
|
|
"""Test light turn off command."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
SERVICE_TURN_OFF,
|
|
{ATTR_ENTITY_ID: "light.standing_light"} | data,
|
|
blocking=True,
|
|
)
|
|
assert devices.execute_device_command.mock_calls == calls
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_state_update(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test state update."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get("light.standing_light").state == STATE_OFF
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH,
|
|
Attribute.SWITCH,
|
|
"on",
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").state == STATE_ON
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_updating_brightness(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test brightness update."""
|
|
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_CONTROL,
|
|
Attribute.HUE,
|
|
40,
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").attributes[ATTR_BRIGHTNESS] == 178
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.SWITCH_LEVEL,
|
|
Attribute.LEVEL,
|
|
20,
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").attributes[ATTR_BRIGHTNESS] == 51
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_updating_hs(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test hue/saturation update."""
|
|
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_CONTROL,
|
|
Attribute.HUE,
|
|
40,
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").attributes[ATTR_HS_COLOR] == (
|
|
144.0,
|
|
60,
|
|
)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_CONTROL,
|
|
Attribute.HUE,
|
|
20,
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").attributes[ATTR_HS_COLOR] == (
|
|
72.0,
|
|
60,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_updating_color_temp(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test color temperature update."""
|
|
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_TEMPERATURE,
|
|
Attribute.COLOR_TEMPERATURE,
|
|
3000,
|
|
)
|
|
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
|
|
is ColorMode.COLOR_TEMP
|
|
)
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_TEMP_KELVIN]
|
|
== 3000
|
|
)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_TEMPERATURE,
|
|
Attribute.COLOR_TEMPERATURE,
|
|
2000,
|
|
)
|
|
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_TEMP_KELVIN]
|
|
== 2000
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_color_modes(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test color mode changes."""
|
|
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
|
|
set_attribute_value(devices, Capability.COLOR_CONTROL, Attribute.SATURATION, 50)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
|
|
is ColorMode.HS
|
|
)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_TEMPERATURE,
|
|
Attribute.COLOR_TEMPERATURE,
|
|
2000,
|
|
)
|
|
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
|
|
is ColorMode.COLOR_TEMP
|
|
)
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"cb958955-b015-498c-9e62-fc0c51abd054",
|
|
Capability.COLOR_CONTROL,
|
|
Attribute.HUE,
|
|
20,
|
|
)
|
|
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
|
|
is ColorMode.HS
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_color_mode_after_startup(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test color mode after startup."""
|
|
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
|
|
|
|
RESTORE_DATA = {
|
|
ATTR_BRIGHTNESS: 178,
|
|
ATTR_COLOR_MODE: ColorMode.COLOR_TEMP,
|
|
ATTR_COLOR_TEMP_KELVIN: 3000,
|
|
ATTR_HS_COLOR: (144.0, 60),
|
|
ATTR_MAX_COLOR_TEMP_KELVIN: 9000,
|
|
ATTR_MIN_COLOR_TEMP_KELVIN: 2000,
|
|
ATTR_RGB_COLOR: (255, 128, 0),
|
|
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.COLOR_TEMP, ColorMode.HS],
|
|
ATTR_XY_COLOR: (0.61, 0.35),
|
|
}
|
|
|
|
mock_restore_cache_with_extra_data(
|
|
hass, ((State("light.standing_light", STATE_ON), RESTORE_DATA),)
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert (
|
|
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
|
|
is ColorMode.COLOR_TEMP
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_availability(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test availability."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get("light.standing_light").state == STATE_OFF
|
|
|
|
await trigger_health_update(
|
|
hass, devices, "cb958955-b015-498c-9e62-fc0c51abd054", HealthStatus.OFFLINE
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").state == STATE_UNAVAILABLE
|
|
|
|
await trigger_health_update(
|
|
hass, devices, "cb958955-b015-498c-9e62-fc0c51abd054", HealthStatus.ONLINE
|
|
)
|
|
|
|
assert hass.states.get("light.standing_light").state == STATE_OFF
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
|
|
async def test_availability_at_start(
|
|
hass: HomeAssistant,
|
|
unavailable_device: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test unavailable at boot."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
assert hass.states.get("light.standing_light").state == STATE_UNAVAILABLE
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["da_ks_hood_01001"])
|
|
@pytest.mark.parametrize(
|
|
("service", "command"),
|
|
[
|
|
(SERVICE_TURN_ON, Command.ON),
|
|
(SERVICE_TURN_OFF, Command.OFF),
|
|
],
|
|
)
|
|
async def test_lamp_with_switch(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
service: str,
|
|
command: Command,
|
|
) -> None:
|
|
"""Test samsungce.lamp on/off with switch capability."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
service,
|
|
{ATTR_ENTITY_ID: "light.range_hood_light"},
|
|
blocking=True,
|
|
)
|
|
devices.execute_device_command.assert_called_once_with(
|
|
"fa5fca25-fa7a-1807-030a-2f72ee0f7bff",
|
|
Capability.SWITCH,
|
|
command,
|
|
"lamp",
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("brightness", "brightness_level"),
|
|
[(128, "low"), (129, "high"), (240, "high")],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
("device_fixture", "entity_id", "device_id", "component"),
|
|
[
|
|
(
|
|
"da_ks_hood_01001",
|
|
"light.range_hood_light",
|
|
"fa5fca25-fa7a-1807-030a-2f72ee0f7bff",
|
|
"lamp",
|
|
),
|
|
(
|
|
"da_ks_microwave_0101x",
|
|
"light.microwave_light",
|
|
"2bad3237-4886-e699-1b90-4a51a3d55c8a",
|
|
"hood",
|
|
),
|
|
],
|
|
)
|
|
async def test_lamp_component_with_brightness(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
entity_id: str,
|
|
device_id: str,
|
|
component: str,
|
|
brightness: int,
|
|
brightness_level: str,
|
|
) -> None:
|
|
"""Test samsungce.lamp on/off with switch capability."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
SERVICE_TURN_ON,
|
|
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: brightness},
|
|
blocking=True,
|
|
)
|
|
devices.execute_device_command.assert_called_once_with(
|
|
device_id,
|
|
Capability.SAMSUNG_CE_LAMP,
|
|
Command.SET_BRIGHTNESS_LEVEL,
|
|
component,
|
|
argument=brightness_level,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["da_ks_range_0101x"])
|
|
@pytest.mark.parametrize(
|
|
("service", "argument"),
|
|
[(SERVICE_TURN_ON, "extraHigh"), (SERVICE_TURN_OFF, "off")],
|
|
)
|
|
async def test_lamp_without_switch(
|
|
hass: HomeAssistant,
|
|
devices: AsyncMock,
|
|
mock_config_entry: MockConfigEntry,
|
|
service: str,
|
|
argument: str,
|
|
) -> None:
|
|
"""Test samsungce.lamp on/off without switch capability."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
service,
|
|
{ATTR_ENTITY_ID: "light.vulcan_light"},
|
|
blocking=True,
|
|
)
|
|
devices.execute_device_command.assert_called_once_with(
|
|
"2c3cbaa0-1899-5ddc-7b58-9d657bd48f18",
|
|
Capability.SAMSUNG_CE_LAMP,
|
|
Command.SET_BRIGHTNESS_LEVEL,
|
|
MAIN,
|
|
argument=argument,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["da_ks_hood_01001"])
|
|
async def test_lamp_from_off(
|
|
hass: HomeAssistant, devices: AsyncMock, mock_config_entry: MockConfigEntry
|
|
) -> None:
|
|
"""Test samsungce.lamp on with brightness level from off state."""
|
|
set_attribute_value(
|
|
devices, Capability.SWITCH, Attribute.SWITCH, "off", component="lamp"
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get("light.range_hood_light").state == STATE_OFF
|
|
|
|
await hass.services.async_call(
|
|
LIGHT_DOMAIN,
|
|
SERVICE_TURN_ON,
|
|
{ATTR_ENTITY_ID: "light.range_hood_light", ATTR_BRIGHTNESS: 255},
|
|
blocking=True,
|
|
)
|
|
assert devices.execute_device_command.mock_calls == [
|
|
call(
|
|
"fa5fca25-fa7a-1807-030a-2f72ee0f7bff",
|
|
Capability.SAMSUNG_CE_LAMP,
|
|
Command.SET_BRIGHTNESS_LEVEL,
|
|
"lamp",
|
|
argument="high",
|
|
),
|
|
call(
|
|
"fa5fca25-fa7a-1807-030a-2f72ee0f7bff",
|
|
Capability.SWITCH,
|
|
Command.ON,
|
|
"lamp",
|
|
),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["da_ks_hood_01001"])
|
|
async def test_lamp_unknown_switch(
|
|
hass: HomeAssistant, devices: AsyncMock, mock_config_entry: MockConfigEntry
|
|
) -> None:
|
|
"""Test lamp state becomes unknown when switch state is unknown."""
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get("light.range_hood_light").state == STATE_ON
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"fa5fca25-fa7a-1807-030a-2f72ee0f7bff",
|
|
Capability.SWITCH,
|
|
Attribute.SWITCH,
|
|
None,
|
|
component="lamp",
|
|
)
|
|
|
|
assert hass.states.get("light.range_hood_light").state == STATE_UNKNOWN
|
|
|
|
|
|
@pytest.mark.parametrize("device_fixture", ["da_ks_range_0101x"])
|
|
async def test_lamp_unknown_brightness(
|
|
hass: HomeAssistant, devices: AsyncMock, mock_config_entry: MockConfigEntry
|
|
) -> None:
|
|
"""Test lamp state becomes unknown when brightness level is unknown."""
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get("light.vulcan_light").state == STATE_ON
|
|
|
|
await trigger_update(
|
|
hass,
|
|
devices,
|
|
"2c3cbaa0-1899-5ddc-7b58-9d657bd48f18",
|
|
Capability.SAMSUNG_CE_LAMP,
|
|
Attribute.BRIGHTNESS_LEVEL,
|
|
None,
|
|
)
|
|
|
|
assert hass.states.get("light.vulcan_light").state == STATE_UNKNOWN
|