lifx-emulator 2.4.0__py3-none-any.whl → 3.1.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 (70) hide show
  1. lifx_emulator-3.1.0.dist-info/METADATA +103 -0
  2. lifx_emulator-3.1.0.dist-info/RECORD +19 -0
  3. {lifx_emulator-2.4.0.dist-info → lifx_emulator-3.1.0.dist-info}/WHEEL +1 -1
  4. lifx_emulator-3.1.0.dist-info/entry_points.txt +2 -0
  5. lifx_emulator_app/__init__.py +10 -0
  6. {lifx_emulator → lifx_emulator_app}/__main__.py +2 -3
  7. {lifx_emulator → lifx_emulator_app}/api/__init__.py +1 -1
  8. {lifx_emulator → lifx_emulator_app}/api/app.py +9 -4
  9. {lifx_emulator → lifx_emulator_app}/api/mappers/__init__.py +1 -1
  10. {lifx_emulator → lifx_emulator_app}/api/mappers/device_mapper.py +1 -1
  11. {lifx_emulator → lifx_emulator_app}/api/models.py +1 -2
  12. lifx_emulator_app/api/routers/__init__.py +11 -0
  13. {lifx_emulator → lifx_emulator_app}/api/routers/devices.py +2 -2
  14. {lifx_emulator → lifx_emulator_app}/api/routers/monitoring.py +1 -1
  15. {lifx_emulator → lifx_emulator_app}/api/routers/scenarios.py +1 -1
  16. lifx_emulator_app/api/services/__init__.py +8 -0
  17. {lifx_emulator → lifx_emulator_app}/api/services/device_service.py +3 -2
  18. lifx_emulator_app/api/static/dashboard.js +588 -0
  19. lifx_emulator_app/api/templates/dashboard.html +357 -0
  20. lifx_emulator/__init__.py +0 -31
  21. lifx_emulator/api/routers/__init__.py +0 -11
  22. lifx_emulator/api/services/__init__.py +0 -8
  23. lifx_emulator/api/templates/dashboard.html +0 -899
  24. lifx_emulator/constants.py +0 -33
  25. lifx_emulator/devices/__init__.py +0 -37
  26. lifx_emulator/devices/device.py +0 -395
  27. lifx_emulator/devices/manager.py +0 -256
  28. lifx_emulator/devices/observers.py +0 -139
  29. lifx_emulator/devices/persistence.py +0 -308
  30. lifx_emulator/devices/state_restorer.py +0 -259
  31. lifx_emulator/devices/state_serializer.py +0 -157
  32. lifx_emulator/devices/states.py +0 -381
  33. lifx_emulator/factories/__init__.py +0 -39
  34. lifx_emulator/factories/builder.py +0 -375
  35. lifx_emulator/factories/default_config.py +0 -158
  36. lifx_emulator/factories/factory.py +0 -252
  37. lifx_emulator/factories/firmware_config.py +0 -77
  38. lifx_emulator/factories/serial_generator.py +0 -82
  39. lifx_emulator/handlers/__init__.py +0 -39
  40. lifx_emulator/handlers/base.py +0 -49
  41. lifx_emulator/handlers/device_handlers.py +0 -322
  42. lifx_emulator/handlers/light_handlers.py +0 -503
  43. lifx_emulator/handlers/multizone_handlers.py +0 -249
  44. lifx_emulator/handlers/registry.py +0 -110
  45. lifx_emulator/handlers/tile_handlers.py +0 -488
  46. lifx_emulator/products/__init__.py +0 -28
  47. lifx_emulator/products/generator.py +0 -1079
  48. lifx_emulator/products/registry.py +0 -1530
  49. lifx_emulator/products/specs.py +0 -284
  50. lifx_emulator/products/specs.yml +0 -386
  51. lifx_emulator/protocol/__init__.py +0 -1
  52. lifx_emulator/protocol/base.py +0 -446
  53. lifx_emulator/protocol/const.py +0 -8
  54. lifx_emulator/protocol/generator.py +0 -1384
  55. lifx_emulator/protocol/header.py +0 -159
  56. lifx_emulator/protocol/packets.py +0 -1351
  57. lifx_emulator/protocol/protocol_types.py +0 -817
  58. lifx_emulator/protocol/serializer.py +0 -379
  59. lifx_emulator/repositories/__init__.py +0 -22
  60. lifx_emulator/repositories/device_repository.py +0 -155
  61. lifx_emulator/repositories/storage_backend.py +0 -107
  62. lifx_emulator/scenarios/__init__.py +0 -22
  63. lifx_emulator/scenarios/manager.py +0 -322
  64. lifx_emulator/scenarios/models.py +0 -112
  65. lifx_emulator/scenarios/persistence.py +0 -241
  66. lifx_emulator/server.py +0 -464
  67. lifx_emulator-2.4.0.dist-info/METADATA +0 -107
  68. lifx_emulator-2.4.0.dist-info/RECORD +0 -62
  69. lifx_emulator-2.4.0.dist-info/entry_points.txt +0 -2
  70. lifx_emulator-2.4.0.dist-info/licenses/LICENSE +0 -35
