mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add effects feature to Hue lights (#68567)
This commit is contained in:
parent
8c10963bc0
commit
dbef90654f
@ -6,11 +6,13 @@ from typing import Any
|
||||
from aiohue import HueBridgeV2
|
||||
from aiohue.v2.controllers.events import EventType
|
||||
from aiohue.v2.controllers.lights import LightsController
|
||||
from aiohue.v2.models.feature import EffectStatus, TimedEffectStatus
|
||||
from aiohue.v2.models.light import Light
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_FLASH,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_XY_COLOR,
|
||||
@ -19,6 +21,7 @@ from homeassistant.components.light import (
|
||||
COLOR_MODE_ONOFF,
|
||||
COLOR_MODE_XY,
|
||||
FLASH_SHORT,
|
||||
SUPPORT_EFFECT,
|
||||
SUPPORT_FLASH,
|
||||
SUPPORT_TRANSITION,
|
||||
LightEntity,
|
||||
@ -36,6 +39,8 @@ from .helpers import (
|
||||
normalize_hue_transition,
|
||||
)
|
||||
|
||||
EFFECT_NONE = "None"
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@ -86,6 +91,21 @@ class HueLight(HueBaseEntity, LightEntity):
|
||||
self._supported_color_modes.add(COLOR_MODE_BRIGHTNESS)
|
||||
# support transition if brightness control
|
||||
self._attr_supported_features |= SUPPORT_TRANSITION
|
||||
# get list of supported effects (combine effects and timed_effects)
|
||||
self._attr_effect_list = []
|
||||
if effects := resource.effects:
|
||||
self._attr_effect_list = [
|
||||
x.value for x in effects.status_values if x != EffectStatus.NO_EFFECT
|
||||
]
|
||||
if timed_effects := resource.timed_effects:
|
||||
self._attr_effect_list += [
|
||||
x.value
|
||||
for x in timed_effects.status_values
|
||||
if x != TimedEffectStatus.NO_EFFECT
|
||||
]
|
||||
if len(self._attr_effect_list) > 0:
|
||||
self._attr_effect_list.insert(0, EFFECT_NONE)
|
||||
self._attr_supported_features |= SUPPORT_EFFECT
|
||||
|
||||
@property
|
||||
def brightness(self) -> int | None:
|
||||
@ -155,6 +175,17 @@ class HueLight(HueBaseEntity, LightEntity):
|
||||
"dynamics": self.resource.dynamics.status.value,
|
||||
}
|
||||
|
||||
@property
|
||||
def effect(self) -> str | None:
|
||||
"""Return the current effect."""
|
||||
if effects := self.resource.effects:
|
||||
if effects.status != EffectStatus.NO_EFFECT:
|
||||
return effects.status.value
|
||||
if timed_effects := self.resource.timed_effects:
|
||||
if timed_effects.status != TimedEffectStatus.NO_EFFECT:
|
||||
return timed_effects.status.value
|
||||
return EFFECT_NONE
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
|
||||
@ -162,6 +193,17 @@ class HueLight(HueBaseEntity, LightEntity):
|
||||
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP))
|
||||
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
|
||||
flash = kwargs.get(ATTR_FLASH)
|
||||
effect = effect_str = kwargs.get(ATTR_EFFECT)
|
||||
if effect_str == EFFECT_NONE:
|
||||
effect = EffectStatus.NO_EFFECT
|
||||
elif effect_str is not None:
|
||||
# work out if we got a regular effect or timed effect
|
||||
effect = EffectStatus(effect_str)
|
||||
if effect == EffectStatus.UNKNOWN:
|
||||
effect = TimedEffectStatus(effect_str)
|
||||
if transition is None:
|
||||
# a transition is required for timed effect, default to 10 minutes
|
||||
transition = 600000
|
||||
|
||||
if flash is not None:
|
||||
await self.async_set_flash(flash)
|
||||
@ -179,6 +221,7 @@ class HueLight(HueBaseEntity, LightEntity):
|
||||
color_xy=xy_color,
|
||||
color_temp=color_temp,
|
||||
transition_time=transition,
|
||||
effect=effect,
|
||||
)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,8 @@ async def test_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
||||
assert light_1.attributes["min_mireds"] == 153
|
||||
assert light_1.attributes["max_mireds"] == 500
|
||||
assert light_1.attributes["dynamics"] == "dynamic_palette"
|
||||
assert light_1.attributes["effect_list"] == ["None", "candle", "fire"]
|
||||
assert light_1.attributes["effect"] == "None"
|
||||
|
||||
# test light which supports color temperature only
|
||||
light_2 = hass.states.get("light.hue_light_with_color_temperature_only")
|
||||
@ -49,6 +51,7 @@ async def test_lights(hass, mock_bridge_v2, v2_resources_test_data):
|
||||
assert light_2.attributes["min_mireds"] == 153
|
||||
assert light_2.attributes["max_mireds"] == 454
|
||||
assert light_2.attributes["dynamics"] == "none"
|
||||
assert light_2.attributes["effect_list"] == ["None", "candle", "sunrise"]
|
||||
|
||||
# test light which supports color only
|
||||
light_3 = hass.states.get("light.hue_light_with_color_only")
|
||||
@ -164,6 +167,39 @@ async def test_light_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat
|
||||
assert len(mock_bridge_v2.mock_requests) == 6
|
||||
assert mock_bridge_v2.mock_requests[5]["json"]["color_temperature"]["mirek"] == 500
|
||||
|
||||
# test enable effect
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": test_light_id, "effect": "candle"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_bridge_v2.mock_requests) == 7
|
||||
assert mock_bridge_v2.mock_requests[6]["json"]["effects"]["effect"] == "candle"
|
||||
|
||||
# test disable effect
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": test_light_id, "effect": "None"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_bridge_v2.mock_requests) == 8
|
||||
assert mock_bridge_v2.mock_requests[7]["json"]["effects"]["effect"] == "no_effect"
|
||||
|
||||
# test timed effect
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
"turn_on",
|
||||
{"entity_id": test_light_id, "effect": "sunrise", "transition": 6},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_bridge_v2.mock_requests) == 9
|
||||
assert (
|
||||
mock_bridge_v2.mock_requests[8]["json"]["timed_effects"]["effect"] == "sunrise"
|
||||
)
|
||||
assert mock_bridge_v2.mock_requests[8]["json"]["timed_effects"]["duration"] == 6000
|
||||
|
||||
|
||||
async def test_light_turn_off_service(hass, mock_bridge_v2, v2_resources_test_data):
|
||||
"""Test calling the turn off service on a light."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user