mirror of
https://github.com/home-assistant/core.git
synced 2025-04-27 02:37:50 +00:00
Add platform tests to yeelight (#37745)
* Add platform tests to yeelight * Update requirements * Break long string
This commit is contained in:
parent
c913d17913
commit
e8b6ed5a27
@ -972,7 +972,6 @@ omit =
|
||||
homeassistant/components/yale_smart_alarm/alarm_control_panel.py
|
||||
homeassistant/components/yamaha_musiccast/media_player.py
|
||||
homeassistant/components/yandex_transport/*
|
||||
homeassistant/components/yeelight/*
|
||||
homeassistant/components/yeelightsunflower/light.py
|
||||
homeassistant/components/yi/camera.py
|
||||
homeassistant/components/zabbix/*
|
||||
|
@ -995,6 +995,9 @@ wolf_smartset==0.1.4
|
||||
# homeassistant.components.zestimate
|
||||
xmltodict==0.12.0
|
||||
|
||||
# homeassistant.components.yeelight
|
||||
yeelight==0.5.2
|
||||
|
||||
# homeassistant.components.zeroconf
|
||||
zeroconf==0.28.0
|
||||
|
||||
|
87
tests/components/yeelight/__init__.py
Normal file
87
tests/components/yeelight/__init__.py
Normal file
@ -0,0 +1,87 @@
|
||||
"""Tests for the Yeelight integration."""
|
||||
from yeelight import BulbType
|
||||
from yeelight.main import _MODEL_SPECS
|
||||
|
||||
from homeassistant.components.yeelight import (
|
||||
CONF_MODE_MUSIC,
|
||||
CONF_NIGHTLIGHT_SWITCH_TYPE,
|
||||
CONF_SAVE_ON_CHANGE,
|
||||
DOMAIN,
|
||||
NIGHTLIGHT_SWITCH_TYPE_LIGHT,
|
||||
)
|
||||
from homeassistant.const import CONF_DEVICES, CONF_NAME
|
||||
|
||||
from tests.async_mock import MagicMock
|
||||
|
||||
IP_ADDRESS = "192.168.1.239"
|
||||
MODEL = "color"
|
||||
ID = "0x000000000015243f"
|
||||
FW_VER = "18"
|
||||
|
||||
CAPABILITIES = {
|
||||
"id": ID,
|
||||
"model": MODEL,
|
||||
"fw_ver": FW_VER,
|
||||
"support": "get_prop set_default set_power toggle set_bright start_cf stop_cf"
|
||||
" set_scene cron_add cron_get cron_del set_ct_abx set_rgb",
|
||||
"name": "",
|
||||
}
|
||||
|
||||
NAME = f"yeelight_{MODEL}_{ID}"
|
||||
|
||||
MODULE = "homeassistant.components.yeelight"
|
||||
MODULE_CONFIG_FLOW = f"{MODULE}.config_flow"
|
||||
|
||||
PROPERTIES = {
|
||||
"power": "on",
|
||||
"main_power": "on",
|
||||
"bright": "50",
|
||||
"ct": "4000",
|
||||
"rgb": "16711680",
|
||||
"hue": "100",
|
||||
"sat": "35",
|
||||
"color_mode": "1",
|
||||
"flowing": "0",
|
||||
"bg_power": "on",
|
||||
"bg_lmode": "1",
|
||||
"bg_flowing": "0",
|
||||
"bg_ct": "5000",
|
||||
"bg_bright": "80",
|
||||
"bg_rgb": "16711680",
|
||||
"nl_br": "23",
|
||||
"active_mode": "0",
|
||||
"current_brightness": "30",
|
||||
}
|
||||
|
||||
ENTITY_BINARY_SENSOR = f"binary_sensor.{NAME}_nightlight"
|
||||
ENTITY_LIGHT = f"light.{NAME}"
|
||||
ENTITY_NIGHTLIGHT = f"light.{NAME}_nightlight"
|
||||
|
||||
YAML_CONFIGURATION = {
|
||||
DOMAIN: {
|
||||
CONF_DEVICES: {
|
||||
IP_ADDRESS: {
|
||||
CONF_NAME: NAME,
|
||||
CONF_NIGHTLIGHT_SWITCH_TYPE: NIGHTLIGHT_SWITCH_TYPE_LIGHT,
|
||||
CONF_MODE_MUSIC: True,
|
||||
CONF_SAVE_ON_CHANGE: True,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def _mocked_bulb(cannot_connect=False):
|
||||
bulb = MagicMock()
|
||||
type(bulb).get_capabilities = MagicMock(
|
||||
return_value=None if cannot_connect else CAPABILITIES
|
||||
)
|
||||
type(bulb).get_model_specs = MagicMock(return_value=_MODEL_SPECS[MODEL])
|
||||
|
||||
bulb.capabilities = CAPABILITIES
|
||||
bulb.model = MODEL
|
||||
bulb.bulb_type = BulbType.Color
|
||||
bulb.last_properties = PROPERTIES
|
||||
bulb.music_mode = False
|
||||
|
||||
return bulb
|
32
tests/components/yeelight/test_binary_sensor.py
Normal file
32
tests/components/yeelight/test_binary_sensor.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""Test the Yeelight binary sensor."""
|
||||
from homeassistant.components.yeelight import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_component
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from . import ENTITY_BINARY_SENSOR, MODULE, PROPERTIES, YAML_CONFIGURATION, _mocked_bulb
|
||||
|
||||
from tests.async_mock import patch
|
||||
|
||||
|
||||
async def test_nightlight(hass: HomeAssistant):
|
||||
"""Test nightlight sensor."""
|
||||
mocked_bulb = _mocked_bulb()
|
||||
with patch(f"{MODULE}.Bulb", return_value=mocked_bulb):
|
||||
await async_setup_component(hass, DOMAIN, YAML_CONFIGURATION)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# active_mode
|
||||
assert hass.states.get(ENTITY_BINARY_SENSOR).state == "off"
|
||||
|
||||
# nl_br
|
||||
properties = {**PROPERTIES}
|
||||
properties.pop("active_mode")
|
||||
mocked_bulb.last_properties = properties
|
||||
await entity_component.async_update_entity(hass, ENTITY_BINARY_SENSOR)
|
||||
assert hass.states.get(ENTITY_BINARY_SENSOR).state == "on"
|
||||
|
||||
# default
|
||||
properties.pop("nl_br")
|
||||
await entity_component.async_update_entity(hass, ENTITY_BINARY_SENSOR)
|
||||
assert hass.states.get(ENTITY_BINARY_SENSOR).state == "off"
|
546
tests/components/yeelight/test_light.py
Normal file
546
tests/components/yeelight/test_light.py
Normal file
@ -0,0 +1,546 @@
|
||||
"""Test the Yeelight light."""
|
||||
import logging
|
||||
|
||||
from yeelight import (
|
||||
BulbException,
|
||||
BulbType,
|
||||
HSVTransition,
|
||||
LightType,
|
||||
PowerMode,
|
||||
RGBTransition,
|
||||
SceneClass,
|
||||
SleepTransition,
|
||||
TemperatureTransition,
|
||||
transitions,
|
||||
)
|
||||
from yeelight.flow import Flow
|
||||
from yeelight.main import _MODEL_SPECS
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_FLASH,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_KELVIN,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
FLASH_LONG,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
)
|
||||
from homeassistant.components.yeelight import (
|
||||
ATTR_COUNT,
|
||||
ATTR_TRANSITIONS,
|
||||
CONF_CUSTOM_EFFECTS,
|
||||
CONF_FLOW_PARAMS,
|
||||
CONF_NIGHTLIGHT_SWITCH_TYPE,
|
||||
DEFAULT_TRANSITION,
|
||||
DOMAIN,
|
||||
NIGHTLIGHT_SWITCH_TYPE_LIGHT,
|
||||
YEELIGHT_HSV_TRANSACTION,
|
||||
YEELIGHT_RGB_TRANSITION,
|
||||
YEELIGHT_SLEEP_TRANSACTION,
|
||||
YEELIGHT_TEMPERATURE_TRANSACTION,
|
||||
)
|
||||
from homeassistant.components.yeelight.light import (
|
||||
ATTR_MINUTES,
|
||||
ATTR_MODE,
|
||||
EFFECT_DISCO,
|
||||
EFFECT_FACEBOOK,
|
||||
EFFECT_FAST_RANDOM_LOOP,
|
||||
EFFECT_STOP,
|
||||
EFFECT_TWITTER,
|
||||
EFFECT_WHATSAPP,
|
||||
SERVICE_SET_AUTO_DELAY_OFF_SCENE,
|
||||
SERVICE_SET_COLOR_FLOW_SCENE,
|
||||
SERVICE_SET_COLOR_SCENE,
|
||||
SERVICE_SET_COLOR_TEMP_SCENE,
|
||||
SERVICE_SET_HSV_SCENE,
|
||||
SERVICE_SET_MODE,
|
||||
SERVICE_START_FLOW,
|
||||
SUPPORT_YEELIGHT,
|
||||
SUPPORT_YEELIGHT_RGB,
|
||||
SUPPORT_YEELIGHT_WHITE_TEMP,
|
||||
YEELIGHT_COLOR_EFFECT_LIST,
|
||||
YEELIGHT_MONO_EFFECT_LIST,
|
||||
YEELIGHT_TEMP_ONLY_EFFECT_LIST,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_DEVICES, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.color import (
|
||||
color_hs_to_RGB,
|
||||
color_hs_to_xy,
|
||||
color_RGB_to_hs,
|
||||
color_RGB_to_xy,
|
||||
color_temperature_kelvin_to_mired,
|
||||
color_temperature_mired_to_kelvin,
|
||||
)
|
||||
|
||||
from . import (
|
||||
CAPABILITIES,
|
||||
ENTITY_LIGHT,
|
||||
ENTITY_NIGHTLIGHT,
|
||||
MODULE,
|
||||
NAME,
|
||||
PROPERTIES,
|
||||
YAML_CONFIGURATION,
|
||||
_mocked_bulb,
|
||||
)
|
||||
|
||||
from tests.async_mock import MagicMock, patch
|
||||
|
||||
|
||||
async def test_services(hass: HomeAssistant, caplog):
|
||||
"""Test Yeelight services."""
|
||||
mocked_bulb = _mocked_bulb()
|
||||
with patch(f"{MODULE}.Bulb", return_value=mocked_bulb):
|
||||
await async_setup_component(hass, DOMAIN, YAML_CONFIGURATION)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
async def _async_test_service(service, data, method, payload=None, domain=DOMAIN):
|
||||
err_count = len([x for x in caplog.records if x.levelno == logging.ERROR])
|
||||
|
||||
# success
|
||||
mocked_method = MagicMock()
|
||||
setattr(type(mocked_bulb), method, mocked_method)
|
||||
await hass.services.async_call(domain, service, data, blocking=True)
|
||||
if payload is None:
|
||||
mocked_method.assert_called_once()
|
||||
elif type(payload) == list:
|
||||
mocked_method.assert_called_once_with(*payload)
|
||||
else:
|
||||
mocked_method.assert_called_once_with(**payload)
|
||||
assert (
|
||||
len([x for x in caplog.records if x.levelno == logging.ERROR]) == err_count
|
||||
)
|
||||
|
||||
# failure
|
||||
mocked_method = MagicMock(side_effect=BulbException)
|
||||
setattr(type(mocked_bulb), method, mocked_method)
|
||||
await hass.services.async_call(domain, service, data, blocking=True)
|
||||
assert (
|
||||
len([x for x in caplog.records if x.levelno == logging.ERROR])
|
||||
== err_count + 1
|
||||
)
|
||||
|
||||
# turn_on
|
||||
brightness = 100
|
||||
color_temp = 200
|
||||
transition = 1
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: ENTITY_LIGHT,
|
||||
ATTR_BRIGHTNESS: brightness,
|
||||
ATTR_COLOR_TEMP: color_temp,
|
||||
ATTR_FLASH: FLASH_LONG,
|
||||
ATTR_EFFECT: EFFECT_STOP,
|
||||
ATTR_TRANSITION: transition,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
mocked_bulb.turn_on.assert_called_once_with(
|
||||
duration=transition * 1000,
|
||||
light_type=LightType.Main,
|
||||
power_mode=PowerMode.NORMAL,
|
||||
)
|
||||
mocked_bulb.turn_on.reset_mock()
|
||||
mocked_bulb.start_music.assert_called_once()
|
||||
mocked_bulb.set_brightness.assert_called_once_with(
|
||||
brightness / 255 * 100, duration=transition * 1000, light_type=LightType.Main
|
||||
)
|
||||
mocked_bulb.set_color_temp.assert_called_once_with(
|
||||
color_temperature_mired_to_kelvin(color_temp),
|
||||
duration=transition * 1000,
|
||||
light_type=LightType.Main,
|
||||
)
|
||||
mocked_bulb.start_flow.assert_called_once() # flash
|
||||
mocked_bulb.stop_flow.assert_called_once_with(light_type=LightType.Main)
|
||||
|
||||
# turn_on nightlight
|
||||
await _async_test_service(
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_NIGHTLIGHT},
|
||||
"turn_on",
|
||||
payload={
|
||||
"duration": DEFAULT_TRANSITION,
|
||||
"light_type": LightType.Main,
|
||||
"power_mode": PowerMode.MOONLIGHT,
|
||||
},
|
||||
domain="light",
|
||||
)
|
||||
|
||||
# turn_off
|
||||
await _async_test_service(
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_TRANSITION: transition},
|
||||
"turn_off",
|
||||
domain="light",
|
||||
payload={"duration": transition * 1000, "light_type": LightType.Main},
|
||||
)
|
||||
|
||||
# set_mode
|
||||
mode = "rgb"
|
||||
await _async_test_service(
|
||||
SERVICE_SET_MODE,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_MODE: "rgb"},
|
||||
"set_power_mode",
|
||||
[PowerMode[mode.upper()]],
|
||||
)
|
||||
|
||||
# start_flow
|
||||
await _async_test_service(
|
||||
SERVICE_START_FLOW,
|
||||
{
|
||||
ATTR_ENTITY_ID: ENTITY_LIGHT,
|
||||
ATTR_TRANSITIONS: [{YEELIGHT_TEMPERATURE_TRANSACTION: [1900, 2000, 60]}],
|
||||
},
|
||||
"start_flow",
|
||||
)
|
||||
|
||||
# set_color_scene
|
||||
await _async_test_service(
|
||||
SERVICE_SET_COLOR_SCENE,
|
||||
{
|
||||
ATTR_ENTITY_ID: ENTITY_LIGHT,
|
||||
ATTR_RGB_COLOR: [10, 20, 30],
|
||||
ATTR_BRIGHTNESS: 50,
|
||||
},
|
||||
"set_scene",
|
||||
[SceneClass.COLOR, 10, 20, 30, 50],
|
||||
)
|
||||
|
||||
# set_hsv_scene
|
||||
await _async_test_service(
|
||||
SERVICE_SET_HSV_SCENE,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_HS_COLOR: [180, 50], ATTR_BRIGHTNESS: 50},
|
||||
"set_scene",
|
||||
[SceneClass.HSV, 180, 50, 50],
|
||||
)
|
||||
|
||||
# set_color_temp_scene
|
||||
await _async_test_service(
|
||||
SERVICE_SET_COLOR_TEMP_SCENE,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_KELVIN: 4000, ATTR_BRIGHTNESS: 50},
|
||||
"set_scene",
|
||||
[SceneClass.CT, 4000, 50],
|
||||
)
|
||||
|
||||
# set_color_flow_scene
|
||||
await _async_test_service(
|
||||
SERVICE_SET_COLOR_FLOW_SCENE,
|
||||
{
|
||||
ATTR_ENTITY_ID: ENTITY_LIGHT,
|
||||
ATTR_TRANSITIONS: [{YEELIGHT_TEMPERATURE_TRANSACTION: [1900, 2000, 60]}],
|
||||
},
|
||||
"set_scene",
|
||||
)
|
||||
|
||||
# set_auto_delay_off_scene
|
||||
await _async_test_service(
|
||||
SERVICE_SET_AUTO_DELAY_OFF_SCENE,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_MINUTES: 1, ATTR_BRIGHTNESS: 50},
|
||||
"set_scene",
|
||||
[SceneClass.AUTO_DELAY_OFF, 50, 1],
|
||||
)
|
||||
|
||||
# test _cmd wrapper error handler
|
||||
err_count = len([x for x in caplog.records if x.levelno == logging.ERROR])
|
||||
type(mocked_bulb).turn_on = MagicMock()
|
||||
type(mocked_bulb).set_brightness = MagicMock(side_effect=BulbException)
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_BRIGHTNESS: 50},
|
||||
blocking=True,
|
||||
)
|
||||
assert (
|
||||
len([x for x in caplog.records if x.levelno == logging.ERROR]) == err_count + 1
|
||||
)
|
||||
|
||||
|
||||
async def test_device_types(hass: HomeAssistant):
|
||||
"""Test different device types."""
|
||||
properties = {**PROPERTIES}
|
||||
properties.pop("active_mode")
|
||||
properties["color_mode"] = "3"
|
||||
|
||||
def _create_mocked_bulb(bulb_type, model, unique_id):
|
||||
capabilities = {**CAPABILITIES}
|
||||
capabilities["id"] = f"yeelight.{unique_id}"
|
||||
mocked_bulb = _mocked_bulb()
|
||||
mocked_bulb.bulb_type = bulb_type
|
||||
mocked_bulb.last_properties = properties
|
||||
mocked_bulb.capabilities = capabilities
|
||||
model_specs = _MODEL_SPECS.get(model)
|
||||
type(mocked_bulb).get_model_specs = MagicMock(return_value=model_specs)
|
||||
return mocked_bulb
|
||||
|
||||
types = {
|
||||
"default": (None, "mono"),
|
||||
"white": (BulbType.White, "mono"),
|
||||
"color": (BulbType.Color, "color"),
|
||||
"white_temp": (BulbType.WhiteTemp, "ceiling1"),
|
||||
"white_temp_mood": (BulbType.WhiteTempMood, "ceiling4"),
|
||||
"ambient": (BulbType.WhiteTempMood, "ceiling4"),
|
||||
}
|
||||
|
||||
devices = {}
|
||||
mocked_bulbs = []
|
||||
unique_id = 0
|
||||
for name, (bulb_type, model) in types.items():
|
||||
devices[f"{name}.yeelight"] = {CONF_NAME: name}
|
||||
devices[f"{name}_nightlight.yeelight"] = {
|
||||
CONF_NAME: f"{name}_nightlight",
|
||||
CONF_NIGHTLIGHT_SWITCH_TYPE: NIGHTLIGHT_SWITCH_TYPE_LIGHT,
|
||||
}
|
||||
mocked_bulbs.append(_create_mocked_bulb(bulb_type, model, unique_id))
|
||||
mocked_bulbs.append(_create_mocked_bulb(bulb_type, model, unique_id + 1))
|
||||
unique_id += 2
|
||||
|
||||
with patch(f"{MODULE}.Bulb", side_effect=mocked_bulbs):
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_DEVICES: devices}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
async def _async_test(
|
||||
name,
|
||||
bulb_type,
|
||||
model,
|
||||
target_properties,
|
||||
nightlight_properties=None,
|
||||
entity_name=None,
|
||||
entity_id=None,
|
||||
):
|
||||
if entity_id is None:
|
||||
entity_id = f"light.{name}"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == "on"
|
||||
target_properties["friendly_name"] = entity_name or name
|
||||
target_properties["flowing"] = False
|
||||
target_properties["night_light"] = True
|
||||
assert dict(state.attributes) == target_properties
|
||||
|
||||
# nightlight
|
||||
if nightlight_properties is None:
|
||||
return
|
||||
name += "_nightlight"
|
||||
entity_id = f"light.{name}"
|
||||
assert hass.states.get(entity_id).state == "off"
|
||||
state = hass.states.get(f"{entity_id}_nightlight")
|
||||
assert state.state == "on"
|
||||
nightlight_properties["friendly_name"] = f"{name} nightlight"
|
||||
nightlight_properties["icon"] = "mdi:weather-night"
|
||||
nightlight_properties["flowing"] = False
|
||||
nightlight_properties["night_light"] = True
|
||||
assert dict(state.attributes) == nightlight_properties
|
||||
|
||||
bright = round(255 * int(PROPERTIES["bright"]) / 100)
|
||||
current_brightness = round(255 * int(PROPERTIES["current_brightness"]) / 100)
|
||||
ct = color_temperature_kelvin_to_mired(int(PROPERTIES["ct"]))
|
||||
hue = int(PROPERTIES["hue"])
|
||||
sat = int(PROPERTIES["sat"])
|
||||
hs_color = (round(hue / 360 * 65536, 3), round(sat / 100 * 255, 3))
|
||||
rgb_color = color_hs_to_RGB(*hs_color)
|
||||
xy_color = color_hs_to_xy(*hs_color)
|
||||
bg_bright = round(255 * int(PROPERTIES["bg_bright"]) / 100)
|
||||
bg_ct = color_temperature_kelvin_to_mired(int(PROPERTIES["bg_ct"]))
|
||||
bg_rgb = int(PROPERTIES["bg_rgb"])
|
||||
bg_rgb_color = ((bg_rgb >> 16) & 0xFF, (bg_rgb >> 8) & 0xFF, bg_rgb & 0xFF)
|
||||
bg_hs_color = color_RGB_to_hs(*bg_rgb_color)
|
||||
bg_xy_color = color_RGB_to_xy(*bg_rgb_color)
|
||||
nl_br = round(255 * int(PROPERTIES["nl_br"]) / 100)
|
||||
|
||||
# Default
|
||||
await _async_test(
|
||||
"default",
|
||||
None,
|
||||
"mono",
|
||||
{
|
||||
"effect_list": YEELIGHT_MONO_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT,
|
||||
"brightness": bright,
|
||||
},
|
||||
)
|
||||
|
||||
# White
|
||||
await _async_test(
|
||||
"white",
|
||||
BulbType.White,
|
||||
"mono",
|
||||
{
|
||||
"effect_list": YEELIGHT_MONO_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT,
|
||||
"brightness": bright,
|
||||
},
|
||||
)
|
||||
|
||||
# Color
|
||||
model_specs = _MODEL_SPECS["color"]
|
||||
await _async_test(
|
||||
"color",
|
||||
BulbType.Color,
|
||||
"color",
|
||||
{
|
||||
"effect_list": YEELIGHT_COLOR_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT_RGB,
|
||||
"min_mireds": color_temperature_kelvin_to_mired(
|
||||
model_specs["color_temp"]["max"]
|
||||
),
|
||||
"max_mireds": color_temperature_kelvin_to_mired(
|
||||
model_specs["color_temp"]["min"]
|
||||
),
|
||||
"brightness": current_brightness,
|
||||
"color_temp": ct,
|
||||
"hs_color": hs_color,
|
||||
"rgb_color": rgb_color,
|
||||
"xy_color": xy_color,
|
||||
},
|
||||
{"supported_features": 0},
|
||||
)
|
||||
|
||||
# WhiteTemp
|
||||
model_specs = _MODEL_SPECS["ceiling1"]
|
||||
await _async_test(
|
||||
"white_temp",
|
||||
BulbType.WhiteTemp,
|
||||
"ceiling1",
|
||||
{
|
||||
"effect_list": YEELIGHT_TEMP_ONLY_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT_WHITE_TEMP,
|
||||
"min_mireds": color_temperature_kelvin_to_mired(
|
||||
model_specs["color_temp"]["max"]
|
||||
),
|
||||
"max_mireds": color_temperature_kelvin_to_mired(
|
||||
model_specs["color_temp"]["min"]
|
||||
),
|
||||
"brightness": current_brightness,
|
||||
"color_temp": ct,
|
||||
},
|
||||
{
|
||||
"effect_list": YEELIGHT_TEMP_ONLY_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT,
|
||||
"brightness": nl_br,
|
||||
},
|
||||
)
|
||||
|
||||
# WhiteTempMood
|
||||
model_specs = _MODEL_SPECS["ceiling4"]
|
||||
await _async_test(
|
||||
"white_temp_mood",
|
||||
BulbType.WhiteTempMood,
|
||||
"ceiling4",
|
||||
{
|
||||
"friendly_name": NAME,
|
||||
"effect_list": YEELIGHT_TEMP_ONLY_EFFECT_LIST,
|
||||
"flowing": False,
|
||||
"night_light": True,
|
||||
"supported_features": SUPPORT_YEELIGHT_WHITE_TEMP,
|
||||
"min_mireds": color_temperature_kelvin_to_mired(
|
||||
model_specs["color_temp"]["max"]
|
||||
),
|
||||
"max_mireds": color_temperature_kelvin_to_mired(
|
||||
model_specs["color_temp"]["min"]
|
||||
),
|
||||
"brightness": current_brightness,
|
||||
"color_temp": ct,
|
||||
},
|
||||
{
|
||||
"effect_list": YEELIGHT_TEMP_ONLY_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT,
|
||||
"brightness": nl_br,
|
||||
},
|
||||
)
|
||||
await _async_test(
|
||||
"ambient",
|
||||
BulbType.WhiteTempMood,
|
||||
"ceiling4",
|
||||
{
|
||||
"effect_list": YEELIGHT_COLOR_EFFECT_LIST,
|
||||
"supported_features": SUPPORT_YEELIGHT_RGB,
|
||||
"min_mireds": color_temperature_kelvin_to_mired(6500),
|
||||
"max_mireds": color_temperature_kelvin_to_mired(1700),
|
||||
"brightness": bg_bright,
|
||||
"color_temp": bg_ct,
|
||||
"hs_color": bg_hs_color,
|
||||
"rgb_color": bg_rgb_color,
|
||||
"xy_color": bg_xy_color,
|
||||
},
|
||||
entity_name="ambient ambilight",
|
||||
entity_id="light.ambient_ambilight",
|
||||
)
|
||||
|
||||
|
||||
async def test_effects(hass: HomeAssistant):
|
||||
"""Test effects."""
|
||||
yaml_configuration = {
|
||||
DOMAIN: {
|
||||
CONF_DEVICES: YAML_CONFIGURATION[DOMAIN][CONF_DEVICES],
|
||||
CONF_CUSTOM_EFFECTS: [
|
||||
{
|
||||
CONF_NAME: "mock_effect",
|
||||
CONF_FLOW_PARAMS: {
|
||||
ATTR_COUNT: 3,
|
||||
ATTR_TRANSITIONS: [
|
||||
{YEELIGHT_HSV_TRANSACTION: [300, 50, 500, 50]},
|
||||
{YEELIGHT_RGB_TRANSITION: [100, 100, 100, 300, 30]},
|
||||
{YEELIGHT_TEMPERATURE_TRANSACTION: [3000, 200, 20]},
|
||||
{YEELIGHT_SLEEP_TRANSACTION: [800]},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
mocked_bulb = _mocked_bulb()
|
||||
with patch(f"{MODULE}.Bulb", return_value=mocked_bulb):
|
||||
assert await async_setup_component(hass, DOMAIN, yaml_configuration)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(ENTITY_LIGHT).attributes.get(
|
||||
"effect_list"
|
||||
) == YEELIGHT_COLOR_EFFECT_LIST + ["mock_effect"]
|
||||
|
||||
async def _async_test_effect(name, target=None, called=True):
|
||||
mocked_start_flow = MagicMock()
|
||||
type(mocked_bulb).start_flow = mocked_start_flow
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_EFFECT: name},
|
||||
blocking=True,
|
||||
)
|
||||
if not called:
|
||||
return
|
||||
mocked_start_flow.assert_called_once()
|
||||
if target is None:
|
||||
return
|
||||
args, _ = mocked_start_flow.call_args
|
||||
flow = args[0]
|
||||
assert flow.count == target.count
|
||||
assert flow.action == target.action
|
||||
assert str(flow.transitions) == str(target.transitions)
|
||||
|
||||
effects = {
|
||||
"mock_effect": Flow(
|
||||
count=3,
|
||||
transitions=[
|
||||
HSVTransition(300, 50, 500, 50),
|
||||
RGBTransition(100, 100, 100, 300, 30),
|
||||
TemperatureTransition(3000, 200, 20),
|
||||
SleepTransition(800),
|
||||
],
|
||||
),
|
||||
EFFECT_DISCO: Flow(transitions=transitions.disco()),
|
||||
EFFECT_FAST_RANDOM_LOOP: None,
|
||||
EFFECT_WHATSAPP: Flow(count=2, transitions=transitions.pulse(37, 211, 102)),
|
||||
EFFECT_FACEBOOK: Flow(count=2, transitions=transitions.pulse(59, 89, 152)),
|
||||
EFFECT_TWITTER: Flow(count=2, transitions=transitions.pulse(0, 172, 237)),
|
||||
}
|
||||
|
||||
for name, target in effects.items():
|
||||
await _async_test_effect(name, target)
|
||||
await _async_test_effect("not_existed", called=False)
|
Loading…
x
Reference in New Issue
Block a user