Always request at least one zone for multi-zone LIFX devices (#92683)

pull/92933/head
J. Nick Koston 2023-05-11 19:02:32 +09:00 committed by GitHub
parent c1f716487c
commit 52c773a776
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 6 deletions

View File

@ -11,6 +11,7 @@ from typing import Any, cast
from aiolifx.aiolifx import ( from aiolifx.aiolifx import (
Light, Light,
Message,
MultiZoneDirection, MultiZoneDirection,
MultiZoneEffectType, MultiZoneEffectType,
TileEffectType, TileEffectType,
@ -56,6 +57,8 @@ from .util import (
LIGHT_UPDATE_INTERVAL = 10 LIGHT_UPDATE_INTERVAL = 10
REQUEST_REFRESH_DELAY = 0.35 REQUEST_REFRESH_DELAY = 0.35
LIFX_IDENTIFY_DELAY = 3.0 LIFX_IDENTIFY_DELAY = 3.0
ZONES_PER_COLOR_UPDATE_REQUEST = 8
RSSI_DBM_FW = AwesomeVersion("2.77") RSSI_DBM_FW = AwesomeVersion("2.77")
@ -208,18 +211,50 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator[None]):
def get_number_of_zones(self) -> int: def get_number_of_zones(self) -> int:
"""Return the number of zones. """Return the number of zones.
If the number of zones is not yet populated, return 0 If the number of zones is not yet populated, return 1 since
the device will have a least one zone.
""" """
return len(self.device.color_zones) if self.device.color_zones else 0 return len(self.device.color_zones) if self.device.color_zones else 1
@callback @callback
def _async_build_color_zones_update_requests(self) -> list[Callable]: def _async_build_color_zones_update_requests(self) -> list[Callable]:
"""Build a color zones update request.""" """Build a color zones update request."""
device = self.device device = self.device
return [ calls: list[Callable] = []
partial(device.get_color_zones, start_index=zone) for zone in range(
for zone in range(0, self.get_number_of_zones(), 8) 0, self.get_number_of_zones(), ZONES_PER_COLOR_UPDATE_REQUEST
] ):
def _wrap_get_color_zones(
callb: Callable[[Message, dict[str, Any] | None], None],
get_color_zones_args: dict[str, Any],
) -> None:
"""Capture the callback and make sure resp_set_multizonemultizone is called before."""
def _wrapped_callback(
bulb: Light,
response: Message,
**kwargs: Any,
) -> None:
# We need to call resp_set_multizonemultizone to populate
# the color_zones attribute before calling the callback
device.resp_set_multizonemultizone(response)
# Now call the original callback
callb(bulb, response, **kwargs)
device.get_color_zones(**get_color_zones_args, callb=_wrapped_callback)
calls.append(
partial(
_wrap_get_color_zones,
get_color_zones_args={
"start_index": zone,
"end_index": zone + ZONES_PER_COLOR_UPDATE_REQUEST - 1,
},
)
)
return calls
async def _async_update_data(self) -> None: async def _async_update_data(self) -> None:
"""Fetch all device data from the api.""" """Fetch all device data from the api."""

View File

@ -1754,6 +1754,8 @@ async def test_light_strip_zones_not_populated_yet(hass: HomeAssistant) -> None:
bulb.power_level = 65535 bulb.power_level = 65535
bulb.color_zones = None bulb.color_zones = None
bulb.color = [65535, 65535, 65535, 65535] bulb.color = [65535, 65535, 65535, 65535]
assert bulb.get_color_zones.calls == []
with _patch_discovery(device=bulb), _patch_config_flow_try_connect( with _patch_discovery(device=bulb), _patch_config_flow_try_connect(
device=bulb device=bulb
), _patch_device(device=bulb): ), _patch_device(device=bulb):
@ -1761,6 +1763,14 @@ async def test_light_strip_zones_not_populated_yet(hass: HomeAssistant) -> None:
await hass.async_block_till_done() await hass.async_block_till_done()
entity_id = "light.my_bulb" entity_id = "light.my_bulb"
# Make sure we at least try to fetch the first zone
# to ensure we populate the zones from the 503 response
assert len(bulb.get_color_zones.calls) == 3
# Once to populate the number of zones
assert bulb.get_color_zones.calls[0][1]["start_index"] == 0
# Again once we know the number of zones
assert bulb.get_color_zones.calls[1][1]["start_index"] == 0
assert bulb.get_color_zones.calls[2][1]["start_index"] == 8
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "on" assert state.state == "on"