Always request at least one zone for multi-zone LIFX devices (#92683)
parent
c1f716487c
commit
52c773a776
|
@ -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."""
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue