Add set_music_mode service to flux_led for detailed music mode control (#62429)
parent
eb897c6f48
commit
4b30c9631f
|
@ -76,6 +76,11 @@ class FluxEntity(CoordinatorEntity):
|
|||
unique_id, self._device, coordinator.entry
|
||||
)
|
||||
|
||||
async def _async_ensure_device_on(self) -> None:
|
||||
"""Turn the device on if it needs to be turned on before a command."""
|
||||
if self._device.requires_turn_on and not self._device.is_on:
|
||||
await self._device.async_turn_on()
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, str]:
|
||||
"""Return the attributes."""
|
||||
|
|
|
@ -6,6 +6,7 @@ import logging
|
|||
from typing import Any, Final
|
||||
|
||||
from flux_led.const import MultiColorEffects
|
||||
from flux_led.protocol import MusicMode
|
||||
from flux_led.utils import (
|
||||
color_temp_to_white_levels,
|
||||
rgbcw_brightness,
|
||||
|
@ -73,6 +74,11 @@ MODE_ATTRS = {
|
|||
ATTR_WHITE,
|
||||
}
|
||||
|
||||
ATTR_FOREGROUND_COLOR: Final = "foreground_color"
|
||||
ATTR_BACKGROUND_COLOR: Final = "background_color"
|
||||
ATTR_SENSITIVITY: Final = "sensitivity"
|
||||
ATTR_LIGHT_SCREEN: Final = "light_screen"
|
||||
|
||||
# Constant color temp values for 2 flux_led special modes
|
||||
# Warm-white and Cool-white modes
|
||||
COLOR_TEMP_WARM_VS_COLD_WHITE_CUT_OFF: Final = 285
|
||||
|
@ -81,6 +87,7 @@ EFFECT_CUSTOM: Final = "custom"
|
|||
|
||||
SERVICE_CUSTOM_EFFECT: Final = "set_custom_effect"
|
||||
SERVICE_SET_ZONES: Final = "set_zones"
|
||||
SERVICE_SET_MUSIC_MODE: Final = "set_music_mode"
|
||||
|
||||
CUSTOM_EFFECT_DICT: Final = {
|
||||
vol.Required(CONF_COLORS): vol.All(
|
||||
|
@ -96,6 +103,25 @@ CUSTOM_EFFECT_DICT: Final = {
|
|||
),
|
||||
}
|
||||
|
||||
SET_MUSIC_MODE_DICT: Final = {
|
||||
vol.Optional(ATTR_SENSITIVITY, default=100): vol.All(
|
||||
vol.Range(min=0, max=100), vol.Coerce(int)
|
||||
),
|
||||
vol.Optional(ATTR_BRIGHTNESS, default=100): vol.All(
|
||||
vol.Range(min=0, max=100), vol.Coerce(int)
|
||||
),
|
||||
vol.Optional(ATTR_EFFECT, default=1): vol.All(
|
||||
vol.Range(min=1, max=16), vol.Coerce(int)
|
||||
),
|
||||
vol.Optional(ATTR_LIGHT_SCREEN, default=False): bool,
|
||||
vol.Optional(ATTR_FOREGROUND_COLOR): vol.All(
|
||||
vol.Coerce(tuple), vol.ExactSequence((cv.byte,) * 3)
|
||||
),
|
||||
vol.Optional(ATTR_BACKGROUND_COLOR): vol.All(
|
||||
vol.Coerce(tuple), vol.ExactSequence((cv.byte,) * 3)
|
||||
),
|
||||
}
|
||||
|
||||
SET_ZONES_DICT: Final = {
|
||||
vol.Required(CONF_COLORS): vol.All(
|
||||
cv.ensure_list,
|
||||
|
@ -130,6 +156,11 @@ async def async_setup_entry(
|
|||
SET_ZONES_DICT,
|
||||
"async_set_zones",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_MUSIC_MODE,
|
||||
SET_MUSIC_MODE_DICT,
|
||||
"async_set_music_mode",
|
||||
)
|
||||
options = entry.options
|
||||
|
||||
try:
|
||||
|
@ -330,3 +361,23 @@ class FluxLight(FluxOnOffEntity, CoordinatorEntity, LightEntity):
|
|||
speed_pct,
|
||||
_str_to_multi_color_effect(effect),
|
||||
)
|
||||
|
||||
async def async_set_music_mode(
|
||||
self,
|
||||
sensitivity: int,
|
||||
brightness: int,
|
||||
effect: int,
|
||||
light_screen: bool,
|
||||
foreground_color: tuple[int, int, int] | None = None,
|
||||
background_color: tuple[int, int, int] | None = None,
|
||||
) -> None:
|
||||
"""Configure music mode."""
|
||||
await self._async_ensure_device_on()
|
||||
await self._device.async_set_music_mode(
|
||||
sensitivity=sensitivity,
|
||||
brightness=brightness,
|
||||
mode=MusicMode.LIGHT_SCREEN.value if light_screen else None,
|
||||
effect=effect,
|
||||
foreground_color=foreground_color,
|
||||
background_color=background_color,
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"config_flow": true,
|
||||
"dependencies": ["network"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/flux_led",
|
||||
"requirements": ["flux_led==0.27.8"],
|
||||
"requirements": ["flux_led==0.27.10"],
|
||||
"quality_scale": "platinum",
|
||||
"codeowners": ["@icemanch"],
|
||||
"iot_class": "local_push",
|
||||
|
|
|
@ -77,3 +77,60 @@ set_zones:
|
|||
- "strobe"
|
||||
- "jump"
|
||||
- "breathing"
|
||||
set_music_mode:
|
||||
description: Configure music mode on Controller RGB with MIC (0x08), Addressable v2 (0xA2), and Addressable v3 (0xA3) devices that have a built-in microphone.
|
||||
target:
|
||||
entity:
|
||||
integration: flux_led
|
||||
domain: light
|
||||
fields:
|
||||
sensitivity:
|
||||
description: Microphone sensitivity (0-100)
|
||||
example: 80
|
||||
default: 100
|
||||
required: false
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
step: 1
|
||||
max: 100
|
||||
unit_of_measurement: "%"
|
||||
brightness:
|
||||
description: Light brightness (0-100)
|
||||
example: 80
|
||||
default: 100
|
||||
required: false
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
step: 1
|
||||
max: 100
|
||||
unit_of_measurement: "%"
|
||||
light_screen:
|
||||
description: Light screen mode for 2 dimensional pixels (Addressable models only)
|
||||
default: false
|
||||
required: false
|
||||
selector:
|
||||
boolean:
|
||||
effect:
|
||||
description: Effect (1-16 on Addressable models, 0-3 on RGB with MIC models)
|
||||
example: 1
|
||||
default: 1
|
||||
required: false
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
step: 1
|
||||
max: 16
|
||||
foreground_color:
|
||||
description: The foreground RGB color
|
||||
example: "[255, 100, 100]"
|
||||
required: false
|
||||
selector:
|
||||
object:
|
||||
background_color:
|
||||
description: The background RGB color (Addressable models only)
|
||||
example: "[255, 100, 100]"
|
||||
required: false
|
||||
selector:
|
||||
object:
|
||||
|
|
|
@ -126,8 +126,7 @@ class FluxMusicSwitch(FluxEntity, SwitchEntity):
|
|||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the microphone on."""
|
||||
if self._device.requires_turn_on and not self._device.is_on:
|
||||
await self._device.async_turn_on()
|
||||
await self._async_ensure_device_on()
|
||||
await self._device.async_set_music_mode()
|
||||
self.async_write_ha_state()
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
|
|
@ -664,7 +664,7 @@ fjaraskupan==1.0.2
|
|||
flipr-api==1.4.1
|
||||
|
||||
# homeassistant.components.flux_led
|
||||
flux_led==0.27.8
|
||||
flux_led==0.27.10
|
||||
|
||||
# homeassistant.components.homekit
|
||||
fnvhash==0.1.0
|
||||
|
|
|
@ -405,7 +405,7 @@ fjaraskupan==1.0.2
|
|||
flipr-api==1.4.1
|
||||
|
||||
# homeassistant.components.flux_led
|
||||
flux_led==0.27.8
|
||||
flux_led==0.27.10
|
||||
|
||||
# homeassistant.components.homekit
|
||||
fnvhash==0.1.0
|
||||
|
|
|
@ -10,8 +10,10 @@ 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,
|
||||
MODE_MUSIC,
|
||||
MultiColorEffects,
|
||||
)
|
||||
from flux_led.protocol import MusicMode
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import flux_led
|
||||
|
@ -26,6 +28,12 @@ from homeassistant.components.flux_led.const import (
|
|||
DOMAIN,
|
||||
TRANSITION_JUMP,
|
||||
)
|
||||
from homeassistant.components.flux_led.light import (
|
||||
ATTR_BACKGROUND_COLOR,
|
||||
ATTR_FOREGROUND_COLOR,
|
||||
ATTR_LIGHT_SCREEN,
|
||||
ATTR_SENSITIVITY,
|
||||
)
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_MODE,
|
||||
|
@ -1191,3 +1199,47 @@ async def test_addressable_light(hass: HomeAssistant) -> None:
|
|||
bulb.async_turn_on.assert_called_once()
|
||||
bulb.async_turn_on.reset_mock()
|
||||
await async_mock_device_turn_on(hass, bulb)
|
||||
|
||||
|
||||
async def test_music_mode_service(hass: HomeAssistant) -> None:
|
||||
"""Test music mode service."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
bulb.raw_state = bulb.raw_state._replace(model_num=0xA3) # has music mode
|
||||
bulb.microphone = True
|
||||
with _patch_discovery(), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.bulb_rgbcw_ddeeff"
|
||||
assert hass.states.get(entity_id)
|
||||
|
||||
bulb.effect = MODE_MUSIC
|
||||
bulb.is_on = False
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"set_music_mode",
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
ATTR_EFFECT: 12,
|
||||
ATTR_LIGHT_SCREEN: True,
|
||||
ATTR_SENSITIVITY: 50,
|
||||
ATTR_BRIGHTNESS: 50,
|
||||
ATTR_FOREGROUND_COLOR: [255, 0, 0],
|
||||
ATTR_BACKGROUND_COLOR: [0, 255, 0],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.async_set_music_mode.assert_called_once_with(
|
||||
sensitivity=50,
|
||||
brightness=50,
|
||||
mode=MusicMode.LIGHT_SCREEN.value,
|
||||
effect=12,
|
||||
foreground_color=(255, 0, 0),
|
||||
background_color=(0, 255, 0),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue