mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
Add support for LIFX 26"x13" Ceiling (#148459)
Signed-off-by: Avi Miller <me@dje.li>
This commit is contained in:
parent
87aecf0ed9
commit
ec5991bc68
@ -70,6 +70,7 @@ INFRARED_BRIGHTNESS_VALUES_MAP = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LIFX_CEILING_PRODUCT_IDS = {176, 177, 201, 202}
|
LIFX_CEILING_PRODUCT_IDS = {176, 177, 201, 202}
|
||||||
|
LIFX_128ZONE_CEILING_PRODUCT_IDS = {201, 202}
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__package__)
|
_LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ from .const import (
|
|||||||
DEFAULT_ATTEMPTS,
|
DEFAULT_ATTEMPTS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
IDENTIFY_WAVEFORM,
|
IDENTIFY_WAVEFORM,
|
||||||
|
LIFX_128ZONE_CEILING_PRODUCT_IDS,
|
||||||
MAX_ATTEMPTS_PER_UPDATE_REQUEST_MESSAGE,
|
MAX_ATTEMPTS_PER_UPDATE_REQUEST_MESSAGE,
|
||||||
MAX_UPDATE_TIME,
|
MAX_UPDATE_TIME,
|
||||||
MESSAGE_RETRIES,
|
MESSAGE_RETRIES,
|
||||||
@ -183,6 +184,11 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||||||
"""Return true if this is a matrix device."""
|
"""Return true if this is a matrix device."""
|
||||||
return bool(lifx_features(self.device)["matrix"])
|
return bool(lifx_features(self.device)["matrix"])
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def is_128zone_matrix(self) -> bool:
|
||||||
|
"""Return true if this is a 128-zone matrix device."""
|
||||||
|
return bool(self.device.product in LIFX_128ZONE_CEILING_PRODUCT_IDS)
|
||||||
|
|
||||||
async def diagnostics(self) -> dict[str, Any]:
|
async def diagnostics(self) -> dict[str, Any]:
|
||||||
"""Return diagnostic information about the device."""
|
"""Return diagnostic information about the device."""
|
||||||
features = lifx_features(self.device)
|
features = lifx_features(self.device)
|
||||||
@ -216,6 +222,16 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||||||
"last_result": self.device.last_hev_cycle_result,
|
"last_result": self.device.last_hev_cycle_result,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if features["matrix"] is True:
|
||||||
|
device_data["matrix"] = {
|
||||||
|
"effect": self.device.effect,
|
||||||
|
"chain": self.device.chain,
|
||||||
|
"chain_length": self.device.chain_length,
|
||||||
|
"tile_devices": self.device.tile_devices,
|
||||||
|
"tile_devices_count": self.device.tile_devices_count,
|
||||||
|
"tile_device_width": self.device.tile_device_width,
|
||||||
|
}
|
||||||
|
|
||||||
if features["infrared"] is True:
|
if features["infrared"] is True:
|
||||||
device_data["infrared"] = {"brightness": self.device.infrared_brightness}
|
device_data["infrared"] = {"brightness": self.device.infrared_brightness}
|
||||||
|
|
||||||
@ -291,6 +307,37 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||||||
|
|
||||||
return calls
|
return calls
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_build_get64_update_requests(self) -> list[Callable]:
|
||||||
|
"""Build one or more get64 update requests."""
|
||||||
|
if self.device.tile_device_width == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
calls: list[Callable] = []
|
||||||
|
calls.append(
|
||||||
|
partial(
|
||||||
|
self.device.get64,
|
||||||
|
tile_index=0,
|
||||||
|
length=1,
|
||||||
|
x=0,
|
||||||
|
y=0,
|
||||||
|
width=self.device.tile_device_width,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self.is_128zone_matrix:
|
||||||
|
# For 128-zone ceiling devices, we need another get64 request for the next set of zones
|
||||||
|
calls.append(
|
||||||
|
partial(
|
||||||
|
self.device.get64,
|
||||||
|
tile_index=0,
|
||||||
|
length=1,
|
||||||
|
x=0,
|
||||||
|
y=4,
|
||||||
|
width=self.device.tile_device_width,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
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."""
|
||||||
device = self.device
|
device = self.device
|
||||||
@ -312,9 +359,9 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||||||
[
|
[
|
||||||
self.device.get_tile_effect,
|
self.device.get_tile_effect,
|
||||||
self.device.get_device_chain,
|
self.device.get_device_chain,
|
||||||
self.device.get64,
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
methods.extend(self._async_build_get64_update_requests())
|
||||||
if self.is_extended_multizone:
|
if self.is_extended_multizone:
|
||||||
methods.append(self.device.get_extended_color_zones)
|
methods.append(self.device.get_extended_color_zones)
|
||||||
elif self.is_legacy_multizone:
|
elif self.is_legacy_multizone:
|
||||||
@ -339,6 +386,7 @@ class LIFXUpdateCoordinator(DataUpdateCoordinator[None]):
|
|||||||
|
|
||||||
if self.is_matrix or self.is_extended_multizone or self.is_legacy_multizone:
|
if self.is_matrix or self.is_extended_multizone or self.is_legacy_multizone:
|
||||||
self.active_effect = FirmwareEffect[self.device.effect.get("effect", "OFF")]
|
self.active_effect = FirmwareEffect[self.device.effect.get("effect", "OFF")]
|
||||||
|
|
||||||
if self.is_legacy_multizone and num_zones != self.get_number_of_zones():
|
if self.is_legacy_multizone and num_zones != self.get_number_of_zones():
|
||||||
# The number of zones has changed so we need
|
# The number of zones has changed so we need
|
||||||
# to update the zones again. This happens rarely.
|
# to update the zones again. This happens rarely.
|
||||||
|
@ -199,6 +199,17 @@ def _mocked_ceiling() -> Light:
|
|||||||
return bulb
|
return bulb
|
||||||
|
|
||||||
|
|
||||||
|
def _mocked_128zone_ceiling() -> Light:
|
||||||
|
bulb = _mocked_bulb()
|
||||||
|
bulb.product = 201 # LIFX 26"x13" Ceiling
|
||||||
|
bulb.effect = {"effect": "OFF"}
|
||||||
|
bulb.get_tile_effect = MockLifxCommand(bulb)
|
||||||
|
bulb.set_tile_effect = MockLifxCommand(bulb)
|
||||||
|
bulb.get64 = MockLifxCommand(bulb)
|
||||||
|
bulb.get_device_chain = MockLifxCommand(bulb)
|
||||||
|
return bulb
|
||||||
|
|
||||||
|
|
||||||
def _mocked_bulb_old_firmware() -> Light:
|
def _mocked_bulb_old_firmware() -> Light:
|
||||||
bulb = _mocked_bulb()
|
bulb = _mocked_bulb()
|
||||||
bulb.host_firmware_version = "2.77"
|
bulb.host_firmware_version = "2.77"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,9 @@ from . import (
|
|||||||
IP_ADDRESS,
|
IP_ADDRESS,
|
||||||
SERIAL,
|
SERIAL,
|
||||||
MockLifxCommand,
|
MockLifxCommand,
|
||||||
|
_mocked_128zone_ceiling,
|
||||||
_mocked_bulb,
|
_mocked_bulb,
|
||||||
|
_mocked_ceiling,
|
||||||
_mocked_clean_bulb,
|
_mocked_clean_bulb,
|
||||||
_mocked_infrared_bulb,
|
_mocked_infrared_bulb,
|
||||||
_mocked_light_strip,
|
_mocked_light_strip,
|
||||||
@ -209,3 +211,101 @@ async def test_multizone_bulb_diagnostics(
|
|||||||
|
|
||||||
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
||||||
assert diag == snapshot
|
assert diag == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
async def test_matrix_diagnostics(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test diagnostics for a standard bulb."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=lifx.DOMAIN,
|
||||||
|
title=DEFAULT_ENTRY_TITLE,
|
||||||
|
data={CONF_HOST: IP_ADDRESS},
|
||||||
|
unique_id=SERIAL,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_ceiling()
|
||||||
|
bulb.effect = {"effect": "OFF"}
|
||||||
|
bulb.tile_devices_count = 1
|
||||||
|
bulb.tile_device_width = 8
|
||||||
|
bulb.tile_devices = [
|
||||||
|
{
|
||||||
|
"accel_meas_x": 0,
|
||||||
|
"accel_meas_y": 0,
|
||||||
|
"accel_meas_z": 2000,
|
||||||
|
"user_x": 0.0,
|
||||||
|
"user_y": 0.0,
|
||||||
|
"width": 8,
|
||||||
|
"height": 8,
|
||||||
|
"supported_frame_buffers": 5,
|
||||||
|
"device_version_vendor": 1,
|
||||||
|
"device_version_product": 176,
|
||||||
|
"firmware_build": 1729829374000000000,
|
||||||
|
"firmware_version_minor": 10,
|
||||||
|
"firmware_version_major": 4,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
bulb.chain = {0: [(0, 0, 0, 3500)] * 64}
|
||||||
|
bulb.chain_length = 1
|
||||||
|
|
||||||
|
with (
|
||||||
|
_patch_discovery(device=bulb),
|
||||||
|
_patch_config_flow_try_connect(device=bulb),
|
||||||
|
_patch_device(device=bulb),
|
||||||
|
):
|
||||||
|
await async_setup_component(hass, lifx.DOMAIN, {lifx.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
||||||
|
assert diag == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
async def test_128zone_matrix_diagnostics(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test diagnostics for a standard bulb."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=lifx.DOMAIN,
|
||||||
|
title=DEFAULT_ENTRY_TITLE,
|
||||||
|
data={CONF_HOST: IP_ADDRESS},
|
||||||
|
unique_id=SERIAL,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_128zone_ceiling()
|
||||||
|
bulb.effect = {"effect": "OFF"}
|
||||||
|
bulb.tile_devices_count = 1
|
||||||
|
bulb.tile_device_width = 16
|
||||||
|
bulb.tile_devices = [
|
||||||
|
{
|
||||||
|
"accel_meas_x": 0,
|
||||||
|
"accel_meas_y": 0,
|
||||||
|
"accel_meas_z": 2000,
|
||||||
|
"user_x": 0.0,
|
||||||
|
"user_y": 0.0,
|
||||||
|
"width": 8,
|
||||||
|
"height": 16,
|
||||||
|
"supported_frame_buffers": 5,
|
||||||
|
"device_version_vendor": 1,
|
||||||
|
"device_version_product": 201,
|
||||||
|
"firmware_build": 1729829374000000000,
|
||||||
|
"firmware_version_minor": 10,
|
||||||
|
"firmware_version_major": 4,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
bulb.chain = {0: [(0, 0, 0, 3500)] * 128}
|
||||||
|
bulb.chain_length = 1
|
||||||
|
|
||||||
|
with (
|
||||||
|
_patch_discovery(device=bulb),
|
||||||
|
_patch_config_flow_try_connect(device=bulb),
|
||||||
|
_patch_device(device=bulb),
|
||||||
|
):
|
||||||
|
await async_setup_component(hass, lifx.DOMAIN, {lifx.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
||||||
|
assert diag == snapshot
|
||||||
|
Loading…
x
Reference in New Issue
Block a user