1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-19 15:00:27 +01:00
Files
core/tests/components/knx/test_light.py
T

1349 lines
46 KiB
Python

"""Test KNX light."""
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_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_kelvin=4000)
# 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_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_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_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_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"},
"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,
},
"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,
"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": [],
},
"color": {
"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(
knx: KNXTestKit,
entity_registry: er.EntityRegistry,
) -> None:
"""Test loading a light from storage."""
await knx.setup_integration(config_store_fixture="config_store_light_switch.json")
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