Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 14 additions & 10 deletions modules/photons_app/mimic/operators/multizone.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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))
Expand All @@ -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
11 changes: 10 additions & 1 deletion modules/photons_messages/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

########################
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions modules/tests/photons_app_tests/mimic/test_public_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)])
Expand Down
17 changes: 17 additions & 0 deletions modules/tests/photons_control_tests/test_multizone.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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]


Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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
Expand All @@ -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):
Expand Down
9 changes: 9 additions & 0 deletions tools/generate_photons_messages/adjustments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down