Add zones support to flux_led (#61072)
parent
3d75befe0a
commit
abc7dcf6bf
|
@ -62,6 +62,7 @@ TRANSITION_STROBE: Final = "strobe"
|
|||
CONF_COLORS: Final = "colors"
|
||||
CONF_SPEED_PCT: Final = "speed_pct"
|
||||
CONF_TRANSITION: Final = "transition"
|
||||
CONF_EFFECT: Final = "effect"
|
||||
|
||||
|
||||
EFFECT_SPEED_SUPPORT_MODES: Final = {COLOR_MODE_RGB, COLOR_MODE_RGBW, COLOR_MODE_RGBWW}
|
||||
|
|
|
@ -5,6 +5,7 @@ import ast
|
|||
import logging
|
||||
from typing import Any, Final
|
||||
|
||||
from flux_led.const import MultiColorEffects
|
||||
from flux_led.utils import (
|
||||
color_temp_to_white_levels,
|
||||
rgbcw_brightness,
|
||||
|
@ -43,6 +44,7 @@ from .const import (
|
|||
CONF_CUSTOM_EFFECT_COLORS,
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION,
|
||||
CONF_EFFECT,
|
||||
CONF_SPEED_PCT,
|
||||
CONF_TRANSITION,
|
||||
DEFAULT_EFFECT_SPEED,
|
||||
|
@ -53,7 +55,12 @@ from .const import (
|
|||
)
|
||||
from .coordinator import FluxLedUpdateCoordinator
|
||||
from .entity import FluxOnOffEntity
|
||||
from .util import _effect_brightness, _flux_color_mode_to_hass, _hass_color_modes
|
||||
from .util import (
|
||||
_effect_brightness,
|
||||
_flux_color_mode_to_hass,
|
||||
_hass_color_modes,
|
||||
_str_to_multi_color_effect,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -73,6 +80,7 @@ COLOR_TEMP_WARM_VS_COLD_WHITE_CUT_OFF: Final = 285
|
|||
EFFECT_CUSTOM: Final = "custom"
|
||||
|
||||
SERVICE_CUSTOM_EFFECT: Final = "set_custom_effect"
|
||||
SERVICE_SET_ZONES: Final = "set_zones"
|
||||
|
||||
CUSTOM_EFFECT_DICT: Final = {
|
||||
vol.Required(CONF_COLORS): vol.All(
|
||||
|
@ -88,6 +96,20 @@ CUSTOM_EFFECT_DICT: Final = {
|
|||
),
|
||||
}
|
||||
|
||||
SET_ZONES_DICT: Final = {
|
||||
vol.Required(CONF_COLORS): vol.All(
|
||||
cv.ensure_list,
|
||||
vol.Length(min=1, max=2048),
|
||||
[vol.All(vol.Coerce(tuple), vol.ExactSequence((cv.byte, cv.byte, cv.byte)))],
|
||||
),
|
||||
vol.Optional(CONF_SPEED_PCT, default=50): vol.All(
|
||||
vol.Range(min=0, max=100), vol.Coerce(int)
|
||||
),
|
||||
vol.Optional(CONF_EFFECT, default=MultiColorEffects.STATIC.name.lower()): vol.All(
|
||||
cv.string, vol.In([effect.name.lower() for effect in MultiColorEffects])
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
|
@ -103,6 +125,11 @@ async def async_setup_entry(
|
|||
CUSTOM_EFFECT_DICT,
|
||||
"async_set_custom_effect",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_ZONES,
|
||||
SET_ZONES_DICT,
|
||||
"async_set_zones",
|
||||
)
|
||||
options = entry.options
|
||||
|
||||
try:
|
||||
|
@ -293,3 +320,13 @@ class FluxLight(FluxOnOffEntity, CoordinatorEntity, LightEntity):
|
|||
speed_pct,
|
||||
transition,
|
||||
)
|
||||
|
||||
async def async_set_zones(
|
||||
self, colors: list[tuple[int, int, int]], speed_pct: int, effect: str
|
||||
) -> None:
|
||||
"""Set a colors for zones."""
|
||||
await self._device.async_set_zones(
|
||||
colors,
|
||||
speed_pct,
|
||||
_str_to_multi_color_effect(effect),
|
||||
)
|
||||
|
|
|
@ -36,3 +36,44 @@ set_custom_effect:
|
|||
- "gradual"
|
||||
- "jump"
|
||||
- "strobe"
|
||||
set_zones:
|
||||
description: Set strip zones for Addressable v3 controllers (0xA3).
|
||||
target:
|
||||
entity:
|
||||
integration: flux_led
|
||||
domain: light
|
||||
fields:
|
||||
colors:
|
||||
description: List of colors for each zone (RGB). The length of each zone is the number of pixels per segment divided by the number of colors. (Max 2048 Colors)
|
||||
example: |
|
||||
- [255,0,0]
|
||||
- [0,255,0]
|
||||
- [0,0,255]
|
||||
- [255,255,255]
|
||||
required: true
|
||||
selector:
|
||||
object:
|
||||
speed_pct:
|
||||
description: Effect speed for the custom effect (0-100)
|
||||
example: 80
|
||||
default: 50
|
||||
required: false
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
step: 1
|
||||
max: 100
|
||||
unit_of_measurement: "%"
|
||||
effect:
|
||||
description: Effect
|
||||
example: 'running_water'
|
||||
default: 'static'
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "static"
|
||||
- "running_water"
|
||||
- "strobe"
|
||||
- "jump"
|
||||
- "breathing"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from flux_led.aio import AIOWifiLedBulb
|
||||
from flux_led.const import COLOR_MODE_DIM as FLUX_COLOR_MODE_DIM
|
||||
from flux_led.const import COLOR_MODE_DIM as FLUX_COLOR_MODE_DIM, MultiColorEffects
|
||||
|
||||
from homeassistant.components.light import (
|
||||
COLOR_MODE_BRIGHTNESS,
|
||||
|
@ -34,3 +34,12 @@ def _flux_color_mode_to_hass(
|
|||
def _effect_brightness(brightness: int) -> int:
|
||||
"""Convert hass brightness to effect brightness."""
|
||||
return round(brightness / 255 * 100)
|
||||
|
||||
|
||||
def _str_to_multi_color_effect(effect_str: str) -> MultiColorEffects:
|
||||
"""Convert an multicolor effect string to MultiColorEffects."""
|
||||
for effect in MultiColorEffects:
|
||||
if effect.name.lower() == effect_str:
|
||||
return effect
|
||||
# unreachable due to schema validation
|
||||
assert False # pragma: no cover
|
||||
|
|
|
@ -10,6 +10,7 @@ from flux_led.const import (
|
|||
COLOR_MODE_RGBW as FLUX_COLOR_MODE_RGBW,
|
||||
COLOR_MODE_RGBWW as FLUX_COLOR_MODE_RGBWW,
|
||||
COLOR_MODES_RGB_W as FLUX_COLOR_MODES_RGB_W,
|
||||
MultiColorEffects,
|
||||
)
|
||||
import pytest
|
||||
|
||||
|
@ -19,6 +20,7 @@ from homeassistant.components.flux_led.const import (
|
|||
CONF_CUSTOM_EFFECT_COLORS,
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION,
|
||||
CONF_EFFECT,
|
||||
CONF_SPEED_PCT,
|
||||
CONF_TRANSITION,
|
||||
DOMAIN,
|
||||
|
@ -1119,6 +1121,36 @@ async def test_rgb_light_custom_effect_via_service(
|
|||
)
|
||||
bulb.async_set_custom_pattern.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"set_zones",
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
CONF_COLORS: [[0, 0, 255], [255, 0, 0]],
|
||||
CONF_EFFECT: "running_water",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.async_set_zones.assert_called_with(
|
||||
[(0, 0, 255), (255, 0, 0)], 50, MultiColorEffects.RUNNING_WATER
|
||||
)
|
||||
bulb.async_set_zones.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"set_zones",
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
CONF_COLORS: [[0, 0, 255], [255, 0, 0]],
|
||||
CONF_SPEED_PCT: 30,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.async_set_zones.assert_called_with(
|
||||
[(0, 0, 255), (255, 0, 0)], 30, MultiColorEffects.STATIC
|
||||
)
|
||||
bulb.async_set_zones.reset_mock()
|
||||
|
||||
|
||||
async def test_addressable_light(hass: HomeAssistant) -> None:
|
||||
"""Test an addressable light."""
|
||||
|
|
Loading…
Reference in New Issue