mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Avoid increasing yeelight rate limit when the state is already set (#54410)
This commit is contained in:
parent
4da451fcf7
commit
4ae6435a64
@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
|
||||
import voluptuous as vol
|
||||
import yeelight
|
||||
@ -576,6 +577,13 @@ class YeelightGenericLight(YeelightEntity, LightEntity):
|
||||
async def async_set_brightness(self, brightness, duration) -> None:
|
||||
"""Set bulb brightness."""
|
||||
if brightness:
|
||||
if math.floor(self.brightness) == math.floor(brightness):
|
||||
_LOGGER.debug("brightness already set to: %s", brightness)
|
||||
# Already set, and since we get pushed updates
|
||||
# we avoid setting it again to ensure we do not
|
||||
# hit the rate limit
|
||||
return
|
||||
|
||||
_LOGGER.debug("Setting brightness: %s", brightness)
|
||||
await self._bulb.async_set_brightness(
|
||||
brightness / 255 * 100, duration=duration, light_type=self.light_type
|
||||
@ -585,6 +593,13 @@ class YeelightGenericLight(YeelightEntity, LightEntity):
|
||||
async def async_set_hs(self, hs_color, duration) -> None:
|
||||
"""Set bulb's color."""
|
||||
if hs_color and COLOR_MODE_HS in self.supported_color_modes:
|
||||
if self.color_mode == COLOR_MODE_HS and self.hs_color == hs_color:
|
||||
_LOGGER.debug("HS already set to: %s", hs_color)
|
||||
# Already set, and since we get pushed updates
|
||||
# we avoid setting it again to ensure we do not
|
||||
# hit the rate limit
|
||||
return
|
||||
|
||||
_LOGGER.debug("Setting HS: %s", hs_color)
|
||||
await self._bulb.async_set_hsv(
|
||||
hs_color[0], hs_color[1], duration=duration, light_type=self.light_type
|
||||
@ -594,9 +609,16 @@ class YeelightGenericLight(YeelightEntity, LightEntity):
|
||||
async def async_set_rgb(self, rgb, duration) -> None:
|
||||
"""Set bulb's color."""
|
||||
if rgb and COLOR_MODE_RGB in self.supported_color_modes:
|
||||
if self.color_mode == COLOR_MODE_RGB and self.rgb_color == rgb:
|
||||
_LOGGER.debug("RGB already set to: %s", rgb)
|
||||
# Already set, and since we get pushed updates
|
||||
# we avoid setting it again to ensure we do not
|
||||
# hit the rate limit
|
||||
return
|
||||
|
||||
_LOGGER.debug("Setting RGB: %s", rgb)
|
||||
await self._bulb.async_set_rgb(
|
||||
rgb[0], rgb[1], rgb[2], duration=duration, light_type=self.light_type
|
||||
*rgb, duration=duration, light_type=self.light_type
|
||||
)
|
||||
|
||||
@_async_cmd
|
||||
@ -604,7 +626,16 @@ class YeelightGenericLight(YeelightEntity, LightEntity):
|
||||
"""Set bulb's color temperature."""
|
||||
if colortemp and COLOR_MODE_COLOR_TEMP in self.supported_color_modes:
|
||||
temp_in_k = mired_to_kelvin(colortemp)
|
||||
_LOGGER.debug("Setting color temp: %s K", temp_in_k)
|
||||
|
||||
if (
|
||||
self.color_mode == COLOR_MODE_COLOR_TEMP
|
||||
and self.color_temp == colortemp
|
||||
):
|
||||
_LOGGER.debug("Color temp already set to: %s", temp_in_k)
|
||||
# Already set, and since we get pushed updates
|
||||
# we avoid setting it again to ensure we do not
|
||||
# hit the rate limit
|
||||
return
|
||||
|
||||
await self._bulb.async_set_color_temp(
|
||||
temp_in_k, duration=duration, light_type=self.light_type
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Test the Yeelight light."""
|
||||
import logging
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from unittest.mock import ANY, AsyncMock, MagicMock, call, patch
|
||||
|
||||
from yeelight import (
|
||||
BulbException,
|
||||
@ -19,6 +19,7 @@ from yeelight.main import _MODEL_SPECS
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_FLASH,
|
||||
@ -428,6 +429,115 @@ async def test_services(hass: HomeAssistant, caplog):
|
||||
)
|
||||
|
||||
|
||||
async def test_state_already_set_avoid_ratelimit(hass: HomeAssistant):
|
||||
"""Ensure we suppress state changes that will increase the rate limit when there is no change."""
|
||||
mocked_bulb = _mocked_bulb()
|
||||
properties = {**PROPERTIES}
|
||||
properties.pop("active_mode")
|
||||
properties["color_mode"] = "3" # HSV
|
||||
mocked_bulb.last_properties = properties
|
||||
mocked_bulb.bulb_type = BulbType.Color
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={**CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: False}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
with 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()
|
||||
# We use asyncio.create_task now to avoid
|
||||
# blocking starting so we need to block again
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: ENTITY_LIGHT,
|
||||
ATTR_HS_COLOR: (PROPERTIES["hue"], PROPERTIES["sat"]),
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert mocked_bulb.async_set_hsv.mock_calls == []
|
||||
assert mocked_bulb.async_set_rgb.mock_calls == []
|
||||
assert mocked_bulb.async_set_color_temp.mock_calls == []
|
||||
assert mocked_bulb.async_set_brightness.mock_calls == []
|
||||
|
||||
mocked_bulb.last_properties["color_mode"] = 1
|
||||
rgb = int(PROPERTIES["rgb"])
|
||||
blue = rgb & 0xFF
|
||||
green = (rgb >> 8) & 0xFF
|
||||
red = (rgb >> 16) & 0xFF
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_RGB_COLOR: (red, green, blue)},
|
||||
blocking=True,
|
||||
)
|
||||
assert mocked_bulb.async_set_hsv.mock_calls == []
|
||||
assert mocked_bulb.async_set_rgb.mock_calls == []
|
||||
assert mocked_bulb.async_set_color_temp.mock_calls == []
|
||||
assert mocked_bulb.async_set_brightness.mock_calls == []
|
||||
mocked_bulb.async_set_rgb.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: ENTITY_LIGHT,
|
||||
ATTR_BRIGHTNESS_PCT: PROPERTIES["current_brightness"],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert mocked_bulb.async_set_hsv.mock_calls == []
|
||||
assert mocked_bulb.async_set_rgb.mock_calls == []
|
||||
assert mocked_bulb.async_set_color_temp.mock_calls == []
|
||||
assert mocked_bulb.async_set_brightness.mock_calls == []
|
||||
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_COLOR_TEMP: 250},
|
||||
blocking=True,
|
||||
)
|
||||
assert mocked_bulb.async_set_hsv.mock_calls == []
|
||||
assert mocked_bulb.async_set_rgb.mock_calls == []
|
||||
# Should call for the color mode change
|
||||
assert mocked_bulb.async_set_color_temp.mock_calls == [
|
||||
call(4000, duration=350, light_type=ANY)
|
||||
]
|
||||
assert mocked_bulb.async_set_brightness.mock_calls == []
|
||||
mocked_bulb.async_set_color_temp.reset_mock()
|
||||
|
||||
mocked_bulb.last_properties["color_mode"] = 2
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_COLOR_TEMP: 250},
|
||||
blocking=True,
|
||||
)
|
||||
assert mocked_bulb.async_set_hsv.mock_calls == []
|
||||
assert mocked_bulb.async_set_rgb.mock_calls == []
|
||||
assert mocked_bulb.async_set_color_temp.mock_calls == []
|
||||
assert mocked_bulb.async_set_brightness.mock_calls == []
|
||||
|
||||
mocked_bulb.last_properties["color_mode"] = 3
|
||||
# This last change should generate a call even though
|
||||
# the color mode is the same since the HSV has changed
|
||||
await hass.services.async_call(
|
||||
"light",
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_HS_COLOR: (5, 5)},
|
||||
blocking=True,
|
||||
)
|
||||
assert mocked_bulb.async_set_hsv.mock_calls == [
|
||||
call(5.0, 5.0, duration=350, light_type=ANY)
|
||||
]
|
||||
assert mocked_bulb.async_set_rgb.mock_calls == []
|
||||
assert mocked_bulb.async_set_color_temp.mock_calls == []
|
||||
assert mocked_bulb.async_set_brightness.mock_calls == []
|
||||
|
||||
|
||||
async def test_device_types(hass: HomeAssistant, caplog):
|
||||
"""Test different device types."""
|
||||
mocked_bulb = _mocked_bulb()
|
||||
|
Loading…
x
Reference in New Issue
Block a user