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,1446 @@
1
+ """LIFX product definitions and capability detection.
2
+
3
+ DO NOT EDIT THIS FILE MANUALLY.
4
+ Generated from https://github.com/LIFX/products/blob/master/products.json
5
+ by products/generator.py
6
+
7
+ This module provides pre-generated product information for efficient runtime lookups.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+ from enum import IntEnum
14
+
15
+
16
+ class ProductCapability(IntEnum):
17
+ """Product capability flags."""
18
+
19
+ COLOR = 1
20
+ INFRARED = 2
21
+ MULTIZONE = 4
22
+ CHAIN = 8
23
+ MATRIX = 16
24
+ RELAYS = 32
25
+ BUTTONS = 64
26
+ HEV = 128
27
+ EXTENDED_MULTIZONE = 256
28
+
29
+
30
+ @dataclass
31
+ class TemperatureRange:
32
+ """Color temperature range in Kelvin."""
33
+
34
+ min: int
35
+ max: int
36
+
37
+
38
+ @dataclass
39
+ class ProductInfo:
40
+ """Information about a LIFX product.
41
+
42
+ Attributes:
43
+ pid: Product ID
44
+ name: Product name
45
+ vendor: Vendor ID (always 1 for LIFX)
46
+ capabilities: Bitfield of ProductCapability flags
47
+ temperature_range: Min/max color temperature in Kelvin
48
+ min_ext_mz_firmware: Minimum firmware version for extended multizone
49
+ """
50
+
51
+ pid: int
52
+ name: str
53
+ vendor: int
54
+ capabilities: int
55
+ temperature_range: TemperatureRange | None
56
+ min_ext_mz_firmware: int | None
57
+
58
+ def has_capability(self, capability: ProductCapability) -> bool:
59
+ """Check if product has a specific capability.
60
+
61
+ Args:
62
+ capability: Capability to check
63
+
64
+ Returns:
65
+ True if product has the capability
66
+ """
67
+ return bool(self.capabilities & capability)
68
+
69
+ @property
70
+ def has_color(self) -> bool:
71
+ """Check if product supports color."""
72
+ return self.has_capability(ProductCapability.COLOR)
73
+
74
+ @property
75
+ def has_infrared(self) -> bool:
76
+ """Check if product supports infrared."""
77
+ return self.has_capability(ProductCapability.INFRARED)
78
+
79
+ @property
80
+ def has_multizone(self) -> bool:
81
+ """Check if product supports multizone."""
82
+ return self.has_capability(ProductCapability.MULTIZONE)
83
+
84
+ @property
85
+ def has_chain(self) -> bool:
86
+ """Check if product supports chaining."""
87
+ return self.has_capability(ProductCapability.CHAIN)
88
+
89
+ @property
90
+ def has_matrix(self) -> bool:
91
+ """Check if product supports matrix (2D grid)."""
92
+ return self.has_capability(ProductCapability.MATRIX)
93
+
94
+ @property
95
+ def has_relays(self) -> bool:
96
+ """Check if product has relays."""
97
+ return self.has_capability(ProductCapability.RELAYS)
98
+
99
+ @property
100
+ def has_buttons(self) -> bool:
101
+ """Check if product has buttons."""
102
+ return self.has_capability(ProductCapability.BUTTONS)
103
+
104
+ @property
105
+ def has_hev(self) -> bool:
106
+ """Check if product supports HEV."""
107
+ return self.has_capability(ProductCapability.HEV)
108
+
109
+ @property
110
+ def has_extended_multizone(self) -> bool:
111
+ """Check if product supports extended multizone."""
112
+ return self.has_capability(ProductCapability.EXTENDED_MULTIZONE)
113
+
114
+ def supports_extended_multizone(self, firmware_version: int | None = None) -> bool:
115
+ """Check if extended multizone is supported for given firmware version.
116
+
117
+ Args:
118
+ firmware_version: Firmware version to check (optional)
119
+
120
+ Returns:
121
+ True if extended multizone is supported
122
+ """
123
+ if not self.has_extended_multizone:
124
+ return False
125
+ if self.min_ext_mz_firmware is None:
126
+ return True
127
+ if firmware_version is None:
128
+ return True
129
+ return firmware_version >= self.min_ext_mz_firmware
130
+
131
+
132
+ # Pre-generated product definitions
133
+ PRODUCTS: dict[int, ProductInfo] = {
134
+ 1: ProductInfo(
135
+ pid=1,
136
+ name="LIFX Original 1000",
137
+ vendor=1,
138
+ capabilities=ProductCapability.COLOR,
139
+ temperature_range=TemperatureRange(min=2500, max=9000),
140
+ min_ext_mz_firmware=None,
141
+ ),
142
+ 3: ProductInfo(
143
+ pid=3,
144
+ name="LIFX Color 650",
145
+ vendor=1,
146
+ capabilities=ProductCapability.COLOR,
147
+ temperature_range=TemperatureRange(min=2500, max=9000),
148
+ min_ext_mz_firmware=None,
149
+ ),
150
+ 10: ProductInfo(
151
+ pid=10,
152
+ name="LIFX White 800 (Low Voltage)",
153
+ vendor=1,
154
+ capabilities=0,
155
+ temperature_range=TemperatureRange(min=2700, max=6500),
156
+ min_ext_mz_firmware=None,
157
+ ),
158
+ 11: ProductInfo(
159
+ pid=11,
160
+ name="LIFX White 800 (High Voltage)",
161
+ vendor=1,
162
+ capabilities=0,
163
+ temperature_range=TemperatureRange(min=2700, max=6500),
164
+ min_ext_mz_firmware=None,
165
+ ),
166
+ 15: ProductInfo(
167
+ pid=15,
168
+ name="LIFX Color 1000",
169
+ vendor=1,
170
+ capabilities=ProductCapability.COLOR,
171
+ temperature_range=TemperatureRange(min=2500, max=9000),
172
+ min_ext_mz_firmware=None,
173
+ ),
174
+ 18: ProductInfo(
175
+ pid=18,
176
+ name="LIFX White 900 BR30 (Low Voltage)",
177
+ vendor=1,
178
+ capabilities=0,
179
+ temperature_range=TemperatureRange(min=2500, max=9000),
180
+ min_ext_mz_firmware=None,
181
+ ),
182
+ 19: ProductInfo(
183
+ pid=19,
184
+ name="LIFX White 900 BR30 (High Voltage)",
185
+ vendor=1,
186
+ capabilities=0,
187
+ temperature_range=TemperatureRange(min=2500, max=9000),
188
+ min_ext_mz_firmware=None,
189
+ ),
190
+ 20: ProductInfo(
191
+ pid=20,
192
+ name="LIFX Color 1000 BR30",
193
+ vendor=1,
194
+ capabilities=ProductCapability.COLOR,
195
+ temperature_range=TemperatureRange(min=2500, max=9000),
196
+ min_ext_mz_firmware=None,
197
+ ),
198
+ 22: ProductInfo(
199
+ pid=22,
200
+ name="LIFX Color 1000",
201
+ vendor=1,
202
+ capabilities=ProductCapability.COLOR,
203
+ temperature_range=TemperatureRange(min=2500, max=9000),
204
+ min_ext_mz_firmware=None,
205
+ ),
206
+ 27: ProductInfo(
207
+ pid=27,
208
+ name="LIFX A19",
209
+ vendor=1,
210
+ capabilities=ProductCapability.COLOR,
211
+ temperature_range=TemperatureRange(min=2500, max=9000),
212
+ min_ext_mz_firmware=None,
213
+ ),
214
+ 28: ProductInfo(
215
+ pid=28,
216
+ name="LIFX BR30",
217
+ vendor=1,
218
+ capabilities=ProductCapability.COLOR,
219
+ temperature_range=TemperatureRange(min=2500, max=9000),
220
+ min_ext_mz_firmware=None,
221
+ ),
222
+ 29: ProductInfo(
223
+ pid=29,
224
+ name="LIFX A19 Night Vision",
225
+ vendor=1,
226
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
227
+ temperature_range=TemperatureRange(min=2500, max=9000),
228
+ min_ext_mz_firmware=None,
229
+ ),
230
+ 30: ProductInfo(
231
+ pid=30,
232
+ name="LIFX BR30 Night Vision",
233
+ vendor=1,
234
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
235
+ temperature_range=TemperatureRange(min=2500, max=9000),
236
+ min_ext_mz_firmware=None,
237
+ ),
238
+ 31: ProductInfo(
239
+ pid=31,
240
+ name="LIFX Z",
241
+ vendor=1,
242
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
243
+ temperature_range=TemperatureRange(min=2500, max=9000),
244
+ min_ext_mz_firmware=None,
245
+ ),
246
+ 32: ProductInfo(
247
+ pid=32,
248
+ name="LIFX Z",
249
+ vendor=1,
250
+ capabilities=ProductCapability.COLOR
251
+ | ProductCapability.MULTIZONE
252
+ | ProductCapability.EXTENDED_MULTIZONE,
253
+ temperature_range=TemperatureRange(min=2500, max=9000),
254
+ min_ext_mz_firmware=131149,
255
+ ),
256
+ 36: ProductInfo(
257
+ pid=36,
258
+ name="LIFX Downlight",
259
+ vendor=1,
260
+ capabilities=ProductCapability.COLOR,
261
+ temperature_range=TemperatureRange(min=2500, max=9000),
262
+ min_ext_mz_firmware=None,
263
+ ),
264
+ 37: ProductInfo(
265
+ pid=37,
266
+ name="LIFX Downlight",
267
+ vendor=1,
268
+ capabilities=ProductCapability.COLOR,
269
+ temperature_range=TemperatureRange(min=2500, max=9000),
270
+ min_ext_mz_firmware=None,
271
+ ),
272
+ 38: ProductInfo(
273
+ pid=38,
274
+ name="LIFX Beam",
275
+ vendor=1,
276
+ capabilities=ProductCapability.COLOR
277
+ | ProductCapability.MULTIZONE
278
+ | ProductCapability.EXTENDED_MULTIZONE,
279
+ temperature_range=TemperatureRange(min=2500, max=9000),
280
+ min_ext_mz_firmware=131149,
281
+ ),
282
+ 39: ProductInfo(
283
+ pid=39,
284
+ name="LIFX Downlight White to Warm",
285
+ vendor=1,
286
+ capabilities=0,
287
+ temperature_range=TemperatureRange(min=2500, max=9000),
288
+ min_ext_mz_firmware=None,
289
+ ),
290
+ 40: ProductInfo(
291
+ pid=40,
292
+ name="LIFX Downlight",
293
+ vendor=1,
294
+ capabilities=ProductCapability.COLOR,
295
+ temperature_range=TemperatureRange(min=2500, max=9000),
296
+ min_ext_mz_firmware=None,
297
+ ),
298
+ 43: ProductInfo(
299
+ pid=43,
300
+ name="LIFX A19",
301
+ vendor=1,
302
+ capabilities=ProductCapability.COLOR,
303
+ temperature_range=TemperatureRange(min=2500, max=9000),
304
+ min_ext_mz_firmware=None,
305
+ ),
306
+ 44: ProductInfo(
307
+ pid=44,
308
+ name="LIFX BR30",
309
+ vendor=1,
310
+ capabilities=ProductCapability.COLOR,
311
+ temperature_range=TemperatureRange(min=2500, max=9000),
312
+ min_ext_mz_firmware=None,
313
+ ),
314
+ 45: ProductInfo(
315
+ pid=45,
316
+ name="LIFX A19 Night Vision",
317
+ vendor=1,
318
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
319
+ temperature_range=TemperatureRange(min=2500, max=9000),
320
+ min_ext_mz_firmware=None,
321
+ ),
322
+ 46: ProductInfo(
323
+ pid=46,
324
+ name="LIFX BR30 Night Vision",
325
+ vendor=1,
326
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
327
+ temperature_range=TemperatureRange(min=2500, max=9000),
328
+ min_ext_mz_firmware=None,
329
+ ),
330
+ 49: ProductInfo(
331
+ pid=49,
332
+ name="LIFX Mini Color",
333
+ vendor=1,
334
+ capabilities=ProductCapability.COLOR,
335
+ temperature_range=TemperatureRange(min=1500, max=9000),
336
+ min_ext_mz_firmware=None,
337
+ ),
338
+ 50: ProductInfo(
339
+ pid=50,
340
+ name="LIFX Mini White to Warm",
341
+ vendor=1,
342
+ capabilities=0,
343
+ temperature_range=TemperatureRange(min=1500, max=6500),
344
+ min_ext_mz_firmware=None,
345
+ ),
346
+ 51: ProductInfo(
347
+ pid=51,
348
+ name="LIFX Mini White",
349
+ vendor=1,
350
+ capabilities=0,
351
+ temperature_range=TemperatureRange(min=2700, max=2700),
352
+ min_ext_mz_firmware=None,
353
+ ),
354
+ 52: ProductInfo(
355
+ pid=52,
356
+ name="LIFX GU10",
357
+ vendor=1,
358
+ capabilities=ProductCapability.COLOR,
359
+ temperature_range=TemperatureRange(min=1500, max=9000),
360
+ min_ext_mz_firmware=None,
361
+ ),
362
+ 53: ProductInfo(
363
+ pid=53,
364
+ name="LIFX GU10",
365
+ vendor=1,
366
+ capabilities=ProductCapability.COLOR,
367
+ temperature_range=TemperatureRange(min=1500, max=9000),
368
+ min_ext_mz_firmware=None,
369
+ ),
370
+ 55: ProductInfo(
371
+ pid=55,
372
+ name="LIFX Tile",
373
+ vendor=1,
374
+ capabilities=ProductCapability.COLOR
375
+ | ProductCapability.CHAIN
376
+ | ProductCapability.MATRIX,
377
+ temperature_range=TemperatureRange(min=2500, max=9000),
378
+ min_ext_mz_firmware=None,
379
+ ),
380
+ 57: ProductInfo(
381
+ pid=57,
382
+ name="LIFX Candle",
383
+ vendor=1,
384
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
385
+ temperature_range=TemperatureRange(min=1500, max=9000),
386
+ min_ext_mz_firmware=None,
387
+ ),
388
+ 59: ProductInfo(
389
+ pid=59,
390
+ name="LIFX Mini Color",
391
+ vendor=1,
392
+ capabilities=ProductCapability.COLOR,
393
+ temperature_range=TemperatureRange(min=1500, max=9000),
394
+ min_ext_mz_firmware=None,
395
+ ),
396
+ 60: ProductInfo(
397
+ pid=60,
398
+ name="LIFX Mini White to Warm",
399
+ vendor=1,
400
+ capabilities=0,
401
+ temperature_range=TemperatureRange(min=1500, max=6500),
402
+ min_ext_mz_firmware=None,
403
+ ),
404
+ 61: ProductInfo(
405
+ pid=61,
406
+ name="LIFX Mini White",
407
+ vendor=1,
408
+ capabilities=0,
409
+ temperature_range=TemperatureRange(min=2700, max=2700),
410
+ min_ext_mz_firmware=None,
411
+ ),
412
+ 62: ProductInfo(
413
+ pid=62,
414
+ name="LIFX A19",
415
+ vendor=1,
416
+ capabilities=ProductCapability.COLOR,
417
+ temperature_range=TemperatureRange(min=1500, max=9000),
418
+ min_ext_mz_firmware=None,
419
+ ),
420
+ 63: ProductInfo(
421
+ pid=63,
422
+ name="LIFX BR30",
423
+ vendor=1,
424
+ capabilities=ProductCapability.COLOR,
425
+ temperature_range=TemperatureRange(min=1500, max=9000),
426
+ min_ext_mz_firmware=None,
427
+ ),
428
+ 64: ProductInfo(
429
+ pid=64,
430
+ name="LIFX A19 Night Vision",
431
+ vendor=1,
432
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
433
+ temperature_range=TemperatureRange(min=1500, max=9000),
434
+ min_ext_mz_firmware=None,
435
+ ),
436
+ 65: ProductInfo(
437
+ pid=65,
438
+ name="LIFX BR30 Night Vision",
439
+ vendor=1,
440
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
441
+ temperature_range=TemperatureRange(min=1500, max=9000),
442
+ min_ext_mz_firmware=None,
443
+ ),
444
+ 66: ProductInfo(
445
+ pid=66,
446
+ name="LIFX Mini White",
447
+ vendor=1,
448
+ capabilities=0,
449
+ temperature_range=TemperatureRange(min=2700, max=2700),
450
+ min_ext_mz_firmware=None,
451
+ ),
452
+ 68: ProductInfo(
453
+ pid=68,
454
+ name="LIFX Candle",
455
+ vendor=1,
456
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
457
+ temperature_range=TemperatureRange(min=1500, max=9000),
458
+ min_ext_mz_firmware=None,
459
+ ),
460
+ 70: ProductInfo(
461
+ pid=70,
462
+ name="LIFX Switch",
463
+ vendor=1,
464
+ capabilities=ProductCapability.RELAYS | ProductCapability.BUTTONS,
465
+ temperature_range=None,
466
+ min_ext_mz_firmware=None,
467
+ ),
468
+ 71: ProductInfo(
469
+ pid=71,
470
+ name="LIFX Switch",
471
+ vendor=1,
472
+ capabilities=ProductCapability.RELAYS | ProductCapability.BUTTONS,
473
+ temperature_range=None,
474
+ min_ext_mz_firmware=None,
475
+ ),
476
+ 81: ProductInfo(
477
+ pid=81,
478
+ name="LIFX Candle White to Warm",
479
+ vendor=1,
480
+ capabilities=0,
481
+ temperature_range=TemperatureRange(min=2200, max=6500),
482
+ min_ext_mz_firmware=None,
483
+ ),
484
+ 82: ProductInfo(
485
+ pid=82,
486
+ name="LIFX Filament Clear",
487
+ vendor=1,
488
+ capabilities=0,
489
+ temperature_range=TemperatureRange(min=2100, max=2100),
490
+ min_ext_mz_firmware=None,
491
+ ),
492
+ 85: ProductInfo(
493
+ pid=85,
494
+ name="LIFX Filament Amber",
495
+ vendor=1,
496
+ capabilities=0,
497
+ temperature_range=TemperatureRange(min=2000, max=2000),
498
+ min_ext_mz_firmware=None,
499
+ ),
500
+ 87: ProductInfo(
501
+ pid=87,
502
+ name="LIFX Mini White",
503
+ vendor=1,
504
+ capabilities=0,
505
+ temperature_range=TemperatureRange(min=2700, max=2700),
506
+ min_ext_mz_firmware=None,
507
+ ),
508
+ 88: ProductInfo(
509
+ pid=88,
510
+ name="LIFX Mini White",
511
+ vendor=1,
512
+ capabilities=0,
513
+ temperature_range=TemperatureRange(min=2700, max=2700),
514
+ min_ext_mz_firmware=None,
515
+ ),
516
+ 89: ProductInfo(
517
+ pid=89,
518
+ name="LIFX Switch",
519
+ vendor=1,
520
+ capabilities=ProductCapability.RELAYS | ProductCapability.BUTTONS,
521
+ temperature_range=None,
522
+ min_ext_mz_firmware=None,
523
+ ),
524
+ 90: ProductInfo(
525
+ pid=90,
526
+ name="LIFX Clean",
527
+ vendor=1,
528
+ capabilities=ProductCapability.COLOR | ProductCapability.HEV,
529
+ temperature_range=TemperatureRange(min=1500, max=9000),
530
+ min_ext_mz_firmware=None,
531
+ ),
532
+ 91: ProductInfo(
533
+ pid=91,
534
+ name="LIFX Color",
535
+ vendor=1,
536
+ capabilities=ProductCapability.COLOR,
537
+ temperature_range=TemperatureRange(min=1500, max=9000),
538
+ min_ext_mz_firmware=None,
539
+ ),
540
+ 92: ProductInfo(
541
+ pid=92,
542
+ name="LIFX Color",
543
+ vendor=1,
544
+ capabilities=ProductCapability.COLOR,
545
+ temperature_range=TemperatureRange(min=1500, max=9000),
546
+ min_ext_mz_firmware=None,
547
+ ),
548
+ 93: ProductInfo(
549
+ pid=93,
550
+ name="LIFX A19 US",
551
+ vendor=1,
552
+ capabilities=ProductCapability.COLOR,
553
+ temperature_range=TemperatureRange(min=1500, max=9000),
554
+ min_ext_mz_firmware=None,
555
+ ),
556
+ 94: ProductInfo(
557
+ pid=94,
558
+ name="LIFX BR30",
559
+ vendor=1,
560
+ capabilities=ProductCapability.COLOR,
561
+ temperature_range=TemperatureRange(min=1500, max=9000),
562
+ min_ext_mz_firmware=None,
563
+ ),
564
+ 96: ProductInfo(
565
+ pid=96,
566
+ name="LIFX Candle White to Warm",
567
+ vendor=1,
568
+ capabilities=0,
569
+ temperature_range=TemperatureRange(min=2200, max=6500),
570
+ min_ext_mz_firmware=None,
571
+ ),
572
+ 97: ProductInfo(
573
+ pid=97,
574
+ name="LIFX A19",
575
+ vendor=1,
576
+ capabilities=ProductCapability.COLOR,
577
+ temperature_range=TemperatureRange(min=1500, max=9000),
578
+ min_ext_mz_firmware=None,
579
+ ),
580
+ 98: ProductInfo(
581
+ pid=98,
582
+ name="LIFX BR30",
583
+ vendor=1,
584
+ capabilities=ProductCapability.COLOR,
585
+ temperature_range=TemperatureRange(min=1500, max=9000),
586
+ min_ext_mz_firmware=None,
587
+ ),
588
+ 99: ProductInfo(
589
+ pid=99,
590
+ name="LIFX Clean",
591
+ vendor=1,
592
+ capabilities=ProductCapability.COLOR | ProductCapability.HEV,
593
+ temperature_range=TemperatureRange(min=1500, max=9000),
594
+ min_ext_mz_firmware=None,
595
+ ),
596
+ 100: ProductInfo(
597
+ pid=100,
598
+ name="LIFX Filament Clear",
599
+ vendor=1,
600
+ capabilities=0,
601
+ temperature_range=TemperatureRange(min=2100, max=2100),
602
+ min_ext_mz_firmware=None,
603
+ ),
604
+ 101: ProductInfo(
605
+ pid=101,
606
+ name="LIFX Filament Amber",
607
+ vendor=1,
608
+ capabilities=0,
609
+ temperature_range=TemperatureRange(min=2000, max=2000),
610
+ min_ext_mz_firmware=None,
611
+ ),
612
+ 109: ProductInfo(
613
+ pid=109,
614
+ name="LIFX A19 Night Vision",
615
+ vendor=1,
616
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
617
+ temperature_range=TemperatureRange(min=1500, max=9000),
618
+ min_ext_mz_firmware=None,
619
+ ),
620
+ 110: ProductInfo(
621
+ pid=110,
622
+ name="LIFX BR30 Night Vision",
623
+ vendor=1,
624
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
625
+ temperature_range=TemperatureRange(min=1500, max=9000),
626
+ min_ext_mz_firmware=None,
627
+ ),
628
+ 111: ProductInfo(
629
+ pid=111,
630
+ name="LIFX A19 Night Vision",
631
+ vendor=1,
632
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
633
+ temperature_range=TemperatureRange(min=1500, max=9000),
634
+ min_ext_mz_firmware=None,
635
+ ),
636
+ 112: ProductInfo(
637
+ pid=112,
638
+ name="LIFX BR30 Night Vision Intl",
639
+ vendor=1,
640
+ capabilities=ProductCapability.COLOR | ProductCapability.INFRARED,
641
+ temperature_range=TemperatureRange(min=1500, max=9000),
642
+ min_ext_mz_firmware=None,
643
+ ),
644
+ 113: ProductInfo(
645
+ pid=113,
646
+ name="LIFX Mini WW US",
647
+ vendor=1,
648
+ capabilities=0,
649
+ temperature_range=TemperatureRange(min=1500, max=9000),
650
+ min_ext_mz_firmware=None,
651
+ ),
652
+ 114: ProductInfo(
653
+ pid=114,
654
+ name="LIFX Mini WW Intl",
655
+ vendor=1,
656
+ capabilities=0,
657
+ temperature_range=TemperatureRange(min=1500, max=9000),
658
+ min_ext_mz_firmware=None,
659
+ ),
660
+ 115: ProductInfo(
661
+ pid=115,
662
+ name="LIFX Switch",
663
+ vendor=1,
664
+ capabilities=ProductCapability.RELAYS | ProductCapability.BUTTONS,
665
+ temperature_range=None,
666
+ min_ext_mz_firmware=None,
667
+ ),
668
+ 116: ProductInfo(
669
+ pid=116,
670
+ name="LIFX Switch",
671
+ vendor=1,
672
+ capabilities=ProductCapability.RELAYS | ProductCapability.BUTTONS,
673
+ temperature_range=None,
674
+ min_ext_mz_firmware=None,
675
+ ),
676
+ 117: ProductInfo(
677
+ pid=117,
678
+ name="LIFX Z US",
679
+ vendor=1,
680
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
681
+ temperature_range=TemperatureRange(min=1500, max=9000),
682
+ min_ext_mz_firmware=None,
683
+ ),
684
+ 118: ProductInfo(
685
+ pid=118,
686
+ name="LIFX Z Intl",
687
+ vendor=1,
688
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
689
+ temperature_range=TemperatureRange(min=1500, max=9000),
690
+ min_ext_mz_firmware=None,
691
+ ),
692
+ 119: ProductInfo(
693
+ pid=119,
694
+ name="LIFX Beam US",
695
+ vendor=1,
696
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
697
+ temperature_range=TemperatureRange(min=1500, max=9000),
698
+ min_ext_mz_firmware=None,
699
+ ),
700
+ 120: ProductInfo(
701
+ pid=120,
702
+ name="LIFX Beam Intl",
703
+ vendor=1,
704
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
705
+ temperature_range=TemperatureRange(min=1500, max=9000),
706
+ min_ext_mz_firmware=None,
707
+ ),
708
+ 121: ProductInfo(
709
+ pid=121,
710
+ name="LIFX Downlight Intl",
711
+ vendor=1,
712
+ capabilities=ProductCapability.COLOR,
713
+ temperature_range=TemperatureRange(min=1500, max=9000),
714
+ min_ext_mz_firmware=None,
715
+ ),
716
+ 122: ProductInfo(
717
+ pid=122,
718
+ name="LIFX Downlight US",
719
+ vendor=1,
720
+ capabilities=ProductCapability.COLOR,
721
+ temperature_range=TemperatureRange(min=1500, max=9000),
722
+ min_ext_mz_firmware=None,
723
+ ),
724
+ 123: ProductInfo(
725
+ pid=123,
726
+ name="LIFX Color US",
727
+ vendor=1,
728
+ capabilities=ProductCapability.COLOR,
729
+ temperature_range=TemperatureRange(min=1500, max=9000),
730
+ min_ext_mz_firmware=None,
731
+ ),
732
+ 124: ProductInfo(
733
+ pid=124,
734
+ name="LIFX Colour Intl",
735
+ vendor=1,
736
+ capabilities=ProductCapability.COLOR,
737
+ temperature_range=TemperatureRange(min=1500, max=9000),
738
+ min_ext_mz_firmware=None,
739
+ ),
740
+ 125: ProductInfo(
741
+ pid=125,
742
+ name="LIFX White to Warm US",
743
+ vendor=1,
744
+ capabilities=0,
745
+ temperature_range=TemperatureRange(min=1500, max=9000),
746
+ min_ext_mz_firmware=None,
747
+ ),
748
+ 126: ProductInfo(
749
+ pid=126,
750
+ name="LIFX White to Warm Intl",
751
+ vendor=1,
752
+ capabilities=0,
753
+ temperature_range=TemperatureRange(min=1500, max=9000),
754
+ min_ext_mz_firmware=None,
755
+ ),
756
+ 127: ProductInfo(
757
+ pid=127,
758
+ name="LIFX White US",
759
+ vendor=1,
760
+ capabilities=0,
761
+ temperature_range=TemperatureRange(min=2700, max=2700),
762
+ min_ext_mz_firmware=None,
763
+ ),
764
+ 128: ProductInfo(
765
+ pid=128,
766
+ name="LIFX White Intl",
767
+ vendor=1,
768
+ capabilities=0,
769
+ temperature_range=TemperatureRange(min=2700, max=2700),
770
+ min_ext_mz_firmware=None,
771
+ ),
772
+ 129: ProductInfo(
773
+ pid=129,
774
+ name="LIFX Color US",
775
+ vendor=1,
776
+ capabilities=ProductCapability.COLOR,
777
+ temperature_range=TemperatureRange(min=1500, max=9000),
778
+ min_ext_mz_firmware=None,
779
+ ),
780
+ 130: ProductInfo(
781
+ pid=130,
782
+ name="LIFX Colour Intl",
783
+ vendor=1,
784
+ capabilities=ProductCapability.COLOR,
785
+ temperature_range=TemperatureRange(min=1500, max=9000),
786
+ min_ext_mz_firmware=None,
787
+ ),
788
+ 131: ProductInfo(
789
+ pid=131,
790
+ name="LIFX White To Warm US",
791
+ vendor=1,
792
+ capabilities=0,
793
+ temperature_range=TemperatureRange(min=1500, max=9000),
794
+ min_ext_mz_firmware=None,
795
+ ),
796
+ 132: ProductInfo(
797
+ pid=132,
798
+ name="LIFX White To Warm Intl",
799
+ vendor=1,
800
+ capabilities=0,
801
+ temperature_range=TemperatureRange(min=1500, max=9000),
802
+ min_ext_mz_firmware=None,
803
+ ),
804
+ 133: ProductInfo(
805
+ pid=133,
806
+ name="LIFX White US",
807
+ vendor=1,
808
+ capabilities=0,
809
+ temperature_range=TemperatureRange(min=2700, max=2700),
810
+ min_ext_mz_firmware=None,
811
+ ),
812
+ 134: ProductInfo(
813
+ pid=134,
814
+ name="LIFX White Intl",
815
+ vendor=1,
816
+ capabilities=0,
817
+ temperature_range=TemperatureRange(min=2700, max=2700),
818
+ min_ext_mz_firmware=None,
819
+ ),
820
+ 135: ProductInfo(
821
+ pid=135,
822
+ name="LIFX GU10 Color US",
823
+ vendor=1,
824
+ capabilities=ProductCapability.COLOR,
825
+ temperature_range=TemperatureRange(min=1500, max=9000),
826
+ min_ext_mz_firmware=None,
827
+ ),
828
+ 136: ProductInfo(
829
+ pid=136,
830
+ name="LIFX GU10 Colour Intl",
831
+ vendor=1,
832
+ capabilities=ProductCapability.COLOR,
833
+ temperature_range=TemperatureRange(min=1500, max=9000),
834
+ min_ext_mz_firmware=None,
835
+ ),
836
+ 137: ProductInfo(
837
+ pid=137,
838
+ name="LIFX Candle Color US",
839
+ vendor=1,
840
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
841
+ temperature_range=TemperatureRange(min=1500, max=9000),
842
+ min_ext_mz_firmware=None,
843
+ ),
844
+ 138: ProductInfo(
845
+ pid=138,
846
+ name="LIFX Candle Colour Intl",
847
+ vendor=1,
848
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
849
+ temperature_range=TemperatureRange(min=1500, max=9000),
850
+ min_ext_mz_firmware=None,
851
+ ),
852
+ 141: ProductInfo(
853
+ pid=141,
854
+ name="LIFX Neon US",
855
+ vendor=1,
856
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
857
+ temperature_range=TemperatureRange(min=1500, max=9000),
858
+ min_ext_mz_firmware=None,
859
+ ),
860
+ 142: ProductInfo(
861
+ pid=142,
862
+ name="LIFX Neon Intl",
863
+ vendor=1,
864
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
865
+ temperature_range=TemperatureRange(min=1500, max=9000),
866
+ min_ext_mz_firmware=None,
867
+ ),
868
+ 143: ProductInfo(
869
+ pid=143,
870
+ name="LIFX String US",
871
+ vendor=1,
872
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
873
+ temperature_range=TemperatureRange(min=1500, max=9000),
874
+ min_ext_mz_firmware=None,
875
+ ),
876
+ 144: ProductInfo(
877
+ pid=144,
878
+ name="LIFX String Intl",
879
+ vendor=1,
880
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
881
+ temperature_range=TemperatureRange(min=1500, max=9000),
882
+ min_ext_mz_firmware=None,
883
+ ),
884
+ 161: ProductInfo(
885
+ pid=161,
886
+ name="LIFX Outdoor Neon US",
887
+ vendor=1,
888
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
889
+ temperature_range=TemperatureRange(min=1500, max=9000),
890
+ min_ext_mz_firmware=None,
891
+ ),
892
+ 162: ProductInfo(
893
+ pid=162,
894
+ name="LIFX Outdoor Neon Intl",
895
+ vendor=1,
896
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
897
+ temperature_range=TemperatureRange(min=1500, max=9000),
898
+ min_ext_mz_firmware=None,
899
+ ),
900
+ 163: ProductInfo(
901
+ pid=163,
902
+ name="LIFX A19 US",
903
+ vendor=1,
904
+ capabilities=ProductCapability.COLOR,
905
+ temperature_range=TemperatureRange(min=1500, max=9000),
906
+ min_ext_mz_firmware=None,
907
+ ),
908
+ 164: ProductInfo(
909
+ pid=164,
910
+ name="LIFX BR30 US",
911
+ vendor=1,
912
+ capabilities=ProductCapability.COLOR,
913
+ temperature_range=TemperatureRange(min=1500, max=9000),
914
+ min_ext_mz_firmware=None,
915
+ ),
916
+ 165: ProductInfo(
917
+ pid=165,
918
+ name="LIFX A19 Intl",
919
+ vendor=1,
920
+ capabilities=ProductCapability.COLOR,
921
+ temperature_range=TemperatureRange(min=1500, max=9000),
922
+ min_ext_mz_firmware=None,
923
+ ),
924
+ 166: ProductInfo(
925
+ pid=166,
926
+ name="LIFX BR30 Intl",
927
+ vendor=1,
928
+ capabilities=ProductCapability.COLOR,
929
+ temperature_range=TemperatureRange(min=1500, max=9000),
930
+ min_ext_mz_firmware=None,
931
+ ),
932
+ 167: ProductInfo(
933
+ pid=167,
934
+ name="LIFX Downlight",
935
+ vendor=1,
936
+ capabilities=ProductCapability.COLOR,
937
+ temperature_range=TemperatureRange(min=1500, max=9000),
938
+ min_ext_mz_firmware=None,
939
+ ),
940
+ 168: ProductInfo(
941
+ pid=168,
942
+ name="LIFX Downlight",
943
+ vendor=1,
944
+ capabilities=ProductCapability.COLOR,
945
+ temperature_range=TemperatureRange(min=1500, max=9000),
946
+ min_ext_mz_firmware=None,
947
+ ),
948
+ 169: ProductInfo(
949
+ pid=169,
950
+ name="LIFX A21 1600lm US",
951
+ vendor=1,
952
+ capabilities=ProductCapability.COLOR,
953
+ temperature_range=TemperatureRange(min=1500, max=9000),
954
+ min_ext_mz_firmware=None,
955
+ ),
956
+ 170: ProductInfo(
957
+ pid=170,
958
+ name="LIFX A21 1600lm Intl",
959
+ vendor=1,
960
+ capabilities=ProductCapability.COLOR,
961
+ temperature_range=TemperatureRange(min=1500, max=9000),
962
+ min_ext_mz_firmware=None,
963
+ ),
964
+ 171: ProductInfo(
965
+ pid=171,
966
+ name="LIFX Round Spot US",
967
+ vendor=1,
968
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
969
+ temperature_range=TemperatureRange(min=1500, max=9000),
970
+ min_ext_mz_firmware=None,
971
+ ),
972
+ 173: ProductInfo(
973
+ pid=173,
974
+ name="LIFX Round Path US",
975
+ vendor=1,
976
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
977
+ temperature_range=TemperatureRange(min=1500, max=9000),
978
+ min_ext_mz_firmware=None,
979
+ ),
980
+ 174: ProductInfo(
981
+ pid=174,
982
+ name="LIFX Square Path US",
983
+ vendor=1,
984
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
985
+ temperature_range=TemperatureRange(min=1500, max=9000),
986
+ min_ext_mz_firmware=None,
987
+ ),
988
+ 175: ProductInfo(
989
+ pid=175,
990
+ name="LIFX PAR38 US",
991
+ vendor=1,
992
+ capabilities=ProductCapability.COLOR,
993
+ temperature_range=TemperatureRange(min=1500, max=9000),
994
+ min_ext_mz_firmware=None,
995
+ ),
996
+ 176: ProductInfo(
997
+ pid=176,
998
+ name="LIFX Ceiling US",
999
+ vendor=1,
1000
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1001
+ temperature_range=TemperatureRange(min=1500, max=9000),
1002
+ min_ext_mz_firmware=None,
1003
+ ),
1004
+ 177: ProductInfo(
1005
+ pid=177,
1006
+ name="LIFX Ceiling Intl",
1007
+ vendor=1,
1008
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1009
+ temperature_range=TemperatureRange(min=1500, max=9000),
1010
+ min_ext_mz_firmware=None,
1011
+ ),
1012
+ 178: ProductInfo(
1013
+ pid=178,
1014
+ name="LIFX Downlight US",
1015
+ vendor=1,
1016
+ capabilities=ProductCapability.COLOR,
1017
+ temperature_range=TemperatureRange(min=1500, max=9000),
1018
+ min_ext_mz_firmware=None,
1019
+ ),
1020
+ 179: ProductInfo(
1021
+ pid=179,
1022
+ name="LIFX Downlight US",
1023
+ vendor=1,
1024
+ capabilities=ProductCapability.COLOR,
1025
+ temperature_range=TemperatureRange(min=1500, max=9000),
1026
+ min_ext_mz_firmware=None,
1027
+ ),
1028
+ 180: ProductInfo(
1029
+ pid=180,
1030
+ name="LIFX Downlight US",
1031
+ vendor=1,
1032
+ capabilities=ProductCapability.COLOR,
1033
+ temperature_range=TemperatureRange(min=1500, max=9000),
1034
+ min_ext_mz_firmware=None,
1035
+ ),
1036
+ 181: ProductInfo(
1037
+ pid=181,
1038
+ name="LIFX Color US",
1039
+ vendor=1,
1040
+ capabilities=ProductCapability.COLOR,
1041
+ temperature_range=TemperatureRange(min=1500, max=9000),
1042
+ min_ext_mz_firmware=None,
1043
+ ),
1044
+ 182: ProductInfo(
1045
+ pid=182,
1046
+ name="LIFX Colour Intl",
1047
+ vendor=1,
1048
+ capabilities=ProductCapability.COLOR,
1049
+ temperature_range=TemperatureRange(min=1500, max=9000),
1050
+ min_ext_mz_firmware=None,
1051
+ ),
1052
+ 185: ProductInfo(
1053
+ pid=185,
1054
+ name="LIFX Candle Color US",
1055
+ vendor=1,
1056
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1057
+ temperature_range=TemperatureRange(min=1500, max=9000),
1058
+ min_ext_mz_firmware=None,
1059
+ ),
1060
+ 186: ProductInfo(
1061
+ pid=186,
1062
+ name="LIFX Candle Colour Intl",
1063
+ vendor=1,
1064
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1065
+ temperature_range=TemperatureRange(min=1500, max=9000),
1066
+ min_ext_mz_firmware=None,
1067
+ ),
1068
+ 187: ProductInfo(
1069
+ pid=187,
1070
+ name="LIFX Candle Color US",
1071
+ vendor=1,
1072
+ capabilities=ProductCapability.COLOR,
1073
+ temperature_range=TemperatureRange(min=1500, max=9000),
1074
+ min_ext_mz_firmware=None,
1075
+ ),
1076
+ 188: ProductInfo(
1077
+ pid=188,
1078
+ name="LIFX Candle Colour Intl",
1079
+ vendor=1,
1080
+ capabilities=ProductCapability.COLOR,
1081
+ temperature_range=TemperatureRange(min=1500, max=9000),
1082
+ min_ext_mz_firmware=None,
1083
+ ),
1084
+ 201: ProductInfo(
1085
+ pid=201,
1086
+ name='LIFX Ceiling 13x26" US',
1087
+ vendor=1,
1088
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1089
+ temperature_range=TemperatureRange(min=1500, max=9000),
1090
+ min_ext_mz_firmware=None,
1091
+ ),
1092
+ 202: ProductInfo(
1093
+ pid=202,
1094
+ name='LIFX Ceiling 13x26" Intl',
1095
+ vendor=1,
1096
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1097
+ temperature_range=TemperatureRange(min=1500, max=9000),
1098
+ min_ext_mz_firmware=None,
1099
+ ),
1100
+ 203: ProductInfo(
1101
+ pid=203,
1102
+ name="LIFX String US",
1103
+ vendor=1,
1104
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
1105
+ temperature_range=TemperatureRange(min=1500, max=9000),
1106
+ min_ext_mz_firmware=None,
1107
+ ),
1108
+ 204: ProductInfo(
1109
+ pid=204,
1110
+ name="LIFX String Intl",
1111
+ vendor=1,
1112
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
1113
+ temperature_range=TemperatureRange(min=1500, max=9000),
1114
+ min_ext_mz_firmware=None,
1115
+ ),
1116
+ 205: ProductInfo(
1117
+ pid=205,
1118
+ name="LIFX Indoor Neon US",
1119
+ vendor=1,
1120
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
1121
+ temperature_range=TemperatureRange(min=1500, max=9000),
1122
+ min_ext_mz_firmware=None,
1123
+ ),
1124
+ 206: ProductInfo(
1125
+ pid=206,
1126
+ name="LIFX Indoor Neon Intl",
1127
+ vendor=1,
1128
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
1129
+ temperature_range=TemperatureRange(min=1500, max=9000),
1130
+ min_ext_mz_firmware=None,
1131
+ ),
1132
+ 213: ProductInfo(
1133
+ pid=213,
1134
+ name="LIFX Permanent Outdoor US",
1135
+ vendor=1,
1136
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
1137
+ temperature_range=TemperatureRange(min=1500, max=9000),
1138
+ min_ext_mz_firmware=None,
1139
+ ),
1140
+ 214: ProductInfo(
1141
+ pid=214,
1142
+ name="LIFX Permanent Outdoor Intl",
1143
+ vendor=1,
1144
+ capabilities=ProductCapability.COLOR | ProductCapability.MULTIZONE,
1145
+ temperature_range=TemperatureRange(min=1500, max=9000),
1146
+ min_ext_mz_firmware=None,
1147
+ ),
1148
+ 215: ProductInfo(
1149
+ pid=215,
1150
+ name="LIFX Candle Color US",
1151
+ vendor=1,
1152
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1153
+ temperature_range=TemperatureRange(min=1500, max=9000),
1154
+ min_ext_mz_firmware=None,
1155
+ ),
1156
+ 216: ProductInfo(
1157
+ pid=216,
1158
+ name="LIFX Candle Colour Intl",
1159
+ vendor=1,
1160
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1161
+ temperature_range=TemperatureRange(min=1500, max=9000),
1162
+ min_ext_mz_firmware=None,
1163
+ ),
1164
+ 217: ProductInfo(
1165
+ pid=217,
1166
+ name="LIFX Tube US",
1167
+ vendor=1,
1168
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1169
+ temperature_range=TemperatureRange(min=1500, max=9000),
1170
+ min_ext_mz_firmware=None,
1171
+ ),
1172
+ 218: ProductInfo(
1173
+ pid=218,
1174
+ name="LIFX Tube Intl",
1175
+ vendor=1,
1176
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1177
+ temperature_range=TemperatureRange(min=1500, max=9000),
1178
+ min_ext_mz_firmware=None,
1179
+ ),
1180
+ 219: ProductInfo(
1181
+ pid=219,
1182
+ name="LIFX Luna US",
1183
+ vendor=1,
1184
+ capabilities=ProductCapability.COLOR
1185
+ | ProductCapability.MATRIX
1186
+ | ProductCapability.BUTTONS,
1187
+ temperature_range=TemperatureRange(min=1500, max=9000),
1188
+ min_ext_mz_firmware=None,
1189
+ ),
1190
+ 220: ProductInfo(
1191
+ pid=220,
1192
+ name="LIFX Luna Intl",
1193
+ vendor=1,
1194
+ capabilities=ProductCapability.COLOR
1195
+ | ProductCapability.MATRIX
1196
+ | ProductCapability.BUTTONS,
1197
+ temperature_range=TemperatureRange(min=1500, max=9000),
1198
+ min_ext_mz_firmware=None,
1199
+ ),
1200
+ 221: ProductInfo(
1201
+ pid=221,
1202
+ name="LIFX Round Spot Intl",
1203
+ vendor=1,
1204
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1205
+ temperature_range=TemperatureRange(min=1500, max=9000),
1206
+ min_ext_mz_firmware=None,
1207
+ ),
1208
+ 222: ProductInfo(
1209
+ pid=222,
1210
+ name="LIFX Round Path Intl",
1211
+ vendor=1,
1212
+ capabilities=ProductCapability.COLOR | ProductCapability.MATRIX,
1213
+ temperature_range=TemperatureRange(min=1500, max=9000),
1214
+ min_ext_mz_firmware=None,
1215
+ ),
1216
+ 223: ProductInfo(
1217
+ pid=223,
1218
+ name="LIFX Downlight US",
1219
+ vendor=1,
1220
+ capabilities=ProductCapability.COLOR,
1221
+ temperature_range=TemperatureRange(min=1500, max=9000),
1222
+ min_ext_mz_firmware=None,
1223
+ ),
1224
+ 224: ProductInfo(
1225
+ pid=224,
1226
+ name="LIFX Downlight Intl",
1227
+ vendor=1,
1228
+ capabilities=ProductCapability.COLOR,
1229
+ temperature_range=TemperatureRange(min=1500, max=9000),
1230
+ min_ext_mz_firmware=None,
1231
+ ),
1232
+ 225: ProductInfo(
1233
+ pid=225,
1234
+ name="LIFX PAR38 INTL",
1235
+ vendor=1,
1236
+ capabilities=ProductCapability.COLOR,
1237
+ temperature_range=TemperatureRange(min=1500, max=9000),
1238
+ min_ext_mz_firmware=None,
1239
+ ),
1240
+ }
1241
+
1242
+
1243
+ class ProductRegistry:
1244
+ """Registry of LIFX products and their capabilities."""
1245
+
1246
+ def __init__(self) -> None:
1247
+ """Initialize product registry with pre-generated data."""
1248
+ self._products = PRODUCTS.copy() # Copy to allow test overrides
1249
+ self._loaded = True # Always loaded in generated registry
1250
+
1251
+ def load_from_dict(self, data: dict | list) -> None:
1252
+ """Load products from parsed JSON data (for testing).
1253
+
1254
+ Args:
1255
+ data: Parsed products.json dictionary or array
1256
+ """
1257
+ from typing import Any
1258
+
1259
+ # Clear existing products
1260
+ self._products.clear()
1261
+
1262
+ # Handle both array and object formats
1263
+ all_vendors = []
1264
+ if isinstance(data, list):
1265
+ all_vendors = data
1266
+ else:
1267
+ all_vendors = [data]
1268
+
1269
+ # Process each vendor
1270
+ for vendor_data in all_vendors:
1271
+ vendor_id = vendor_data.get("vid", 1)
1272
+ defaults = vendor_data.get("defaults", {})
1273
+ default_features = defaults.get("features", {})
1274
+
1275
+ # Parse each product
1276
+ for product in vendor_data.get("products", []):
1277
+ pid = product["pid"]
1278
+ name = product["name"]
1279
+
1280
+ # Merge features with defaults
1281
+ prod_features = product.get("features", {})
1282
+ features: dict[str, Any] = {**default_features, **prod_features}
1283
+
1284
+ # Build capabilities bitfield
1285
+ capabilities = 0
1286
+ if features.get("color"):
1287
+ capabilities |= ProductCapability.COLOR
1288
+ if features.get("infrared"):
1289
+ capabilities |= ProductCapability.INFRARED
1290
+ if features.get("multizone"):
1291
+ capabilities |= ProductCapability.MULTIZONE
1292
+ if features.get("chain"):
1293
+ capabilities |= ProductCapability.CHAIN
1294
+ if features.get("matrix"):
1295
+ capabilities |= ProductCapability.MATRIX
1296
+ if features.get("relays"):
1297
+ capabilities |= ProductCapability.RELAYS
1298
+ if features.get("buttons"):
1299
+ capabilities |= ProductCapability.BUTTONS
1300
+ if features.get("hev"):
1301
+ capabilities |= ProductCapability.HEV
1302
+
1303
+ # Check for extended multizone in upgrades
1304
+ min_ext_mz_firmware = None
1305
+ for upgrade in product.get("upgrades", []):
1306
+ if upgrade.get("features", {}).get("extended_multizone"):
1307
+ capabilities |= ProductCapability.EXTENDED_MULTIZONE
1308
+ # Parse firmware version (major.minor format)
1309
+ major = upgrade.get("major", 0)
1310
+ minor = upgrade.get("minor", 0)
1311
+ min_ext_mz_firmware = (major << 16) | minor
1312
+ break
1313
+
1314
+ # Parse temperature range
1315
+ temp_range = None
1316
+ if "temperature_range" in features:
1317
+ temp_list = features["temperature_range"]
1318
+ if len(temp_list) >= 2:
1319
+ temp_range = TemperatureRange(
1320
+ min=temp_list[0], max=temp_list[1]
1321
+ )
1322
+
1323
+ product_info = ProductInfo(
1324
+ pid=pid,
1325
+ name=name,
1326
+ vendor=vendor_id,
1327
+ capabilities=capabilities,
1328
+ temperature_range=temp_range,
1329
+ min_ext_mz_firmware=min_ext_mz_firmware,
1330
+ )
1331
+
1332
+ self._products[pid] = product_info
1333
+
1334
+ self._loaded = True
1335
+
1336
+ @property
1337
+ def is_loaded(self) -> bool:
1338
+ """Check if registry has been loaded."""
1339
+ return self._loaded
1340
+
1341
+ def get_product(self, pid: int) -> ProductInfo | None:
1342
+ """Get product info by product ID.
1343
+
1344
+ Args:
1345
+ pid: Product ID
1346
+
1347
+ Returns:
1348
+ ProductInfo if found, None otherwise
1349
+ """
1350
+ return self._products.get(pid)
1351
+
1352
+ def get_device_class_name(
1353
+ self, pid: int, firmware_version: int | None = None
1354
+ ) -> str:
1355
+ """Get appropriate device class name for a product.
1356
+
1357
+ Args:
1358
+ pid: Product ID
1359
+ firmware_version: Firmware version (optional)
1360
+
1361
+ Returns:
1362
+ Device class name: "TileDevice", "MultiZoneLight", "HevLight",
1363
+ "InfraredLight", "Light", or "Device"
1364
+ """
1365
+ product = self.get_product(pid)
1366
+ if product is None:
1367
+ # Unknown product - default to Light if we don't know
1368
+ return "Light"
1369
+
1370
+ # Matrix devices (Tiles, Candles) → TileDevice
1371
+ if product.has_matrix:
1372
+ return "TileDevice"
1373
+
1374
+ # MultiZone devices (Strips, Beams) → MultiZoneLight
1375
+ if product.has_multizone:
1376
+ return "MultiZoneLight"
1377
+
1378
+ # HEV lights → HevLight
1379
+ if product.has_hev:
1380
+ return "HevLight"
1381
+
1382
+ # Infrared lights → InfraredLight
1383
+ if product.has_infrared:
1384
+ return "InfraredLight"
1385
+
1386
+ # Color lights → Light
1387
+ if product.has_color:
1388
+ return "Light"
1389
+
1390
+ # Devices with relays (switches/relays) → Device
1391
+ if product.has_relays:
1392
+ return "Device"
1393
+
1394
+ # Devices with buttons but no color (switches) → Device
1395
+ if product.has_buttons:
1396
+ return "Device"
1397
+
1398
+ # Everything else (basic lights, white-to-warm lights) → Light
1399
+ # These have no special capabilities but still support Light protocol
1400
+ return "Light"
1401
+
1402
+ def __len__(self) -> int:
1403
+ """Get number of products in registry."""
1404
+ return len(self._products)
1405
+
1406
+ def __contains__(self, pid: int) -> bool:
1407
+ """Check if product ID exists in registry."""
1408
+ return pid in self._products
1409
+
1410
+
1411
+ # Global registry instance
1412
+ _registry = ProductRegistry()
1413
+
1414
+
1415
+ def get_registry() -> ProductRegistry:
1416
+ """Get the global product registry.
1417
+
1418
+ Returns:
1419
+ Global ProductRegistry instance
1420
+ """
1421
+ return _registry
1422
+
1423
+
1424
+ def get_product(pid: int) -> ProductInfo | None:
1425
+ """Get product info by product ID.
1426
+
1427
+ Args:
1428
+ pid: Product ID
1429
+
1430
+ Returns:
1431
+ ProductInfo if found, None otherwise
1432
+ """
1433
+ return _registry.get_product(pid)
1434
+
1435
+
1436
+ def get_device_class_name(pid: int, firmware_version: int | None = None) -> str:
1437
+ """Get appropriate device class name for a product.
1438
+
1439
+ Args:
1440
+ pid: Product ID
1441
+ firmware_version: Firmware version (optional)
1442
+
1443
+ Returns:
1444
+ Device class name: "TileDevice", "MultiZoneLight", "Light", or "Device"
1445
+ """
1446
+ return _registry.get_device_class_name(pid, firmware_version)