lifx-emulator-core 3.1.0__py3-none-any.whl → 3.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lifx_emulator/devices/device.py +19 -0
- lifx_emulator/handlers/multizone_handlers.py +19 -15
- lifx_emulator/handlers/tile_handlers.py +59 -52
- {lifx_emulator_core-3.1.0.dist-info → lifx_emulator_core-3.2.0.dist-info}/METADATA +1 -1
- {lifx_emulator_core-3.1.0.dist-info → lifx_emulator_core-3.2.0.dist-info}/RECORD +6 -6
- {lifx_emulator_core-3.1.0.dist-info → lifx_emulator_core-3.2.0.dist-info}/WHEEL +0 -0
lifx_emulator/devices/device.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import copy
|
|
7
7
|
import logging
|
|
8
|
+
import random
|
|
8
9
|
import time
|
|
9
10
|
from typing import Any
|
|
10
11
|
|
|
@@ -304,6 +305,24 @@ class EmulatedLifxDevice:
|
|
|
304
305
|
|
|
305
306
|
# Handle specific packet types - handlers always return list
|
|
306
307
|
response_packets = self._handle_packet_type(header, packet)
|
|
308
|
+
|
|
309
|
+
# Apply partial_responses: truncate multi-packet responses to random subset
|
|
310
|
+
if len(response_packets) > 1:
|
|
311
|
+
first_pkt = response_packets[0]
|
|
312
|
+
if (
|
|
313
|
+
hasattr(first_pkt, "PKT_TYPE")
|
|
314
|
+
and first_pkt.PKT_TYPE in scenario.partial_responses
|
|
315
|
+
):
|
|
316
|
+
original_count = len(response_packets)
|
|
317
|
+
partial_count = random.randint(1, original_count - 1) # nosec
|
|
318
|
+
response_packets = response_packets[:partial_count]
|
|
319
|
+
logger.info(
|
|
320
|
+
"Sending partial response for packet type %s (%d of %d packets)",
|
|
321
|
+
first_pkt.PKT_TYPE,
|
|
322
|
+
partial_count,
|
|
323
|
+
original_count,
|
|
324
|
+
)
|
|
325
|
+
|
|
307
326
|
# Handlers now always return list (empty if no response)
|
|
308
327
|
for resp_packet in response_packets:
|
|
309
328
|
# Cache packed payload to avoid double packing (performance optimization)
|
|
@@ -124,22 +124,26 @@ class ExtendedGetColorZonesHandler(PacketHandler):
|
|
|
124
124
|
if not device_state.has_multizone:
|
|
125
125
|
return []
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
127
|
+
responses = []
|
|
128
|
+
index = 0
|
|
129
|
+
while index < device_state.zone_count:
|
|
130
|
+
end = min(index + 82, device_state.zone_count)
|
|
131
|
+
colors_count = end - index
|
|
132
|
+
colors = list(device_state.zone_colors[index:end])
|
|
133
|
+
# Pad to 82 colors
|
|
134
|
+
while len(colors) < 82:
|
|
135
|
+
colors.append(LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500))
|
|
136
|
+
responses.append(
|
|
137
|
+
MultiZone.ExtendedStateMultiZone(
|
|
138
|
+
count=device_state.zone_count,
|
|
139
|
+
index=index,
|
|
140
|
+
colors_count=colors_count,
|
|
141
|
+
colors=colors,
|
|
142
|
+
)
|
|
141
143
|
)
|
|
142
|
-
|
|
144
|
+
index += 82
|
|
145
|
+
|
|
146
|
+
return responses
|
|
143
147
|
|
|
144
148
|
|
|
145
149
|
class ExtendedSetColorZonesHandler(PacketHandler):
|
|
@@ -128,64 +128,71 @@ class Get64Handler(PacketHandler):
|
|
|
128
128
|
if not device_state.has_matrix or not packet:
|
|
129
129
|
return []
|
|
130
130
|
|
|
131
|
-
tile_index = packet.tile_index
|
|
132
131
|
rect = packet.rect
|
|
132
|
+
length = max(1, packet.length)
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
tile_width = tile["width"]
|
|
139
|
-
tile_height = tile["height"]
|
|
140
|
-
|
|
141
|
-
# Get64 always returns framebuffer 0 (the visible buffer)
|
|
142
|
-
# regardless of which fb_index is in the request
|
|
143
|
-
tile_colors = tile["colors"]
|
|
144
|
-
|
|
145
|
-
# Calculate how many rows fit in 64 zones
|
|
146
|
-
rows_to_return = 64 // rect.width if rect.width > 0 else 1
|
|
147
|
-
rows_to_return = min(rows_to_return, tile_height - rect.y)
|
|
148
|
-
|
|
149
|
-
# Extract colors from the requested rectangle
|
|
150
|
-
colors = []
|
|
151
|
-
zones_extracted = 0
|
|
152
|
-
|
|
153
|
-
for row in range(rows_to_return):
|
|
154
|
-
y = rect.y + row
|
|
155
|
-
if y >= tile_height:
|
|
134
|
+
responses = []
|
|
135
|
+
for i in range(length):
|
|
136
|
+
idx = packet.tile_index + i
|
|
137
|
+
if idx >= len(device_state.tile_devices):
|
|
156
138
|
break
|
|
157
139
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
140
|
+
tile = device_state.tile_devices[idx]
|
|
141
|
+
tile_width = tile["width"]
|
|
142
|
+
tile_height = tile["height"]
|
|
143
|
+
|
|
144
|
+
# Get64 always returns framebuffer 0 (the visible buffer)
|
|
145
|
+
# regardless of which fb_index is in the request
|
|
146
|
+
tile_colors = tile["colors"]
|
|
147
|
+
|
|
148
|
+
# Calculate how many rows fit in 64 zones
|
|
149
|
+
rows_to_return = 64 // rect.width if rect.width > 0 else 1
|
|
150
|
+
rows_to_return = min(rows_to_return, tile_height - rect.y)
|
|
151
|
+
|
|
152
|
+
# Extract colors from the requested rectangle
|
|
153
|
+
colors = []
|
|
154
|
+
zones_extracted = 0
|
|
155
|
+
|
|
156
|
+
for row in range(rows_to_return):
|
|
157
|
+
y = rect.y + row
|
|
158
|
+
if y >= tile_height:
|
|
159
|
+
break
|
|
160
|
+
|
|
161
|
+
for col in range(rect.width):
|
|
162
|
+
x = rect.x + col
|
|
163
|
+
if x >= tile_width or zones_extracted >= 64:
|
|
164
|
+
colors.append(
|
|
165
|
+
LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500)
|
|
166
|
+
)
|
|
167
|
+
zones_extracted += 1
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
# Calculate zone index in flat color array
|
|
171
|
+
zone_idx = y * tile_width + x
|
|
172
|
+
if zone_idx < len(tile_colors):
|
|
173
|
+
colors.append(tile_colors[zone_idx])
|
|
174
|
+
else:
|
|
175
|
+
colors.append(
|
|
176
|
+
LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500)
|
|
177
|
+
)
|
|
164
178
|
zones_extracted += 1
|
|
165
|
-
continue
|
|
166
179
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
fb_index=0, # Always return FB0
|
|
184
|
-
x=rect.x,
|
|
185
|
-
y=rect.y,
|
|
186
|
-
width=rect.width,
|
|
187
|
-
)
|
|
188
|
-
return [Tile.State64(tile_index=tile_index, rect=return_rect, colors=colors)]
|
|
180
|
+
# Pad to exactly 64 colors
|
|
181
|
+
while len(colors) < 64:
|
|
182
|
+
colors.append(LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500))
|
|
183
|
+
|
|
184
|
+
# Return with fb_index forced to 0 (visible buffer)
|
|
185
|
+
return_rect = TileBufferRect(
|
|
186
|
+
fb_index=0, # Always return FB0
|
|
187
|
+
x=rect.x,
|
|
188
|
+
y=rect.y,
|
|
189
|
+
width=rect.width,
|
|
190
|
+
)
|
|
191
|
+
responses.append(
|
|
192
|
+
Tile.State64(tile_index=idx, rect=return_rect, colors=colors)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return responses
|
|
189
196
|
|
|
190
197
|
|
|
191
198
|
class Set64Handler(PacketHandler):
|
|
@@ -2,7 +2,7 @@ lifx_emulator/__init__.py,sha256=SSnQg0RiCaID7DhHOGZoVIDQ3_8Lyt0J9cA_2StF63s,824
|
|
|
2
2
|
lifx_emulator/constants.py,sha256=DFZkUsdewE-x_3MgO28tMGkjUCWPeYc3xLj_EXViGOw,1032
|
|
3
3
|
lifx_emulator/server.py,sha256=Fc0AiSeJ43XnF1MMTqWBkeYIW-KOhZpqNp0Y2x4RqEE,16622
|
|
4
4
|
lifx_emulator/devices/__init__.py,sha256=QlBTPnFErJcSKLvGyeDwemh7xcpjYvB_L5siKsjr3s8,1089
|
|
5
|
-
lifx_emulator/devices/device.py,sha256=
|
|
5
|
+
lifx_emulator/devices/device.py,sha256=99uxNdK3vFnBHh9M2F92zxNeFkq3w-XXV0Mt8wRTUQw,16556
|
|
6
6
|
lifx_emulator/devices/manager.py,sha256=XDrT82um5sgNpNihLj5RsNvHqdVI1bK9YY2eBzWIcf0,8162
|
|
7
7
|
lifx_emulator/devices/observers.py,sha256=-KnUgFcKdhlNo7CNVstP-u0wU2W0JAGg055ZPV15Sj0,3874
|
|
8
8
|
lifx_emulator/devices/persistence.py,sha256=9Mhj46-xrweOmyzjORCi2jKIwa8XJWpQ5CgaKcw6U98,10513
|
|
@@ -19,9 +19,9 @@ lifx_emulator/handlers/__init__.py,sha256=3Hj1hRo3yL3E7GKwG9TaYh33ymk_N3bRiQ8nvq
|
|
|
19
19
|
lifx_emulator/handlers/base.py,sha256=0avCLXY_rNlw16PpJ5JrRCwXNE4uMpBqF3PfSfNJ0b8,1654
|
|
20
20
|
lifx_emulator/handlers/device_handlers.py,sha256=1AmslA4Ut6L7b3SfduDdvnQizTpzUB3KKWBXmp4WYLQ,9462
|
|
21
21
|
lifx_emulator/handlers/light_handlers.py,sha256=255aoiIjSIL63kbHQa6wqUpEwFzFFx7SG6P1nWM9jgU,17769
|
|
22
|
-
lifx_emulator/handlers/multizone_handlers.py,sha256=
|
|
22
|
+
lifx_emulator/handlers/multizone_handlers.py,sha256=ypv9G7od2bdQc7plRb38hyPyd02ugiMsinUHKCB2cdM,8094
|
|
23
23
|
lifx_emulator/handlers/registry.py,sha256=s1ht4PmPhXhAcwu1hoY4yW39wy3SPJBMY-9Uxd0FWuE,3292
|
|
24
|
-
lifx_emulator/handlers/tile_handlers.py,sha256=
|
|
24
|
+
lifx_emulator/handlers/tile_handlers.py,sha256=TRrXfq1L-1WR35dhYMv3_GE-8pDX9yrYDHZUGbBNlSE,17495
|
|
25
25
|
lifx_emulator/products/__init__.py,sha256=qcNop_kRYFF3zSjNemzQEgu3jPrIxfyQyLv9GsnaLEI,627
|
|
26
26
|
lifx_emulator/products/generator.py,sha256=fvrhw_b7shLCtEtUFxWF5VBEQAeSrsaiXxoGIP5Vn4g,34675
|
|
27
27
|
lifx_emulator/products/registry.py,sha256=1SZ3fXVFFL8jhKYIZBqwtIQDN3qL1Lvf86P3N1_Kdx8,47323
|
|
@@ -42,6 +42,6 @@ lifx_emulator/scenarios/__init__.py,sha256=CGjudoWvyysvFj2xej11N2cr3mYROGtRb9zVH
|
|
|
42
42
|
lifx_emulator/scenarios/manager.py,sha256=1esxRdz74UynNk1wb86MGZ2ZFAuMzByuu74nRe3D-Og,11163
|
|
43
43
|
lifx_emulator/scenarios/models.py,sha256=BKS_fGvrbkGe-vK3arZ0w2f9adS1UZhiOoKpu7GENnc,4099
|
|
44
44
|
lifx_emulator/scenarios/persistence.py,sha256=3vjtPNFYfag38tUxuqxkGpWhQ7uBitc1rLroSAuw9N8,8881
|
|
45
|
-
lifx_emulator_core-3.
|
|
46
|
-
lifx_emulator_core-3.
|
|
47
|
-
lifx_emulator_core-3.
|
|
45
|
+
lifx_emulator_core-3.2.0.dist-info/METADATA,sha256=qxUBmkizy2Eu0QNVQ8y6FNppwJaqbR5pEIDnZzTasu8,3217
|
|
46
|
+
lifx_emulator_core-3.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
47
|
+
lifx_emulator_core-3.2.0.dist-info/RECORD,,
|
|
File without changes
|