core/tests/components/knx/test_light.py

1359 lines
46 KiB
Python

"""Test KNX light."""
from __future__ import annotations
from datetime import timedelta
from freezegun.api import FrozenDateTimeFactory
import pytest
from xknx.core import XknxConnectionState
from xknx.devices.light import Light as XknxLight
from homeassistant.components.knx.const import CONF_STATE_ADDRESS, KNX_ADDRESS, Platform
from homeassistant.components.knx.schema import LightSchema
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_NAME,
ATTR_COLOR_TEMP_KELVIN,
ATTR_HS_COLOR,
ATTR_RGBW_COLOR,
ColorMode,
)
from homeassistant.const import CONF_NAME, STATE_OFF, STATE_ON, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import KnxEntityGenerator
from .conftest import KNXTestKit
from tests.common import async_fire_time_changed
async def test_light_simple(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test simple KNX light."""
test_address = "1/1/1"
await knx.setup_integration(
{
LightSchema.PLATFORM: {
CONF_NAME: "test",
KNX_ADDRESS: test_address,
}
}
)
knx.assert_state(
"light.test",
STATE_OFF,
supported_color_modes=[ColorMode.ONOFF],
)
# turn on light
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test"},
blocking=True,
)
await knx.assert_write(test_address, True)
knx.assert_state(
"light.test",
STATE_ON,
color_mode=ColorMode.ONOFF,
)
# turn off light
await hass.services.async_call(
"light",
"turn_off",
{"entity_id": "light.test"},
blocking=True,
)
await knx.assert_write(test_address, False)
knx.assert_state("light.test", STATE_OFF)
# receive ON telegram
await knx.receive_write(test_address, True)
knx.assert_state("light.test", STATE_ON)
# receive OFF telegram
await knx.receive_write(test_address, False)
knx.assert_state("light.test", STATE_OFF)
# switch does not respond to read by default
await knx.receive_read(test_address)
await knx.assert_telegram_count(0)
async def test_light_brightness(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test dimmable KNX light."""
test_address = "1/1/1"
test_brightness = "1/1/2"
test_brightness_state = "1/1/3"
await knx.setup_integration(
{
LightSchema.PLATFORM: {
CONF_NAME: "test",
KNX_ADDRESS: test_address,
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_brightness,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_brightness_state,
}
}
)
# StateUpdater initialize state
await knx.assert_read(test_brightness_state)
knx.xknx.connection_manager.connection_state_changed(XknxConnectionState.CONNECTED)
# turn on light via brightness
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 80},
blocking=True,
)
await knx.assert_write(test_brightness, (80,))
# state is still OFF until controller reports otherwise
knx.assert_state("light.test", STATE_OFF)
await knx.receive_write(test_address, True)
knx.assert_state(
"light.test",
STATE_ON,
brightness=80,
supported_color_modes=[ColorMode.BRIGHTNESS],
color_mode=ColorMode.BRIGHTNESS,
)
# receive brightness changes from KNX
await knx.receive_write(test_brightness_state, (255,))
knx.assert_state("light.test", STATE_ON, brightness=255)
await knx.receive_write(test_brightness, (128,))
knx.assert_state("light.test", STATE_ON, brightness=128)
# turn off light via brightness
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 0},
blocking=True,
)
await knx.assert_write(test_address, False)
knx.assert_state("light.test", STATE_OFF)
async def test_light_color_temp_absolute(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light color temperature adjustable in Kelvin."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_brightness = "1/1/3"
test_brightness_state = "1/1/4"
test_ct = "1/1/5"
test_ct_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_brightness,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_brightness_state,
LightSchema.CONF_COLOR_TEMP_ADDRESS: test_ct,
LightSchema.CONF_COLOR_TEMP_STATE_ADDRESS: test_ct_state,
LightSchema.CONF_COLOR_TEMP_MODE: "absolute",
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_brightness_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_brightness_state, (255,))
# # StateUpdater semaphore allows 2 concurrent requests
await knx.assert_read(test_ct_state)
await knx.receive_response(test_ct_state, (0x0A, 0x8C)) # 2700 Kelvin - 370 Mired
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.COLOR_TEMP],
color_mode=ColorMode.COLOR_TEMP,
color_temp=370,
color_temp_kelvin=2700,
)
# change color temperature from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_TEMP_KELVIN: 4000}, # 4000 - 0x0FA0
blocking=True,
)
await knx.assert_write(test_ct, (0x0F, 0xA0))
knx.assert_state("light.test", STATE_ON, color_temp=250)
# change color temperature from KNX
await knx.receive_write(test_ct_state, (0x17, 0x70)) # 6000 Kelvin - 166 Mired
knx.assert_state(
"light.test",
STATE_ON,
color_temp=166,
color_temp_kelvin=6000,
)
async def test_light_color_temp_relative(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light color temperature adjustable in percent."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_brightness = "1/1/3"
test_brightness_state = "1/1/4"
test_ct = "1/1/5"
test_ct_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_brightness,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_brightness_state,
LightSchema.CONF_COLOR_TEMP_ADDRESS: test_ct,
LightSchema.CONF_COLOR_TEMP_STATE_ADDRESS: test_ct_state,
LightSchema.CONF_COLOR_TEMP_MODE: "relative",
LightSchema.CONF_MIN_KELVIN: 3000,
LightSchema.CONF_MAX_KELVIN: 4000,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_brightness_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_brightness_state, (255,))
# # StateUpdater semaphore allows 2 concurrent requests
await knx.assert_read(test_ct_state)
await knx.receive_response(test_ct_state, (0xFF,)) # 100 % - 4000 K - 250 Mired
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.COLOR_TEMP],
color_mode=ColorMode.COLOR_TEMP,
color_temp=250,
color_temp_kelvin=4000,
)
# change color temperature from HA
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.test",
ATTR_COLOR_TEMP_KELVIN: 3333, # 3333 Kelvin - 33.3 % - 0x55
},
blocking=True,
)
await knx.assert_write(test_ct, (0x55,))
knx.assert_state(
"light.test",
STATE_ON,
color_temp=300,
color_temp_kelvin=3333,
)
# change color temperature from KNX
await knx.receive_write(test_ct_state, (0xE6,)) # 3901 Kelvin - 90.1 % - 256 Mired
knx.assert_state(
"light.test",
STATE_ON,
color_temp=256,
color_temp_kelvin=3901,
)
async def test_light_hs_color(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light with hs color."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_brightness = "1/1/3"
test_brightness_state = "1/1/4"
test_hue = "1/1/5"
test_hue_state = "1/1/6"
test_sat = "1/1/7"
test_sat_state = "1/1/8"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_brightness,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_brightness_state,
LightSchema.CONF_HUE_ADDRESS: test_hue,
LightSchema.CONF_HUE_STATE_ADDRESS: test_hue_state,
LightSchema.CONF_SATURATION_ADDRESS: test_sat,
LightSchema.CONF_SATURATION_STATE_ADDRESS: test_sat_state,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_brightness_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_brightness_state, (255,))
# # StateUpdater semaphore allows 2 concurrent requests
await knx.assert_read(test_hue_state)
await knx.assert_read(test_sat_state)
await knx.receive_response(test_hue_state, (0xFF,))
await knx.receive_response(test_sat_state, (0xFF,))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.HS],
color_mode=ColorMode.HS,
hs_color=(360, 100),
)
# change color from HA - only hue
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "blue"}, # hue: 240, sat: 100
blocking=True,
)
await knx.assert_write(test_hue, (0xAA,))
knx.assert_state("light.test", STATE_ON, brightness=255, hs_color=(240, 100))
# change color from HA - only saturation
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.test",
ATTR_HS_COLOR: (240, 50),
}, # hue: 60, sat: 12.157
blocking=True,
)
await knx.assert_write(test_sat, (0x80,))
knx.assert_state("light.test", STATE_ON, brightness=255, hs_color=(240, 50))
# change color from HA - hue and sat
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "hotpink"}, # hue: 330, sat: 59
blocking=True,
)
await knx.assert_write(test_hue, (0xEA,))
await knx.assert_write(test_sat, (0x96,))
knx.assert_state("light.test", STATE_ON, brightness=255, hs_color=(330, 59))
# change color and brightness from KNX
await knx.receive_write(test_brightness, (0xB2,))
knx.assert_state("light.test", STATE_ON, brightness=178, hs_color=(330, 59))
await knx.receive_write(test_hue, (0x7D,))
knx.assert_state("light.test", STATE_ON, brightness=178, hs_color=(176, 59))
await knx.receive_write(test_sat, (0xD1,))
knx.assert_state("light.test", STATE_ON, brightness=178, hs_color=(176, 82))
async def test_light_xyy_color(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light with xyy color."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_xyy = "1/1/5"
test_xyy_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_XYY_ADDRESS: test_xyy,
LightSchema.CONF_XYY_STATE_ADDRESS: test_xyy_state,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_xyy_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_xyy_state, (0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x03))
knx.assert_state(
"light.test",
STATE_ON,
brightness=204,
supported_color_modes=[ColorMode.XY],
color_mode=ColorMode.XY,
xy_color=(0.8, 0.8),
)
# change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 139, ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_xyy, (179, 116, 76, 139, 139, 3))
knx.assert_state("light.test", STATE_ON, brightness=139, xy_color=(0.701, 0.299))
# change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 255},
blocking=True,
)
await knx.assert_write(test_xyy, (0, 0, 0, 0, 255, 1))
knx.assert_state("light.test", STATE_ON, brightness=255, xy_color=(0.701, 0.299))
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_xyy, (120, 16, 63, 59, 0, 2))
knx.assert_state("light.test", STATE_ON, brightness=255, xy_color=(0.469, 0.247))
# change color and brightness from KNX
await knx.receive_write(test_xyy, (0x85, 0x1E, 0x4F, 0x5C, 0x19, 0x03))
knx.assert_state("light.test", STATE_ON, brightness=25, xy_color=(0.52, 0.31))
# change brightness from KNX
await knx.receive_write(test_xyy, (0x00, 0x00, 0x00, 0x00, 0x80, 0x01))
knx.assert_state("light.test", STATE_ON, brightness=128, xy_color=(0.52, 0.31))
# change color from KNX
await knx.receive_write(test_xyy, (0x2E, 0x14, 0x40, 0x00, 0x00, 0x02))
knx.assert_state("light.test", STATE_ON, brightness=128, xy_color=(0.18, 0.25))
async def test_light_xyy_color_with_brightness(
hass: HomeAssistant, knx: KNXTestKit
) -> None:
"""Test KNX light with xyy color and explicit brightness address."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_brightness = "1/1/3"
test_brightness_state = "1/1/4"
test_xyy = "1/1/5"
test_xyy_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_brightness,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_brightness_state,
LightSchema.CONF_XYY_ADDRESS: test_xyy,
LightSchema.CONF_XYY_STATE_ADDRESS: test_xyy_state,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_brightness_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_brightness_state, (255,))
# # StateUpdater semaphore allows 2 concurrent requests
await knx.assert_read(test_xyy_state)
await knx.receive_response(test_xyy_state, (0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x03))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255, # brightness form xyy_color ignored when extra brightness GA is used
supported_color_modes=[ColorMode.XY],
color_mode=ColorMode.XY,
xy_color=(0.8, 0.8),
)
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_xyy, (179, 116, 76, 139, 0, 2))
knx.assert_state("light.test", STATE_ON, brightness=255, xy_color=(0.701, 0.299))
# change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 139},
blocking=True,
)
await knx.assert_write(test_brightness, (0x8B,))
knx.assert_state("light.test", STATE_ON, brightness=139, xy_color=(0.701, 0.299))
# change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 255, ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_xyy, (120, 16, 63, 59, 255, 3))
# brightness relies on brightness_state GA
await knx.receive_write(test_brightness_state, (255,))
knx.assert_state("light.test", STATE_ON, brightness=255, xy_color=(0.469, 0.247))
# change color and brightness from KNX
await knx.receive_write(test_xyy, (0x85, 0x1E, 0x4F, 0x5C, 0x00, 0x02))
knx.assert_state("light.test", STATE_ON, brightness=255, xy_color=(0.52, 0.31))
await knx.receive_write(test_brightness, (21,))
knx.assert_state("light.test", STATE_ON, brightness=21, xy_color=(0.52, 0.31))
async def test_light_rgb_individual(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light with rgb color in individual GAs."""
test_red = "1/1/3"
test_red_state = "1/1/4"
test_green = "1/1/5"
test_green_state = "1/1/6"
test_blue = "1/1/7"
test_blue_state = "1/1/8"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
LightSchema.CONF_INDIVIDUAL_COLORS: {
LightSchema.CONF_RED: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_red,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_red_state,
},
LightSchema.CONF_GREEN: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_green,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_green_state,
},
LightSchema.CONF_BLUE: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_blue,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_blue_state,
},
},
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_red_state)
await knx.assert_read(test_green_state)
await knx.receive_response(test_red_state, (255,))
await knx.receive_response(test_green_state, (255,))
# # StateUpdater semaphore allows 2 concurrent requests
await knx.assert_read(test_blue_state)
await knx.receive_response(test_blue_state, (255,))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.RGB],
color_mode=ColorMode.RGB,
rgb_color=(255, 255, 255),
)
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_red, (255,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
knx.assert_state("light.test", STATE_ON, brightness=255, rgb_color=(255, 0, 0))
# change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 200},
blocking=True,
)
await knx.assert_write(test_red, (200,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
knx.assert_state("light.test", STATE_ON, brightness=200, rgb_color=(255, 0, 0))
# change only color, keep brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_red, (200,))
await knx.assert_write(test_green, (82,))
await knx.assert_write(test_blue, (141,))
knx.assert_state("light.test", STATE_ON, brightness=200, rgb_color=(255, 105, 180))
# change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 100, ATTR_COLOR_NAME: "yellow"},
blocking=True,
)
await knx.assert_write(test_red, (100,))
await knx.assert_write(test_green, (100,))
await knx.assert_write(test_blue, (0,))
knx.assert_state("light.test", STATE_ON, brightness=100, rgb_color=(255, 255, 0))
# turn OFF from KNX
await knx.receive_write(test_red, (0,))
await knx.receive_write(test_green, (0,))
await knx.receive_write(test_blue, (0,))
knx.assert_state("light.test", STATE_OFF)
# turn ON from KNX
await knx.receive_write(test_red, (0,))
await knx.receive_write(test_green, (180,))
await knx.receive_write(test_blue, (0,))
knx.assert_state("light.test", STATE_ON, brightness=180, rgb_color=(0, 255, 0))
# turn OFF from HA
await hass.services.async_call(
"light",
"turn_off",
{"entity_id": "light.test"},
blocking=True,
)
await knx.assert_write(test_red, (0,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
knx.assert_state("light.test", STATE_OFF)
# turn ON from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test"},
blocking=True,
)
# color will not be restored - defaults to white
await knx.assert_write(test_red, (255,))
await knx.assert_write(test_green, (255,))
await knx.assert_write(test_blue, (255,))
knx.assert_state("light.test", STATE_ON, brightness=255, rgb_color=(255, 255, 255))
# turn ON with brightness only from HA - defaults to white
await knx.receive_write(test_red, (0,))
await knx.receive_write(test_green, (0,))
await knx.receive_write(test_blue, (0,))
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 45},
blocking=True,
)
await knx.assert_write(test_red, (45,))
await knx.assert_write(test_green, (45,))
await knx.assert_write(test_blue, (45,))
async def test_light_rgbw_individual(
hass: HomeAssistant, knx: KNXTestKit, freezer: FrozenDateTimeFactory
) -> None:
"""Test KNX light with rgbw color in individual GAs."""
test_red = "1/1/3"
test_red_state = "1/1/4"
test_green = "1/1/5"
test_green_state = "1/1/6"
test_blue = "1/1/7"
test_blue_state = "1/1/8"
test_white = "1/1/9"
test_white_state = "1/1/10"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
LightSchema.CONF_INDIVIDUAL_COLORS: {
LightSchema.CONF_RED: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_red,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_red_state,
},
LightSchema.CONF_GREEN: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_green,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_green_state,
},
LightSchema.CONF_BLUE: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_blue,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_blue_state,
},
LightSchema.CONF_WHITE: {
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_white,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_white_state,
},
},
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_red_state)
await knx.assert_read(test_green_state)
await knx.receive_response(test_red_state, (0,))
await knx.receive_response(test_green_state, (0,))
# # StateUpdater semaphore allows 2 concurrent requests
await knx.assert_read(test_blue_state)
await knx.assert_read(test_white_state)
await knx.receive_response(test_blue_state, (0,))
await knx.receive_response(test_white_state, (255,))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.RGBW],
color_mode=ColorMode.RGBW,
rgbw_color=(0, 0, 0, 255),
)
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_red, (255,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
await knx.assert_write(test_white, (0,))
knx.assert_state("light.test", STATE_ON, brightness=255, rgbw_color=(255, 0, 0, 0))
# change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 200},
blocking=True,
)
await knx.assert_write(test_red, (200,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
await knx.assert_write(test_white, (0,))
knx.assert_state("light.test", STATE_ON, brightness=200, rgbw_color=(255, 0, 0, 0))
# change only color, keep brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_red, (200,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (100,))
await knx.assert_write(test_white, (139,))
knx.assert_state(
"light.test",
STATE_ON,
brightness=200,
rgb_color=(255, 104, 179), # minor rounding error - expected (255, 105, 180)
rgbw_color=(255, 0, 127, 177), # expected (255, 0, 128, 178)
)
# change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 100, ATTR_COLOR_NAME: "yellow"},
blocking=True,
)
await knx.assert_write(test_red, (100,))
await knx.assert_write(test_green, (100,))
await knx.assert_write(test_blue, (0,))
await knx.assert_write(test_white, (0,))
knx.assert_state(
"light.test", STATE_ON, brightness=100, rgbw_color=(255, 255, 0, 0)
)
# turn OFF from KNX
await knx.receive_write(test_red, (0,))
await knx.receive_write(test_green, (0,))
# # individual color debounce takes 0.2 seconds if not all 4 addresses received
knx.assert_state("light.test", STATE_ON)
freezer.tick(timedelta(seconds=XknxLight.DEBOUNCE_TIMEOUT))
async_fire_time_changed(hass)
await knx.xknx.task_registry.block_till_done()
knx.assert_state("light.test", STATE_OFF)
# turn ON from KNX
await knx.receive_write(test_red, (0,))
await knx.receive_write(test_green, (180,))
await knx.receive_write(test_blue, (0,))
await knx.receive_write(test_white, (0,))
knx.assert_state("light.test", STATE_ON, brightness=180, rgbw_color=(0, 255, 0, 0))
# turn OFF from HA
await hass.services.async_call(
"light",
"turn_off",
{"entity_id": "light.test"},
blocking=True,
)
await knx.assert_write(test_red, (0,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
await knx.assert_write(test_white, (0,))
knx.assert_state("light.test", STATE_OFF)
# turn ON from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test"},
blocking=True,
)
# color will not be restored - defaults to 100% on all channels
await knx.assert_write(test_red, (255,))
await knx.assert_write(test_green, (255,))
await knx.assert_write(test_blue, (255,))
await knx.assert_write(test_white, (255,))
knx.assert_state(
"light.test", STATE_ON, brightness=255, rgbw_color=(255, 255, 255, 255)
)
# turn ON with brightness only from HA - defaults to white
await knx.receive_write(test_red, (0,))
await knx.receive_write(test_green, (0,))
await knx.receive_write(test_blue, (0,))
await knx.receive_write(test_white, (0,))
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 45},
blocking=True,
)
await knx.assert_write(test_red, (0,))
await knx.assert_write(test_green, (0,))
await knx.assert_write(test_blue, (0,))
await knx.assert_write(test_white, (45,))
async def test_light_rgb(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light with rgb color."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_rgb = "1/1/5"
test_rgb_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_COLOR_ADDRESS: test_rgb,
LightSchema.CONF_COLOR_STATE_ADDRESS: test_rgb_state,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_rgb_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_rgb_state, (0xFF, 0xFF, 0xFF))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.RGB],
color_mode=ColorMode.RGB,
rgb_color=(255, 255, 255),
)
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_rgb, (255, 0, 0))
knx.assert_state("light.test", STATE_ON, brightness=255, rgb_color=(255, 0, 0))
# change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 200},
blocking=True,
)
await knx.assert_write(test_rgb, (200, 0, 0))
knx.assert_state("light.test", STATE_ON, brightness=200, rgb_color=(255, 0, 0))
# change color, keep brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_rgb, (200, 82, 141))
knx.assert_state(
"light.test",
STATE_ON,
brightness=200,
rgb_color=(255, 105, 180),
)
# change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 100, ATTR_COLOR_NAME: "yellow"},
blocking=True,
)
await knx.assert_write(test_rgb, (100, 100, 0))
knx.assert_state("light.test", STATE_ON, brightness=100, rgb_color=(255, 255, 0))
# turn OFF from KNX
await knx.receive_write(test_address_state, False)
knx.assert_state("light.test", STATE_OFF)
# receive color update from KNX - still OFF
await knx.receive_write(test_rgb, (0, 180, 0))
knx.assert_state("light.test", STATE_OFF)
# turn ON from KNX - include color update
await knx.receive_write(test_address_state, True)
knx.assert_state("light.test", STATE_ON, brightness=180, rgb_color=(0, 255, 0))
# turn OFF from HA
await hass.services.async_call(
"light",
"turn_off",
{"entity_id": "light.test"},
blocking=True,
)
await knx.assert_write(test_address, False)
knx.assert_state("light.test", STATE_OFF)
# turn ON from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test"},
blocking=True,
)
# color will be restored in no other state was received
await knx.assert_write(test_address, True)
knx.assert_state("light.test", STATE_ON, brightness=180, rgb_color=(0, 255, 0))
async def test_light_rgbw(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light with rgbw color."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_rgbw = "1/1/5"
test_rgbw_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_RGBW_ADDRESS: test_rgbw,
LightSchema.CONF_RGBW_STATE_ADDRESS: test_rgbw_state,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_rgbw_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_rgbw_state, (0xFF, 0x65, 0x66, 0x67, 0x00, 0x0F))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.RGBW],
color_mode=ColorMode.RGBW,
rgbw_color=(255, 101, 102, 103),
)
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_rgbw, (0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F))
knx.assert_state("light.test", STATE_ON, brightness=255, rgbw_color=(255, 0, 0, 0))
# change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 200},
blocking=True,
)
await knx.assert_write(test_rgbw, (0xC8, 0x00, 0x00, 0x00, 0x00, 0x0F))
knx.assert_state("light.test", STATE_ON, brightness=200, rgbw_color=(255, 0, 0, 0))
# change color, keep brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_rgbw, (200, 0, 100, 139, 0x00, 0x0F))
knx.assert_state(
"light.test",
STATE_ON,
brightness=200,
rgb_color=(255, 104, 179), # minor rounding error - expected (255, 105, 180)
rgbw_color=(255, 0, 127, 177), # expected (255, 0, 128, 178)
)
# change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 100, ATTR_COLOR_NAME: "yellow"},
blocking=True,
)
await knx.assert_write(test_rgbw, (100, 100, 0, 0, 0x00, 0x0F))
knx.assert_state(
"light.test", STATE_ON, brightness=100, rgbw_color=(255, 255, 0, 0)
)
# turn OFF from KNX
await knx.receive_write(test_address_state, False)
knx.assert_state("light.test", STATE_OFF)
# receive color update from KNX - still OFF
await knx.receive_write(test_rgbw, (0, 180, 0, 0, 0x00, 0x0F))
knx.assert_state("light.test", STATE_OFF)
# turn ON from KNX - include color update
await knx.receive_write(test_address_state, True)
knx.assert_state("light.test", STATE_ON, brightness=180, rgbw_color=(0, 255, 0, 0))
# turn OFF from HA
await hass.services.async_call(
"light",
"turn_off",
{"entity_id": "light.test"},
blocking=True,
)
await knx.assert_write(test_address, False)
knx.assert_state("light.test", STATE_OFF)
# turn ON from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test"},
blocking=True,
)
# color will be restored if no other state was received
await knx.assert_write(test_address, True)
knx.assert_state("light.test", STATE_ON, brightness=180, rgbw_color=(0, 255, 0, 0))
async def test_light_rgbw_brightness(hass: HomeAssistant, knx: KNXTestKit) -> None:
"""Test KNX light with rgbw color with dedicated brightness."""
test_address = "1/1/1"
test_address_state = "1/1/2"
test_brightness = "1/1/3"
test_brightness_state = "1/1/4"
test_rgbw = "1/1/5"
test_rgbw_state = "1/1/6"
await knx.setup_integration(
{
LightSchema.PLATFORM: [
{
CONF_NAME: "test",
KNX_ADDRESS: test_address,
CONF_STATE_ADDRESS: test_address_state,
LightSchema.CONF_BRIGHTNESS_ADDRESS: test_brightness,
LightSchema.CONF_BRIGHTNESS_STATE_ADDRESS: test_brightness_state,
LightSchema.CONF_RGBW_ADDRESS: test_rgbw,
LightSchema.CONF_RGBW_STATE_ADDRESS: test_rgbw_state,
},
]
}
)
# StateUpdater initialize state
await knx.assert_read(test_address_state)
await knx.assert_read(test_brightness_state)
await knx.receive_response(test_address_state, True)
await knx.receive_response(test_brightness_state, (0xFF,))
await knx.assert_read(test_rgbw_state)
await knx.receive_response(test_rgbw_state, (0xFF, 0x65, 0x66, 0x67, 0x00, 0x0F))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
supported_color_modes=[ColorMode.RGBW],
color_mode=ColorMode.RGBW,
rgbw_color=(255, 101, 102, 103),
)
# change color from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_NAME: "red"},
blocking=True,
)
await knx.assert_write(test_rgbw, (0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F))
knx.assert_state("light.test", STATE_ON, brightness=255, rgbw_color=(255, 0, 0, 0))
# # update from dedicated brightness state
await knx.receive_write(test_brightness_state, (0xF0,))
knx.assert_state("light.test", STATE_ON, brightness=240, rgbw_color=(255, 0, 0, 0))
# single encoded brightness - at least one primary color = 255
# # change brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 128},
blocking=True,
)
await knx.assert_write(test_brightness, (128,))
knx.assert_state("light.test", STATE_ON, brightness=128, rgbw_color=(255, 0, 0, 0))
# # change color and brightness from HA
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_BRIGHTNESS: 128, ATTR_COLOR_NAME: "hotpink"},
blocking=True,
)
await knx.assert_write(test_rgbw, (255, 0, 128, 178, 0x00, 0x0F))
await knx.assert_write(test_brightness, (128,))
knx.assert_state(
"light.test",
STATE_ON,
brightness=128,
rgb_color=(255, 105, 180),
rgbw_color=(255, 0, 128, 178),
)
# doubly encoded brightness
# brightness is handled by dedicated brightness address only
# # from dedicated rgbw state
await knx.receive_write(test_rgbw_state, (0xC8, 0x00, 0x00, 0x00, 0x00, 0x0F))
knx.assert_state("light.test", STATE_ON, brightness=128, rgbw_color=(200, 0, 0, 0))
# # from HA - only color
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_RGBW_COLOR: (20, 30, 40, 50)},
blocking=True,
)
await knx.assert_write(test_rgbw, (20, 30, 40, 50, 0x00, 0x0F))
knx.assert_state(
"light.test", STATE_ON, brightness=128, rgbw_color=(20, 30, 40, 50)
)
# # from HA - brightness and color
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.test",
ATTR_BRIGHTNESS: 50,
ATTR_RGBW_COLOR: (100, 200, 55, 12),
},
blocking=True,
)
await knx.assert_write(test_rgbw, (100, 200, 55, 12, 0x00, 0x0F))
await knx.assert_write(test_brightness, (50,))
knx.assert_state(
"light.test", STATE_ON, brightness=50, rgbw_color=(100, 200, 55, 12)
)
async def test_light_ui_create(
hass: HomeAssistant,
knx: KNXTestKit,
create_ui_entity: KnxEntityGenerator,
) -> None:
"""Test creating a light."""
await knx.setup_integration({})
await create_ui_entity(
platform=Platform.LIGHT,
entity_data={"name": "test"},
knx_data={
"ga_switch": {"write": "1/1/1", "state": "2/2/2"},
"_light_color_mode_schema": "default",
"sync_state": True,
},
)
# created entity sends read-request to KNX bus
await knx.assert_read("2/2/2")
await knx.receive_response("2/2/2", True)
knx.assert_state(
"light.test",
STATE_ON,
supported_color_modes=[ColorMode.ONOFF],
color_mode=ColorMode.ONOFF,
)
@pytest.mark.parametrize(
("color_temp_mode", "raw_ct"),
[
("7.600", (0x10, 0x68)),
("9", (0x46, 0x69)),
("5.001", (0x74,)),
],
)
async def test_light_ui_color_temp(
hass: HomeAssistant,
knx: KNXTestKit,
create_ui_entity: KnxEntityGenerator,
color_temp_mode: str,
raw_ct: tuple[int, ...],
) -> None:
"""Test creating a color-temp light."""
await knx.setup_integration({})
await create_ui_entity(
platform=Platform.LIGHT,
entity_data={"name": "test"},
knx_data={
"ga_switch": {"write": "1/1/1", "state": "2/2/2"},
"ga_color_temp": {
"write": "3/3/3",
"dpt": color_temp_mode,
},
"_light_color_mode_schema": "default",
"sync_state": True,
},
)
await knx.assert_read("2/2/2", True)
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": "light.test", ATTR_COLOR_TEMP_KELVIN: 4200},
blocking=True,
)
await knx.assert_write("3/3/3", raw_ct)
knx.assert_state(
"light.test",
STATE_ON,
supported_color_modes=[ColorMode.COLOR_TEMP],
color_mode=ColorMode.COLOR_TEMP,
color_temp_kelvin=pytest.approx(4200, abs=1),
)
async def test_light_ui_multi_mode(
hass: HomeAssistant,
knx: KNXTestKit,
create_ui_entity: KnxEntityGenerator,
) -> None:
"""Test creating a light with multiple color modes."""
await knx.setup_integration({})
await create_ui_entity(
platform=Platform.LIGHT,
entity_data={"name": "test"},
knx_data={
"color_temp_min": 2700,
"color_temp_max": 6000,
"_light_color_mode_schema": "default",
"ga_switch": {
"write": "1/1/1",
"passive": [],
"state": "2/2/2",
},
"sync_state": True,
"ga_brightness": {
"write": "0/6/0",
"state": "0/6/1",
"passive": [],
},
"ga_color_temp": {
"write": "0/6/2",
"dpt": "7.600",
"state": "0/6/3",
"passive": [],
},
"ga_color": {
"write": "0/6/4",
"dpt": "251.600",
"state": "0/6/5",
"passive": [],
},
},
)
await knx.assert_read("2/2/2", True)
await knx.assert_read("0/6/1", (0xFF,))
await knx.assert_read("0/6/5", (0xFF, 0x65, 0x66, 0x67, 0x00, 0x0F))
await knx.assert_read("0/6/3", (0x12, 0x34))
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.test",
ATTR_COLOR_NAME: "hotpink",
},
blocking=True,
)
await knx.assert_write("0/6/4", (255, 0, 128, 178, 0, 15))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
color_temp_kelvin=None,
rgbw_color=(255, 0, 128, 178),
supported_color_modes=[
ColorMode.COLOR_TEMP,
ColorMode.RGBW,
],
color_mode=ColorMode.RGBW,
)
await hass.services.async_call(
"light",
"turn_on",
{
"entity_id": "light.test",
ATTR_COLOR_TEMP_KELVIN: 4200,
},
blocking=True,
)
await knx.assert_write("0/6/2", (0x10, 0x68))
knx.assert_state(
"light.test",
STATE_ON,
brightness=255,
color_temp_kelvin=4200,
rgbw_color=None,
supported_color_modes=[
ColorMode.COLOR_TEMP,
ColorMode.RGBW,
],
color_mode=ColorMode.COLOR_TEMP,
)
async def test_light_ui_load(
hass: HomeAssistant,
knx: KNXTestKit,
load_config_store: None,
entity_registry: er.EntityRegistry,
) -> None:
"""Test loading a light from storage."""
await knx.setup_integration({})
await knx.assert_read("1/0/21", response=True, ignore_order=True)
# unrelated switch in config store
await knx.assert_read("1/0/45", response=True, ignore_order=True)
knx.assert_state(
"light.test",
STATE_ON,
supported_color_modes=[ColorMode.ONOFF],
color_mode=ColorMode.ONOFF,
)
entity = entity_registry.async_get("light.test")
assert entity.entity_category is EntityCategory.CONFIG