lifx-emulator 1.0.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.
Files changed (40) hide show
  1. lifx_emulator/__init__.py +31 -0
  2. lifx_emulator/__main__.py +607 -0
  3. lifx_emulator/api.py +1825 -0
  4. lifx_emulator/async_storage.py +308 -0
  5. lifx_emulator/constants.py +33 -0
  6. lifx_emulator/device.py +750 -0
  7. lifx_emulator/device_states.py +114 -0
  8. lifx_emulator/factories.py +380 -0
  9. lifx_emulator/handlers/__init__.py +39 -0
  10. lifx_emulator/handlers/base.py +49 -0
  11. lifx_emulator/handlers/device_handlers.py +340 -0
  12. lifx_emulator/handlers/light_handlers.py +372 -0
  13. lifx_emulator/handlers/multizone_handlers.py +249 -0
  14. lifx_emulator/handlers/registry.py +110 -0
  15. lifx_emulator/handlers/tile_handlers.py +309 -0
  16. lifx_emulator/observers.py +139 -0
  17. lifx_emulator/products/__init__.py +28 -0
  18. lifx_emulator/products/generator.py +771 -0
  19. lifx_emulator/products/registry.py +1446 -0
  20. lifx_emulator/products/specs.py +242 -0
  21. lifx_emulator/products/specs.yml +327 -0
  22. lifx_emulator/protocol/__init__.py +1 -0
  23. lifx_emulator/protocol/base.py +334 -0
  24. lifx_emulator/protocol/const.py +8 -0
  25. lifx_emulator/protocol/generator.py +1371 -0
  26. lifx_emulator/protocol/header.py +159 -0
  27. lifx_emulator/protocol/packets.py +1351 -0
  28. lifx_emulator/protocol/protocol_types.py +844 -0
  29. lifx_emulator/protocol/serializer.py +379 -0
  30. lifx_emulator/scenario_manager.py +402 -0
  31. lifx_emulator/scenario_persistence.py +206 -0
  32. lifx_emulator/server.py +482 -0
  33. lifx_emulator/state_restorer.py +259 -0
  34. lifx_emulator/state_serializer.py +130 -0
  35. lifx_emulator/storage_protocol.py +100 -0
  36. lifx_emulator-1.0.0.dist-info/METADATA +445 -0
  37. lifx_emulator-1.0.0.dist-info/RECORD +40 -0
  38. lifx_emulator-1.0.0.dist-info/WHEEL +4 -0
  39. lifx_emulator-1.0.0.dist-info/entry_points.txt +2 -0
  40. lifx_emulator-1.0.0.dist-info/licenses/LICENSE +35 -0
