From 3d9e8d457773a7594abec1df9d29626e684f00d6 Mon Sep 17 00:00:00 2001 From: Stephen Moore Date: Sun, 28 Sep 2025 17:42:23 +1000 Subject: [PATCH 1/3] Making it so the mimic can return multiple extended multi zones states --- .../photons_app/mimic/operators/multizone.py | 24 +++++++++++-------- .../mimic/test_public_protocol.py | 14 +++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/modules/photons_app/mimic/operators/multizone.py b/modules/photons_app/mimic/operators/multizone.py index da6871c1..f74bc1c6 100644 --- a/modules/photons_app/mimic/operators/multizone.py +++ b/modules/photons_app/mimic/operators/multizone.py @@ -16,8 +16,6 @@ async def __call__(self, event, options): elif not options.zones_count: zones_count = len(options.zones) - if zones_count > 82: - zones_count = 82 if zones_count < 0: zones_count = 0 @@ -157,7 +155,7 @@ async def respond(self, event): return if event | MultiZoneMessages.GetExtendedColorZones: - event.add_replies(self.state_for(MultiZoneMessages.StateExtendedColorZones)) + event.add_replies(self.state_for(MultiZoneMessages.StateExtendedColorZones, expect_one=len(self.device.attrs.zones) <= 82)) elif event | MultiZoneMessages.SetExtendedColorZones: event.add_replies(self.state_for(MultiZoneMessages.StateExtendedColorZones)) @@ -174,11 +172,17 @@ def make_state_for(self, kls, result): return if kls | MultiZoneMessages.StateExtendedColorZones: - result.append( - kls( - zones_count=len(self.device.attrs.zones), - zone_index=0, - colors_count=len(self.device.attrs.zones), - colors=[z.as_dict() for z in self.device.attrs.zones], + zones_index = 0 + zones_count = len(self.device.attrs.zones) + + while zones_index < zones_count: + colors_count = min([82, zones_count - zones_index]) + result.append( + kls( + zones_count=zones_count, + zone_index=zones_index, + colors_count=colors_count, + colors=[z.as_dict() for z in self.device.attrs.zones[zones_index : zones_index + colors_count]], + ) ) - ) + zones_index += colors_count diff --git a/modules/tests/photons_app_tests/mimic/test_public_protocol.py b/modules/tests/photons_app_tests/mimic/test_public_protocol.py index 40fa88d2..76dfaf16 100644 --- a/modules/tests/photons_app_tests/mimic/test_public_protocol.py +++ b/modules/tests/photons_app_tests/mimic/test_public_protocol.py @@ -446,6 +446,20 @@ async def test_it_responds_to_all_messages_if_we_have_extended_multizone(self): True, ) + async def test_it_can_respond_with_multiple_extended_zones(self): + device = await self.make_device("striplcm2extended", zones=[hp.Color(0, 0, 0, 0)] * 100) + devices.store(device).assertAttrs(zones_effect=MultiZoneEffectType.OFF, zones=[hp.Color(0, 0, 0, 0)] * 100) + + assertResponse = makeAssertResponse(device) + + await assertResponse( + MultiZoneMessages.GetExtendedColorZones(), + ( + MultiZoneMessages.StateExtendedColorZones(zones_count=100, zone_index=0, colors_count=82, colors=[hp.Color(0, 0, 0, 0)] * 82), + MultiZoneMessages.StateExtendedColorZones(zones_count=100, zone_index=82, colors_count=18, colors=[hp.Color(0, 0, 0, 0)] * 18), + ), + ) + async def test_it_responds_to_effect_messages(self): device = await self.make_device("striplcm2extended", zones=[hp.Color(0, 0, 0, 0)]) devices.store(device).assertAttrs(zones_effect=MultiZoneEffectType.OFF, zones=[hp.Color(0, 0, 0, 0)]) From 007a3ab323e725d49b4421f15d948a810c96f5b1 Mon Sep 17 00:00:00 2001 From: Stephen Moore Date: Sun, 28 Sep 2025 18:06:52 +1000 Subject: [PATCH 2/3] Make photons know that ExtendedGetMultiZones may return multiple --- modules/photons_messages/messages.py | 11 ++++++++++- .../photons_control_tests/test_multizone.py | 17 +++++++++++++++++ tools/generate_photons_messages/adjustments.yml | 9 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/modules/photons_messages/messages.py b/modules/photons_messages/messages.py index 9665ee15..aa376d68 100644 --- a/modules/photons_messages/messages.py +++ b/modules/photons_messages/messages.py @@ -18,6 +18,10 @@ def color_zones_response_count(req, res): return min([req_count, res_count]) +def extended_color_zones_response_count(res): + return math.ceil(res.zones_count // 82) + 1 + + # fmt: off ######################## @@ -338,7 +342,12 @@ class MultiZoneMessages(Messages): , ("colors", T.Bytes(64).multiple(82, kls=fields.Color)) ) - GetExtendedColorZones = msg(511) + GetExtendedColorZones = msg(511 + , multi = MultiOptions( + lambda req: [MultiZoneMessages.StateExtendedColorZones] + , lambda req, res: extended_color_zones_response_count(res) + ) + ) StateExtendedColorZones = msg(512 , ("zones_count", T.Uint16) diff --git a/modules/tests/photons_control_tests/test_multizone.py b/modules/tests/photons_control_tests/test_multizone.py index ca084d12..19f02443 100644 --- a/modules/tests/photons_control_tests/test_multizone.py +++ b/modules/tests/photons_control_tests/test_multizone.py @@ -25,6 +25,7 @@ zones1 = [hp.Color(i, 1, 1, 3500) for i in range(30)] zones2 = [hp.Color(90 - i, 1, 1, 3500) for i in range(6)] zones3 = [hp.Color(300 - i, 1, 1, 3500) for i in range(16)] +zones4 = [hp.Color(300 - i, 1, 1, 3500) for i in range(100)] devices = pytest.helpers.mimic() @@ -85,6 +86,18 @@ ), ) + +neon = devices.add("neon")( + "d073d5000006", + Products.LCM3_NEON_INTL, + hp.Firmware(3, 100), + value_store=dict( + power=0, + label="neon", + zones=zones4, + ), +) + strips = [striplcm1, striplcm2extended, striplcm2noextended] @@ -451,6 +464,7 @@ async def test_it_yields_serials_and_capability(self, sender): striplcm1.serial: False, striplcm2noextended.serial: False, striplcm2extended.serial: True, + neon.serial: True, } async def test_it_resends_messages_each_time_if_we_reset_the_gatherer(self, sender): @@ -491,6 +505,7 @@ async def test_it_yield_zones(self, sender): striplcm1.serial: [(i, c) for i, c in enumerate(zones1)], striplcm2noextended.serial: [(i, c) for i, c in enumerate(zones2)], striplcm2extended.serial: [(i, c) for i, c in enumerate(zones3)], + neon.serial: [(i, c) for i, c in enumerate(zones4)], } async def test_it_resends_messages_if_no_gatherer_is_reset_between_runs(self, sender): @@ -501,6 +516,7 @@ async def test_it_resends_messages_if_no_gatherer_is_reset_between_runs(self, se want[striplcm1].append(MultiZoneMessages.GetColorZones(start_index=0, end_index=255)) want[striplcm2noextended].append(MultiZoneMessages.GetColorZones(start_index=0, end_index=255)) want[striplcm2extended].append(MultiZoneMessages.GetExtendedColorZones()) + want[neon].append(MultiZoneMessages.GetExtendedColorZones()) compare_received(want) del sender.gatherer @@ -517,6 +533,7 @@ async def test_it_uses_cached_gatherer_on_the_sender(self, sender): want[striplcm1].append(MultiZoneMessages.GetColorZones(start_index=0, end_index=255)) want[striplcm2noextended].append(MultiZoneMessages.GetColorZones(start_index=0, end_index=255)) want[striplcm2extended].append(MultiZoneMessages.GetExtendedColorZones()) + want[neon].append(MultiZoneMessages.GetExtendedColorZones()) compare_received(want) async for serial, zones in zones_from_reference(devices.serials, sender): diff --git a/tools/generate_photons_messages/adjustments.yml b/tools/generate_photons_messages/adjustments.yml index 8b813c02..b6a05da8 100644 --- a/tools/generate_photons_messages/adjustments.yml +++ b/tools/generate_photons_messages/adjustments.yml @@ -94,6 +94,10 @@ output: return min([req_count, res_count]) + def extended_color_zones_response_count(res): + return math.ceil(res.zones_count // 82) + + types: duration_type: type: uint32 @@ -422,6 +426,11 @@ changes: MultiZoneExtendedGetColorZones: rename: GetExtendedColorZones + multi: | + MultiOptions( + lambda req: [MultiZoneMessages.StateExtendedColorZones] + , lambda req, res: extended_color_zones_response_count(res) + ) MultiZoneExtendedSetColorZones: rename: SetExtendedColorZones From 33e128d30856a5454440ee54c335a0604f5b4786 Mon Sep 17 00:00:00 2001 From: Stephen Moore Date: Sun, 28 Sep 2025 18:36:47 +1000 Subject: [PATCH 3/3] Downgrade to macos 14 so the tests work https://github.com/actions/runner-images/issues/10924#issuecomment-3312900750 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c73659e..5c158a31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] # TODO: make this pass on github hosted windows: , windows-latest] + os: [ubuntu-latest, macos-14] # TODO: make this pass on github hosted windows: , windows-latest] python-version: ["3.12"] steps: - uses: actions/checkout@v4