mirror of
https://github.com/home-assistant/core.git
synced 2026-09-08 06:31:35 +01:00
Fix Yeelight ambilight effect state (#178787)
This commit is contained in:
@@ -12,7 +12,6 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
|
||||
from .const import (
|
||||
ACTIVE_COLOR_FLOWING,
|
||||
ACTIVE_MODE_NIGHTLIGHT,
|
||||
DATA_UPDATED,
|
||||
STATE_CHANGE_TIME,
|
||||
@@ -142,19 +141,10 @@ class YeelightDevice:
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_color_flow_enabled(self) -> bool:
|
||||
"""Return true / false if color flow is currently running."""
|
||||
return self._color_flow and int(self._color_flow) == ACTIVE_COLOR_FLOWING
|
||||
|
||||
@property
|
||||
def _active_mode(self):
|
||||
return self.bulb.last_properties.get("active_mode")
|
||||
|
||||
@property
|
||||
def _color_flow(self):
|
||||
return self.bulb.last_properties.get("flowing")
|
||||
|
||||
@property
|
||||
def _nightlight_brightness(self):
|
||||
return self.bulb.last_properties.get("nl_br")
|
||||
|
||||
@@ -40,6 +40,7 @@ from homeassistant.util import color as color_util
|
||||
from . import YEELIGHT_FLOW_TRANSITION_SCHEMA, YeelightConfigEntry
|
||||
from .const import (
|
||||
ACTION_RECOVER,
|
||||
ACTIVE_COLOR_FLOWING,
|
||||
ATTR_ACTION,
|
||||
ATTR_COUNT,
|
||||
ATTR_MODE_MUSIC,
|
||||
@@ -549,7 +550,12 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
@override
|
||||
def effect(self) -> str | None:
|
||||
"""Return the current effect."""
|
||||
return self._effect if self.device.is_color_flow_enabled else None
|
||||
return self._effect if self._is_color_flow_enabled else None
|
||||
|
||||
@property
|
||||
def _is_color_flow_enabled(self) -> bool:
|
||||
color_flow = self._get_property("flowing")
|
||||
return bool(color_flow) and int(color_flow) == ACTIVE_COLOR_FLOWING
|
||||
|
||||
@property
|
||||
def _bulb(self) -> AsyncBulb:
|
||||
@@ -583,7 +589,7 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the device specific state attributes."""
|
||||
attributes = {
|
||||
"flowing": self.device.is_color_flow_enabled,
|
||||
"flowing": self._is_color_flow_enabled,
|
||||
"music_mode": self._bulb.music_mode,
|
||||
}
|
||||
|
||||
@@ -655,7 +661,7 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
):
|
||||
return
|
||||
if (
|
||||
not self.device.is_color_flow_enabled
|
||||
not self._is_color_flow_enabled
|
||||
and self.color_mode == ColorMode.HS
|
||||
and self.hs_color == hs_color
|
||||
):
|
||||
@@ -680,7 +686,7 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
):
|
||||
return
|
||||
if (
|
||||
not self.device.is_color_flow_enabled
|
||||
not self._is_color_flow_enabled
|
||||
and self.color_mode == ColorMode.RGB
|
||||
and self.rgb_color == rgb
|
||||
):
|
||||
@@ -706,7 +712,7 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
return
|
||||
|
||||
if (
|
||||
not self.device.is_color_flow_enabled
|
||||
not self._is_color_flow_enabled
|
||||
and self.color_mode == ColorMode.COLOR_TEMP
|
||||
and self.color_temp_kelvin == temp_in_k
|
||||
):
|
||||
@@ -764,6 +770,8 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
|
||||
if effect == EFFECT_STOP:
|
||||
await self._bulb.async_stop_flow(light_type=self.light_type)
|
||||
self._effect = None
|
||||
await self.device.async_update(True)
|
||||
return
|
||||
|
||||
if effect in self.custom_effects_names:
|
||||
@@ -783,6 +791,7 @@ class YeelightBaseLight(YeelightEntity, LightEntity):
|
||||
|
||||
await self._bulb.async_start_flow(flow, light_type=self.light_type)
|
||||
self._effect = effect
|
||||
await self.device.async_update(True)
|
||||
|
||||
@_async_cmd
|
||||
async def _async_turn_on(self, duration) -> None:
|
||||
|
||||
@@ -57,6 +57,7 @@ from homeassistant.components.yeelight.const import (
|
||||
DEFAULT_SAVE_ON_CHANGE,
|
||||
DEFAULT_TRANSITION,
|
||||
DOMAIN,
|
||||
UPDATE_REQUEST_PROPERTIES,
|
||||
YEELIGHT_HSV_TRANSACTION,
|
||||
YEELIGHT_RGB_TRANSITION,
|
||||
YEELIGHT_SLEEP_TRANSACTION,
|
||||
@@ -1251,6 +1252,87 @@ async def test_ambilight_with_nightlight_disabled(hass: HomeAssistant) -> None:
|
||||
assert state.attributes[ATTR_BRIGHTNESS] == 128
|
||||
|
||||
|
||||
async def test_ambilight_effect(hass: HomeAssistant) -> None:
|
||||
"""Test an effect on the ambilight is tracked separately from the main light."""
|
||||
mocked_bulb = _mocked_bulb()
|
||||
capabilities = {**CAPABILITIES, "model": "ceiling10"}
|
||||
mocked_bulb.last_properties = {
|
||||
**PROPERTIES,
|
||||
"flowing": "0",
|
||||
"bg_flowing": "0",
|
||||
}
|
||||
mocked_bulb.bulb_type = BulbType.WhiteTempMood
|
||||
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data=CONFIG_ENTRY_DATA)
|
||||
config_entry.add_to_hass(hass)
|
||||
with (
|
||||
_patch_discovery(capabilities=capabilities),
|
||||
_patch_discovery_interval(),
|
||||
patch(f"{MODULE}.AsyncBulb", return_value=mocked_bulb),
|
||||
):
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
main_light_entity_id = "light.yeelight_ceiling10_0x15243f"
|
||||
ambilight_entity_id = f"{main_light_entity_id}_ambilight"
|
||||
mocked_bulb.async_get_properties.reset_mock()
|
||||
|
||||
async def _async_get_properties(properties: list[str]) -> None:
|
||||
assert properties == UPDATE_REQUEST_PROPERTIES
|
||||
assert mocked_bulb.async_start_flow.await_count > 0
|
||||
mocked_bulb.last_properties["bg_flowing"] = "1"
|
||||
|
||||
mocked_bulb.async_get_properties.side_effect = _async_get_properties
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ambilight_entity_id, ATTR_EFFECT: EFFECT_DISCO},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mocked_bulb.async_start_flow.assert_awaited_once_with(
|
||||
ANY, light_type=LightType.Ambient
|
||||
)
|
||||
mocked_bulb.async_get_properties.assert_awaited_once_with(UPDATE_REQUEST_PROPERTIES)
|
||||
|
||||
assert hass.states.get(main_light_entity_id).attributes.get(ATTR_EFFECT) is None
|
||||
ambilight_state = hass.states.get(ambilight_entity_id)
|
||||
assert ambilight_state.attributes[ATTR_EFFECT] == EFFECT_DISCO
|
||||
assert ambilight_state.attributes["flowing"] is True
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ambilight_entity_id, ATTR_EFFECT: EFFECT_WHATSAPP},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert mocked_bulb.async_get_properties.await_count == 2
|
||||
assert (
|
||||
hass.states.get(ambilight_entity_id).attributes[ATTR_EFFECT] == EFFECT_WHATSAPP
|
||||
)
|
||||
|
||||
async def _async_get_stopped_properties(properties: list[str]) -> None:
|
||||
assert properties == UPDATE_REQUEST_PROPERTIES
|
||||
assert mocked_bulb.async_stop_flow.await_count > 0
|
||||
mocked_bulb.last_properties["bg_flowing"] = "0"
|
||||
|
||||
mocked_bulb.async_get_properties.side_effect = _async_get_stopped_properties
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ambilight_entity_id, ATTR_EFFECT: EFFECT_STOP},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mocked_bulb.async_stop_flow.assert_awaited_once_with(light_type=LightType.Ambient)
|
||||
assert mocked_bulb.async_get_properties.await_count == 3
|
||||
ambilight_state = hass.states.get(ambilight_entity_id)
|
||||
assert ambilight_state.attributes.get(ATTR_EFFECT) is None
|
||||
assert ambilight_state.attributes["flowing"] is False
|
||||
|
||||
|
||||
async def test_state_fails_to_update_triggers_update(hass: HomeAssistant) -> None:
|
||||
"""Ensure async_get_properties is called on failed state update."""
|
||||
mocked_bulb = _mocked_bulb()
|
||||
|
||||
Reference in New Issue
Block a user