core/tests/components/wled/test_light.py

358 lines
11 KiB
Python
Raw Normal View History

"""Tests for the WLED light platform."""
import json
from unittest.mock import MagicMock
import pytest
from wled import Device as WLEDDevice, WLEDConnectionError, WLEDError
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_EFFECT,
ATTR_HS_COLOR,
ATTR_RGB_COLOR,
ATTR_RGBW_COLOR,
ATTR_TRANSITION,
DOMAIN as LIGHT_DOMAIN,
)
2021-11-29 14:15:50 +00:00
from homeassistant.components.wled.const import CONF_KEEP_MASTER_LIGHT, SCAN_INTERVAL
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_ICON,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
2022-05-24 14:30:41 +00:00
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
import homeassistant.util.dt as dt_util
from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
2023-02-20 12:00:02 +00:00
pytestmark = pytest.mark.usefixtures("init_integration")
async def test_rgb_light_state(
2023-02-20 12:00:02 +00:00
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
"""Test the creation and values of the WLED lights."""
# First segment of the strip
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light"))
assert state.attributes.get(ATTR_BRIGHTNESS) == 127
assert state.attributes.get(ATTR_EFFECT) == "Solid"
assert state.attributes.get(ATTR_HS_COLOR) == (37.412, 100.0)
assert state.attributes.get(ATTR_ICON) == "mdi:led-strip-variant"
assert state.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert (entry := entity_registry.async_get("light.wled_rgb_light"))
assert entry.unique_id == "aabbccddeeff_0"
# Second segment of the strip
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light_segment_1"))
assert state.attributes.get(ATTR_BRIGHTNESS) == 127
assert state.attributes.get(ATTR_EFFECT) == "Blink"
assert state.attributes.get(ATTR_HS_COLOR) == (148.941, 100.0)
assert state.attributes.get(ATTR_ICON) == "mdi:led-strip-variant"
assert state.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert (entry := entity_registry.async_get("light.wled_rgb_light_segment_1"))
assert entry.unique_id == "aabbccddeeff_1"
# Test master control of the lightstrip
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light_master"))
assert state.attributes.get(ATTR_BRIGHTNESS) == 127
assert state.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert (entry := entity_registry.async_get("light.wled_rgb_light_master"))
assert entry.unique_id == "aabbccddeeff"
async def test_segment_change_state(
hass: HomeAssistant,
mock_wled: MagicMock,
) -> None:
"""Test the change of state of the WLED segments."""
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.wled_rgb_light", ATTR_TRANSITION: 5},
blocking=True,
)
assert mock_wled.segment.call_count == 1
mock_wled.segment.assert_called_with(
on=False,
segment_id=0,
transition=50,
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{
ATTR_BRIGHTNESS: 42,
ATTR_EFFECT: "Chase",
ATTR_ENTITY_ID: "light.wled_rgb_light",
ATTR_RGB_COLOR: [255, 0, 0],
ATTR_TRANSITION: 5,
},
blocking=True,
)
assert mock_wled.segment.call_count == 2
mock_wled.segment.assert_called_with(
brightness=42,
color_primary=(255, 0, 0),
effect="Chase",
on=True,
segment_id=0,
transition=50,
)
async def test_master_change_state(
hass: HomeAssistant,
mock_wled: MagicMock,
) -> None:
"""Test the change of state of the WLED master light control."""
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.wled_rgb_light_master", ATTR_TRANSITION: 5},
blocking=True,
)
assert mock_wled.master.call_count == 1
mock_wled.master.assert_called_with(
on=False,
transition=50,
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{
ATTR_BRIGHTNESS: 42,
ATTR_ENTITY_ID: "light.wled_rgb_light_master",
ATTR_TRANSITION: 5,
},
blocking=True,
)
assert mock_wled.master.call_count == 2
mock_wled.master.assert_called_with(
brightness=42,
on=True,
transition=50,
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.wled_rgb_light_master", ATTR_TRANSITION: 5},
blocking=True,
)
assert mock_wled.master.call_count == 3
mock_wled.master.assert_called_with(
on=False,
transition=50,
)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{
ATTR_BRIGHTNESS: 42,
ATTR_ENTITY_ID: "light.wled_rgb_light_master",
ATTR_TRANSITION: 5,
},
blocking=True,
)
assert mock_wled.master.call_count == 4
mock_wled.master.assert_called_with(
brightness=42,
on=True,
transition=50,
)
2023-02-20 12:00:02 +00:00
@pytest.mark.parametrize("device_fixture", ["rgb_single_segment"])
async def test_dynamically_handle_segments(
hass: HomeAssistant,
mock_wled: MagicMock,
) -> None:
"""Test if a new/deleted segment is dynamically added/removed."""
2023-02-20 12:00:02 +00:00
assert (segment0 := hass.states.get("light.wled_rgb_light"))
assert segment0.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert not hass.states.get("light.wled_rgb_light_master")
assert not hass.states.get("light.wled_rgb_light_segment_1")
return_value = mock_wled.update.return_value
mock_wled.update.return_value = WLEDDevice(
json.loads(load_fixture("wled/rgb.json"))
)
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
2023-02-20 12:00:02 +00:00
assert (master := hass.states.get("light.wled_rgb_light_master"))
assert master.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert (segment0 := hass.states.get("light.wled_rgb_light"))
assert segment0.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert (segment1 := hass.states.get("light.wled_rgb_light_segment_1"))
assert segment1.state == STATE_ON
# Test adding if segment shows up again, including the master entity
mock_wled.update.return_value = return_value
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
2023-02-20 12:00:02 +00:00
assert (master := hass.states.get("light.wled_rgb_light_master"))
assert master.state == STATE_UNAVAILABLE
2023-02-20 12:00:02 +00:00
assert (segment0 := hass.states.get("light.wled_rgb_light"))
assert segment0.state == STATE_ON
2023-02-20 12:00:02 +00:00
assert (segment1 := hass.states.get("light.wled_rgb_light_segment_1"))
assert segment1.state == STATE_UNAVAILABLE
2023-02-20 12:00:02 +00:00
@pytest.mark.parametrize("device_fixture", ["rgb_single_segment"])
async def test_single_segment_behavior(
hass: HomeAssistant,
mock_wled: MagicMock,
) -> None:
"""Test the behavior of the integration with a single segment."""
device = mock_wled.update.return_value
assert not hass.states.get("light.wled_rgb_light_master")
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light"))
assert state.state == STATE_ON
# Test segment brightness takes master into account
device.state.brightness = 100
device.state.segments[0].brightness = 255
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light"))
assert state.attributes.get(ATTR_BRIGHTNESS) == 100
# Test segment is off when master is off
device.state.on = False
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
state = hass.states.get("light.wled_rgb_light")
assert state
assert state.state == STATE_OFF
# Test master is turned off when turning off a single segment
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.wled_rgb_light", ATTR_TRANSITION: 5},
blocking=True,
)
assert mock_wled.master.call_count == 1
mock_wled.master.assert_called_with(
on=False,
transition=50,
)
# Test master is turned on when turning on a single segment, and segment
# brightness is set to 255.
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{
ATTR_ENTITY_ID: "light.wled_rgb_light",
ATTR_TRANSITION: 5,
ATTR_BRIGHTNESS: 42,
},
blocking=True,
)
assert mock_wled.segment.call_count == 1
assert mock_wled.master.call_count == 2
mock_wled.segment.assert_called_with(on=True, segment_id=0, brightness=255)
mock_wled.master.assert_called_with(on=True, transition=50, brightness=42)
async def test_light_error(
hass: HomeAssistant,
mock_wled: MagicMock,
) -> None:
"""Test error handling of the WLED lights."""
mock_wled.segment.side_effect = WLEDError
2022-05-24 14:30:41 +00:00
with pytest.raises(HomeAssistantError, match="Invalid response from WLED API"):
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.wled_rgb_light"},
blocking=True,
)
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light"))
assert state.state == STATE_ON
assert mock_wled.segment.call_count == 1
2021-06-19 15:13:48 +00:00
mock_wled.segment.assert_called_with(on=False, segment_id=0, transition=None)
async def test_light_connection_error(
hass: HomeAssistant,
mock_wled: MagicMock,
) -> None:
"""Test error handling of the WLED switches."""
mock_wled.segment.side_effect = WLEDConnectionError
2022-05-24 14:30:41 +00:00
with pytest.raises(HomeAssistantError, match="Error communicating with WLED API"):
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.wled_rgb_light"},
blocking=True,
)
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light"))
assert state.state == STATE_UNAVAILABLE
assert mock_wled.segment.call_count == 1
2021-06-19 15:13:48 +00:00
mock_wled.segment.assert_called_with(on=False, segment_id=0, transition=None)
2023-02-20 12:00:02 +00:00
@pytest.mark.parametrize("device_fixture", ["rgbw"])
async def test_rgbw_light(hass: HomeAssistant, mock_wled: MagicMock) -> None:
"""Test RGBW support for WLED."""
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgbw_light"))
assert state.state == STATE_ON
assert state.attributes.get(ATTR_RGBW_COLOR) == (255, 0, 0, 139)
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{
ATTR_ENTITY_ID: "light.wled_rgbw_light",
ATTR_RGBW_COLOR: (255, 255, 255, 255),
},
blocking=True,
)
assert mock_wled.segment.call_count == 1
mock_wled.segment.assert_called_with(
color_primary=(255, 255, 255, 255),
on=True,
segment_id=0,
)
2023-02-20 12:00:02 +00:00
@pytest.mark.parametrize("device_fixture", ["rgb_single_segment"])
async def test_single_segment_with_keep_master_light(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_wled: MagicMock,
) -> None:
"""Test the behavior of the integration with a single segment."""
assert not hass.states.get("light.wled_rgb_light_master")
hass.config_entries.async_update_entry(
init_integration, options={CONF_KEEP_MASTER_LIGHT: True}
)
await hass.async_block_till_done()
2023-02-20 12:00:02 +00:00
assert (state := hass.states.get("light.wled_rgb_light_master"))
assert state.state == STATE_ON