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.
- lifx_emulator/__init__.py +31 -0
- lifx_emulator/__main__.py +607 -0
- lifx_emulator/api.py +1825 -0
- lifx_emulator/async_storage.py +308 -0
- lifx_emulator/constants.py +33 -0
- lifx_emulator/device.py +750 -0
- lifx_emulator/device_states.py +114 -0
- lifx_emulator/factories.py +380 -0
- lifx_emulator/handlers/__init__.py +39 -0
- lifx_emulator/handlers/base.py +49 -0
- lifx_emulator/handlers/device_handlers.py +340 -0
- lifx_emulator/handlers/light_handlers.py +372 -0
- lifx_emulator/handlers/multizone_handlers.py +249 -0
- lifx_emulator/handlers/registry.py +110 -0
- lifx_emulator/handlers/tile_handlers.py +309 -0
- lifx_emulator/observers.py +139 -0
- lifx_emulator/products/__init__.py +28 -0
- lifx_emulator/products/generator.py +771 -0
- lifx_emulator/products/registry.py +1446 -0
- lifx_emulator/products/specs.py +242 -0
- lifx_emulator/products/specs.yml +327 -0
- lifx_emulator/protocol/__init__.py +1 -0
- lifx_emulator/protocol/base.py +334 -0
- lifx_emulator/protocol/const.py +8 -0
- lifx_emulator/protocol/generator.py +1371 -0
- lifx_emulator/protocol/header.py +159 -0
- lifx_emulator/protocol/packets.py +1351 -0
- lifx_emulator/protocol/protocol_types.py +844 -0
- lifx_emulator/protocol/serializer.py +379 -0
- lifx_emulator/scenario_manager.py +402 -0
- lifx_emulator/scenario_persistence.py +206 -0
- lifx_emulator/server.py +482 -0
- lifx_emulator/state_restorer.py +259 -0
- lifx_emulator/state_serializer.py +130 -0
- lifx_emulator/storage_protocol.py +100 -0
- lifx_emulator-1.0.0.dist-info/METADATA +445 -0
- lifx_emulator-1.0.0.dist-info/RECORD +40 -0
- lifx_emulator-1.0.0.dist-info/WHEEL +4 -0
- lifx_emulator-1.0.0.dist-info/entry_points.txt +2 -0
- lifx_emulator-1.0.0.dist-info/licenses/LICENSE +35 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""Product specs and defaults for LIFX devices.
|
|
2
|
+
|
|
3
|
+
This module provides access to product-specific details that are not available
|
|
4
|
+
in the upstream LIFX products.json catalog, such as default zone counts and
|
|
5
|
+
tile configurations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import yaml
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ProductSpecs:
|
|
18
|
+
"""Product-specific specs and defaults.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
product_id: Product ID this applies to
|
|
22
|
+
default_zone_count: Default number of zones for multizone devices
|
|
23
|
+
min_zone_count: Minimum zones supported
|
|
24
|
+
max_zone_count: Maximum zones supported
|
|
25
|
+
default_tile_count: Default number of tiles in chain
|
|
26
|
+
min_tile_count: Minimum tiles supported
|
|
27
|
+
max_tile_count: Maximum tiles supported
|
|
28
|
+
tile_width: Width of each tile in pixels
|
|
29
|
+
tile_height: Height of each tile in pixels
|
|
30
|
+
notes: Human-readable notes about this product
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
product_id: int
|
|
34
|
+
default_zone_count: int | None = None
|
|
35
|
+
min_zone_count: int | None = None
|
|
36
|
+
max_zone_count: int | None = None
|
|
37
|
+
default_tile_count: int | None = None
|
|
38
|
+
min_tile_count: int | None = None
|
|
39
|
+
max_tile_count: int | None = None
|
|
40
|
+
tile_width: int | None = None
|
|
41
|
+
tile_height: int | None = None
|
|
42
|
+
notes: str | None = None
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def has_multizone_specs(self) -> bool:
|
|
46
|
+
"""Check if this product has multizone-specific specs."""
|
|
47
|
+
return self.default_zone_count is not None
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def has_matrix_specs(self) -> bool:
|
|
51
|
+
"""Check if this product has matrix-specific specs."""
|
|
52
|
+
return self.tile_width is not None or self.tile_height is not None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class SpecsRegistry:
|
|
56
|
+
"""Registry of product specs loaded from specs.yml."""
|
|
57
|
+
|
|
58
|
+
def __init__(self) -> None:
|
|
59
|
+
"""Initialize empty specs registry."""
|
|
60
|
+
self._specs: dict[int, ProductSpecs] = {}
|
|
61
|
+
self._loaded = False
|
|
62
|
+
|
|
63
|
+
def load_from_file(self, specs_path: Path | None = None) -> None:
|
|
64
|
+
"""Load specs from YAML file.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
specs_path: Path to specs.yml file. If None, uses default location.
|
|
68
|
+
"""
|
|
69
|
+
if specs_path is None:
|
|
70
|
+
specs_path = Path(__file__).parent / "specs.yml"
|
|
71
|
+
|
|
72
|
+
if not specs_path.exists():
|
|
73
|
+
# No specs file, that's okay - we'll use registry defaults only
|
|
74
|
+
self._loaded = True
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
with open(specs_path) as f:
|
|
78
|
+
data = yaml.safe_load(f)
|
|
79
|
+
|
|
80
|
+
if not data or "products" not in data:
|
|
81
|
+
self._loaded = True
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
# Parse product specs
|
|
85
|
+
for pid, specs_data in data["products"].items():
|
|
86
|
+
if isinstance(specs_data, dict):
|
|
87
|
+
self._specs[int(pid)] = ProductSpecs(
|
|
88
|
+
product_id=int(pid),
|
|
89
|
+
default_zone_count=specs_data.get("default_zone_count"),
|
|
90
|
+
min_zone_count=specs_data.get("min_zone_count"),
|
|
91
|
+
max_zone_count=specs_data.get("max_zone_count"),
|
|
92
|
+
default_tile_count=specs_data.get("default_tile_count"),
|
|
93
|
+
min_tile_count=specs_data.get("min_tile_count"),
|
|
94
|
+
max_tile_count=specs_data.get("max_tile_count"),
|
|
95
|
+
tile_width=specs_data.get("tile_width"),
|
|
96
|
+
tile_height=specs_data.get("tile_height"),
|
|
97
|
+
notes=specs_data.get("notes"),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self._loaded = True
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def is_loaded(self) -> bool:
|
|
104
|
+
"""Check if specs have been loaded."""
|
|
105
|
+
return self._loaded
|
|
106
|
+
|
|
107
|
+
def get_specs(self, product_id: int) -> ProductSpecs | None:
|
|
108
|
+
"""Get specs for a specific product.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
product_id: Product ID to look up
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
ProductSpecs if found, None otherwise
|
|
115
|
+
"""
|
|
116
|
+
if not self._loaded:
|
|
117
|
+
self.load_from_file()
|
|
118
|
+
|
|
119
|
+
return self._specs.get(product_id)
|
|
120
|
+
|
|
121
|
+
def has_specs(self, product_id: int) -> bool:
|
|
122
|
+
"""Check if a product has specs defined.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
product_id: Product ID to check
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
True if specs exist for this product
|
|
129
|
+
"""
|
|
130
|
+
if not self._loaded:
|
|
131
|
+
self.load_from_file()
|
|
132
|
+
|
|
133
|
+
return product_id in self._specs
|
|
134
|
+
|
|
135
|
+
def get_default_zone_count(self, product_id: int) -> int | None:
|
|
136
|
+
"""Get default zone count for a multizone product.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
product_id: Product ID
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Default zone count if defined, None otherwise
|
|
143
|
+
"""
|
|
144
|
+
specs = self.get_specs(product_id)
|
|
145
|
+
return specs.default_zone_count if specs else None
|
|
146
|
+
|
|
147
|
+
def get_default_tile_count(self, product_id: int) -> int | None:
|
|
148
|
+
"""Get default tile count for a matrix product.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
product_id: Product ID
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
Default tile count if defined, None otherwise
|
|
155
|
+
"""
|
|
156
|
+
specs = self.get_specs(product_id)
|
|
157
|
+
return specs.default_tile_count if specs else None
|
|
158
|
+
|
|
159
|
+
def get_tile_dimensions(self, product_id: int) -> tuple[int, int] | None:
|
|
160
|
+
"""Get tile dimensions for a matrix product.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
product_id: Product ID
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Tuple of (width, height) if defined, None otherwise
|
|
167
|
+
"""
|
|
168
|
+
specs = self.get_specs(product_id)
|
|
169
|
+
if specs and specs.tile_width and specs.tile_height:
|
|
170
|
+
return (specs.tile_width, specs.tile_height)
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
def __len__(self) -> int:
|
|
174
|
+
"""Get number of products with specs."""
|
|
175
|
+
if not self._loaded:
|
|
176
|
+
self.load_from_file()
|
|
177
|
+
return len(self._specs)
|
|
178
|
+
|
|
179
|
+
def __contains__(self, product_id: int) -> bool:
|
|
180
|
+
"""Check if product has specs."""
|
|
181
|
+
return self.has_specs(product_id)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# Global specs registry instance
|
|
185
|
+
_specs_registry = SpecsRegistry()
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_specs_registry() -> SpecsRegistry:
|
|
189
|
+
"""Get the global specs registry.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Global SpecsRegistry instance
|
|
193
|
+
"""
|
|
194
|
+
return _specs_registry
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def get_specs(product_id: int) -> ProductSpecs | None:
|
|
198
|
+
"""Get specs for a specific product.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
product_id: Product ID to look up
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
ProductSpecs if found, None otherwise
|
|
205
|
+
"""
|
|
206
|
+
return _specs_registry.get_specs(product_id)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_default_zone_count(product_id: int) -> int | None:
|
|
210
|
+
"""Get default zone count for a multizone product.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
product_id: Product ID
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Default zone count if defined, None otherwise
|
|
217
|
+
"""
|
|
218
|
+
return _specs_registry.get_default_zone_count(product_id)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def get_default_tile_count(product_id: int) -> int | None:
|
|
222
|
+
"""Get default tile count for a matrix product.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
product_id: Product ID
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Default tile count if defined, None otherwise
|
|
229
|
+
"""
|
|
230
|
+
return _specs_registry.get_default_tile_count(product_id)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def get_tile_dimensions(product_id: int) -> tuple[int, int] | None:
|
|
234
|
+
"""Get tile dimensions for a matrix product.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
product_id: Product ID
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Tuple of (width, height) if defined, None otherwise
|
|
241
|
+
"""
|
|
242
|
+
return _specs_registry.get_tile_dimensions(product_id)
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# LIFX Product Specs and Defaults
|
|
2
|
+
# =================================
|
|
3
|
+
#
|
|
4
|
+
# This file contains product-specific details that are not available in the
|
|
5
|
+
# upstream LIFX products.json catalog, such as default zone counts, tile
|
|
6
|
+
# configurations, and other device-specific defaults.
|
|
7
|
+
#
|
|
8
|
+
# These values are used by the emulator to create realistic device
|
|
9
|
+
# configurations when specific parameters are not provided by the user.
|
|
10
|
+
#
|
|
11
|
+
# Format:
|
|
12
|
+
# -------
|
|
13
|
+
# products:
|
|
14
|
+
# <product_id>:
|
|
15
|
+
# # For multizone devices
|
|
16
|
+
# default_zone_count: <number> # Default zones (e.g., 16)
|
|
17
|
+
# min_zone_count: <number> # Minimum zones supported
|
|
18
|
+
# max_zone_count: <number> # Maximum zones supported
|
|
19
|
+
#
|
|
20
|
+
# # For matrix devices (tiles, candles, etc.)
|
|
21
|
+
# default_tile_count: <number> # Default number of tiles in chain
|
|
22
|
+
# min_tile_count: <number> # Minimum tiles supported
|
|
23
|
+
# max_tile_count: <number> # Maximum tiles supported
|
|
24
|
+
# tile_width: <number> # Width of each tile in pixels
|
|
25
|
+
# tile_height: <number> # Height of each tile in pixels
|
|
26
|
+
#
|
|
27
|
+
# # Other device-specific defaults
|
|
28
|
+
# notes: "<string>" # Notes about product
|
|
29
|
+
|
|
30
|
+
products:
|
|
31
|
+
# ========================================
|
|
32
|
+
# Multizone Products (Linear Strips)
|
|
33
|
+
# ========================================
|
|
34
|
+
|
|
35
|
+
31: # Original LIFX Z strip, 2 meters, 8 zones per meter
|
|
36
|
+
default_zone_count: 16
|
|
37
|
+
min_zone_count: 8
|
|
38
|
+
max_zone_count: 16
|
|
39
|
+
notes: Original LIFX Z strip, 2 meters, 8 zones per meter
|
|
40
|
+
|
|
41
|
+
32: # LIFX Z with extended multizone firmware support
|
|
42
|
+
default_zone_count: 16
|
|
43
|
+
min_zone_count: 8
|
|
44
|
+
max_zone_count: 16
|
|
45
|
+
notes: LIFX Z with extended multizone firmware support
|
|
46
|
+
|
|
47
|
+
38: # LIFX Beam, 8 individual beams, each with 10 zones and up to 2 corners
|
|
48
|
+
default_zone_count: 80
|
|
49
|
+
min_zone_count: 10
|
|
50
|
+
max_zone_count: 82
|
|
51
|
+
notes: LIFX Beam, 8 individual beams, each with 10 zones and up to 2 corners
|
|
52
|
+
|
|
53
|
+
117: # LIFX Z US variant
|
|
54
|
+
default_zone_count: 16
|
|
55
|
+
min_zone_count: 8
|
|
56
|
+
max_zone_count: 16
|
|
57
|
+
notes: LIFX Z US variant
|
|
58
|
+
|
|
59
|
+
118: # LIFX Z International variant
|
|
60
|
+
default_zone_count: 16
|
|
61
|
+
min_zone_count: 8
|
|
62
|
+
max_zone_count: 16
|
|
63
|
+
notes: LIFX Z International variant
|
|
64
|
+
|
|
65
|
+
119: # LIFX Beam US variant
|
|
66
|
+
default_zone_count: 80
|
|
67
|
+
min_zone_count: 10
|
|
68
|
+
max_zone_count: 82
|
|
69
|
+
notes: LIFX Beam US variant
|
|
70
|
+
|
|
71
|
+
120: # LIFX Beam International variant
|
|
72
|
+
default_zone_count: 80
|
|
73
|
+
min_zone_count: 10
|
|
74
|
+
max_zone_count: 82
|
|
75
|
+
notes: LIFX Beam International variant
|
|
76
|
+
|
|
77
|
+
141: # LIFX Neon flexible light strip
|
|
78
|
+
default_zone_count: 24
|
|
79
|
+
min_zone_count: 24
|
|
80
|
+
max_zone_count: 48
|
|
81
|
+
notes: LIFX Neon flexible light strip
|
|
82
|
+
|
|
83
|
+
142: # LIFX Neon International variant
|
|
84
|
+
default_zone_count: 24
|
|
85
|
+
min_zone_count: 24
|
|
86
|
+
max_zone_count: 48
|
|
87
|
+
notes: LIFX Neon International variant
|
|
88
|
+
|
|
89
|
+
143: # LIFX String lights
|
|
90
|
+
default_zone_count: 36
|
|
91
|
+
min_zone_count: 36
|
|
92
|
+
max_zone_count: 72
|
|
93
|
+
notes: LIFX String lights
|
|
94
|
+
|
|
95
|
+
144: # LIFX String International variant
|
|
96
|
+
default_zone_count: 20
|
|
97
|
+
min_zone_count: 36
|
|
98
|
+
max_zone_count: 72
|
|
99
|
+
notes: LIFX String International variant
|
|
100
|
+
|
|
101
|
+
161: # LIFX Outdoor Neon
|
|
102
|
+
default_zone_count: 60
|
|
103
|
+
min_zone_count: 60
|
|
104
|
+
max_zone_count: 120
|
|
105
|
+
notes: LIFX Outdoor Neon
|
|
106
|
+
|
|
107
|
+
162: # LIFX Outdoor Neon International variant
|
|
108
|
+
default_zone_count: 60
|
|
109
|
+
min_zone_count: 60
|
|
110
|
+
max_zone_count: 120
|
|
111
|
+
notes: LIFX Outdoor Neon International variant
|
|
112
|
+
|
|
113
|
+
203: # LIFX String US (newer model)
|
|
114
|
+
default_zone_count: 36
|
|
115
|
+
min_zone_count: 36
|
|
116
|
+
max_zone_count: 72
|
|
117
|
+
notes: LIFX String US (newer model)
|
|
118
|
+
|
|
119
|
+
204: # LIFX String International (newer model)
|
|
120
|
+
default_zone_count: 36
|
|
121
|
+
min_zone_count: 36
|
|
122
|
+
max_zone_count: 72
|
|
123
|
+
notes: LIFX String International (newer model)
|
|
124
|
+
|
|
125
|
+
205: # LIFX Indoor Neon US
|
|
126
|
+
default_zone_count: 24
|
|
127
|
+
min_zone_count: 24
|
|
128
|
+
max_zone_count: 48
|
|
129
|
+
notes: LIFX Indoor Neon US
|
|
130
|
+
|
|
131
|
+
206: # LIFX Indoor Neon Intl
|
|
132
|
+
default_zone_count: 24
|
|
133
|
+
min_zone_count: 24
|
|
134
|
+
max_zone_count: 48
|
|
135
|
+
notes: LIFX Indoor Neon Intl
|
|
136
|
+
|
|
137
|
+
213: # LIFX Permanent Outdoor US
|
|
138
|
+
default_zone_count: 30
|
|
139
|
+
min_zone_count: 30
|
|
140
|
+
max_zone_count: 120
|
|
141
|
+
notes: LIFX Permanent Outdoor US
|
|
142
|
+
|
|
143
|
+
214: # LIFX Permanent Outdoor Intl
|
|
144
|
+
default_zone_count: 30
|
|
145
|
+
min_zone_count: 30
|
|
146
|
+
max_zone_count: 120
|
|
147
|
+
notes: LIFX Permanent Outdoor Intl
|
|
148
|
+
|
|
149
|
+
# ========================================
|
|
150
|
+
# Matrix Products (Tiles, Candles, etc.)
|
|
151
|
+
# ========================================
|
|
152
|
+
|
|
153
|
+
55: # LIFX Tile, 8x8 pixel matrix, chainable up to 5
|
|
154
|
+
default_tile_count: 5
|
|
155
|
+
min_tile_count: 1
|
|
156
|
+
max_tile_count: 5
|
|
157
|
+
tile_width: 8
|
|
158
|
+
tile_height: 8
|
|
159
|
+
notes: LIFX Tile, 8x8 pixel matrix, chainable up to 5
|
|
160
|
+
|
|
161
|
+
57: # LIFX Candle, 5x6 pixel matrix, single unit
|
|
162
|
+
default_tile_count: 1
|
|
163
|
+
min_tile_count: 1
|
|
164
|
+
max_tile_count: 1
|
|
165
|
+
tile_width: 5
|
|
166
|
+
tile_height: 6
|
|
167
|
+
notes: LIFX Candle, 5x6 pixel matrix, single unit
|
|
168
|
+
|
|
169
|
+
68: # LIFX Candle variant, 5x6 pixel matrix
|
|
170
|
+
default_tile_count: 1
|
|
171
|
+
min_tile_count: 1
|
|
172
|
+
max_tile_count: 1
|
|
173
|
+
tile_width: 5
|
|
174
|
+
tile_height: 6
|
|
175
|
+
notes: LIFX Candle variant, 5x6 pixel matrix
|
|
176
|
+
|
|
177
|
+
137: # LIFX Candle Color US 5x6 variant
|
|
178
|
+
default_tile_count: 1
|
|
179
|
+
min_tile_count: 1
|
|
180
|
+
max_tile_count: 1
|
|
181
|
+
tile_width: 5
|
|
182
|
+
tile_height: 6
|
|
183
|
+
notes: LIFX Candle Color US 5x6 variant
|
|
184
|
+
|
|
185
|
+
138: # LIFX Candle Colour 5x6 International variant
|
|
186
|
+
default_tile_count: 1
|
|
187
|
+
min_tile_count: 1
|
|
188
|
+
max_tile_count: 1
|
|
189
|
+
tile_width: 5
|
|
190
|
+
tile_height: 6
|
|
191
|
+
notes: LIFX Candle Colour 5x6 International variant
|
|
192
|
+
|
|
193
|
+
171: # LIFX Round Spot, 3x1 matrix
|
|
194
|
+
default_tile_count: 1
|
|
195
|
+
min_tile_count: 1
|
|
196
|
+
max_tile_count: 1
|
|
197
|
+
tile_width: 3
|
|
198
|
+
tile_height: 1
|
|
199
|
+
notes: LIFX Round Spot, 3x1 matrix
|
|
200
|
+
|
|
201
|
+
173: # LIFX Round Path, 3x2 matrix
|
|
202
|
+
default_tile_count: 1
|
|
203
|
+
min_tile_count: 1
|
|
204
|
+
max_tile_count: 1
|
|
205
|
+
tile_width: 3
|
|
206
|
+
tile_height: 2
|
|
207
|
+
notes: LIFX Round Path, 3x2 matrix
|
|
208
|
+
|
|
209
|
+
174: # LIFX Square Path, 3x2 matrix
|
|
210
|
+
default_tile_count: 1
|
|
211
|
+
min_tile_count: 1
|
|
212
|
+
max_tile_count: 1
|
|
213
|
+
tile_width: 3
|
|
214
|
+
tile_height: 2
|
|
215
|
+
notes: LIFX Square Path, 3x2 matrix
|
|
216
|
+
|
|
217
|
+
176: # LIFX Ceiling, 8x8 matrix, zones 1-63: downlight, zone 64: uplight
|
|
218
|
+
default_tile_count: 1
|
|
219
|
+
min_tile_count: 1
|
|
220
|
+
max_tile_count: 1
|
|
221
|
+
tile_width: 8
|
|
222
|
+
tile_height: 8
|
|
223
|
+
notes: 'LIFX Ceiling, 8x8 matrix, zones 1-63: downlight, zone 64: uplight'
|
|
224
|
+
|
|
225
|
+
177: # LIFX Tube Intl
|
|
226
|
+
default_tile_count: 1
|
|
227
|
+
min_tile_count: 1
|
|
228
|
+
max_tile_count: 1
|
|
229
|
+
tile_width: 5
|
|
230
|
+
tile_height: 11
|
|
231
|
+
notes: LIFX Tube Intl
|
|
232
|
+
|
|
233
|
+
185: # LIFX Candle Color US
|
|
234
|
+
default_tile_count: 1
|
|
235
|
+
min_tile_count: 1
|
|
236
|
+
max_tile_count: 1
|
|
237
|
+
tile_width: 5
|
|
238
|
+
tile_height: 6
|
|
239
|
+
notes: LIFX Candle Color US
|
|
240
|
+
|
|
241
|
+
186: # LIFX Candle Colour Intl
|
|
242
|
+
default_tile_count: 1
|
|
243
|
+
min_tile_count: 1
|
|
244
|
+
max_tile_count: 1
|
|
245
|
+
tile_width: 5
|
|
246
|
+
tile_height: 6
|
|
247
|
+
notes: LIFX Candle Colour Intl
|
|
248
|
+
|
|
249
|
+
201: # LIFX Ceiling 13x26" US
|
|
250
|
+
default_tile_count: 1
|
|
251
|
+
min_tile_count: 1
|
|
252
|
+
max_tile_count: 1
|
|
253
|
+
tile_width: 16
|
|
254
|
+
tile_height: 8
|
|
255
|
+
notes: LIFX Ceiling 13x26" US
|
|
256
|
+
|
|
257
|
+
202: # LIFX Ceiling 13x26" Intl
|
|
258
|
+
default_tile_count: 1
|
|
259
|
+
min_tile_count: 1
|
|
260
|
+
max_tile_count: 1
|
|
261
|
+
tile_width: 16
|
|
262
|
+
tile_height: 8
|
|
263
|
+
notes: LIFX Ceiling 13x26" Intl
|
|
264
|
+
|
|
265
|
+
215: # LIFX Candle Color US
|
|
266
|
+
default_tile_count: 1
|
|
267
|
+
min_tile_count: 1
|
|
268
|
+
max_tile_count: 1
|
|
269
|
+
tile_width: 5
|
|
270
|
+
tile_height: 6
|
|
271
|
+
notes: LIFX Candle Color US
|
|
272
|
+
|
|
273
|
+
216: # LIFX Candle Colour Intl
|
|
274
|
+
default_tile_count: 1
|
|
275
|
+
min_tile_count: 1
|
|
276
|
+
max_tile_count: 1
|
|
277
|
+
tile_width: 5
|
|
278
|
+
tile_height: 6
|
|
279
|
+
notes: LIFX Candle Colour Intl
|
|
280
|
+
|
|
281
|
+
217: # LIFX Tube US
|
|
282
|
+
default_tile_count: 1
|
|
283
|
+
min_tile_count: 1
|
|
284
|
+
max_tile_count: 1
|
|
285
|
+
tile_width: 5
|
|
286
|
+
tile_height: 11
|
|
287
|
+
notes: LIFX Tube US
|
|
288
|
+
|
|
289
|
+
218: # LIFX Tube Intl
|
|
290
|
+
default_tile_count: 1
|
|
291
|
+
min_tile_count: 1
|
|
292
|
+
max_tile_count: 1
|
|
293
|
+
tile_width: 5
|
|
294
|
+
tile_height: 11
|
|
295
|
+
notes: LIFX Tube Intl
|
|
296
|
+
|
|
297
|
+
219: # LIFX Luna US
|
|
298
|
+
default_tile_count: 1
|
|
299
|
+
min_tile_count: 1
|
|
300
|
+
max_tile_count: 1
|
|
301
|
+
tile_width: 7
|
|
302
|
+
tile_height: 5
|
|
303
|
+
notes: LIFX Luna US
|
|
304
|
+
|
|
305
|
+
220: # LIFX Luna Intl
|
|
306
|
+
default_tile_count: 1
|
|
307
|
+
min_tile_count: 1
|
|
308
|
+
max_tile_count: 1
|
|
309
|
+
tile_width: 7
|
|
310
|
+
tile_height: 5
|
|
311
|
+
notes: LIFX Luna Intl
|
|
312
|
+
|
|
313
|
+
221: # LIFX Round Spot Intl
|
|
314
|
+
default_tile_count: 1
|
|
315
|
+
min_tile_count: 1
|
|
316
|
+
max_tile_count: 1
|
|
317
|
+
tile_width: 3
|
|
318
|
+
tile_height: 1
|
|
319
|
+
notes: LIFX Round Spot Intl
|
|
320
|
+
|
|
321
|
+
222: # LIFX Round Path Intl
|
|
322
|
+
default_tile_count: 1
|
|
323
|
+
min_tile_count: 1
|
|
324
|
+
max_tile_count: 1
|
|
325
|
+
tile_width: 3
|
|
326
|
+
tile_height: 2
|
|
327
|
+
notes: LIFX Round Path Intl
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""LIFX protocol implementation and code generation."""
|