mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Stub light profiles (#42232)
This commit is contained in:
parent
b626df1316
commit
5dac3883b0
@ -199,11 +199,11 @@ def lifx_features(bulb):
|
||||
) or aiolifx().products.features_map.get(1)
|
||||
|
||||
|
||||
def find_hsbk(**kwargs):
|
||||
def find_hsbk(hass, **kwargs):
|
||||
"""Find the desired color from a number of possible inputs."""
|
||||
hue, saturation, brightness, kelvin = [None] * 4
|
||||
|
||||
preprocess_turn_on_alternatives(kwargs)
|
||||
preprocess_turn_on_alternatives(hass, kwargs)
|
||||
|
||||
if ATTR_HS_COLOR in kwargs:
|
||||
hue, saturation = kwargs[ATTR_HS_COLOR]
|
||||
@ -330,11 +330,11 @@ class LIFXManager:
|
||||
period=kwargs.get(ATTR_PERIOD),
|
||||
cycles=kwargs.get(ATTR_CYCLES),
|
||||
mode=kwargs.get(ATTR_MODE),
|
||||
hsbk=find_hsbk(**kwargs),
|
||||
hsbk=find_hsbk(self.hass, **kwargs),
|
||||
)
|
||||
await self.effects_conductor.start(effect, bulbs)
|
||||
elif service == SERVICE_EFFECT_COLORLOOP:
|
||||
preprocess_turn_on_alternatives(kwargs)
|
||||
preprocess_turn_on_alternatives(self.hass, kwargs)
|
||||
|
||||
brightness = None
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
@ -600,7 +600,7 @@ class LIFXLight(LightEntity):
|
||||
power_on = kwargs.get(ATTR_POWER, False)
|
||||
power_off = not kwargs.get(ATTR_POWER, True)
|
||||
|
||||
hsbk = find_hsbk(**kwargs)
|
||||
hsbk = find_hsbk(self.hass, **kwargs)
|
||||
|
||||
# Send messages, waiting for ACK each time
|
||||
ack = AwaitAioLIFX().wait
|
||||
|
@ -3,7 +3,6 @@ import csv
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import os
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
@ -13,6 +12,7 @@ from homeassistant.const import (
|
||||
SERVICE_TURN_ON,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.config_validation import ( # noqa: F401
|
||||
PLATFORM_SCHEMA,
|
||||
@ -28,6 +28,7 @@ import homeassistant.util.color as color_util
|
||||
|
||||
DOMAIN = "light"
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
DATA_PROFILES = "light_profiles"
|
||||
|
||||
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
||||
|
||||
@ -122,15 +123,6 @@ LIGHT_TURN_ON_SCHEMA = {
|
||||
}
|
||||
|
||||
|
||||
PROFILE_SCHEMA = vol.Schema(
|
||||
vol.Any(
|
||||
vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)),
|
||||
vol.ExactSequence(
|
||||
(str, cv.small_float, cv.small_float, cv.byte, cv.positive_int)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -140,14 +132,17 @@ def is_on(hass, entity_id):
|
||||
return hass.states.is_state(entity_id, STATE_ON)
|
||||
|
||||
|
||||
def preprocess_turn_on_alternatives(params):
|
||||
"""Process extra data for turn light on request."""
|
||||
profile = Profiles.get(params.pop(ATTR_PROFILE, None))
|
||||
if profile is not None:
|
||||
params.setdefault(ATTR_XY_COLOR, profile[:2])
|
||||
params.setdefault(ATTR_BRIGHTNESS, profile[2])
|
||||
if len(profile) > 3:
|
||||
params.setdefault(ATTR_TRANSITION, profile[3])
|
||||
def preprocess_turn_on_alternatives(hass, params):
|
||||
"""Process extra data for turn light on request.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
# Bail out, we process this later.
|
||||
if ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params:
|
||||
return
|
||||
|
||||
if ATTR_PROFILE in params:
|
||||
hass.data[DATA_PROFILES].apply_profile(params.pop(ATTR_PROFILE), params)
|
||||
|
||||
color_name = params.pop(ATTR_COLOR_NAME, None)
|
||||
if color_name is not None:
|
||||
@ -174,24 +169,12 @@ def preprocess_turn_on_alternatives(params):
|
||||
if rgb_color is not None:
|
||||
params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
|
||||
|
||||
return params
|
||||
|
||||
|
||||
def filter_turn_off_params(params):
|
||||
"""Filter out params not used in turn off."""
|
||||
return {k: v for k, v in params.items() if k in (ATTR_TRANSITION, ATTR_FLASH)}
|
||||
|
||||
|
||||
def preprocess_turn_off(params):
|
||||
"""Process data for turning light off if brightness is 0."""
|
||||
if ATTR_BRIGHTNESS in params and params[ATTR_BRIGHTNESS] == 0:
|
||||
# Zero brightness: Light will be turned off
|
||||
params = filter_turn_off_params(params)
|
||||
return (True, params) # Light should be turned off
|
||||
|
||||
return (False, None) # Light should be turned on
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Expose light control via state machine and services."""
|
||||
component = hass.data[DOMAIN] = EntityComponent(
|
||||
@ -199,10 +182,8 @@ async def async_setup(hass, config):
|
||||
)
|
||||
await component.async_setup(config)
|
||||
|
||||
# load profiles from files
|
||||
profiles_valid = await Profiles.load_profiles(hass)
|
||||
if not profiles_valid:
|
||||
return False
|
||||
profiles = hass.data[DATA_PROFILES] = Profiles(hass)
|
||||
await profiles.async_initialize()
|
||||
|
||||
def preprocess_data(data):
|
||||
"""Preprocess the service data."""
|
||||
@ -212,7 +193,8 @@ async def async_setup(hass, config):
|
||||
if entity_field in data
|
||||
}
|
||||
|
||||
base["params"] = preprocess_turn_on_alternatives(data)
|
||||
preprocess_turn_on_alternatives(hass, data)
|
||||
base["params"] = data
|
||||
return base
|
||||
|
||||
async def async_handle_light_on_service(light, call):
|
||||
@ -223,17 +205,14 @@ async def async_setup(hass, config):
|
||||
params = call.data["params"]
|
||||
|
||||
if not params:
|
||||
default_profile = Profiles.get_default(light.entity_id)
|
||||
profiles.apply_default(light.entity_id, params)
|
||||
|
||||
if default_profile is not None:
|
||||
params = {ATTR_PROFILE: default_profile}
|
||||
preprocess_turn_on_alternatives(params)
|
||||
|
||||
elif ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params:
|
||||
# Only process params once we processed brightness step
|
||||
if params and (
|
||||
ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params
|
||||
):
|
||||
brightness = light.brightness if light.is_on else 0
|
||||
|
||||
params = params.copy()
|
||||
|
||||
if ATTR_BRIGHTNESS_STEP in params:
|
||||
brightness += params.pop(ATTR_BRIGHTNESS_STEP)
|
||||
|
||||
@ -242,19 +221,18 @@ async def async_setup(hass, config):
|
||||
|
||||
params[ATTR_BRIGHTNESS] = max(0, min(255, brightness))
|
||||
|
||||
turn_light_off, off_params = preprocess_turn_off(params)
|
||||
if turn_light_off:
|
||||
await light.async_turn_off(**off_params)
|
||||
preprocess_turn_on_alternatives(hass, params)
|
||||
|
||||
# Zero brightness: Light will be turned off
|
||||
if params.get(ATTR_BRIGHTNESS) == 0:
|
||||
await light.async_turn_off(**filter_turn_off_params(params))
|
||||
else:
|
||||
await light.async_turn_on(**params)
|
||||
|
||||
async def async_handle_toggle_service(light, call):
|
||||
"""Handle toggling a light.
|
||||
|
||||
If brightness is set to 0, this service will turn the light off.
|
||||
"""
|
||||
"""Handle toggling a light."""
|
||||
if light.is_on:
|
||||
off_params = filter_turn_off_params(call.data["params"])
|
||||
off_params = filter_turn_off_params(call.data)
|
||||
await light.async_turn_off(**off_params)
|
||||
else:
|
||||
await async_handle_light_on_service(light, call)
|
||||
@ -295,73 +273,89 @@ async def async_unload_entry(hass, entry):
|
||||
class Profiles:
|
||||
"""Representation of available color profiles."""
|
||||
|
||||
_all: Optional[Dict[str, Tuple[float, float, int]]] = None
|
||||
SCHEMA = vol.Schema(
|
||||
vol.Any(
|
||||
vol.ExactSequence((str, cv.small_float, cv.small_float, cv.byte)),
|
||||
vol.ExactSequence(
|
||||
(str, cv.small_float, cv.small_float, cv.byte, cv.positive_int)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def load_profiles(cls, hass):
|
||||
"""Load and cache profiles."""
|
||||
def __init__(self, hass):
|
||||
"""Initialize profiles."""
|
||||
self.hass = hass
|
||||
self.data = None
|
||||
|
||||
def load_profile_data(hass):
|
||||
"""Load built-in profiles and custom profiles."""
|
||||
profile_paths = [
|
||||
os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
|
||||
hass.config.path(LIGHT_PROFILES_FILE),
|
||||
]
|
||||
profiles = {}
|
||||
def _load_profile_data(self):
|
||||
"""Load built-in profiles and custom profiles."""
|
||||
profile_paths = [
|
||||
os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
|
||||
self.hass.config.path(LIGHT_PROFILES_FILE),
|
||||
]
|
||||
profiles = {}
|
||||
|
||||
for profile_path in profile_paths:
|
||||
if not os.path.isfile(profile_path):
|
||||
continue
|
||||
with open(profile_path) as inp:
|
||||
reader = csv.reader(inp)
|
||||
for profile_path in profile_paths:
|
||||
if not os.path.isfile(profile_path):
|
||||
continue
|
||||
with open(profile_path) as inp:
|
||||
reader = csv.reader(inp)
|
||||
|
||||
# Skip the header
|
||||
next(reader, None)
|
||||
# Skip the header
|
||||
next(reader, None)
|
||||
|
||||
try:
|
||||
for rec in reader:
|
||||
(
|
||||
profile,
|
||||
color_x,
|
||||
color_y,
|
||||
brightness,
|
||||
*transition,
|
||||
) = PROFILE_SCHEMA(rec)
|
||||
try:
|
||||
for rec in reader:
|
||||
(
|
||||
profile,
|
||||
color_x,
|
||||
color_y,
|
||||
brightness,
|
||||
*transition,
|
||||
) = Profiles.SCHEMA(rec)
|
||||
|
||||
transition = transition[0] if transition else 0
|
||||
transition = transition[0] if transition else 0
|
||||
|
||||
profiles[profile] = (
|
||||
color_x,
|
||||
color_y,
|
||||
brightness,
|
||||
transition,
|
||||
)
|
||||
except vol.MultipleInvalid as ex:
|
||||
_LOGGER.error(
|
||||
"Error parsing light profile from %s: %s", profile_path, ex
|
||||
profiles[profile] = color_util.color_xy_to_hs(
|
||||
color_x, color_y
|
||||
) + (
|
||||
brightness,
|
||||
transition,
|
||||
)
|
||||
return None
|
||||
return profiles
|
||||
except vol.MultipleInvalid as ex:
|
||||
_LOGGER.error(
|
||||
"Error parsing light profile from %s: %s", profile_path, ex
|
||||
)
|
||||
continue
|
||||
return profiles
|
||||
|
||||
cls._all = await hass.async_add_executor_job(load_profile_data, hass)
|
||||
return cls._all is not None
|
||||
async def async_initialize(self):
|
||||
"""Load and cache profiles."""
|
||||
self.data = await self.hass.async_add_executor_job(self._load_profile_data)
|
||||
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
"""Return a named profile."""
|
||||
return cls._all.get(name)
|
||||
|
||||
@classmethod
|
||||
def get_default(cls, entity_id):
|
||||
@callback
|
||||
def apply_default(self, entity_id, params):
|
||||
"""Return the default turn-on profile for the given light."""
|
||||
# pylint: disable=unsupported-membership-test
|
||||
name = f"{entity_id}.default"
|
||||
if name in cls._all:
|
||||
return name
|
||||
if name in self.data:
|
||||
self.apply_profile(name, params)
|
||||
return
|
||||
|
||||
name = "group.all_lights.default"
|
||||
if name in cls._all:
|
||||
return name
|
||||
return None
|
||||
if name in self.data:
|
||||
self.apply_profile(name, params)
|
||||
|
||||
@callback
|
||||
def apply_profile(self, name, params):
|
||||
"""Apply a profile."""
|
||||
profile = self.data.get(name)
|
||||
|
||||
if profile is None:
|
||||
return
|
||||
|
||||
params.setdefault(ATTR_HS_COLOR, profile[:2])
|
||||
params.setdefault(ATTR_BRIGHTNESS, profile[2])
|
||||
params.setdefault(ATTR_TRANSITION, profile[3])
|
||||
|
||||
|
||||
class LightEntity(ToggleEntity):
|
||||
|
@ -3,6 +3,7 @@ import abodepy.helpers.constants as CONST
|
||||
import pytest
|
||||
|
||||
from tests.common import load_fixture
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
2
tests/components/axis/conftest.py
Normal file
2
tests/components/axis/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""axis conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -1,5 +1,4 @@
|
||||
"""PyTest fixtures and test helpers."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import blebox_uniapi
|
||||
@ -11,6 +10,7 @@ from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.async_mock import AsyncMock, PropertyMock, patch
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
def patch_product_identify(path=None, **kwargs):
|
||||
|
2
tests/components/bond/conftest.py
Normal file
2
tests/components/bond/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""bond conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/deconz/conftest.py
Normal file
2
tests/components/deconz/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""deconz conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/demo/conftest.py
Normal file
2
tests/components/demo/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""demo conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/dynalite/conftest.py
Normal file
2
tests/components/dynalite/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""dynalite conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/elgato/conftest.py
Normal file
2
tests/components/elgato/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""elgato conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/everlights/conftest.py
Normal file
2
tests/components/everlights/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""everlights conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/group/conftest.py
Normal file
2
tests/components/group/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""group conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -8,6 +8,7 @@ import pytest
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
import tests.async_mock
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -24,6 +24,7 @@ from .helper import AUTH_TOKEN, HAPID, HAPPIN, HomeFactory
|
||||
|
||||
from tests.async_mock import AsyncMock, MagicMock, Mock, patch
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_connection")
|
||||
|
@ -12,6 +12,7 @@ from homeassistant.components import hue
|
||||
from homeassistant.components.hue import sensor_base as hue_sensor_base
|
||||
|
||||
from tests.async_mock import AsyncMock, Mock, patch
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
2
tests/components/hyperion/conftest.py
Normal file
2
tests/components/hyperion/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""hyperion conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
26
tests/components/light/conftest.py
Normal file
26
tests/components/light/conftest.py
Normal file
@ -0,0 +1,26 @@
|
||||
"""Light conftest."""
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.light import Profiles
|
||||
|
||||
from tests.async_mock import AsyncMock, patch
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_light_profiles():
|
||||
"""Mock loading of profiles."""
|
||||
data = {}
|
||||
|
||||
def mock_profiles_class(hass):
|
||||
profiles = Profiles(hass)
|
||||
profiles.data = data
|
||||
profiles.async_initialize = AsyncMock()
|
||||
return profiles
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.light.Profiles",
|
||||
SCHEMA=Profiles.SCHEMA,
|
||||
side_effect=mock_profiles_class,
|
||||
):
|
||||
yield data
|
@ -1,8 +1,4 @@
|
||||
"""The tests for the Light component."""
|
||||
# pylint: disable=protected-access
|
||||
from io import StringIO
|
||||
import os
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
@ -20,19 +16,11 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.exceptions import Unauthorized
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import color
|
||||
|
||||
import tests.async_mock as mock
|
||||
from tests.common import async_mock_service
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_storage(hass, hass_storage):
|
||||
"""Clean up user light files at the end."""
|
||||
yield
|
||||
user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE)
|
||||
|
||||
if os.path.isfile(user_light_file):
|
||||
os.remove(user_light_file)
|
||||
orig_Profiles = light.Profiles
|
||||
|
||||
|
||||
async def test_methods(hass):
|
||||
@ -117,7 +105,7 @@ async def test_methods(hass):
|
||||
assert call.data[light.ATTR_TRANSITION] == "transition_val"
|
||||
|
||||
|
||||
async def test_services(hass):
|
||||
async def test_services(hass, mock_light_profiles):
|
||||
"""Test the provided services."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
|
||||
@ -292,6 +280,7 @@ async def test_services(hass):
|
||||
assert data == {}
|
||||
|
||||
# One of the light profiles
|
||||
mock_light_profiles["relax"] = (35.932, 69.412, 144, 0)
|
||||
prof_name, prof_h, prof_s, prof_bri, prof_t = "relax", 35.932, 69.412, 144, 0
|
||||
|
||||
# Test light profiles
|
||||
@ -418,34 +407,13 @@ async def test_services(hass):
|
||||
assert data == {}
|
||||
|
||||
|
||||
async def test_broken_light_profiles(hass, mock_storage):
|
||||
async def test_light_profiles(hass, mock_light_profiles):
|
||||
"""Test light profiles."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init()
|
||||
|
||||
user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE)
|
||||
|
||||
# Setup a wrong light file
|
||||
with open(user_light_file, "w") as user_file:
|
||||
user_file.write("id,x,y,brightness,transition\n")
|
||||
user_file.write("I,WILL,NOT,WORK,EVER\n")
|
||||
|
||||
assert not await async_setup_component(
|
||||
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
|
||||
|
||||
async def test_light_profiles(hass, mock_storage):
|
||||
"""Test light profiles."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init()
|
||||
|
||||
user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE)
|
||||
|
||||
with open(user_light_file, "w") as user_file:
|
||||
user_file.write("id,x,y,brightness\n")
|
||||
user_file.write("test,.4,.6,100\n")
|
||||
user_file.write("test_off,0,0,0\n")
|
||||
mock_light_profiles["test"] = color.color_xy_to_hs(0.4, 0.6) + (100, 0)
|
||||
mock_light_profiles["test_off"] = 0, 0, 0, 0
|
||||
|
||||
assert await async_setup_component(
|
||||
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
|
||||
@ -484,80 +452,21 @@ async def test_light_profiles(hass, mock_storage):
|
||||
assert data == {light.ATTR_TRANSITION: 0}
|
||||
|
||||
|
||||
async def test_light_profiles_with_transition(hass, mock_storage):
|
||||
"""Test light profiles with transition."""
|
||||
async def test_default_profiles_group(hass, mock_light_profiles):
|
||||
"""Test default turn-on light profile for all lights."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init()
|
||||
|
||||
user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE)
|
||||
|
||||
with open(user_light_file, "w") as user_file:
|
||||
user_file.write("id,x,y,brightness,transition\n")
|
||||
user_file.write("test,.4,.6,100,2\n")
|
||||
user_file.write("test_off,0,0,0,0\n")
|
||||
|
||||
assert await async_setup_component(
|
||||
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
ent1, _, _ = platform.ENTITIES
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ent1.entity_id, light.ATTR_PROFILE: "test"},
|
||||
blocking=True,
|
||||
mock_light_profiles["group.all_lights.default"] = color.color_xy_to_hs(0.4, 0.6) + (
|
||||
99,
|
||||
2,
|
||||
)
|
||||
|
||||
_, data = ent1.last_call("turn_on")
|
||||
assert light.is_on(hass, ent1.entity_id)
|
||||
assert data == {
|
||||
light.ATTR_HS_COLOR: (71.059, 100),
|
||||
light.ATTR_BRIGHTNESS: 100,
|
||||
light.ATTR_TRANSITION: 2,
|
||||
}
|
||||
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ent1.entity_id, light.ATTR_PROFILE: "test_off"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
_, data = ent1.last_call("turn_off")
|
||||
assert not light.is_on(hass, ent1.entity_id)
|
||||
assert data == {light.ATTR_TRANSITION: 0}
|
||||
|
||||
|
||||
async def test_default_profiles_group(hass, mock_storage):
|
||||
"""Test default turn-on light profile for all lights."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init()
|
||||
|
||||
user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE)
|
||||
real_isfile = os.path.isfile
|
||||
real_open = open
|
||||
|
||||
def _mock_isfile(path):
|
||||
if path == user_light_file:
|
||||
return True
|
||||
return real_isfile(path)
|
||||
|
||||
def _mock_open(path, *args, **kwargs):
|
||||
if path == user_light_file:
|
||||
return StringIO(profile_data)
|
||||
return real_open(path, *args, **kwargs)
|
||||
|
||||
profile_data = "id,x,y,brightness,transition\ngroup.all_lights.default,.4,.6,99,2\n"
|
||||
with mock.patch("os.path.isfile", side_effect=_mock_isfile), mock.patch(
|
||||
"builtins.open", side_effect=_mock_open
|
||||
):
|
||||
assert await async_setup_component(
|
||||
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
ent, _, _ = platform.ENTITIES
|
||||
await hass.services.async_call(
|
||||
light.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ent.entity_id}, blocking=True
|
||||
@ -571,37 +480,24 @@ async def test_default_profiles_group(hass, mock_storage):
|
||||
}
|
||||
|
||||
|
||||
async def test_default_profiles_light(hass, mock_storage):
|
||||
async def test_default_profiles_light(hass, mock_light_profiles):
|
||||
"""Test default turn-on light profile for a specific light."""
|
||||
platform = getattr(hass.components, "test.light")
|
||||
platform.init()
|
||||
|
||||
user_light_file = hass.config.path(light.LIGHT_PROFILES_FILE)
|
||||
real_isfile = os.path.isfile
|
||||
real_open = open
|
||||
|
||||
def _mock_isfile(path):
|
||||
if path == user_light_file:
|
||||
return True
|
||||
return real_isfile(path)
|
||||
|
||||
def _mock_open(path, *args, **kwargs):
|
||||
if path == user_light_file:
|
||||
return StringIO(profile_data)
|
||||
return real_open(path, *args, **kwargs)
|
||||
|
||||
profile_data = (
|
||||
"id,x,y,brightness,transition\n"
|
||||
+ "group.all_lights.default,.3,.5,200,0\n"
|
||||
+ "light.ceiling_2.default,.6,.6,100,3\n"
|
||||
assert await async_setup_component(
|
||||
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_light_profiles["group.all_lights.default"] = color.color_xy_to_hs(0.3, 0.5) + (
|
||||
200,
|
||||
0,
|
||||
)
|
||||
mock_light_profiles["light.ceiling_2.default"] = color.color_xy_to_hs(0.6, 0.6) + (
|
||||
100,
|
||||
3,
|
||||
)
|
||||
with mock.patch("os.path.isfile", side_effect=_mock_isfile), mock.patch(
|
||||
"builtins.open", side_effect=_mock_open
|
||||
):
|
||||
assert await async_setup_component(
|
||||
hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
dev = next(filter(lambda x: x.entity_id == "light.ceiling_2", platform.ENTITIES))
|
||||
await hass.services.async_call(
|
||||
@ -775,3 +671,15 @@ def test_deprecated_base_class(caplog):
|
||||
|
||||
CustomLight()
|
||||
assert "Light is deprecated, modify CustomLight" in caplog.text
|
||||
|
||||
|
||||
async def test_profiles(hass):
|
||||
"""Test profiles loading."""
|
||||
profiles = orig_Profiles(hass)
|
||||
await profiles.async_initialize()
|
||||
assert profiles.data == {
|
||||
"concentrate": (35.932, 69.412, 219, 0),
|
||||
"energize": (43.333, 21.176, 203, 0),
|
||||
"reading": (38.88, 49.02, 240, 0),
|
||||
"relax": (35.932, 69.412, 144, 0),
|
||||
}
|
||||
|
2
tests/components/litejet/conftest.py
Normal file
2
tests/components/litejet/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""litejet conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/mochad/conftest.py
Normal file
2
tests/components/mochad/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""mochad conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -1 +1,2 @@
|
||||
"""Test fixtures for mqtt component."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
@ -7,6 +7,7 @@ from .common import MQTTMessage
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.common import load_fixture
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture(name="generic_data", scope="session")
|
||||
|
2
tests/components/rflink/conftest.py
Normal file
2
tests/components/rflink/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""rflink conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -9,6 +9,7 @@ from homeassistant.util.dt import utcnow
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
def create_rfx_test_cfg(device="abcd", automatic_add=False, devices=None):
|
||||
|
@ -5,6 +5,7 @@ import pytest
|
||||
import requests_mock
|
||||
|
||||
from tests.common import load_fixture
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture(name="requests_mock")
|
||||
|
@ -47,6 +47,7 @@ from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.async_mock import Mock, patch
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
COMPONENT_PREFIX = "homeassistant.components.smartthings."
|
||||
|
||||
|
2
tests/components/switch/conftest.py
Normal file
2
tests/components/switch/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""switch conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -1,5 +1,4 @@
|
||||
"""Test fixtures for Tasmota component."""
|
||||
|
||||
from hatasmota.discovery import get_status_sensor_entities
|
||||
import pytest
|
||||
|
||||
@ -17,6 +16,7 @@ from tests.common import (
|
||||
mock_device_registry,
|
||||
mock_registry,
|
||||
)
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
2
tests/components/template/conftest.py
Normal file
2
tests/components/template/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""template conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/tplink/conftest.py
Normal file
2
tests/components/tplink/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""tplink conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -4,6 +4,7 @@ import pytest
|
||||
from . import MOCK_GATEWAY_ID
|
||||
|
||||
from tests.async_mock import Mock, patch
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
"""Fixtures for tests."""
|
||||
|
||||
import pytest
|
||||
|
||||
from .common import ComponentFactory
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
2
tests/components/wilight/conftest.py
Normal file
2
tests/components/wilight/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""wilight conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/wled/conftest.py
Normal file
2
tests/components/wled/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""wled conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/yeelight/conftest.py
Normal file
2
tests/components/yeelight/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""yeelight conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
2
tests/components/zerproc/conftest.py
Normal file
2
tests/components/zerproc/conftest.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""zerproc conftest."""
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
@ -1,5 +1,4 @@
|
||||
"""Test configuration for the ZHA component."""
|
||||
|
||||
import pytest
|
||||
import zigpy
|
||||
from zigpy.application import ControllerApplication
|
||||
@ -16,6 +15,7 @@ from .common import FakeDevice, FakeEndpoint, get_zha_gateway
|
||||
|
||||
from tests.async_mock import AsyncMock, MagicMock, PropertyMock, patch
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
|
||||
FIXTURE_GRP_ID = 0x1001
|
||||
FIXTURE_GRP_NAME = "fixture group"
|
||||
|
@ -4,6 +4,7 @@ import pytest
|
||||
from homeassistant.components.zwave import const
|
||||
|
||||
from tests.async_mock import AsyncMock, MagicMock, patch
|
||||
from tests.components.light.conftest import mock_light_profiles # noqa
|
||||
from tests.mock.zwave import MockNetwork, MockNode, MockOption, MockValue
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user