mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Add support for the Flame and Morph effects for Tile and Candle (#80014)
This commit is contained in:
parent
117c12d135
commit
257ae4d8d3
@ -7,7 +7,12 @@ from enum import IntEnum
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from aiolifx.aiolifx import Light, MultiZoneDirection, MultiZoneEffectType
|
from aiolifx.aiolifx import (
|
||||||
|
Light,
|
||||||
|
MultiZoneDirection,
|
||||||
|
MultiZoneEffectType,
|
||||||
|
TileEffectType,
|
||||||
|
)
|
||||||
from aiolifx.connection import LIFXConnection
|
from aiolifx.connection import LIFXConnection
|
||||||
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
@ -279,7 +284,11 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
self.active_effect = FirmwareEffect[self.device.effect.get("effect", "OFF")]
|
self.active_effect = FirmwareEffect[self.device.effect.get("effect", "OFF")]
|
||||||
|
|
||||||
async def async_set_multizone_effect(
|
async def async_set_multizone_effect(
|
||||||
self, effect: str, speed: float, direction: str, power_on: bool = True
|
self,
|
||||||
|
effect: str,
|
||||||
|
speed: float = 3,
|
||||||
|
direction: str = "RIGHT",
|
||||||
|
power_on: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Control the firmware-based Move effect on a multizone device."""
|
"""Control the firmware-based Move effect on a multizone device."""
|
||||||
if lifx_features(self.device)["multizone"] is True:
|
if lifx_features(self.device)["multizone"] is True:
|
||||||
@ -296,6 +305,31 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
)
|
)
|
||||||
self.active_effect = FirmwareEffect[effect.upper()]
|
self.active_effect = FirmwareEffect[effect.upper()]
|
||||||
|
|
||||||
|
async def async_set_matrix_effect(
|
||||||
|
self,
|
||||||
|
effect: str,
|
||||||
|
palette: list[tuple[int, int, int, int]] | None = None,
|
||||||
|
speed: float = 3,
|
||||||
|
power_on: bool = True,
|
||||||
|
) -> None:
|
||||||
|
"""Control the firmware-based effects on a matrix device."""
|
||||||
|
if lifx_features(self.device)["matrix"] is True:
|
||||||
|
if power_on and self.device.power_level == 0:
|
||||||
|
await self.async_set_power(True, 0)
|
||||||
|
|
||||||
|
if palette is None:
|
||||||
|
palette = []
|
||||||
|
|
||||||
|
await async_execute_lifx(
|
||||||
|
partial(
|
||||||
|
self.device.set_tile_effect,
|
||||||
|
effect=TileEffectType[effect.upper()].value,
|
||||||
|
speed=speed,
|
||||||
|
palette=palette,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.active_effect = FirmwareEffect[effect.upper()]
|
||||||
|
|
||||||
def async_get_active_effect(self) -> int:
|
def async_get_active_effect(self) -> int:
|
||||||
"""Return the enum value of the currently active firmware effect."""
|
"""Return the enum value of the currently active firmware effect."""
|
||||||
return self.active_effect.value
|
return self.active_effect.value
|
||||||
|
@ -40,6 +40,8 @@ from .coordinator import FirmwareEffect, LIFXUpdateCoordinator
|
|||||||
from .entity import LIFXEntity
|
from .entity import LIFXEntity
|
||||||
from .manager import (
|
from .manager import (
|
||||||
SERVICE_EFFECT_COLORLOOP,
|
SERVICE_EFFECT_COLORLOOP,
|
||||||
|
SERVICE_EFFECT_FLAME,
|
||||||
|
SERVICE_EFFECT_MORPH,
|
||||||
SERVICE_EFFECT_MOVE,
|
SERVICE_EFFECT_MOVE,
|
||||||
SERVICE_EFFECT_PULSE,
|
SERVICE_EFFECT_PULSE,
|
||||||
SERVICE_EFFECT_STOP,
|
SERVICE_EFFECT_STOP,
|
||||||
@ -93,8 +95,10 @@ async def async_setup_entry(
|
|||||||
LIFX_SET_HEV_CYCLE_STATE_SCHEMA,
|
LIFX_SET_HEV_CYCLE_STATE_SCHEMA,
|
||||||
"set_hev_cycle_state",
|
"set_hev_cycle_state",
|
||||||
)
|
)
|
||||||
if lifx_features(device)["extended_multizone"]:
|
if lifx_features(device)["matrix"]:
|
||||||
entity: LIFXLight = LIFXExtendedMultiZone(coordinator, manager, entry)
|
entity: LIFXLight = LIFXMatrix(coordinator, manager, entry)
|
||||||
|
elif lifx_features(device)["extended_multizone"]:
|
||||||
|
entity = LIFXExtendedMultiZone(coordinator, manager, entry)
|
||||||
elif lifx_features(device)["multizone"]:
|
elif lifx_features(device)["multizone"]:
|
||||||
entity = LIFXMultiZone(coordinator, manager, entry)
|
entity = LIFXMultiZone(coordinator, manager, entry)
|
||||||
elif lifx_features(device)["color"]:
|
elif lifx_features(device)["color"]:
|
||||||
@ -471,3 +475,15 @@ class LIFXExtendedMultiZone(LIFXMultiZone):
|
|||||||
# set_extended_color_zones does not update the
|
# set_extended_color_zones does not update the
|
||||||
# state of the device, so we need to do that
|
# state of the device, so we need to do that
|
||||||
await self.get_color()
|
await self.get_color()
|
||||||
|
|
||||||
|
|
||||||
|
class LIFXMatrix(LIFXColor):
|
||||||
|
"""Representation of a LIFX matrix device."""
|
||||||
|
|
||||||
|
_attr_effect_list = [
|
||||||
|
SERVICE_EFFECT_COLORLOOP,
|
||||||
|
SERVICE_EFFECT_FLAME,
|
||||||
|
SERVICE_EFFECT_PULSE,
|
||||||
|
SERVICE_EFFECT_MORPH,
|
||||||
|
SERVICE_EFFECT_STOP,
|
||||||
|
]
|
||||||
|
@ -7,6 +7,7 @@ from datetime import timedelta
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import aiolifx_effects
|
import aiolifx_effects
|
||||||
|
from aiolifx_themes.themes import Theme, ThemeLibrary
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
@ -34,9 +35,11 @@ from .util import convert_8_to_16, find_hsbk
|
|||||||
|
|
||||||
SCAN_INTERVAL = timedelta(seconds=10)
|
SCAN_INTERVAL = timedelta(seconds=10)
|
||||||
|
|
||||||
SERVICE_EFFECT_PULSE = "effect_pulse"
|
|
||||||
SERVICE_EFFECT_COLORLOOP = "effect_colorloop"
|
SERVICE_EFFECT_COLORLOOP = "effect_colorloop"
|
||||||
|
SERVICE_EFFECT_FLAME = "effect_flame"
|
||||||
|
SERVICE_EFFECT_MORPH = "effect_morph"
|
||||||
SERVICE_EFFECT_MOVE = "effect_move"
|
SERVICE_EFFECT_MOVE = "effect_move"
|
||||||
|
SERVICE_EFFECT_PULSE = "effect_pulse"
|
||||||
SERVICE_EFFECT_STOP = "effect_stop"
|
SERVICE_EFFECT_STOP = "effect_stop"
|
||||||
|
|
||||||
ATTR_POWER_OFF = "power_off"
|
ATTR_POWER_OFF = "power_off"
|
||||||
@ -47,11 +50,20 @@ ATTR_SPREAD = "spread"
|
|||||||
ATTR_CHANGE = "change"
|
ATTR_CHANGE = "change"
|
||||||
ATTR_DIRECTION = "direction"
|
ATTR_DIRECTION = "direction"
|
||||||
ATTR_SPEED = "speed"
|
ATTR_SPEED = "speed"
|
||||||
|
ATTR_PALETTE = "palette"
|
||||||
|
ATTR_THEME = "theme"
|
||||||
|
|
||||||
|
EFFECT_FLAME = "FLAME"
|
||||||
|
EFFECT_MORPH = "MORPH"
|
||||||
EFFECT_MOVE = "MOVE"
|
EFFECT_MOVE = "MOVE"
|
||||||
EFFECT_OFF = "OFF"
|
EFFECT_OFF = "OFF"
|
||||||
|
|
||||||
EFFECT_MOVE_DEFAULT_SPEED = 3.0
|
EFFECT_FLAME_DEFAULT_SPEED = 3
|
||||||
|
|
||||||
|
EFFECT_MORPH_DEFAULT_SPEED = 3
|
||||||
|
EFFECT_MORPH_DEFAULT_THEME = "exciting"
|
||||||
|
|
||||||
|
EFFECT_MOVE_DEFAULT_SPEED = 3
|
||||||
EFFECT_MOVE_DEFAULT_DIRECTION = "right"
|
EFFECT_MOVE_DEFAULT_DIRECTION = "right"
|
||||||
EFFECT_MOVE_DIRECTION_RIGHT = "right"
|
EFFECT_MOVE_DIRECTION_RIGHT = "right"
|
||||||
EFFECT_MOVE_DIRECTION_LEFT = "left"
|
EFFECT_MOVE_DIRECTION_LEFT = "left"
|
||||||
@ -128,6 +140,37 @@ SERVICES = (
|
|||||||
SERVICE_EFFECT_COLORLOOP,
|
SERVICE_EFFECT_COLORLOOP,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LIFX_EFFECT_FLAME_SCHEMA = cv.make_entity_service_schema(
|
||||||
|
{
|
||||||
|
**LIFX_EFFECT_SCHEMA,
|
||||||
|
ATTR_SPEED: vol.All(vol.Coerce(int), vol.Clamp(min=1, max=25)),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
HSBK_SCHEMA = vol.All(
|
||||||
|
vol.Coerce(tuple),
|
||||||
|
vol.ExactSequence(
|
||||||
|
(
|
||||||
|
vol.All(vol.Coerce(float), vol.Range(min=0, max=360)),
|
||||||
|
vol.All(vol.Coerce(float), vol.Range(min=0, max=100)),
|
||||||
|
vol.All(vol.Coerce(float), vol.Clamp(min=0, max=100)),
|
||||||
|
vol.All(vol.Coerce(int), vol.Clamp(min=1500, max=9000)),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
LIFX_EFFECT_MORPH_SCHEMA = cv.make_entity_service_schema(
|
||||||
|
{
|
||||||
|
**LIFX_EFFECT_SCHEMA,
|
||||||
|
ATTR_SPEED: vol.All(vol.Coerce(int), vol.Clamp(min=1, max=25)),
|
||||||
|
vol.Exclusive(ATTR_THEME, COLOR_GROUP): vol.Optional(
|
||||||
|
vol.In(ThemeLibrary().themes)
|
||||||
|
),
|
||||||
|
vol.Exclusive(ATTR_PALETTE, COLOR_GROUP): vol.All(
|
||||||
|
cv.ensure_list, [HSBK_SCHEMA]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
LIFX_EFFECT_MOVE_SCHEMA = cv.make_entity_service_schema(
|
LIFX_EFFECT_MOVE_SCHEMA = cv.make_entity_service_schema(
|
||||||
{
|
{
|
||||||
@ -192,6 +235,20 @@ class LIFXManager:
|
|||||||
schema=LIFX_EFFECT_COLORLOOP_SCHEMA,
|
schema=LIFX_EFFECT_COLORLOOP_SCHEMA,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_EFFECT_FLAME,
|
||||||
|
service_handler,
|
||||||
|
schema=LIFX_EFFECT_FLAME_SCHEMA,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_EFFECT_MORPH,
|
||||||
|
service_handler,
|
||||||
|
schema=LIFX_EFFECT_MORPH_SCHEMA,
|
||||||
|
)
|
||||||
|
|
||||||
self.hass.services.async_register(
|
self.hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_EFFECT_MOVE,
|
SERVICE_EFFECT_MOVE,
|
||||||
@ -222,7 +279,43 @@ class LIFXManager:
|
|||||||
coordinators.append(coordinator)
|
coordinators.append(coordinator)
|
||||||
bulbs.append(coordinator.device)
|
bulbs.append(coordinator.device)
|
||||||
|
|
||||||
if service == SERVICE_EFFECT_MOVE:
|
if service == SERVICE_EFFECT_FLAME:
|
||||||
|
await asyncio.gather(
|
||||||
|
*(
|
||||||
|
coordinator.async_set_matrix_effect(
|
||||||
|
effect=EFFECT_FLAME,
|
||||||
|
speed=kwargs.get(ATTR_SPEED, EFFECT_FLAME_DEFAULT_SPEED),
|
||||||
|
power_on=kwargs.get(ATTR_POWER_ON, True),
|
||||||
|
)
|
||||||
|
for coordinator in coordinators
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
elif service == SERVICE_EFFECT_MORPH:
|
||||||
|
|
||||||
|
theme_name = kwargs.get(ATTR_THEME, "exciting")
|
||||||
|
palette = kwargs.get(ATTR_PALETTE, None)
|
||||||
|
|
||||||
|
if palette is not None:
|
||||||
|
theme = Theme()
|
||||||
|
for hsbk in palette:
|
||||||
|
theme.add_hsbk(hsbk[0], hsbk[1], hsbk[2], hsbk[3])
|
||||||
|
else:
|
||||||
|
theme = ThemeLibrary().get_theme(theme_name)
|
||||||
|
|
||||||
|
await asyncio.gather(
|
||||||
|
*(
|
||||||
|
coordinator.async_set_matrix_effect(
|
||||||
|
effect=EFFECT_MORPH,
|
||||||
|
speed=kwargs.get(ATTR_SPEED, EFFECT_MORPH_DEFAULT_SPEED),
|
||||||
|
palette=theme.colors,
|
||||||
|
power_on=kwargs.get(ATTR_POWER_ON, True),
|
||||||
|
)
|
||||||
|
for coordinator in coordinators
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
elif service == SERVICE_EFFECT_MOVE:
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
*(
|
*(
|
||||||
coordinator.async_set_multizone_effect(
|
coordinator.async_set_multizone_effect(
|
||||||
@ -269,9 +362,9 @@ class LIFXManager:
|
|||||||
await self.effects_conductor.stop(bulbs)
|
await self.effects_conductor.stop(bulbs)
|
||||||
|
|
||||||
for coordinator in coordinators:
|
for coordinator in coordinators:
|
||||||
await coordinator.async_set_multizone_effect(
|
await coordinator.async_set_matrix_effect(
|
||||||
effect=EFFECT_OFF,
|
effect=EFFECT_OFF, power_on=False
|
||||||
speed=EFFECT_MOVE_DEFAULT_SPEED,
|
)
|
||||||
direction=EFFECT_MOVE_DEFAULT_DIRECTION,
|
await coordinator.async_set_multizone_effect(
|
||||||
power_on=False,
|
effect=EFFECT_OFF, power_on=False
|
||||||
)
|
)
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
"name": "LIFX",
|
"name": "LIFX",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/lifx",
|
"documentation": "https://www.home-assistant.io/integrations/lifx",
|
||||||
"requirements": ["aiolifx==0.8.6", "aiolifx_effects==0.2.2"],
|
"requirements": [
|
||||||
|
"aiolifx==0.8.6",
|
||||||
|
"aiolifx_effects==0.2.2",
|
||||||
|
"aiolifx_themes==0.1.1"
|
||||||
|
],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"dependencies": ["network"],
|
"dependencies": ["network"],
|
||||||
"homekit": {
|
"homekit": {
|
||||||
|
@ -205,7 +205,91 @@ effect_move:
|
|||||||
default: true
|
default: true
|
||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
|
effect_flame:
|
||||||
|
name: Flame effect
|
||||||
|
description: Start the firmware-based Flame effect on LIFX Tiles or Candle.
|
||||||
|
target:
|
||||||
|
entity:
|
||||||
|
integration: lifx
|
||||||
|
domain: light
|
||||||
|
fields:
|
||||||
|
speed:
|
||||||
|
name: Speed
|
||||||
|
description: How fast the flames will move.
|
||||||
|
default: 3
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
max: 25
|
||||||
|
step: 1
|
||||||
|
unit_of_measurement: seconds
|
||||||
|
power_on:
|
||||||
|
name: Power on
|
||||||
|
description: Powered off lights will be turned on before starting the effect.
|
||||||
|
default: true
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
effect_morph:
|
||||||
|
name: Morph effect
|
||||||
|
description: Start the firmware-based Morph effect on LIFX Tiles on Candle.
|
||||||
|
target:
|
||||||
|
entity:
|
||||||
|
integration: lifx
|
||||||
|
domain: light
|
||||||
|
fields:
|
||||||
|
speed:
|
||||||
|
name: Speed
|
||||||
|
description: How fast the colors will move.
|
||||||
|
default: 3
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 1
|
||||||
|
max: 25
|
||||||
|
step: 1
|
||||||
|
unit_of_measurement: seconds
|
||||||
|
palette:
|
||||||
|
name: Palette
|
||||||
|
description: List of at least 2 and at most 16 colors as hue (0-360), saturation (0-100), brightness (0-100) and kelvin (1500-900) values to use for this effect. Overrides the theme attribute.
|
||||||
|
example:
|
||||||
|
- "[[0, 100, 100, 3500], [60, 100, 100, 3500]]"
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
theme:
|
||||||
|
name: Theme
|
||||||
|
description: Predefined color theme to use for the effect. Overridden by the palette attribute.
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- "autumn"
|
||||||
|
- "blissful"
|
||||||
|
- "cheerful"
|
||||||
|
- "dream"
|
||||||
|
- "energizing"
|
||||||
|
- "epic"
|
||||||
|
- "exciting"
|
||||||
|
- "focusing"
|
||||||
|
- "halloween"
|
||||||
|
- "hanukkah"
|
||||||
|
- "holly"
|
||||||
|
- "independence day"
|
||||||
|
- "intense"
|
||||||
|
- "mellow"
|
||||||
|
- "peaceful"
|
||||||
|
- "powerful"
|
||||||
|
- "relaxing"
|
||||||
|
- "santa"
|
||||||
|
- "serene"
|
||||||
|
- "soothing"
|
||||||
|
- "sports"
|
||||||
|
- "spring"
|
||||||
|
- "tranquil"
|
||||||
|
- "warming"
|
||||||
|
power_on:
|
||||||
|
name: Power on
|
||||||
|
description: Powered off lights will be turned on before starting the effect.
|
||||||
|
default: true
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
effect_stop:
|
effect_stop:
|
||||||
name: Stop effect
|
name: Stop effect
|
||||||
description: Stop a running effect.
|
description: Stop a running effect.
|
||||||
|
@ -198,6 +198,9 @@ aiolifx==0.8.6
|
|||||||
# homeassistant.components.lifx
|
# homeassistant.components.lifx
|
||||||
aiolifx_effects==0.2.2
|
aiolifx_effects==0.2.2
|
||||||
|
|
||||||
|
# homeassistant.components.lifx
|
||||||
|
aiolifx_themes==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.lookin
|
# homeassistant.components.lookin
|
||||||
aiolookin==0.1.1
|
aiolookin==0.1.1
|
||||||
|
|
||||||
|
@ -176,6 +176,9 @@ aiolifx==0.8.6
|
|||||||
# homeassistant.components.lifx
|
# homeassistant.components.lifx
|
||||||
aiolifx_effects==0.2.2
|
aiolifx_effects==0.2.2
|
||||||
|
|
||||||
|
# homeassistant.components.lifx
|
||||||
|
aiolifx_themes==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.lookin
|
# homeassistant.components.lookin
|
||||||
aiolookin==0.1.1
|
aiolookin==0.1.1
|
||||||
|
|
||||||
|
@ -156,6 +156,15 @@ def _mocked_light_strip() -> Light:
|
|||||||
return bulb
|
return bulb
|
||||||
|
|
||||||
|
|
||||||
|
def _mocked_tile() -> Light:
|
||||||
|
bulb = _mocked_bulb()
|
||||||
|
bulb.product = 55 # LIFX Tile
|
||||||
|
bulb.effect = {"effect": "OFF"}
|
||||||
|
bulb.get_tile_effect = MockLifxCommand(bulb)
|
||||||
|
bulb.set_tile_effect = MockLifxCommand(bulb)
|
||||||
|
return bulb
|
||||||
|
|
||||||
|
|
||||||
def _mocked_bulb_new_firmware() -> Light:
|
def _mocked_bulb_new_firmware() -> Light:
|
||||||
bulb = _mocked_bulb()
|
bulb = _mocked_bulb()
|
||||||
bulb.host_firmware_version = "3.90"
|
bulb.host_firmware_version = "3.90"
|
||||||
|
@ -12,8 +12,11 @@ from homeassistant.components.lifx.const import ATTR_POWER
|
|||||||
from homeassistant.components.lifx.light import ATTR_INFRARED, ATTR_ZONES
|
from homeassistant.components.lifx.light import ATTR_INFRARED, ATTR_ZONES
|
||||||
from homeassistant.components.lifx.manager import (
|
from homeassistant.components.lifx.manager import (
|
||||||
ATTR_DIRECTION,
|
ATTR_DIRECTION,
|
||||||
|
ATTR_PALETTE,
|
||||||
ATTR_SPEED,
|
ATTR_SPEED,
|
||||||
|
ATTR_THEME,
|
||||||
SERVICE_EFFECT_COLORLOOP,
|
SERVICE_EFFECT_COLORLOOP,
|
||||||
|
SERVICE_EFFECT_MORPH,
|
||||||
SERVICE_EFFECT_MOVE,
|
SERVICE_EFFECT_MOVE,
|
||||||
)
|
)
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
@ -55,6 +58,7 @@ from . import (
|
|||||||
_mocked_bulb_new_firmware,
|
_mocked_bulb_new_firmware,
|
||||||
_mocked_clean_bulb,
|
_mocked_clean_bulb,
|
||||||
_mocked_light_strip,
|
_mocked_light_strip,
|
||||||
|
_mocked_tile,
|
||||||
_mocked_white_bulb,
|
_mocked_white_bulb,
|
||||||
_patch_config_flow_try_connect,
|
_patch_config_flow_try_connect,
|
||||||
_patch_device,
|
_patch_device,
|
||||||
@ -650,6 +654,146 @@ async def test_extended_multizone_messages(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_matrix_flame_morph_effects(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the firmware flame and morph effects on a matrix device."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=SERIAL
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_tile()
|
||||||
|
bulb.power_level = 0
|
||||||
|
bulb.color = [65535, 65535, 65535, 65535]
|
||||||
|
with _patch_discovery(device=bulb), _patch_config_flow_try_connect(
|
||||||
|
device=bulb
|
||||||
|
), _patch_device(device=bulb):
|
||||||
|
await async_setup_component(hass, lifx.DOMAIN, {lifx.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entity_id = "light.my_bulb"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
LIGHT_DOMAIN,
|
||||||
|
"turn_on",
|
||||||
|
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "effect_flame"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(bulb.set_power.calls) == 1
|
||||||
|
assert len(bulb.set_tile_effect.calls) == 1
|
||||||
|
|
||||||
|
call_dict = bulb.set_tile_effect.calls[0][1]
|
||||||
|
call_dict.pop("callb")
|
||||||
|
assert call_dict == {
|
||||||
|
"effect": 3,
|
||||||
|
"speed": 3,
|
||||||
|
"palette": [],
|
||||||
|
}
|
||||||
|
bulb.get_tile_effect.reset_mock()
|
||||||
|
bulb.set_tile_effect.reset_mock()
|
||||||
|
bulb.set_power.reset_mock()
|
||||||
|
|
||||||
|
bulb.power_level = 0
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_EFFECT_MORPH,
|
||||||
|
{ATTR_ENTITY_ID: entity_id, ATTR_SPEED: 4, ATTR_THEME: "autumn"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
bulb.power_level = 65535
|
||||||
|
bulb.effect = {
|
||||||
|
"effect": "MORPH",
|
||||||
|
"speed": 4.0,
|
||||||
|
"palette": [
|
||||||
|
(5643, 65535, 32768, 3500),
|
||||||
|
(15109, 65535, 32768, 3500),
|
||||||
|
(8920, 65535, 32768, 3500),
|
||||||
|
(10558, 65535, 32768, 3500),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
assert len(bulb.set_power.calls) == 1
|
||||||
|
assert len(bulb.set_tile_effect.calls) == 1
|
||||||
|
call_dict = bulb.set_tile_effect.calls[0][1]
|
||||||
|
call_dict.pop("callb")
|
||||||
|
assert call_dict == {
|
||||||
|
"effect": 2,
|
||||||
|
"speed": 4,
|
||||||
|
"palette": [
|
||||||
|
(5643, 65535, 32768, 3500),
|
||||||
|
(15109, 65535, 32768, 3500),
|
||||||
|
(8920, 65535, 32768, 3500),
|
||||||
|
(10558, 65535, 32768, 3500),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
bulb.get_tile_effect.reset_mock()
|
||||||
|
bulb.set_tile_effect.reset_mock()
|
||||||
|
bulb.set_power.reset_mock()
|
||||||
|
|
||||||
|
bulb.power_level = 0
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_EFFECT_MORPH,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: entity_id,
|
||||||
|
ATTR_SPEED: 6,
|
||||||
|
ATTR_PALETTE: [
|
||||||
|
(0, 100, 255, 3500),
|
||||||
|
(60, 100, 255, 3500),
|
||||||
|
(120, 100, 255, 3500),
|
||||||
|
(180, 100, 255, 3500),
|
||||||
|
(240, 100, 255, 3500),
|
||||||
|
(300, 100, 255, 3500),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
bulb.power_level = 65535
|
||||||
|
bulb.effect = {
|
||||||
|
"effect": "MORPH",
|
||||||
|
"speed": 6,
|
||||||
|
"palette": [
|
||||||
|
(0, 65535, 65535, 3500),
|
||||||
|
(10922, 65535, 65535, 3500),
|
||||||
|
(21845, 65535, 65535, 3500),
|
||||||
|
(32768, 65535, 65535, 3500),
|
||||||
|
(43690, 65535, 65535, 3500),
|
||||||
|
(54612, 65535, 65535, 3500),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
assert len(bulb.set_power.calls) == 1
|
||||||
|
assert len(bulb.set_tile_effect.calls) == 1
|
||||||
|
call_dict = bulb.set_tile_effect.calls[0][1]
|
||||||
|
call_dict.pop("callb")
|
||||||
|
assert call_dict == {
|
||||||
|
"effect": 2,
|
||||||
|
"speed": 6,
|
||||||
|
"palette": [
|
||||||
|
(0, 65535, 65535, 3500),
|
||||||
|
(10922, 65535, 65535, 3500),
|
||||||
|
(21845, 65535, 65535, 3500),
|
||||||
|
(32768, 65535, 65535, 3500),
|
||||||
|
(43690, 65535, 65535, 3500),
|
||||||
|
(54613, 65535, 65535, 3500),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
bulb.get_tile_effect.reset_mock()
|
||||||
|
bulb.set_tile_effect.reset_mock()
|
||||||
|
bulb.set_power.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
async def test_lightstrip_move_effect(hass: HomeAssistant) -> None:
|
async def test_lightstrip_move_effect(hass: HomeAssistant) -> None:
|
||||||
"""Test the firmware move effect on a light strip."""
|
"""Test the firmware move effect on a light strip."""
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
@ -697,7 +841,7 @@ async def test_lightstrip_move_effect(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
bulb.power_level = 65535
|
bulb.power_level = 65535
|
||||||
bulb.effect = {"name": "effect_move", "enable": 1}
|
bulb.effect = {"name": "MOVE", "speed": 4.5, "direction": "Left"}
|
||||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
|
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user