@@ -1,817 +0,0 @@
1
- """Auto-generated LIFX protocol types.
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 Pythonic naming conventions (snake_case fields, shortened enums) while
8
- maintaining compatibility with the official LIFX protocol through mappings.
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- from dataclasses import dataclass
14
- from enum import IntEnum
15
-
16
-
17
- class DeviceService(IntEnum):
18
- """Auto-generated enum."""
19
-
20
- UDP = 1
21
- RESERVED_0 = 2
22
- RESERVED_1 = 3
23
- RESERVED_2 = 4
24
- RESERVED_3 = 5
25
-
26
-
27
- class LightLastHevCycleResult(IntEnum):
28
- """Auto-generated enum."""
29
-
30
- SUCCESS = 0
31
- BUSY = 1
32
- INTERRUPTED_BY_RESET = 2
33
- INTERRUPTED_BY_HOMEKIT = 3
34
- INTERRUPTED_BY_LAN = 4
35
- INTERRUPTED_BY_CLOUD = 5
36
- NONE = 255
37
-
38
-
39
- class LightWaveform(IntEnum):
40
- """Auto-generated enum."""
41
-
42
- SAW = 0
43
- SINE = 1
44
- HALF_SINE = 2
45
- TRIANGLE = 3
46
- PULSE = 4
47
-
48
-
49
- class MultiZoneApplicationRequest(IntEnum):
50
- """Auto-generated enum."""
51
-
52
- NO_APPLY = 0
53
- APPLY = 1
54
- APPLY_ONLY = 2
55
-
56
-
57
- class MultiZoneEffectType(IntEnum):
58
- """Auto-generated enum."""
59
-
60
- OFF = 0
61
- MOVE = 1
62
- RESERVED_0 = 2
63
- RESERVED_1 = 3
64
-
65
-
66
- class MultiZoneExtendedApplicationRequest(IntEnum):
67
- """Auto-generated enum."""
68
-
69
- NO_APPLY = 0
70
- APPLY = 1
71
- APPLY_ONLY = 2
72
-
73
-
74
- class TileEffectSkyPalette(IntEnum):
75
- """Auto-generated enum."""
76
-
77
- CLOUDS_SKY = 0
78
- NIGHT_SKY = 1
79
- DAWN_SKY = 2
80
- DAWN_SUN = 3
81
- FULL_SUN = 4
82
- FINAL_SUN = 5
83
- NUM_COLOURS = 6
84
-
85
-
86
- class TileEffectSkyType(IntEnum):
87
- """Auto-generated enum."""
88
-
89
- SUNRISE = 0
90
- SUNSET = 1
91
- CLOUDS = 2
92
-
93
-
94
- class TileEffectType(IntEnum):
95
- """Auto-generated enum."""
96
-
97
- OFF = 0
98
- RESERVED_0 = 1
99
- MORPH = 2
100
- FLAME = 3
101
- RESERVED_1 = 4
102
- SKY = 5
103
-
104
-
105
- @dataclass
106
- class DeviceStateHostFirmware:
107
- """Auto-generated field structure."""
108
-
109
- build: int
110
- version_minor: int
111
- version_major: int
112
-
113
- def pack(self) -> bytes:
114
- """Pack to bytes."""
115
- from lifx_emulator.protocol import serializer
116
-
117
- result = b""
118
-
119
- # build: uint64
120
- result += serializer.pack_value(self.build, "uint64")
121
- # Reserved 8 bytes
122
- result += serializer.pack_reserved(8)
123
- # version_minor: uint16
124
- result += serializer.pack_value(self.version_minor, "uint16")
125
- # version_major: uint16
126
- result += serializer.pack_value(self.version_major, "uint16")
127
-
128
- return result
129
-
130
- @classmethod
131
- def unpack(
132
- cls, data: bytes, offset: int = 0
133
- ) -> tuple[DeviceStateHostFirmware, int]:
134
- """Unpack from bytes."""
135
- from lifx_emulator.protocol import serializer
136
-
137
- current_offset = offset
138
- # build: uint64
139
- build, current_offset = serializer.unpack_value(data, "uint64", current_offset)
140
- # Skip reserved 8 bytes
141
- current_offset += 8
142
- # version_minor: uint16
143
- version_minor, current_offset = serializer.unpack_value(
144
- data, "uint16", current_offset
145
- )
146
- # version_major: uint16
147
- version_major, current_offset = serializer.unpack_value(
148
- data, "uint16", current_offset
149
- )
150
-
151
- return cls(
152
- build=build, version_minor=version_minor, version_major=version_major
153
- ), current_offset
154
-
155
-
156
- @dataclass
157
- class DeviceStateVersion:
158
- """Auto-generated field structure."""
159
-
160
- vendor: int
161
- product: int
162
-
163
- def pack(self) -> bytes:
164
- """Pack to bytes."""
165
- from lifx_emulator.protocol import serializer
166
-
167
- result = b""
168
-
169
- # vendor: uint32
170
- result += serializer.pack_value(self.vendor, "uint32")
171
- # product: uint32
172
- result += serializer.pack_value(self.product, "uint32")
173
- # Reserved 4 bytes
174
- result += serializer.pack_reserved(4)
175
-
176
- return result
177
-
178
- @classmethod
179
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[DeviceStateVersion, int]:
180
- """Unpack from bytes."""
181
- from lifx_emulator.protocol import serializer
182
-
183
- current_offset = offset
184
- # vendor: uint32
185
- vendor, current_offset = serializer.unpack_value(data, "uint32", current_offset)
186
- # product: uint32
187
- product, current_offset = serializer.unpack_value(
188
- data, "uint32", current_offset
189
- )
190
- # Skip reserved 4 bytes
191
- current_offset += 4
192
-
193
- return cls(vendor=vendor, product=product), current_offset
194
-
195
-
196
- @dataclass
197
- class LightHsbk:
198
- """Auto-generated field structure."""
199
-
200
- hue: int
201
- saturation: int
202
- brightness: int
203
- kelvin: int
204
-
205
- def pack(self) -> bytes:
206
- """Pack to bytes."""
207
- from lifx_emulator.protocol import serializer
208
-
209
- result = b""
210
-
211
- # hue: uint16
212
- result += serializer.pack_value(self.hue, "uint16")
213
- # saturation: uint16
214
- result += serializer.pack_value(self.saturation, "uint16")
215
- # brightness: uint16
216
- result += serializer.pack_value(self.brightness, "uint16")
217
- # kelvin: uint16
218
- result += serializer.pack_value(self.kelvin, "uint16")
219
-
220
- return result
221
-
222
- @classmethod
223
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[LightHsbk, int]:
224
- """Unpack from bytes."""
225
- from lifx_emulator.protocol import serializer
226
-
227
- current_offset = offset
228
- # hue: uint16
229
- hue, current_offset = serializer.unpack_value(data, "uint16", current_offset)
230
- # saturation: uint16
231
- saturation, current_offset = serializer.unpack_value(
232
- data, "uint16", current_offset
233
- )
234
- # brightness: uint16
235
- brightness, current_offset = serializer.unpack_value(
236
- data, "uint16", current_offset
237
- )
238
- # kelvin: uint16
239
- kelvin, current_offset = serializer.unpack_value(data, "uint16", current_offset)
240
-
241
- return cls(
242
- hue=hue, saturation=saturation, brightness=brightness, kelvin=kelvin
243
- ), current_offset
244
-
245
-
246
- @dataclass
247
- class MultiZoneEffectParameter:
248
- """Auto-generated field structure."""
249
-
250
- parameter0: int
251
- parameter1: int
252
- parameter2: int
253
- parameter3: int
254
- parameter4: int
255
- parameter5: int
256
- parameter6: int
257
- parameter7: int
258
-
259
- def pack(self) -> bytes:
260
- """Pack to bytes."""
261
- from lifx_emulator.protocol import serializer
262
-
263
- result = b""
264
-
265
- # parameter0: uint32
266
- result += serializer.pack_value(self.parameter0, "uint32")
267
- # parameter1: uint32
268
- result += serializer.pack_value(self.parameter1, "uint32")
269
- # parameter2: uint32
270
- result += serializer.pack_value(self.parameter2, "uint32")
271
- # parameter3: uint32
272
- result += serializer.pack_value(self.parameter3, "uint32")
273
- # parameter4: uint32
274
- result += serializer.pack_value(self.parameter4, "uint32")
275
- # parameter5: uint32
276
- result += serializer.pack_value(self.parameter5, "uint32")
277
- # parameter6: uint32
278
- result += serializer.pack_value(self.parameter6, "uint32")
279
- # parameter7: uint32
280
- result += serializer.pack_value(self.parameter7, "uint32")
281
-
282
- return result
283
-
284
- @classmethod
285
- def unpack(
286
- cls, data: bytes, offset: int = 0
287
- ) -> tuple[MultiZoneEffectParameter, int]:
288
- """Unpack from bytes."""
289
- from lifx_emulator.protocol import serializer
290
-
291
- current_offset = offset
292
- # parameter0: uint32
293
- parameter0, current_offset = serializer.unpack_value(
294
- data, "uint32", current_offset
295
- )
296
- # parameter1: uint32
297
- parameter1, current_offset = serializer.unpack_value(
298
- data, "uint32", current_offset
299
- )
300
- # parameter2: uint32
301
- parameter2, current_offset = serializer.unpack_value(
302
- data, "uint32", current_offset
303
- )
304
- # parameter3: uint32
305
- parameter3, current_offset = serializer.unpack_value(
306
- data, "uint32", current_offset
307
- )
308
- # parameter4: uint32
309
- parameter4, current_offset = serializer.unpack_value(
310
- data, "uint32", current_offset
311
- )
312
- # parameter5: uint32
313
- parameter5, current_offset = serializer.unpack_value(
314
- data, "uint32", current_offset
315
- )
316
- # parameter6: uint32
317
- parameter6, current_offset = serializer.unpack_value(
318
- data, "uint32", current_offset
319
- )
320
- # parameter7: uint32
321
- parameter7, current_offset = serializer.unpack_value(
322
- data, "uint32", current_offset
323
- )
324
-
325
- return (
326
- cls(
327
- parameter0=parameter0,
328
- parameter1=parameter1,
329
- parameter2=parameter2,
330
- parameter3=parameter3,
331
- parameter4=parameter4,
332
- parameter5=parameter5,
333
- parameter6=parameter6,
334
- parameter7=parameter7,
335
- ),
336
- current_offset,
337
- )
338
-
339
-
340
- @dataclass
341
- class MultiZoneEffectSettings:
342
- """Auto-generated field structure."""
343
-
344
- instanceid: int
345
- type: MultiZoneEffectType
346
- speed: int
347
- duration: int
348
- parameter: MultiZoneEffectParameter
349
-
350
- def pack(self) -> bytes:
351
- """Pack to bytes."""
352
- from lifx_emulator.protocol import serializer
353
-
354
- result = b""
355
-
356
- # instanceid: uint32
357
- result += serializer.pack_value(self.instanceid, "uint32")
358
- # type: MultiZoneEffectType (enum)
359
- result += serializer.pack_value(int(self.type), "uint8")
360
- # Reserved 2 bytes
361
- result += serializer.pack_reserved(2)
362
- # speed: uint32
363
- result += serializer.pack_value(self.speed, "uint32")
364
- # duration: uint64
365
- result += serializer.pack_value(self.duration, "uint64")
366
- # Reserved 4 bytes
367
- result += serializer.pack_reserved(4)
368
- # Reserved 4 bytes
369
- result += serializer.pack_reserved(4)
370
- # parameter: MultiZoneEffectParameter
371
- result += self.parameter.pack()
372
-
373
- return result
374
-
375
- @classmethod
376
- def unpack(
377
- cls, data: bytes, offset: int = 0
378
- ) -> tuple[MultiZoneEffectSettings, int]:
379
- """Unpack from bytes."""
380
- from lifx_emulator.protocol import serializer
381
-
382
- current_offset = offset
383
- # instanceid: uint32
384
- instanceid, current_offset = serializer.unpack_value(
385
- data, "uint32", current_offset
386
- )
387
- # type: MultiZoneEffectType (enum)
388
- type_raw, current_offset = serializer.unpack_value(
389
- data, "uint8", current_offset
390
- )
391
- type = MultiZoneEffectType(type_raw)
392
- # Skip reserved 2 bytes
393
- current_offset += 2
394
- # speed: uint32
395
- speed, current_offset = serializer.unpack_value(data, "uint32", current_offset)
396
- # duration: uint64
397
- duration, current_offset = serializer.unpack_value(
398
- data, "uint64", current_offset
399
- )
400
- # Skip reserved 4 bytes
401
- current_offset += 4
402
- # Skip reserved 4 bytes
403
- current_offset += 4
404
- # parameter: MultiZoneEffectParameter
405
- parameter, current_offset = MultiZoneEffectParameter.unpack(
406
- data, current_offset
407
- )
408
-
409
- return (
410
- cls(
411
- instanceid=instanceid,
412
- type=type,
413
- speed=speed,
414
- duration=duration,
415
- parameter=parameter,
416
- ),
417
- current_offset,
418
- )
419
-
420
-
421
- @dataclass
422
- class TileAccelMeas:
423
- """Auto-generated field structure."""
424
-
425
- x: int
426
- y: int
427
- z: int
428
-
429
- def pack(self) -> bytes:
430
- """Pack to bytes."""
431
- from lifx_emulator.protocol import serializer
432
-
433
- result = b""
434
-
435
- # x: int16
436
- result += serializer.pack_value(self.x, "int16")
437
- # y: int16
438
- result += serializer.pack_value(self.y, "int16")
439
- # z: int16
440
- result += serializer.pack_value(self.z, "int16")
441
-
442
- return result
443
-
444
- @classmethod
445
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[TileAccelMeas, int]:
446
- """Unpack from bytes."""
447
- from lifx_emulator.protocol import serializer
448
-
449
- current_offset = offset
450
- # x: int16
451
- x, current_offset = serializer.unpack_value(data, "int16", current_offset)
452
- # y: int16
453
- y, current_offset = serializer.unpack_value(data, "int16", current_offset)
454
- # z: int16
455
- z, current_offset = serializer.unpack_value(data, "int16", current_offset)
456
-
457
- return cls(x=x, y=y, z=z), current_offset
458
-
459
-
460
- @dataclass
461
- class TileBufferRect:
462
- """Auto-generated field structure."""
463
-
464
- fb_index: int
465
- x: int
466
- y: int
467
- width: int
468
-
469
- def pack(self) -> bytes:
470
- """Pack to bytes."""
471
- from lifx_emulator.protocol import serializer
472
-
473
- result = b""
474
-
475
- # fb_index: uint8
476
- result += serializer.pack_value(self.fb_index, "uint8")
477
- # x: uint8
478
- result += serializer.pack_value(self.x, "uint8")
479
- # y: uint8
480
- result += serializer.pack_value(self.y, "uint8")
481
- # width: uint8
482
- result += serializer.pack_value(self.width, "uint8")
483
-
484
- return result
485
-
486
- @classmethod
487
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[TileBufferRect, int]:
488
- """Unpack from bytes."""
489
- from lifx_emulator.protocol import serializer
490
-
491
- current_offset = offset
492
- # fb_index: uint8
493
- fb_index, current_offset = serializer.unpack_value(
494
- data, "uint8", current_offset
495
- )
496
- # x: uint8
497
- x, current_offset = serializer.unpack_value(data, "uint8", current_offset)
498
- # y: uint8
499
- y, current_offset = serializer.unpack_value(data, "uint8", current_offset)
500
- # width: uint8
501
- width, current_offset = serializer.unpack_value(data, "uint8", current_offset)
502
-
503
- return cls(fb_index=fb_index, x=x, y=y, width=width), current_offset
504
-
505
-
506
- @dataclass
507
- class TileEffectParameter:
508
- """Auto-generated field structure for Sky effects."""
509
-
510
- sky_type: TileEffectSkyType
511
- cloud_saturation_min: int
512
- cloud_saturation_max: int
513
-
514
- def pack(self) -> bytes:
515
- """Pack to bytes."""
516
- from lifx_emulator.protocol import serializer
517
-
518
- result = b""
519
-
520
- # sky_type: TileEffectSkyType (enum)
521
- result += serializer.pack_value(int(self.sky_type), "uint8")
522
- # Reserved 3 bytes
523
- result += serializer.pack_reserved(3)
524
- # cloud_saturation_min: uint8
525
- result += serializer.pack_value(self.cloud_saturation_min, "uint8")
526
- # Reserved 3 bytes
527
- result += serializer.pack_reserved(3)
528
- # cloud_saturation_max: uint8
529
- result += serializer.pack_value(self.cloud_saturation_max, "uint8")
530
- # Reserved 23 bytes
531
- result += serializer.pack_reserved(23)
532
-
533
- return result
534
-
535
- @classmethod
536
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[TileEffectParameter, int]:
537
- """Unpack from bytes."""
538
- from lifx_emulator.protocol import serializer
539
-
540
- current_offset = offset
541
- # sky_type: TileEffectSkyType (enum)
542
- sky_type_raw, current_offset = serializer.unpack_value(
543
- data, "uint8", current_offset
544
- )
545
- sky_type = TileEffectSkyType(sky_type_raw)
546
- # Skip reserved 3 bytes
547
- current_offset += 3
548
- # cloud_saturation_min: uint8
549
- cloud_saturation_min, current_offset = serializer.unpack_value(
550
- data, "uint8", current_offset
551
- )
552
- # Skip reserved 3 bytes
553
- current_offset += 3
554
- # cloud_saturation_max: uint8
555
- cloud_saturation_max, current_offset = serializer.unpack_value(
556
- data, "uint8", current_offset
557
- )
558
- # Skip reserved 23 bytes
559
- current_offset += 23
560
-
561
- return (
562
- cls(
563
- sky_type=sky_type,
564
- cloud_saturation_min=cloud_saturation_min,
565
- cloud_saturation_max=cloud_saturation_max,
566
- ),
567
- current_offset,
568
- )
569
-
570
-
571
- @dataclass
572
- class TileEffectSettings:
573
- """Auto-generated field structure."""
574
-
575
- instanceid: int
576
- type: TileEffectType
577
- speed: int
578
- duration: int
579
- parameter: TileEffectParameter
580
- palette_count: int
581
- palette: list[LightHsbk]
582
-
583
- def pack(self) -> bytes:
584
- """Pack to bytes."""
585
- from lifx_emulator.protocol import serializer
586
-
587
- result = b""
588
-
589
- # instanceid: uint32
590
- result += serializer.pack_value(self.instanceid, "uint32")
591
- # type: TileEffectType (enum)
592
- result += serializer.pack_value(int(self.type), "uint8")
593
- # speed: uint32
594
- result += serializer.pack_value(self.speed, "uint32")
595
- # duration: uint64
596
- result += serializer.pack_value(self.duration, "uint64")
597
- # Reserved 4 bytes
598
- result += serializer.pack_reserved(4)
599
- # Reserved 4 bytes
600
- result += serializer.pack_reserved(4)
601
- # parameter: TileEffectParameter
602
- result += self.parameter.pack()
603
- # palette_count: uint8
604
- result += serializer.pack_value(self.palette_count, "uint8")
605
- # palette: list[LightHsbk]
606
- for item in self.palette:
607
- result += item.pack()
608
-
609
- return result
610
-
611
- @classmethod
612
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[TileEffectSettings, int]:
613
- """Unpack from bytes."""
614
- from lifx_emulator.protocol import serializer
615
-
616
- current_offset = offset
617
- # instanceid: uint32
618
- instanceid, current_offset = serializer.unpack_value(
619
- data, "uint32", current_offset
620
- )
621
- # type: TileEffectType (enum)
622
- type_raw, current_offset = serializer.unpack_value(
623
- data, "uint8", current_offset
624
- )
625
- type = TileEffectType(type_raw)
626
- # speed: uint32
627
- speed, current_offset = serializer.unpack_value(data, "uint32", current_offset)
628
- # duration: uint64
629
- duration, current_offset = serializer.unpack_value(
630
- data, "uint64", current_offset
631
- )
632
- # Skip reserved 4 bytes
633
- current_offset += 4
634
- # Skip reserved 4 bytes
635
- current_offset += 4
636
- # parameter: TileEffectParameter
637
- parameter, current_offset = TileEffectParameter.unpack(data, current_offset)
638
- # palette_count: uint8
639
- palette_count, current_offset = serializer.unpack_value(
640
- data, "uint8", current_offset
641
- )
642
- # palette: list[LightHsbk]
643
- palette = []
644
- for _ in range(16):
645
- item, current_offset = LightHsbk.unpack(data, current_offset)
646
- palette.append(item)
647
-
648
- return (
649
- cls(
650
- instanceid=instanceid,
651
- type=type,
652
- speed=speed,
653
- duration=duration,
654
- parameter=parameter,
655
- palette_count=palette_count,
656
- palette=palette,
657
- ),
658
- current_offset,
659
- )
660
-
661
-
662
- @dataclass
663
- class TileStateDevice:
664
- """Auto-generated field structure."""
665
-
666
- accel_meas: TileAccelMeas
667
- user_x: float
668
- user_y: float
669
- width: int
670
- height: int
671
- device_version: DeviceStateVersion
672
- firmware: DeviceStateHostFirmware
673
-
674
- def pack(self) -> bytes:
675
- """Pack to bytes."""
676
- from lifx_emulator.protocol import serializer
677
-
678
- result = b""
679
-
680
- # accel_meas: TileAccelMeas
681
- result += self.accel_meas.pack()
682
- # Reserved 1 bytes
683
- result += serializer.pack_reserved(1)
684
- # Reserved 1 bytes
685
- result += serializer.pack_reserved(1)
686
- # user_x: float32
687
- result += serializer.pack_value(self.user_x, "float32")
688
- # user_y: float32
689
- result += serializer.pack_value(self.user_y, "float32")
690
- # width: uint8
691
- result += serializer.pack_value(self.width, "uint8")
692
- # height: uint8
693
- result += serializer.pack_value(self.height, "uint8")
694
- # Reserved 1 bytes
695
- result += serializer.pack_reserved(1)
696
- # device_version: DeviceStateVersion
697
- result += self.device_version.pack()
698
- # firmware: DeviceStateHostFirmware
699
- result += self.firmware.pack()
700
- # Reserved 4 bytes
701
- result += serializer.pack_reserved(4)
702
-
703
- return result
704
-
705
- @classmethod
706
- def unpack(cls, data: bytes, offset: int = 0) -> tuple[TileStateDevice, int]:
707
- """Unpack from bytes."""
708
- from lifx_emulator.protocol import serializer
709
-
710
- current_offset = offset
711
- # accel_meas: TileAccelMeas
712
- accel_meas, current_offset = TileAccelMeas.unpack(data, current_offset)
713
- # Skip reserved 1 bytes
714
- current_offset += 1
715
- # Skip reserved 1 bytes
716
- current_offset += 1
717
- # user_x: float32
718
- user_x, current_offset = serializer.unpack_value(
719
- data, "float32", current_offset
720
- )
721
- # user_y: float32
722
- user_y, current_offset = serializer.unpack_value(
723
- data, "float32", current_offset
724
- )
725
- # width: uint8
726
- width, current_offset = serializer.unpack_value(data, "uint8", current_offset)
727
- # height: uint8
728
- height, current_offset = serializer.unpack_value(data, "uint8", current_offset)
729
- # Skip reserved 1 bytes
730
- current_offset += 1
731
- # device_version: DeviceStateVersion
732
- device_version, current_offset = DeviceStateVersion.unpack(data, current_offset)
733
- # firmware: DeviceStateHostFirmware
734
- firmware, current_offset = DeviceStateHostFirmware.unpack(data, current_offset)
735
- # Skip reserved 4 bytes
736
- current_offset += 4
737
-
738
- return (
739
- cls(
740
- accel_meas=accel_meas,
741
- user_x=user_x,
742
- user_y=user_y,
743
- width=width,
744
- height=height,
745
- device_version=device_version,
746
- firmware=firmware,
747
- ),
748
- current_offset,
749
- )
750
-
751
-
752
- # Type aliases for convenience
753
- TileDevice = TileStateDevice # Pythonic alias
754
-
755
- # Field name mappings: Python name -> Protocol name
756
- # Used by serializer to translate between conventions
757
- FIELD_MAPPINGS: dict[str, dict[str, str]] = {
758
- "DeviceStateHostFirmware": {
759
- "build": "Build",
760
- "version_minor": "VersionMinor",
761
- "version_major": "VersionMajor",
762
- },
763
- "DeviceStateVersion": {"vendor": "Vendor", "product": "Product"},
764
- "LightHsbk": {
765
- "hue": "Hue",
766
- "saturation": "Saturation",
767
- "brightness": "Brightness",
768
- "kelvin": "Kelvin",
769
- },
770
- "MultiZoneEffectParameter": {
771
- "parameter0": "Parameter0",
772
- "parameter1": "Parameter1",
773
- "parameter2": "Parameter2",
774
- "parameter3": "Parameter3",
775
- "parameter4": "Parameter4",
776
- "parameter5": "Parameter5",
777
- "parameter6": "Parameter6",
778
- "parameter7": "Parameter7",
779
- },
780
- "MultiZoneEffectSettings": {
781
- "duration": "Duration",
782
- "instanceid": "Instanceid",
783
- "parameter": "Parameter",
784
- "speed": "Speed",
785
- "type": "Type",
786
- },
787
- "TileAccelMeas": {"x": "X", "y": "Y", "z": "Z"},
788
- "TileBufferRect": {"fb_index": "FbIndex", "x": "X", "y": "Y", "width": "Width"},
789
- "TileEffectParameter": {
790
- "parameter0": "Parameter0",
791
- "parameter1": "Parameter1",
792
- "parameter2": "Parameter2",
793
- "parameter3": "Parameter3",
794
- "parameter4": "Parameter4",
795
- "parameter5": "Parameter5",
796
- "parameter6": "Parameter6",
797
- "parameter7": "Parameter7",
798
- },
799
- "TileEffectSettings": {
800
- "duration": "Duration",
801
- "instanceid": "Instanceid",
802
- "palette": "Palette",
803
- "palette_count": "PaletteCount",
804
- "parameter": "Parameter",
805
- "speed": "Speed",
806
- "type": "Type",
807
- },
808
- "TileStateDevice": {
809
- "accel_meas": "AccelMeas",
810
- "device_version": "DeviceVersion",
811
- "firmware": "Firmware",
812
- "height": "Height",
813
- "user_x": "UserX",
814
- "user_y": "UserY",
815
- "width": "Width",
816
- },
817
- }