@@ -0,0 +1,1351 @@
1
+ """Auto-generated LIFX protocol packets.
2
+
3
+ DO NOT EDIT THIS FILE MANUALLY.
4
+ Generated from https://github.com/LIFX/public-protocol/blob/main/protocol.yml
5
+ by protocol/generator.py
6
+
7
+ Uses nested packet classes organized by category (Device, Light, etc.).
8
+ Each packet inherits from base Packet class which provides generic pack/unpack.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+ from typing import Any, ClassVar
15
+
16
+ from lifx_emulator.protocol.base import Packet
17
+ from lifx_emulator.protocol.protocol_types import (
18
+ DeviceService,
19
+ LightHsbk,
20
+ LightLastHevCycleResult,
21
+ LightWaveform,
22
+ MultiZoneApplicationRequest,
23
+ MultiZoneEffectSettings,
24
+ MultiZoneExtendedApplicationRequest,
25
+ TileBufferRect,
26
+ TileEffectSettings,
27
+ TileStateDevice,
28
+ )
29
+
30
+
31
+ class Device(Packet):
32
+ """Device category packets."""
33
+
34
+ @dataclass
35
+ class Acknowledgement(Packet):
36
+ """Packet type 45."""
37
+
38
+ PKT_TYPE: ClassVar[int] = 45
39
+ _fields: ClassVar[list[dict[str, Any]]] = []
40
+
41
+ # Packet metadata for automatic handling
42
+ _packet_kind: ClassVar[str] = "OTHER"
43
+ _requires_ack: ClassVar[bool] = False
44
+ _requires_response: ClassVar[bool] = False
45
+
46
+ pass
47
+
48
+ @dataclass
49
+ class EchoRequest(Packet):
50
+ """Packet type 58."""
51
+
52
+ PKT_TYPE: ClassVar[int] = 58
53
+ _fields: ClassVar[list[dict[str, Any]]] = [
54
+ {"name": "Payload", "type": "[64]byte", "size_bytes": 64}
55
+ ]
56
+
57
+ # Packet metadata for automatic handling
58
+ _packet_kind: ClassVar[str] = "OTHER"
59
+ _requires_ack: ClassVar[bool] = False
60
+ _requires_response: ClassVar[bool] = False
61
+
62
+ payload: bytes
63
+
64
+ @dataclass
65
+ class EchoResponse(Packet):
66
+ """Packet type 59."""
67
+
68
+ PKT_TYPE: ClassVar[int] = 59
69
+ _fields: ClassVar[list[dict[str, Any]]] = [
70
+ {"name": "Payload", "type": "[64]byte", "size_bytes": 64}
71
+ ]
72
+
73
+ # Packet metadata for automatic handling
74
+ _packet_kind: ClassVar[str] = "OTHER"
75
+ _requires_ack: ClassVar[bool] = False
76
+ _requires_response: ClassVar[bool] = False
77
+
78
+ payload: bytes
79
+
80
+ @dataclass
81
+ class GetGroup(Packet):
82
+ """Packet type 51."""
83
+
84
+ PKT_TYPE: ClassVar[int] = 51
85
+ _fields: ClassVar[list[dict[str, Any]]] = []
86
+
87
+ # Packet metadata for automatic handling
88
+ _packet_kind: ClassVar[str] = "GET"
89
+ _requires_ack: ClassVar[bool] = False
90
+ _requires_response: ClassVar[bool] = False
91
+
92
+ pass
93
+
94
+ @dataclass
95
+ class GetHostFirmware(Packet):
96
+ """Packet type 14."""
97
+
98
+ PKT_TYPE: ClassVar[int] = 14
99
+ _fields: ClassVar[list[dict[str, Any]]] = []
100
+
101
+ # Packet metadata for automatic handling
102
+ _packet_kind: ClassVar[str] = "GET"
103
+ _requires_ack: ClassVar[bool] = False
104
+ _requires_response: ClassVar[bool] = False
105
+
106
+ pass
107
+
108
+ @dataclass
109
+ class GetInfo(Packet):
110
+ """Packet type 34."""
111
+
112
+ PKT_TYPE: ClassVar[int] = 34
113
+ _fields: ClassVar[list[dict[str, Any]]] = []
114
+
115
+ # Packet metadata for automatic handling
116
+ _packet_kind: ClassVar[str] = "GET"
117
+ _requires_ack: ClassVar[bool] = False
118
+ _requires_response: ClassVar[bool] = False
119
+
120
+ pass
121
+
122
+ @dataclass
123
+ class GetLabel(Packet):
124
+ """Packet type 23."""
125
+
126
+ PKT_TYPE: ClassVar[int] = 23
127
+ _fields: ClassVar[list[dict[str, Any]]] = []
128
+
129
+ # Packet metadata for automatic handling
130
+ _packet_kind: ClassVar[str] = "GET"
131
+ _requires_ack: ClassVar[bool] = False
132
+ _requires_response: ClassVar[bool] = False
133
+
134
+ pass
135
+
136
+ @dataclass
137
+ class GetLocation(Packet):
138
+ """Packet type 48."""
139
+
140
+ PKT_TYPE: ClassVar[int] = 48
141
+ _fields: ClassVar[list[dict[str, Any]]] = []
142
+
143
+ # Packet metadata for automatic handling
144
+ _packet_kind: ClassVar[str] = "GET"
145
+ _requires_ack: ClassVar[bool] = False
146
+ _requires_response: ClassVar[bool] = False
147
+
148
+ pass
149
+
150
+ @dataclass
151
+ class GetPower(Packet):
152
+ """Packet type 20."""
153
+
154
+ PKT_TYPE: ClassVar[int] = 20
155
+ _fields: ClassVar[list[dict[str, Any]]] = []
156
+
157
+ # Packet metadata for automatic handling
158
+ _packet_kind: ClassVar[str] = "GET"
159
+ _requires_ack: ClassVar[bool] = False
160
+ _requires_response: ClassVar[bool] = False
161
+
162
+ pass
163
+
164
+ @dataclass
165
+ class GetService(Packet):
166
+ """Packet type 2."""
167
+
168
+ PKT_TYPE: ClassVar[int] = 2
169
+ _fields: ClassVar[list[dict[str, Any]]] = []
170
+
171
+ # Packet metadata for automatic handling
172
+ _packet_kind: ClassVar[str] = "GET"
173
+ _requires_ack: ClassVar[bool] = False
174
+ _requires_response: ClassVar[bool] = False
175
+
176
+ pass
177
+
178
+ @dataclass
179
+ class GetVersion(Packet):
180
+ """Packet type 32."""
181
+
182
+ PKT_TYPE: ClassVar[int] = 32
183
+ _fields: ClassVar[list[dict[str, Any]]] = []
184
+
185
+ # Packet metadata for automatic handling
186
+ _packet_kind: ClassVar[str] = "GET"
187
+ _requires_ack: ClassVar[bool] = False
188
+ _requires_response: ClassVar[bool] = False
189
+
190
+ pass
191
+
192
+ @dataclass
193
+ class GetWifiFirmware(Packet):
194
+ """Packet type 18."""
195
+
196
+ PKT_TYPE: ClassVar[int] = 18
197
+ _fields: ClassVar[list[dict[str, Any]]] = []
198
+
199
+ # Packet metadata for automatic handling
200
+ _packet_kind: ClassVar[str] = "GET"
201
+ _requires_ack: ClassVar[bool] = False
202
+ _requires_response: ClassVar[bool] = False
203
+
204
+ pass
205
+
206
+ @dataclass
207
+ class GetWifiInfo(Packet):
208
+ """Packet type 16."""
209
+
210
+ PKT_TYPE: ClassVar[int] = 16
211
+ _fields: ClassVar[list[dict[str, Any]]] = []
212
+
213
+ # Packet metadata for automatic handling
214
+ _packet_kind: ClassVar[str] = "GET"
215
+ _requires_ack: ClassVar[bool] = False
216
+ _requires_response: ClassVar[bool] = False
217
+
218
+ pass
219
+
220
+ @dataclass
221
+ class SetGroup(Packet):
222
+ """Packet type 52."""
223
+
224
+ PKT_TYPE: ClassVar[int] = 52
225
+ _fields: ClassVar[list[dict[str, Any]]] = [
226
+ {"name": "Group", "type": "[16]byte", "size_bytes": 16},
227
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32},
228
+ {"name": "UpdatedAt", "type": "uint64", "size_bytes": 8},
229
+ ]
230
+
231
+ # Packet metadata for automatic handling
232
+ _packet_kind: ClassVar[str] = "SET"
233
+ _requires_ack: ClassVar[bool] = True
234
+ _requires_response: ClassVar[bool] = False
235
+
236
+ group: bytes
237
+ label: bytes
238
+ updated_at: int
239
+
240
+ @dataclass
241
+ class SetLabel(Packet):
242
+ """Packet type 24."""
243
+
244
+ PKT_TYPE: ClassVar[int] = 24
245
+ _fields: ClassVar[list[dict[str, Any]]] = [
246
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32}
247
+ ]
248
+
249
+ # Packet metadata for automatic handling
250
+ _packet_kind: ClassVar[str] = "SET"
251
+ _requires_ack: ClassVar[bool] = True
252
+ _requires_response: ClassVar[bool] = False
253
+
254
+ label: bytes
255
+
256
+ @dataclass
257
+ class SetLocation(Packet):
258
+ """Packet type 49."""
259
+
260
+ PKT_TYPE: ClassVar[int] = 49
261
+ _fields: ClassVar[list[dict[str, Any]]] = [
262
+ {"name": "Location", "type": "[16]byte", "size_bytes": 16},
263
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32},
264
+ {"name": "UpdatedAt", "type": "uint64", "size_bytes": 8},
265
+ ]
266
+
267
+ # Packet metadata for automatic handling
268
+ _packet_kind: ClassVar[str] = "SET"
269
+ _requires_ack: ClassVar[bool] = True
270
+ _requires_response: ClassVar[bool] = False
271
+
272
+ location: bytes
273
+ label: bytes
274
+ updated_at: int
275
+
276
+ @dataclass
277
+ class SetPower(Packet):
278
+ """Packet type 21."""
279
+
280
+ PKT_TYPE: ClassVar[int] = 21
281
+ _fields: ClassVar[list[dict[str, Any]]] = [
282
+ {"name": "Level", "type": "uint16", "size_bytes": 2}
283
+ ]
284
+
285
+ # Packet metadata for automatic handling
286
+ _packet_kind: ClassVar[str] = "SET"
287
+ _requires_ack: ClassVar[bool] = True
288
+ _requires_response: ClassVar[bool] = False
289
+
290
+ level: int
291
+
292
+ @dataclass
293
+ class SetReboot(Packet):
294
+ """Packet type 38."""
295
+
296
+ PKT_TYPE: ClassVar[int] = 38
297
+ _fields: ClassVar[list[dict[str, Any]]] = []
298
+
299
+ # Packet metadata for automatic handling
300
+ _packet_kind: ClassVar[str] = "SET"
301
+ _requires_ack: ClassVar[bool] = True
302
+ _requires_response: ClassVar[bool] = False
303
+
304
+ pass
305
+
306
+ @dataclass
307
+ class StateGroup(Packet):
308
+ """Packet type 53."""
309
+
310
+ PKT_TYPE: ClassVar[int] = 53
311
+ _fields: ClassVar[list[dict[str, Any]]] = [
312
+ {"name": "Group", "type": "[16]byte", "size_bytes": 16},
313
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32},
314
+ {"name": "UpdatedAt", "type": "uint64", "size_bytes": 8},
315
+ ]
316
+
317
+ # Packet metadata for automatic handling
318
+ _packet_kind: ClassVar[str] = "STATE"
319
+ _requires_ack: ClassVar[bool] = False
320
+ _requires_response: ClassVar[bool] = False
321
+
322
+ group: bytes
323
+ label: bytes
324
+ updated_at: int
325
+
326
+ @dataclass
327
+ class StateHostFirmware(Packet):
328
+ """Packet type 15."""
329
+
330
+ PKT_TYPE: ClassVar[int] = 15
331
+ _fields: ClassVar[list[dict[str, Any]]] = [
332
+ {"name": "Build", "type": "uint64", "size_bytes": 8},
333
+ {"type": "reserved", "size_bytes": 8},
334
+ {"name": "VersionMinor", "type": "uint16", "size_bytes": 2},
335
+ {"name": "VersionMajor", "type": "uint16", "size_bytes": 2},
336
+ ]
337
+
338
+ # Packet metadata for automatic handling
339
+ _packet_kind: ClassVar[str] = "STATE"
340
+ _requires_ack: ClassVar[bool] = False
341
+ _requires_response: ClassVar[bool] = False
342
+
343
+ build: int
344
+ version_minor: int
345
+ version_major: int
346
+
347
+ @dataclass
348
+ class StateInfo(Packet):
349
+ """Packet type 35."""
350
+
351
+ PKT_TYPE: ClassVar[int] = 35
352
+ _fields: ClassVar[list[dict[str, Any]]] = [
353
+ {"name": "Time", "type": "uint64", "size_bytes": 8},
354
+ {"name": "Uptime", "type": "uint64", "size_bytes": 8},
355
+ {"name": "Downtime", "type": "uint64", "size_bytes": 8},
356
+ ]
357
+
358
+ # Packet metadata for automatic handling
359
+ _packet_kind: ClassVar[str] = "STATE"
360
+ _requires_ack: ClassVar[bool] = False
361
+ _requires_response: ClassVar[bool] = False
362
+
363
+ time: int
364
+ uptime: int
365
+ downtime: int
366
+
367
+ @dataclass
368
+ class StateLabel(Packet):
369
+ """Packet type 25."""
370
+
371
+ PKT_TYPE: ClassVar[int] = 25
372
+ _fields: ClassVar[list[dict[str, Any]]] = [
373
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32}
374
+ ]
375
+
376
+ # Packet metadata for automatic handling
377
+ _packet_kind: ClassVar[str] = "STATE"
378
+ _requires_ack: ClassVar[bool] = False
379
+ _requires_response: ClassVar[bool] = False
380
+
381
+ label: bytes
382
+
383
+ @dataclass
384
+ class StateLocation(Packet):
385
+ """Packet type 50."""
386
+
387
+ PKT_TYPE: ClassVar[int] = 50
388
+ _fields: ClassVar[list[dict[str, Any]]] = [
389
+ {"name": "Location", "type": "[16]byte", "size_bytes": 16},
390
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32},
391
+ {"name": "UpdatedAt", "type": "uint64", "size_bytes": 8},
392
+ ]
393
+
394
+ # Packet metadata for automatic handling
395
+ _packet_kind: ClassVar[str] = "STATE"
396
+ _requires_ack: ClassVar[bool] = False
397
+ _requires_response: ClassVar[bool] = False
398
+
399
+ location: bytes
400
+ label: bytes
401
+ updated_at: int
402
+
403
+ @dataclass
404
+ class StatePower(Packet):
405
+ """Packet type 22."""
406
+
407
+ PKT_TYPE: ClassVar[int] = 22
408
+ _fields: ClassVar[list[dict[str, Any]]] = [
409
+ {"name": "Level", "type": "uint16", "size_bytes": 2}
410
+ ]
411
+
412
+ # Packet metadata for automatic handling
413
+ _packet_kind: ClassVar[str] = "STATE"
414
+ _requires_ack: ClassVar[bool] = False
415
+ _requires_response: ClassVar[bool] = False
416
+
417
+ level: int
418
+
419
+ @dataclass
420
+ class StateService(Packet):
421
+ """Packet type 3."""
422
+
423
+ PKT_TYPE: ClassVar[int] = 3
424
+ _fields: ClassVar[list[dict[str, Any]]] = [
425
+ {"name": "Service", "type": "<DeviceService>", "size_bytes": 1},
426
+ {"name": "Port", "type": "uint32", "size_bytes": 4},
427
+ ]
428
+
429
+ # Packet metadata for automatic handling
430
+ _packet_kind: ClassVar[str] = "STATE"
431
+ _requires_ack: ClassVar[bool] = False
432
+ _requires_response: ClassVar[bool] = False
433
+
434
+ service: DeviceService
435
+ port: int
436
+
437
+ @dataclass
438
+ class StateUnhandled(Packet):
439
+ """Packet type 223."""
440
+
441
+ PKT_TYPE: ClassVar[int] = 223
442
+ _fields: ClassVar[list[dict[str, Any]]] = [
443
+ {"name": "UnhandledType", "type": "uint16", "size_bytes": 2}
444
+ ]
445
+
446
+ # Packet metadata for automatic handling
447
+ _packet_kind: ClassVar[str] = "STATE"
448
+ _requires_ack: ClassVar[bool] = False
449
+ _requires_response: ClassVar[bool] = False
450
+
451
+ unhandled_type: int
452
+
453
+ @dataclass
454
+ class StateVersion(Packet):
455
+ """Packet type 33."""
456
+
457
+ PKT_TYPE: ClassVar[int] = 33
458
+ _fields: ClassVar[list[dict[str, Any]]] = [
459
+ {"name": "Vendor", "type": "uint32", "size_bytes": 4},
460
+ {"name": "Product", "type": "uint32", "size_bytes": 4},
461
+ {"type": "reserved", "size_bytes": 4},
462
+ ]
463
+
464
+ # Packet metadata for automatic handling
465
+ _packet_kind: ClassVar[str] = "STATE"
466
+ _requires_ack: ClassVar[bool] = False
467
+ _requires_response: ClassVar[bool] = False
468
+
469
+ vendor: int
470
+ product: int
471
+
472
+ @dataclass
473
+ class StateWifiFirmware(Packet):
474
+ """Packet type 19."""
475
+
476
+ PKT_TYPE: ClassVar[int] = 19
477
+ _fields: ClassVar[list[dict[str, Any]]] = [
478
+ {"name": "Build", "type": "uint64", "size_bytes": 8},
479
+ {"type": "reserved", "size_bytes": 8},
480
+ {"name": "VersionMinor", "type": "uint16", "size_bytes": 2},
481
+ {"name": "VersionMajor", "type": "uint16", "size_bytes": 2},
482
+ ]
483
+
484
+ # Packet metadata for automatic handling
485
+ _packet_kind: ClassVar[str] = "STATE"
486
+ _requires_ack: ClassVar[bool] = False
487
+ _requires_response: ClassVar[bool] = False
488
+
489
+ build: int
490
+ version_minor: int
491
+ version_major: int
492
+
493
+ @dataclass
494
+ class StateWifiInfo(Packet):
495
+ """Packet type 17."""
496
+
497
+ PKT_TYPE: ClassVar[int] = 17
498
+ _fields: ClassVar[list[dict[str, Any]]] = [
499
+ {"name": "Signal", "type": "float32", "size_bytes": 4},
500
+ {"type": "reserved", "size_bytes": 4},
501
+ {"type": "reserved", "size_bytes": 4},
502
+ {"type": "reserved", "size_bytes": 2},
503
+ ]
504
+
505
+ # Packet metadata for automatic handling
506
+ _packet_kind: ClassVar[str] = "STATE"
507
+ _requires_ack: ClassVar[bool] = False
508
+ _requires_response: ClassVar[bool] = False
509
+
510
+ signal: float
511
+
512
+
513
+ class Light(Packet):
514
+ """Light category packets."""
515
+
516
+ @dataclass
517
+ class GetColor(Packet):
518
+ """Packet type 101."""
519
+
520
+ PKT_TYPE: ClassVar[int] = 101
521
+ _fields: ClassVar[list[dict[str, Any]]] = []
522
+
523
+ # Packet metadata for automatic handling
524
+ _packet_kind: ClassVar[str] = "GET"
525
+ _requires_ack: ClassVar[bool] = False
526
+ _requires_response: ClassVar[bool] = False
527
+
528
+ pass
529
+
530
+ @dataclass
531
+ class GetHevCycle(Packet):
532
+ """Packet type 142."""
533
+
534
+ PKT_TYPE: ClassVar[int] = 142
535
+ _fields: ClassVar[list[dict[str, Any]]] = []
536
+
537
+ # Packet metadata for automatic handling
538
+ _packet_kind: ClassVar[str] = "GET"
539
+ _requires_ack: ClassVar[bool] = False
540
+ _requires_response: ClassVar[bool] = False
541
+
542
+ pass
543
+
544
+ @dataclass
545
+ class GetHevCycleConfiguration(Packet):
546
+ """Packet type 145."""
547
+
548
+ PKT_TYPE: ClassVar[int] = 145
549
+ _fields: ClassVar[list[dict[str, Any]]] = []
550
+
551
+ # Packet metadata for automatic handling
552
+ _packet_kind: ClassVar[str] = "GET"
553
+ _requires_ack: ClassVar[bool] = False
554
+ _requires_response: ClassVar[bool] = False
555
+
556
+ pass
557
+
558
+ @dataclass
559
+ class GetInfrared(Packet):
560
+ """Packet type 120."""
561
+
562
+ PKT_TYPE: ClassVar[int] = 120
563
+ _fields: ClassVar[list[dict[str, Any]]] = []
564
+
565
+ # Packet metadata for automatic handling
566
+ _packet_kind: ClassVar[str] = "GET"
567
+ _requires_ack: ClassVar[bool] = False
568
+ _requires_response: ClassVar[bool] = False
569
+
570
+ pass
571
+
572
+ @dataclass
573
+ class GetLastHevCycleResult(Packet):
574
+ """Packet type 148."""
575
+
576
+ PKT_TYPE: ClassVar[int] = 148
577
+ _fields: ClassVar[list[dict[str, Any]]] = []
578
+
579
+ # Packet metadata for automatic handling
580
+ _packet_kind: ClassVar[str] = "GET"
581
+ _requires_ack: ClassVar[bool] = False
582
+ _requires_response: ClassVar[bool] = False
583
+
584
+ pass
585
+
586
+ @dataclass
587
+ class GetPower(Packet):
588
+ """Packet type 116."""
589
+
590
+ PKT_TYPE: ClassVar[int] = 116
591
+ _fields: ClassVar[list[dict[str, Any]]] = []
592
+
593
+ # Packet metadata for automatic handling
594
+ _packet_kind: ClassVar[str] = "GET"
595
+ _requires_ack: ClassVar[bool] = False
596
+ _requires_response: ClassVar[bool] = False
597
+
598
+ pass
599
+
600
+ @dataclass
601
+ class SetColor(Packet):
602
+ """Packet type 102."""
603
+
604
+ PKT_TYPE: ClassVar[int] = 102
605
+ _fields: ClassVar[list[dict[str, Any]]] = [
606
+ {"type": "reserved", "size_bytes": 1},
607
+ {"name": "Color", "type": "<LightHsbk>", "size_bytes": 8},
608
+ {"name": "Duration", "type": "uint32", "size_bytes": 4},
609
+ ]
610
+
611
+ # Packet metadata for automatic handling
612
+ _packet_kind: ClassVar[str] = "SET"
613
+ _requires_ack: ClassVar[bool] = True
614
+ _requires_response: ClassVar[bool] = False
615
+
616
+ color: LightHsbk
617
+ duration: int
618
+
619
+ @dataclass
620
+ class SetHevCycle(Packet):
621
+ """Packet type 143."""
622
+
623
+ PKT_TYPE: ClassVar[int] = 143
624
+ _fields: ClassVar[list[dict[str, Any]]] = [
625
+ {"name": "Enable", "type": "bool", "size_bytes": 1},
626
+ {"name": "DurationS", "type": "uint32", "size_bytes": 4},
627
+ ]
628
+
629
+ # Packet metadata for automatic handling
630
+ _packet_kind: ClassVar[str] = "SET"
631
+ _requires_ack: ClassVar[bool] = True
632
+ _requires_response: ClassVar[bool] = False
633
+
634
+ enable: bool
635
+ duration_s: int
636
+
637
+ @dataclass
638
+ class SetHevCycleConfiguration(Packet):
639
+ """Packet type 146."""
640
+
641
+ PKT_TYPE: ClassVar[int] = 146
642
+ _fields: ClassVar[list[dict[str, Any]]] = [
643
+ {"name": "Indication", "type": "bool", "size_bytes": 1},
644
+ {"name": "DurationS", "type": "uint32", "size_bytes": 4},
645
+ ]
646
+
647
+ # Packet metadata for automatic handling
648
+ _packet_kind: ClassVar[str] = "SET"
649
+ _requires_ack: ClassVar[bool] = True
650
+ _requires_response: ClassVar[bool] = False
651
+
652
+ indication: bool
653
+ duration_s: int
654
+
655
+ @dataclass
656
+ class SetInfrared(Packet):
657
+ """Packet type 122."""
658
+
659
+ PKT_TYPE: ClassVar[int] = 122
660
+ _fields: ClassVar[list[dict[str, Any]]] = [
661
+ {"name": "Brightness", "type": "uint16", "size_bytes": 2}
662
+ ]
663
+
664
+ # Packet metadata for automatic handling
665
+ _packet_kind: ClassVar[str] = "SET"
666
+ _requires_ack: ClassVar[bool] = True
667
+ _requires_response: ClassVar[bool] = False
668
+
669
+ brightness: int
670
+
671
+ @dataclass
672
+ class SetPower(Packet):
673
+ """Packet type 117."""
674
+
675
+ PKT_TYPE: ClassVar[int] = 117
676
+ _fields: ClassVar[list[dict[str, Any]]] = [
677
+ {"name": "Level", "type": "uint16", "size_bytes": 2},
678
+ {"name": "Duration", "type": "uint32", "size_bytes": 4},
679
+ ]
680
+
681
+ # Packet metadata for automatic handling
682
+ _packet_kind: ClassVar[str] = "SET"
683
+ _requires_ack: ClassVar[bool] = True
684
+ _requires_response: ClassVar[bool] = False
685
+
686
+ level: int
687
+ duration: int
688
+
689
+ @dataclass
690
+ class SetWaveform(Packet):
691
+ """Packet type 103."""
692
+
693
+ PKT_TYPE: ClassVar[int] = 103
694
+ _fields: ClassVar[list[dict[str, Any]]] = [
695
+ {"type": "reserved", "size_bytes": 1},
696
+ {"name": "Transient", "type": "bool", "size_bytes": 1},
697
+ {"name": "Color", "type": "<LightHsbk>", "size_bytes": 8},
698
+ {"name": "Period", "type": "uint32", "size_bytes": 4},
699
+ {"name": "Cycles", "type": "float32", "size_bytes": 4},
700
+ {"name": "SkewRatio", "type": "int16", "size_bytes": 2},
701
+ {"name": "Waveform", "type": "<LightWaveform>", "size_bytes": 1},
702
+ ]
703
+
704
+ # Packet metadata for automatic handling
705
+ _packet_kind: ClassVar[str] = "SET"
706
+ _requires_ack: ClassVar[bool] = True
707
+ _requires_response: ClassVar[bool] = False
708
+
709
+ transient: bool
710
+ color: LightHsbk
711
+ period: int
712
+ cycles: float
713
+ skew_ratio: int
714
+ waveform: LightWaveform
715
+
716
+ @dataclass
717
+ class SetWaveformOptional(Packet):
718
+ """Packet type 119."""
719
+
720
+ PKT_TYPE: ClassVar[int] = 119
721
+ _fields: ClassVar[list[dict[str, Any]]] = [
722
+ {"type": "reserved", "size_bytes": 1},
723
+ {"name": "Transient", "type": "bool", "size_bytes": 1},
724
+ {"name": "Color", "type": "<LightHsbk>", "size_bytes": 8},
725
+ {"name": "Period", "type": "uint32", "size_bytes": 4},
726
+ {"name": "Cycles", "type": "float32", "size_bytes": 4},
727
+ {"name": "SkewRatio", "type": "int16", "size_bytes": 2},
728
+ {"name": "Waveform", "type": "<LightWaveform>", "size_bytes": 1},
729
+ {"name": "SetHue", "type": "bool", "size_bytes": 1},
730
+ {"name": "SetSaturation", "type": "bool", "size_bytes": 1},
731
+ {"name": "SetBrightness", "type": "bool", "size_bytes": 1},
732
+ {"name": "SetKelvin", "type": "bool", "size_bytes": 1},
733
+ ]
734
+
735
+ # Packet metadata for automatic handling
736
+ _packet_kind: ClassVar[str] = "SET"
737
+ _requires_ack: ClassVar[bool] = True
738
+ _requires_response: ClassVar[bool] = False
739
+
740
+ transient: bool
741
+ color: LightHsbk
742
+ period: int
743
+ cycles: float
744
+ skew_ratio: int
745
+ waveform: LightWaveform
746
+ set_hue: bool
747
+ set_saturation: bool
748
+ set_brightness: bool
749
+ set_kelvin: bool
750
+
751
+ @dataclass
752
+ class StateColor(Packet):
753
+ """Packet type 107."""
754
+
755
+ PKT_TYPE: ClassVar[int] = 107
756
+ _fields: ClassVar[list[dict[str, Any]]] = [
757
+ {"name": "Color", "type": "<LightHsbk>", "size_bytes": 8},
758
+ {"type": "reserved", "size_bytes": 2},
759
+ {"name": "Power", "type": "uint16", "size_bytes": 2},
760
+ {"name": "Label", "type": "[32]byte", "size_bytes": 32},
761
+ {"type": "reserved", "size_bytes": 8},
762
+ ]
763
+
764
+ # Packet metadata for automatic handling
765
+ _packet_kind: ClassVar[str] = "STATE"
766
+ _requires_ack: ClassVar[bool] = False
767
+ _requires_response: ClassVar[bool] = False
768
+
769
+ color: LightHsbk
770
+ power: int
771
+ label: bytes
772
+
773
+ @dataclass
774
+ class StateHevCycle(Packet):
775
+ """Packet type 144."""
776
+
777
+ PKT_TYPE: ClassVar[int] = 144
778
+ _fields: ClassVar[list[dict[str, Any]]] = [
779
+ {"name": "DurationS", "type": "uint32", "size_bytes": 4},
780
+ {"name": "RemainingS", "type": "uint32", "size_bytes": 4},
781
+ {"name": "LastPower", "type": "bool", "size_bytes": 1},
782
+ ]
783
+
784
+ # Packet metadata for automatic handling
785
+ _packet_kind: ClassVar[str] = "STATE"
786
+ _requires_ack: ClassVar[bool] = False
787
+ _requires_response: ClassVar[bool] = False
788
+
789
+ duration_s: int
790
+ remaining_s: int
791
+ last_power: bool
792
+
793
+ @dataclass
794
+ class StateHevCycleConfiguration(Packet):
795
+ """Packet type 147."""
796
+
797
+ PKT_TYPE: ClassVar[int] = 147
798
+ _fields: ClassVar[list[dict[str, Any]]] = [
799
+ {"name": "Indication", "type": "bool", "size_bytes": 1},
800
+ {"name": "DurationS", "type": "uint32", "size_bytes": 4},
801
+ ]
802
+
803
+ # Packet metadata for automatic handling
804
+ _packet_kind: ClassVar[str] = "STATE"
805
+ _requires_ack: ClassVar[bool] = False
806
+ _requires_response: ClassVar[bool] = False
807
+
808
+ indication: bool
809
+ duration_s: int
810
+
811
+ @dataclass
812
+ class StateInfrared(Packet):
813
+ """Packet type 121."""
814
+
815
+ PKT_TYPE: ClassVar[int] = 121
816
+ _fields: ClassVar[list[dict[str, Any]]] = [
817
+ {"name": "Brightness", "type": "uint16", "size_bytes": 2}
818
+ ]
819
+
820
+ # Packet metadata for automatic handling
821
+ _packet_kind: ClassVar[str] = "STATE"
822
+ _requires_ack: ClassVar[bool] = False
823
+ _requires_response: ClassVar[bool] = False
824
+
825
+ brightness: int
826
+
827
+ @dataclass
828
+ class StateLastHevCycleResult(Packet):
829
+ """Packet type 149."""
830
+
831
+ PKT_TYPE: ClassVar[int] = 149
832
+ _fields: ClassVar[list[dict[str, Any]]] = [
833
+ {"name": "Result", "type": "<LightLastHevCycleResult>", "size_bytes": 1},
834
+ ]
835
+
836
+ # Packet metadata for automatic handling
837
+ _packet_kind: ClassVar[str] = "STATE"
838
+ _requires_ack: ClassVar[bool] = False
839
+ _requires_response: ClassVar[bool] = False
840
+
841
+ result: LightLastHevCycleResult
842
+
843
+ @dataclass
844
+ class StatePower(Packet):
845
+ """Packet type 118."""
846
+
847
+ PKT_TYPE: ClassVar[int] = 118
848
+ _fields: ClassVar[list[dict[str, Any]]] = [
849
+ {"name": "Level", "type": "uint16", "size_bytes": 2}
850
+ ]
851
+
852
+ # Packet metadata for automatic handling
853
+ _packet_kind: ClassVar[str] = "STATE"
854
+ _requires_ack: ClassVar[bool] = False
855
+ _requires_response: ClassVar[bool] = False
856
+
857
+ level: int
858
+
859
+
860
+ class MultiZone(Packet):
861
+ """MultiZone category packets."""
862
+
863
+ @dataclass
864
+ class ExtendedGetColorZones(Packet):
865
+ """Packet type 511."""
866
+
867
+ PKT_TYPE: ClassVar[int] = 511
868
+ _fields: ClassVar[list[dict[str, Any]]] = []
869
+
870
+ # Packet metadata for automatic handling
871
+ _packet_kind: ClassVar[str] = "OTHER"
872
+ _requires_ack: ClassVar[bool] = False
873
+ _requires_response: ClassVar[bool] = False
874
+
875
+ pass
876
+
877
+ @dataclass
878
+ class ExtendedSetColorZones(Packet):
879
+ """Packet type 510."""
880
+
881
+ PKT_TYPE: ClassVar[int] = 510
882
+ _fields: ClassVar[list[dict[str, Any]]] = [
883
+ {"name": "Duration", "type": "uint32", "size_bytes": 4},
884
+ {
885
+ "name": "Apply",
886
+ "type": "<MultiZoneExtendedApplicationRequest>",
887
+ "size_bytes": 1,
888
+ },
889
+ {"name": "Index", "type": "uint16", "size_bytes": 2},
890
+ {"name": "ColorsCount", "type": "uint8", "size_bytes": 1},
891
+ {"name": "Colors", "type": "[82]<LightHsbk>", "size_bytes": 656},
892
+ ]
893
+
894
+ # Packet metadata for automatic handling
895
+ _packet_kind: ClassVar[str] = "OTHER"
896
+ _requires_ack: ClassVar[bool] = False
897
+ _requires_response: ClassVar[bool] = False
898
+
899
+ duration: int
900
+ apply: MultiZoneExtendedApplicationRequest
901
+ index: int
902
+ colors_count: int
903
+ colors: list[LightHsbk]
904
+
905
+ @dataclass
906
+ class ExtendedStateMultiZone(Packet):
907
+ """Packet type 512."""
908
+
909
+ PKT_TYPE: ClassVar[int] = 512
910
+ _fields: ClassVar[list[dict[str, Any]]] = [
911
+ {"name": "Count", "type": "uint16", "size_bytes": 2},
912
+ {"name": "Index", "type": "uint16", "size_bytes": 2},
913
+ {"name": "ColorsCount", "type": "uint8", "size_bytes": 1},
914
+ {"name": "Colors", "type": "[82]<LightHsbk>", "size_bytes": 656},
915
+ ]
916
+
917
+ # Packet metadata for automatic handling
918
+ _packet_kind: ClassVar[str] = "OTHER"
919
+ _requires_ack: ClassVar[bool] = False
920
+ _requires_response: ClassVar[bool] = False
921
+
922
+ count: int
923
+ index: int
924
+ colors_count: int
925
+ colors: list[LightHsbk]
926
+
927
+ @dataclass
928
+ class GetColorZones(Packet):
929
+ """Packet type 502."""
930
+
931
+ PKT_TYPE: ClassVar[int] = 502
932
+ _fields: ClassVar[list[dict[str, Any]]] = [
933
+ {"name": "StartIndex", "type": "uint8", "size_bytes": 1},
934
+ {"name": "EndIndex", "type": "uint8", "size_bytes": 1},
935
+ ]
936
+
937
+ # Packet metadata for automatic handling
938
+ _packet_kind: ClassVar[str] = "GET"
939
+ _requires_ack: ClassVar[bool] = False
940
+ _requires_response: ClassVar[bool] = False
941
+
942
+ start_index: int
943
+ end_index: int
944
+
945
+ @dataclass
946
+ class GetEffect(Packet):
947
+ """Packet type 507."""
948
+
949
+ PKT_TYPE: ClassVar[int] = 507
950
+ _fields: ClassVar[list[dict[str, Any]]] = []
951
+
952
+ # Packet metadata for automatic handling
953
+ _packet_kind: ClassVar[str] = "GET"
954
+ _requires_ack: ClassVar[bool] = False
955
+ _requires_response: ClassVar[bool] = False
956
+
957
+ pass
958
+
959
+ @dataclass
960
+ class SetColorZones(Packet):
961
+ """Packet type 501."""
962
+
963
+ PKT_TYPE: ClassVar[int] = 501
964
+ _fields: ClassVar[list[dict[str, Any]]] = [
965
+ {"name": "StartIndex", "type": "uint8", "size_bytes": 1},
966
+ {"name": "EndIndex", "type": "uint8", "size_bytes": 1},
967
+ {"name": "Color", "type": "<LightHsbk>", "size_bytes": 8},
968
+ {"name": "Duration", "type": "uint32", "size_bytes": 4},
969
+ {"name": "Apply", "type": "<MultiZoneApplicationRequest>", "size_bytes": 1},
970
+ ]
971
+
972
+ # Packet metadata for automatic handling
973
+ _packet_kind: ClassVar[str] = "SET"
974
+ _requires_ack: ClassVar[bool] = True
975
+ _requires_response: ClassVar[bool] = False
976
+
977
+ start_index: int
978
+ end_index: int
979
+ color: LightHsbk
980
+ duration: int
981
+ apply: MultiZoneApplicationRequest
982
+
983
+ @dataclass
984
+ class SetEffect(Packet):
985
+ """Packet type 508."""
986
+
987
+ PKT_TYPE: ClassVar[int] = 508
988
+ _fields: ClassVar[list[dict[str, Any]]] = [
989
+ {"name": "Settings", "type": "<MultiZoneEffectSettings>", "size_bytes": 59},
990
+ ]
991
+
992
+ # Packet metadata for automatic handling
993
+ _packet_kind: ClassVar[str] = "SET"
994
+ _requires_ack: ClassVar[bool] = True
995
+ _requires_response: ClassVar[bool] = False
996
+
997
+ settings: MultiZoneEffectSettings
998
+
999
+ @dataclass
1000
+ class StateEffect(Packet):
1001
+ """Packet type 509."""
1002
+
1003
+ PKT_TYPE: ClassVar[int] = 509
1004
+ _fields: ClassVar[list[dict[str, Any]]] = [
1005
+ {"name": "Settings", "type": "<MultiZoneEffectSettings>", "size_bytes": 59},
1006
+ ]
1007
+
1008
+ # Packet metadata for automatic handling
1009
+ _packet_kind: ClassVar[str] = "STATE"
1010
+ _requires_ack: ClassVar[bool] = False
1011
+ _requires_response: ClassVar[bool] = False
1012
+
1013
+ settings: MultiZoneEffectSettings
1014
+
1015
+ @dataclass
1016
+ class StateMultiZone(Packet):
1017
+ """Packet type 506."""
1018
+
1019
+ PKT_TYPE: ClassVar[int] = 506
1020
+ _fields: ClassVar[list[dict[str, Any]]] = [
1021
+ {"name": "Count", "type": "uint8", "size_bytes": 1},
1022
+ {"name": "Index", "type": "uint8", "size_bytes": 1},
1023
+ {"name": "Colors", "type": "[8]<LightHsbk>", "size_bytes": 64},
1024
+ ]
1025
+
1026
+ # Packet metadata for automatic handling
1027
+ _packet_kind: ClassVar[str] = "STATE"
1028
+ _requires_ack: ClassVar[bool] = False
1029
+ _requires_response: ClassVar[bool] = False
1030
+
1031
+ count: int
1032
+ index: int
1033
+ colors: list[LightHsbk]
1034
+
1035
+ @dataclass
1036
+ class StateZone(Packet):
1037
+ """Packet type 503."""
1038
+
1039
+ PKT_TYPE: ClassVar[int] = 503
1040
+ _fields: ClassVar[list[dict[str, Any]]] = [
1041
+ {"name": "Count", "type": "uint8", "size_bytes": 1},
1042
+ {"name": "Index", "type": "uint8", "size_bytes": 1},
1043
+ {"name": "Color", "type": "<LightHsbk>", "size_bytes": 8},
1044
+ ]
1045
+
1046
+ # Packet metadata for automatic handling
1047
+ _packet_kind: ClassVar[str] = "STATE"
1048
+ _requires_ack: ClassVar[bool] = False
1049
+ _requires_response: ClassVar[bool] = False
1050
+
1051
+ count: int
1052
+ index: int
1053
+ color: LightHsbk
1054
+
1055
+
1056
+ class Tile(Packet):
1057
+ """Tile category packets."""
1058
+
1059
+ @dataclass
1060
+ class CopyFrameBuffer(Packet):
1061
+ """Packet type 716."""
1062
+
1063
+ PKT_TYPE: ClassVar[int] = 716
1064
+ _fields: ClassVar[list[dict[str, Any]]] = [
1065
+ {"name": "TileIndex", "type": "uint8", "size_bytes": 1},
1066
+ {"name": "Length", "type": "uint8", "size_bytes": 1},
1067
+ {"name": "SrcFbIndex", "type": "uint8", "size_bytes": 1},
1068
+ {"name": "DstFbIndex", "type": "uint8", "size_bytes": 1},
1069
+ {"name": "SrcX", "type": "uint8", "size_bytes": 1},
1070
+ {"name": "SrcY", "type": "uint8", "size_bytes": 1},
1071
+ {"name": "DstX", "type": "uint8", "size_bytes": 1},
1072
+ {"name": "DstY", "type": "uint8", "size_bytes": 1},
1073
+ {"name": "Width", "type": "uint8", "size_bytes": 1},
1074
+ {"name": "Height", "type": "uint8", "size_bytes": 1},
1075
+ {"name": "Duration", "type": "uint32", "size_bytes": 4},
1076
+ {"type": "reserved", "size_bytes": 1},
1077
+ ]
1078
+
1079
+ # Packet metadata for automatic handling
1080
+ _packet_kind: ClassVar[str] = "SET"
1081
+ _requires_ack: ClassVar[bool] = True
1082
+ _requires_response: ClassVar[bool] = False
1083
+
1084
+ tile_index: int
1085
+ length: int
1086
+ src_fb_index: int
1087
+ dst_fb_index: int
1088
+ src_x: int
1089
+ src_y: int
1090
+ dst_x: int
1091
+ dst_y: int
1092
+ width: int
1093
+ height: int
1094
+ duration: int
1095
+
1096
+ @dataclass
1097
+ class Get64(Packet):
1098
+ """Packet type 707."""
1099
+
1100
+ PKT_TYPE: ClassVar[int] = 707
1101
+ _fields: ClassVar[list[dict[str, Any]]] = [
1102
+ {"name": "TileIndex", "type": "uint8", "size_bytes": 1},
1103
+ {"name": "Length", "type": "uint8", "size_bytes": 1},
1104
+ {"name": "Rect", "type": "<TileBufferRect>", "size_bytes": 4},
1105
+ ]
1106
+
1107
+ # Packet metadata for automatic handling
1108
+ _packet_kind: ClassVar[str] = "GET"
1109
+ _requires_ack: ClassVar[bool] = False
1110
+ _requires_response: ClassVar[bool] = False
1111
+
1112
+ tile_index: int
1113
+ length: int
1114
+ rect: TileBufferRect
1115
+
1116
+ @dataclass
1117
+ class GetDeviceChain(Packet):
1118
+ """Packet type 701."""
1119
+
1120
+ PKT_TYPE: ClassVar[int] = 701
1121
+ _fields: ClassVar[list[dict[str, Any]]] = []
1122
+
1123
+ # Packet metadata for automatic handling
1124
+ _packet_kind: ClassVar[str] = "GET"
1125
+ _requires_ack: ClassVar[bool] = False
1126
+ _requires_response: ClassVar[bool] = False
1127
+
1128
+ pass
1129
+
1130
+ @dataclass
1131
+ class GetEffect(Packet):
1132
+ """Packet type 718."""
1133
+
1134
+ PKT_TYPE: ClassVar[int] = 718
1135
+ _fields: ClassVar[list[dict[str, Any]]] = [
1136
+ {"type": "reserved", "size_bytes": 1},
1137
+ {"type": "reserved", "size_bytes": 1},
1138
+ ]
1139
+
1140
+ # Packet metadata for automatic handling
1141
+ _packet_kind: ClassVar[str] = "GET"
1142
+ _requires_ack: ClassVar[bool] = False
1143
+ _requires_response: ClassVar[bool] = False
1144
+
1145
+ pass
1146
+
1147
+ @dataclass
1148
+ class Set64(Packet):
1149
+ """Packet type 715."""
1150
+
1151
+ PKT_TYPE: ClassVar[int] = 715
1152
+ _fields: ClassVar[list[dict[str, Any]]] = [
1153
+ {"name": "TileIndex", "type": "uint8", "size_bytes": 1},
1154
+ {"name": "Length", "type": "uint8", "size_bytes": 1},
1155
+ {"name": "Rect", "type": "<TileBufferRect>", "size_bytes": 4},
1156
+ {"name": "Duration", "type": "uint32", "size_bytes": 4},
1157
+ {"name": "Colors", "type": "[64]<LightHsbk>", "size_bytes": 512},
1158
+ ]
1159
+
1160
+ # Packet metadata for automatic handling
1161
+ _packet_kind: ClassVar[str] = "SET"
1162
+ _requires_ack: ClassVar[bool] = True
1163
+ _requires_response: ClassVar[bool] = False
1164
+
1165
+ tile_index: int
1166
+ length: int
1167
+ rect: TileBufferRect
1168
+ duration: int
1169
+ colors: list[LightHsbk]
1170
+
1171
+ @dataclass
1172
+ class SetEffect(Packet):
1173
+ """Packet type 719."""
1174
+
1175
+ PKT_TYPE: ClassVar[int] = 719
1176
+ _fields: ClassVar[list[dict[str, Any]]] = [
1177
+ {"type": "reserved", "size_bytes": 1},
1178
+ {"type": "reserved", "size_bytes": 1},
1179
+ {"name": "Settings", "type": "<TileEffectSettings>", "size_bytes": 186},
1180
+ ]
1181
+
1182
+ # Packet metadata for automatic handling
1183
+ _packet_kind: ClassVar[str] = "SET"
1184
+ _requires_ack: ClassVar[bool] = True
1185
+ _requires_response: ClassVar[bool] = False
1186
+
1187
+ settings: TileEffectSettings
1188
+
1189
+ @dataclass
1190
+ class SetUserPosition(Packet):
1191
+ """Packet type 703."""
1192
+
1193
+ PKT_TYPE: ClassVar[int] = 703
1194
+ _fields: ClassVar[list[dict[str, Any]]] = [
1195
+ {"name": "TileIndex", "type": "uint8", "size_bytes": 1},
1196
+ {"type": "reserved", "size_bytes": 1},
1197
+ {"type": "reserved", "size_bytes": 1},
1198
+ {"name": "UserX", "type": "float32", "size_bytes": 4},
1199
+ {"name": "UserY", "type": "float32", "size_bytes": 4},
1200
+ ]
1201
+
1202
+ # Packet metadata for automatic handling
1203
+ _packet_kind: ClassVar[str] = "SET"
1204
+ _requires_ack: ClassVar[bool] = True
1205
+ _requires_response: ClassVar[bool] = False
1206
+
1207
+ tile_index: int
1208
+ user_x: float
1209
+ user_y: float
1210
+
1211
+ @dataclass
1212
+ class State64(Packet):
1213
+ """Packet type 711."""
1214
+
1215
+ PKT_TYPE: ClassVar[int] = 711
1216
+ _fields: ClassVar[list[dict[str, Any]]] = [
1217
+ {"name": "TileIndex", "type": "uint8", "size_bytes": 1},
1218
+ {"name": "Rect", "type": "<TileBufferRect>", "size_bytes": 4},
1219
+ {"name": "Colors", "type": "[64]<LightHsbk>", "size_bytes": 512},
1220
+ ]
1221
+
1222
+ # Packet metadata for automatic handling
1223
+ _packet_kind: ClassVar[str] = "STATE"
1224
+ _requires_ack: ClassVar[bool] = False
1225
+ _requires_response: ClassVar[bool] = False
1226
+
1227
+ tile_index: int
1228
+ rect: TileBufferRect
1229
+ colors: list[LightHsbk]
1230
+
1231
+ @dataclass
1232
+ class StateDeviceChain(Packet):
1233
+ """Packet type 702."""
1234
+
1235
+ PKT_TYPE: ClassVar[int] = 702
1236
+ _fields: ClassVar[list[dict[str, Any]]] = [
1237
+ {"name": "StartIndex", "type": "uint8", "size_bytes": 1},
1238
+ {"name": "TileDevices", "type": "[16]<TileStateDevice>", "size_bytes": 880},
1239
+ {"name": "TileDevicesCount", "type": "uint8", "size_bytes": 1},
1240
+ ]
1241
+
1242
+ # Packet metadata for automatic handling
1243
+ _packet_kind: ClassVar[str] = "STATE"
1244
+ _requires_ack: ClassVar[bool] = False
1245
+ _requires_response: ClassVar[bool] = False
1246
+
1247
+ start_index: int
1248
+ tile_devices: list[TileStateDevice]
1249
+ tile_devices_count: int
1250
+
1251
+ @dataclass
1252
+ class StateEffect(Packet):
1253
+ """Packet type 720."""
1254
+
1255
+ PKT_TYPE: ClassVar[int] = 720
1256
+ _fields: ClassVar[list[dict[str, Any]]] = [
1257
+ {"type": "reserved", "size_bytes": 1},
1258
+ {"name": "Settings", "type": "<TileEffectSettings>", "size_bytes": 186},
1259
+ ]
1260
+
1261
+ # Packet metadata for automatic handling
1262
+ _packet_kind: ClassVar[str] = "STATE"
1263
+ _requires_ack: ClassVar[bool] = False
1264
+ _requires_response: ClassVar[bool] = False
1265
+
1266
+ settings: TileEffectSettings
1267
+
1268
+
1269
+ # Packet Registry - maps packet type to nested packet class
1270
+ PACKET_REGISTRY: dict[int, type[Packet]] = {
1271
+ 2: Device.GetService,
1272
+ 3: Device.StateService,
1273
+ 14: Device.GetHostFirmware,
1274
+ 15: Device.StateHostFirmware,
1275
+ 16: Device.GetWifiInfo,
1276
+ 17: Device.StateWifiInfo,
1277
+ 18: Device.GetWifiFirmware,
1278
+ 19: Device.StateWifiFirmware,
1279
+ 20: Device.GetPower,
1280
+ 21: Device.SetPower,
1281
+ 22: Device.StatePower,
1282
+ 23: Device.GetLabel,
1283
+ 24: Device.SetLabel,
1284
+ 25: Device.StateLabel,
1285
+ 32: Device.GetVersion,
1286
+ 33: Device.StateVersion,
1287
+ 34: Device.GetInfo,
1288
+ 35: Device.StateInfo,
1289
+ 38: Device.SetReboot,
1290
+ 45: Device.Acknowledgement,
1291
+ 48: Device.GetLocation,
1292
+ 49: Device.SetLocation,
1293
+ 50: Device.StateLocation,
1294
+ 51: Device.GetGroup,
1295
+ 52: Device.SetGroup,
1296
+ 53: Device.StateGroup,
1297
+ 58: Device.EchoRequest,
1298
+ 59: Device.EchoResponse,
1299
+ 101: Light.GetColor,
1300
+ 102: Light.SetColor,
1301
+ 103: Light.SetWaveform,
1302
+ 107: Light.StateColor,
1303
+ 116: Light.GetPower,
1304
+ 117: Light.SetPower,
1305
+ 118: Light.StatePower,
1306
+ 119: Light.SetWaveformOptional,
1307
+ 120: Light.GetInfrared,
1308
+ 121: Light.StateInfrared,
1309
+ 122: Light.SetInfrared,
1310
+ 142: Light.GetHevCycle,
1311
+ 143: Light.SetHevCycle,
1312
+ 144: Light.StateHevCycle,
1313
+ 145: Light.GetHevCycleConfiguration,
1314
+ 146: Light.SetHevCycleConfiguration,
1315
+ 147: Light.StateHevCycleConfiguration,
1316
+ 148: Light.GetLastHevCycleResult,
1317
+ 149: Light.StateLastHevCycleResult,
1318
+ 223: Device.StateUnhandled,
1319
+ 501: MultiZone.SetColorZones,
1320
+ 502: MultiZone.GetColorZones,
1321
+ 503: MultiZone.StateZone,
1322
+ 506: MultiZone.StateMultiZone,
1323
+ 507: MultiZone.GetEffect,
1324
+ 508: MultiZone.SetEffect,
1325
+ 509: MultiZone.StateEffect,
1326
+ 510: MultiZone.ExtendedSetColorZones,
1327
+ 511: MultiZone.ExtendedGetColorZones,
1328
+ 512: MultiZone.ExtendedStateMultiZone,
1329
+ 701: Tile.GetDeviceChain,
1330
+ 702: Tile.StateDeviceChain,
1331
+ 703: Tile.SetUserPosition,
1332
+ 707: Tile.Get64,
1333
+ 711: Tile.State64,
1334
+ 715: Tile.Set64,
1335
+ 716: Tile.CopyFrameBuffer,
1336
+ 718: Tile.GetEffect,
1337
+ 719: Tile.SetEffect,
1338
+ 720: Tile.StateEffect,
1339
+ }
1340
+
1341
+
1342
+ def get_packet_class(pkt_type: int) -> type[Packet] | None:
1343
+ """Get packet class for a given packet type.
1344
+
1345
+ Args:
1346
+ pkt_type: Packet type number
1347
+
1348
+ Returns:
1349
+ Nested packet class, or None if unknown
1350
+ """
1351
+ return PACKET_REGISTRY.get(pkt_type)