core/tests/components/kulersky/test_light.py

287 lines
9.2 KiB
Python

"""Test the Kuler Sky lights."""
from collections.abc import AsyncGenerator
from unittest.mock import MagicMock, patch
import pykulersky
import pytest
from homeassistant.components.kulersky.const import (
DATA_ADDRESSES,
DATA_DISCOVERY_SUBSCRIPTION,
DOMAIN,
)
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_MODE,
ATTR_HS_COLOR,
ATTR_RGB_COLOR,
ATTR_RGBW_COLOR,
ATTR_SUPPORTED_COLOR_MODES,
ATTR_XY_COLOR,
SCAN_INTERVAL,
ColorMode,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
ATTR_SUPPORTED_FEATURES,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_component import async_update_entity
import homeassistant.util.dt as dt_util
from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.fixture
async def mock_entry() -> MockConfigEntry:
"""Create a mock light entity."""
return MockConfigEntry(domain=DOMAIN)
@pytest.fixture
async def mock_light(
hass: HomeAssistant, mock_entry: MockConfigEntry
) -> AsyncGenerator[MagicMock]:
"""Create a mock light entity."""
light = MagicMock(spec=pykulersky.Light)
light.address = "AA:BB:CC:11:22:33"
light.name = "Bedroom"
light.connect.return_value = True
light.get_color.return_value = (0, 0, 0, 0)
with patch(
"homeassistant.components.kulersky.light.pykulersky.discover",
return_value=[light],
):
mock_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_entry.entry_id)
await hass.async_block_till_done()
assert light.connect.called
yield light
async def test_init(hass: HomeAssistant, mock_light: MagicMock) -> None:
"""Test platform setup."""
state = hass.states.get("light.bedroom")
assert state.state == STATE_OFF
assert dict(state.attributes) == {
ATTR_FRIENDLY_NAME: "Bedroom",
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.RGBW],
ATTR_SUPPORTED_FEATURES: 0,
ATTR_COLOR_MODE: None,
ATTR_BRIGHTNESS: None,
ATTR_HS_COLOR: None,
ATTR_RGB_COLOR: None,
ATTR_XY_COLOR: None,
ATTR_RGBW_COLOR: None,
}
with patch.object(hass.loop, "stop"):
await hass.async_stop()
await hass.async_block_till_done()
assert mock_light.disconnect.called
async def test_remove_entry(
hass: HomeAssistant, mock_light: MagicMock, mock_entry: MockConfigEntry
) -> None:
"""Test platform setup."""
assert hass.data[DOMAIN][DATA_ADDRESSES] == {"AA:BB:CC:11:22:33"}
assert DATA_DISCOVERY_SUBSCRIPTION in hass.data[DOMAIN]
await hass.config_entries.async_remove(mock_entry.entry_id)
assert mock_light.disconnect.called
assert DOMAIN not in hass.data
async def test_remove_entry_exceptions_caught(
hass: HomeAssistant, mock_light: MagicMock, mock_entry: MockConfigEntry
) -> None:
"""Assert that disconnect exceptions are caught."""
mock_light.disconnect.side_effect = pykulersky.PykulerskyException("Mock error")
await hass.config_entries.async_remove(mock_entry.entry_id)
assert mock_light.disconnect.called
async def test_update_exception(hass: HomeAssistant, mock_light: MagicMock) -> None:
"""Test platform setup."""
mock_light.get_color.side_effect = pykulersky.PykulerskyException
await async_update_entity(hass, "light.bedroom")
state = hass.states.get("light.bedroom")
assert state is not None
assert state.state == STATE_UNAVAILABLE
async def test_light_turn_on(hass: HomeAssistant, mock_light: MagicMock) -> None:
"""Test KulerSkyLight turn_on."""
mock_light.get_color.return_value = (255, 255, 255, 255)
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: "light.bedroom"},
blocking=True,
)
await hass.async_block_till_done()
mock_light.set_color.assert_called_with(255, 255, 255, 255)
mock_light.get_color.return_value = (50, 50, 50, 50)
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: "light.bedroom", ATTR_BRIGHTNESS: 50},
blocking=True,
)
await hass.async_block_till_done()
mock_light.set_color.assert_called_with(50, 50, 50, 50)
mock_light.get_color.return_value = (50, 25, 13, 6)
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: "light.bedroom", ATTR_RGBW_COLOR: (255, 128, 64, 32)},
blocking=True,
)
await hass.async_block_till_done()
mock_light.set_color.assert_called_with(50, 25, 13, 6)
# RGB color is converted to RGBW by assigning the white component to the white
# channel, see color_rgb_to_rgbw
mock_light.get_color.return_value = (0, 17, 50, 17)
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: "light.bedroom", ATTR_RGB_COLOR: (64, 128, 255)},
blocking=True,
)
await hass.async_block_till_done()
mock_light.set_color.assert_called_with(0, 17, 50, 17)
# HS color is converted to RGBW by assigning the white component to the white
# channel, see color_rgb_to_rgbw
mock_light.get_color.return_value = (50, 41, 0, 50)
await hass.services.async_call(
"light",
"turn_on",
{ATTR_ENTITY_ID: "light.bedroom", ATTR_HS_COLOR: (50, 50)},
blocking=True,
)
await hass.async_block_till_done()
mock_light.set_color.assert_called_with(50, 41, 0, 50)
async def test_light_turn_off(hass: HomeAssistant, mock_light: MagicMock) -> None:
"""Test KulerSkyLight turn_on."""
mock_light.get_color.return_value = (0, 0, 0, 0)
await hass.services.async_call(
"light",
"turn_off",
{ATTR_ENTITY_ID: "light.bedroom"},
blocking=True,
)
await hass.async_block_till_done()
mock_light.set_color.assert_called_with(0, 0, 0, 0)
async def test_light_update(hass: HomeAssistant, mock_light: MagicMock) -> None:
"""Test KulerSkyLight update."""
utcnow = dt_util.utcnow()
state = hass.states.get("light.bedroom")
assert state.state == STATE_OFF
assert dict(state.attributes) == {
ATTR_FRIENDLY_NAME: "Bedroom",
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.RGBW],
ATTR_SUPPORTED_FEATURES: 0,
ATTR_COLOR_MODE: None,
ATTR_BRIGHTNESS: None,
ATTR_HS_COLOR: None,
ATTR_RGB_COLOR: None,
ATTR_RGBW_COLOR: None,
ATTR_XY_COLOR: None,
}
# Test an exception during discovery
mock_light.get_color.side_effect = pykulersky.PykulerskyException("TEST")
utcnow = utcnow + SCAN_INTERVAL
async_fire_time_changed(hass, utcnow)
await hass.async_block_till_done()
state = hass.states.get("light.bedroom")
assert state.state == STATE_UNAVAILABLE
assert dict(state.attributes) == {
ATTR_FRIENDLY_NAME: "Bedroom",
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.RGBW],
ATTR_SUPPORTED_FEATURES: 0,
}
mock_light.get_color.side_effect = None
mock_light.get_color.return_value = (80, 160, 255, 0)
utcnow = utcnow + SCAN_INTERVAL
async_fire_time_changed(hass, utcnow)
await hass.async_block_till_done()
state = hass.states.get("light.bedroom")
assert state.state == STATE_ON
assert dict(state.attributes) == {
ATTR_FRIENDLY_NAME: "Bedroom",
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.RGBW],
ATTR_SUPPORTED_FEATURES: 0,
ATTR_COLOR_MODE: ColorMode.RGBW,
ATTR_BRIGHTNESS: 255,
ATTR_HS_COLOR: (pytest.approx(212.571), pytest.approx(68.627)),
ATTR_RGB_COLOR: (80, 160, 255),
ATTR_RGBW_COLOR: (80, 160, 255, 0),
ATTR_XY_COLOR: (pytest.approx(0.17), pytest.approx(0.193)),
}
mock_light.get_color.side_effect = None
mock_light.get_color.return_value = (80, 160, 200, 255)
utcnow = utcnow + SCAN_INTERVAL
async_fire_time_changed(hass, utcnow)
await hass.async_block_till_done()
state = hass.states.get("light.bedroom")
assert state.state == STATE_ON
assert dict(state.attributes) == {
ATTR_FRIENDLY_NAME: "Bedroom",
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.RGBW],
ATTR_SUPPORTED_FEATURES: 0,
ATTR_COLOR_MODE: ColorMode.RGBW,
ATTR_BRIGHTNESS: 255,
ATTR_HS_COLOR: (pytest.approx(199.701), pytest.approx(26.275)),
ATTR_RGB_COLOR: (188, 233, 255),
ATTR_RGBW_COLOR: (80, 160, 200, 255),
ATTR_XY_COLOR: (pytest.approx(0.259), pytest.approx(0.306)),
}
mock_light.get_color.side_effect = None
mock_light.get_color.return_value = (80, 160, 200, 240)
utcnow = utcnow + SCAN_INTERVAL
async_fire_time_changed(hass, utcnow)
await hass.async_block_till_done()
state = hass.states.get("light.bedroom")
assert state.state == STATE_ON
assert dict(state.attributes) == {
ATTR_FRIENDLY_NAME: "Bedroom",
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.RGBW],
ATTR_SUPPORTED_FEATURES: 0,
ATTR_COLOR_MODE: ColorMode.RGBW,
ATTR_BRIGHTNESS: 240,
ATTR_HS_COLOR: (pytest.approx(200.0), pytest.approx(27.059)),
ATTR_RGB_COLOR: (186, 232, 255),
ATTR_RGBW_COLOR: (85, 170, 212, 255),
ATTR_XY_COLOR: (pytest.approx(0.257), pytest.approx(0.305)),
}