lifx-emulator 2.2.1__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lifx_emulator/devices/device.py +7 -1
- lifx_emulator/devices/state_serializer.py +27 -0
- lifx_emulator/devices/states.py +31 -0
- lifx_emulator/handlers/tile_handlers.py +142 -15
- {lifx_emulator-2.2.1.dist-info → lifx_emulator-2.3.0.dist-info}/METADATA +1 -1
- {lifx_emulator-2.2.1.dist-info → lifx_emulator-2.3.0.dist-info}/RECORD +9 -9
- {lifx_emulator-2.2.1.dist-info → lifx_emulator-2.3.0.dist-info}/WHEEL +0 -0
- {lifx_emulator-2.2.1.dist-info → lifx_emulator-2.3.0.dist-info}/entry_points.txt +0 -0
- {lifx_emulator-2.2.1.dist-info → lifx_emulator-2.3.0.dist-info}/licenses/LICENSE +0 -0
lifx_emulator/devices/device.py
CHANGED
|
@@ -9,7 +9,7 @@ import time
|
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
11
|
from lifx_emulator.constants import LIFX_HEADER_SIZE
|
|
12
|
-
from lifx_emulator.devices.states import DeviceState
|
|
12
|
+
from lifx_emulator.devices.states import DeviceState, TileFramebuffers
|
|
13
13
|
from lifx_emulator.handlers import HandlerRegistry, create_default_registry
|
|
14
14
|
from lifx_emulator.protocol.header import LifxHeader
|
|
15
15
|
from lifx_emulator.protocol.packets import (
|
|
@@ -114,6 +114,12 @@ class EmulatedLifxDevice:
|
|
|
114
114
|
}
|
|
115
115
|
)
|
|
116
116
|
|
|
117
|
+
# Initialize framebuffer storage for each tile (framebuffers 1-7)
|
|
118
|
+
# Framebuffer 0 is stored in tile_devices[i]["colors"]
|
|
119
|
+
if not self.state.tile_framebuffers:
|
|
120
|
+
for i in range(self.state.tile_count):
|
|
121
|
+
self.state.tile_framebuffers.append(TileFramebuffers(tile_index=i))
|
|
122
|
+
|
|
117
123
|
# Save initial state if persistence is enabled
|
|
118
124
|
# This ensures newly created devices are immediately persisted
|
|
119
125
|
if self.storage:
|
|
@@ -97,6 +97,17 @@ def serialize_device_state(device_state: Any) -> dict[str, Any]:
|
|
|
97
97
|
}
|
|
98
98
|
for t in device_state.tile_devices
|
|
99
99
|
]
|
|
100
|
+
# Serialize tile framebuffers (non-visible framebuffers 1-7)
|
|
101
|
+
state_dict["tile_framebuffers"] = [
|
|
102
|
+
{
|
|
103
|
+
"tile_index": fb.tile_index,
|
|
104
|
+
"framebuffers": {
|
|
105
|
+
str(fb_idx): [serialize_hsbk(c) for c in colors]
|
|
106
|
+
for fb_idx, colors in fb.framebuffers.items()
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
for fb in device_state.tile_framebuffers
|
|
110
|
+
]
|
|
100
111
|
|
|
101
112
|
return state_dict
|
|
102
113
|
|
|
@@ -127,4 +138,20 @@ def deserialize_device_state(state_dict: dict[str, Any]) -> dict[str, Any]:
|
|
|
127
138
|
for tile_dict in state_dict["tile_devices"]:
|
|
128
139
|
tile_dict["colors"] = [deserialize_hsbk(c) for c in tile_dict["colors"]]
|
|
129
140
|
|
|
141
|
+
# Deserialize tile framebuffers if present (for backwards compatibility)
|
|
142
|
+
if "tile_framebuffers" in state_dict:
|
|
143
|
+
from lifx_emulator.devices.states import TileFramebuffers
|
|
144
|
+
|
|
145
|
+
deserialized_fbs = []
|
|
146
|
+
for fb_dict in state_dict["tile_framebuffers"]:
|
|
147
|
+
tile_fb = TileFramebuffers(tile_index=fb_dict["tile_index"])
|
|
148
|
+
# Deserialize each framebuffer's colors
|
|
149
|
+
for fb_idx_str, colors_list in fb_dict["framebuffers"].items():
|
|
150
|
+
fb_idx = int(fb_idx_str)
|
|
151
|
+
tile_fb.framebuffers[fb_idx] = [
|
|
152
|
+
deserialize_hsbk(c) for c in colors_list
|
|
153
|
+
]
|
|
154
|
+
deserialized_fbs.append(tile_fb)
|
|
155
|
+
state_dict["tile_framebuffers"] = deserialized_fbs
|
|
156
|
+
|
|
130
157
|
return state_dict
|
lifx_emulator/devices/states.py
CHANGED
|
@@ -82,6 +82,32 @@ class MultiZoneState:
|
|
|
82
82
|
effect_speed: int = 5 # Duration of one cycle in seconds
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
@dataclass
|
|
86
|
+
class TileFramebuffers:
|
|
87
|
+
"""Internal storage for non-visible tile framebuffers (1-7).
|
|
88
|
+
|
|
89
|
+
Framebuffer 0 is stored in tile_devices[i]["colors"] (the visible buffer).
|
|
90
|
+
Framebuffers 1-7 are stored here for Set64/CopyFrameBuffer operations.
|
|
91
|
+
Each framebuffer is a list of LightHsbk colors with length = width * height.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
tile_index: int # Which tile this belongs to
|
|
95
|
+
framebuffers: dict[int, list[LightHsbk]] = field(default_factory=dict)
|
|
96
|
+
|
|
97
|
+
def get_framebuffer(
|
|
98
|
+
self, fb_index: int, width: int, height: int
|
|
99
|
+
) -> list[LightHsbk]:
|
|
100
|
+
"""Get framebuffer by index, creating it if needed."""
|
|
101
|
+
if fb_index not in self.framebuffers:
|
|
102
|
+
# Initialize with default black color
|
|
103
|
+
pixels = width * height
|
|
104
|
+
self.framebuffers[fb_index] = [
|
|
105
|
+
LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500)
|
|
106
|
+
for _ in range(pixels)
|
|
107
|
+
]
|
|
108
|
+
return self.framebuffers[fb_index]
|
|
109
|
+
|
|
110
|
+
|
|
85
111
|
@dataclass
|
|
86
112
|
class MatrixState:
|
|
87
113
|
"""Matrix (tile/candle) capability state."""
|
|
@@ -101,6 +127,9 @@ class MatrixState:
|
|
|
101
127
|
effect_cloud_sat_max: int = (
|
|
102
128
|
0 # Max cloud saturation 0-200 (only when effect_type=5)
|
|
103
129
|
)
|
|
130
|
+
# Internal storage for non-visible framebuffers (1-7) per tile
|
|
131
|
+
# Framebuffer 0 remains in tile_devices[i]["colors"]
|
|
132
|
+
tile_framebuffers: list[TileFramebuffers] = field(default_factory=list)
|
|
104
133
|
|
|
105
134
|
|
|
106
135
|
@dataclass
|
|
@@ -215,6 +244,7 @@ class DeviceState:
|
|
|
215
244
|
"tile_effect_sky_type": ("matrix", "effect_sky_type"),
|
|
216
245
|
"tile_effect_cloud_sat_min": ("matrix", "effect_cloud_sat_min"),
|
|
217
246
|
"tile_effect_cloud_sat_max": ("matrix", "effect_cloud_sat_max"),
|
|
247
|
+
"tile_framebuffers": "matrix",
|
|
218
248
|
}
|
|
219
249
|
|
|
220
250
|
# Default values for optional state attributes when state object is None
|
|
@@ -240,6 +270,7 @@ class DeviceState:
|
|
|
240
270
|
"tile_effect_sky_type": 0,
|
|
241
271
|
"tile_effect_cloud_sat_min": 0,
|
|
242
272
|
"tile_effect_cloud_sat_max": 0,
|
|
273
|
+
"tile_framebuffers": [],
|
|
243
274
|
}
|
|
244
275
|
|
|
245
276
|
def get_target_bytes(self) -> bytes:
|
|
@@ -12,6 +12,7 @@ from lifx_emulator.protocol.protocol_types import (
|
|
|
12
12
|
DeviceStateVersion,
|
|
13
13
|
LightHsbk,
|
|
14
14
|
TileAccelMeas,
|
|
15
|
+
TileBufferRect,
|
|
15
16
|
TileEffectParameter,
|
|
16
17
|
TileEffectSettings,
|
|
17
18
|
TileEffectType,
|
|
@@ -137,6 +138,10 @@ class Get64Handler(PacketHandler):
|
|
|
137
138
|
tile_width = tile["width"]
|
|
138
139
|
tile_height = tile["height"]
|
|
139
140
|
|
|
141
|
+
# Get64 always returns framebuffer 0 (the visible buffer)
|
|
142
|
+
# regardless of which fb_index is in the request
|
|
143
|
+
tile_colors = tile["colors"]
|
|
144
|
+
|
|
140
145
|
# Calculate how many rows fit in 64 pixels
|
|
141
146
|
rows_to_return = 64 // rect.width if rect.width > 0 else 1
|
|
142
147
|
rows_to_return = min(rows_to_return, tile_height - rect.y)
|
|
@@ -161,8 +166,8 @@ class Get64Handler(PacketHandler):
|
|
|
161
166
|
|
|
162
167
|
# Calculate pixel index in flat color array
|
|
163
168
|
pixel_idx = y * tile_width + x
|
|
164
|
-
if pixel_idx < len(
|
|
165
|
-
colors.append(
|
|
169
|
+
if pixel_idx < len(tile_colors):
|
|
170
|
+
colors.append(tile_colors[pixel_idx])
|
|
166
171
|
else:
|
|
167
172
|
colors.append(
|
|
168
173
|
LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500)
|
|
@@ -173,7 +178,14 @@ class Get64Handler(PacketHandler):
|
|
|
173
178
|
while len(colors) < 64:
|
|
174
179
|
colors.append(LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500))
|
|
175
180
|
|
|
176
|
-
|
|
181
|
+
# Return with fb_index forced to 0 (visible buffer)
|
|
182
|
+
return_rect = TileBufferRect(
|
|
183
|
+
fb_index=0, # Always return FB0
|
|
184
|
+
x=rect.x,
|
|
185
|
+
y=rect.y,
|
|
186
|
+
width=rect.width,
|
|
187
|
+
)
|
|
188
|
+
return [Tile.State64(tile_index=tile_index, rect=return_rect, colors=colors)]
|
|
177
189
|
|
|
178
190
|
|
|
179
191
|
class Set64Handler(PacketHandler):
|
|
@@ -188,16 +200,60 @@ class Set64Handler(PacketHandler):
|
|
|
188
200
|
return []
|
|
189
201
|
|
|
190
202
|
tile_index = packet.tile_index
|
|
203
|
+
fb_index = packet.rect.fb_index
|
|
191
204
|
|
|
192
|
-
if tile_index
|
|
193
|
-
|
|
194
|
-
for i, color in enumerate(packet.colors[:64]):
|
|
195
|
-
if i < len(device_state.tile_devices[tile_index]["colors"]):
|
|
196
|
-
device_state.tile_devices[tile_index]["colors"][i] = color
|
|
205
|
+
if tile_index >= len(device_state.tile_devices):
|
|
206
|
+
return []
|
|
197
207
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
208
|
+
tile = device_state.tile_devices[tile_index]
|
|
209
|
+
tile_width = tile["width"]
|
|
210
|
+
tile_height = tile["height"]
|
|
211
|
+
rect = packet.rect
|
|
212
|
+
|
|
213
|
+
# Determine which framebuffer to update
|
|
214
|
+
if fb_index == 0:
|
|
215
|
+
# Update visible framebuffer (stored in tile_devices)
|
|
216
|
+
target_colors = tile["colors"]
|
|
217
|
+
else:
|
|
218
|
+
# Update non-visible framebuffer (stored in tile_framebuffers)
|
|
219
|
+
if tile_index < len(device_state.tile_framebuffers):
|
|
220
|
+
fb_storage = device_state.tile_framebuffers[tile_index]
|
|
221
|
+
target_colors = fb_storage.get_framebuffer(
|
|
222
|
+
fb_index, tile_width, tile_height
|
|
223
|
+
)
|
|
224
|
+
else:
|
|
225
|
+
logger.warning(f"Tile {tile_index} framebuffer storage not initialized")
|
|
226
|
+
return []
|
|
227
|
+
|
|
228
|
+
# Update colors in the specified rectangle
|
|
229
|
+
# Calculate how many rows fit in 64 pixels
|
|
230
|
+
rows_to_write = 64 // rect.width if rect.width > 0 else 1
|
|
231
|
+
rows_to_write = min(rows_to_write, tile_height - rect.y)
|
|
232
|
+
|
|
233
|
+
pixels_written = 0
|
|
234
|
+
for row in range(rows_to_write):
|
|
235
|
+
y = rect.y + row
|
|
236
|
+
if y >= tile_height:
|
|
237
|
+
break
|
|
238
|
+
|
|
239
|
+
for col in range(rect.width):
|
|
240
|
+
x = rect.x + col
|
|
241
|
+
if x >= tile_width or pixels_written >= 64:
|
|
242
|
+
pixels_written += 1
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
# Calculate pixel index in flat color array
|
|
246
|
+
pixel_idx = y * tile_width + x
|
|
247
|
+
if pixel_idx < len(target_colors) and pixels_written < len(
|
|
248
|
+
packet.colors
|
|
249
|
+
):
|
|
250
|
+
target_colors[pixel_idx] = packet.colors[pixels_written]
|
|
251
|
+
pixels_written += 1
|
|
252
|
+
|
|
253
|
+
logger.info(
|
|
254
|
+
f"Tile {tile_index} FB{fb_index} set {pixels_written} colors at "
|
|
255
|
+
f"({rect.x},{rect.y}), duration={packet.duration}ms"
|
|
256
|
+
)
|
|
201
257
|
|
|
202
258
|
# Tiles never return a response to Set64 regardless of res_required
|
|
203
259
|
# https://lan.developer.lifx.com/docs/changing-a-device#set64---packet-715
|
|
@@ -212,12 +268,83 @@ class CopyFrameBufferHandler(PacketHandler):
|
|
|
212
268
|
def handle(
|
|
213
269
|
self, device_state: DeviceState, packet: Any | None, res_required: bool
|
|
214
270
|
) -> list[Any]:
|
|
215
|
-
if not device_state.has_matrix:
|
|
271
|
+
if not device_state.has_matrix or not packet:
|
|
272
|
+
return []
|
|
273
|
+
|
|
274
|
+
tile_index = packet.tile_index
|
|
275
|
+
if tile_index >= len(device_state.tile_devices):
|
|
216
276
|
return []
|
|
217
277
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
278
|
+
tile = device_state.tile_devices[tile_index]
|
|
279
|
+
tile_width = tile["width"]
|
|
280
|
+
tile_height = tile["height"]
|
|
281
|
+
|
|
282
|
+
src_fb_index = packet.src_fb_index
|
|
283
|
+
dst_fb_index = packet.dst_fb_index
|
|
284
|
+
|
|
285
|
+
# Get source framebuffer
|
|
286
|
+
if src_fb_index == 0:
|
|
287
|
+
src_colors = tile["colors"]
|
|
288
|
+
else:
|
|
289
|
+
if tile_index < len(device_state.tile_framebuffers):
|
|
290
|
+
fb_storage = device_state.tile_framebuffers[tile_index]
|
|
291
|
+
src_colors = fb_storage.get_framebuffer(
|
|
292
|
+
src_fb_index, tile_width, tile_height
|
|
293
|
+
)
|
|
294
|
+
else:
|
|
295
|
+
logger.warning(f"Tile {tile_index} framebuffer storage not initialized")
|
|
296
|
+
return []
|
|
297
|
+
|
|
298
|
+
# Get destination framebuffer
|
|
299
|
+
if dst_fb_index == 0:
|
|
300
|
+
dst_colors = tile["colors"]
|
|
301
|
+
else:
|
|
302
|
+
if tile_index < len(device_state.tile_framebuffers):
|
|
303
|
+
fb_storage = device_state.tile_framebuffers[tile_index]
|
|
304
|
+
dst_colors = fb_storage.get_framebuffer(
|
|
305
|
+
dst_fb_index, tile_width, tile_height
|
|
306
|
+
)
|
|
307
|
+
else:
|
|
308
|
+
logger.warning(f"Tile {tile_index} framebuffer storage not initialized")
|
|
309
|
+
return []
|
|
310
|
+
|
|
311
|
+
# Copy the specified rectangle from source to destination
|
|
312
|
+
src_x = packet.src_x
|
|
313
|
+
src_y = packet.src_y
|
|
314
|
+
dst_x = packet.dst_x
|
|
315
|
+
dst_y = packet.dst_y
|
|
316
|
+
width = packet.width
|
|
317
|
+
height = packet.height
|
|
318
|
+
|
|
319
|
+
pixels_copied = 0
|
|
320
|
+
for row in range(height):
|
|
321
|
+
src_row = src_y + row
|
|
322
|
+
dst_row = dst_y + row
|
|
323
|
+
|
|
324
|
+
if src_row >= tile_height or dst_row >= tile_height:
|
|
325
|
+
break
|
|
326
|
+
|
|
327
|
+
for col in range(width):
|
|
328
|
+
src_col = src_x + col
|
|
329
|
+
dst_col = dst_x + col
|
|
330
|
+
|
|
331
|
+
if src_col >= tile_width or dst_col >= tile_width:
|
|
332
|
+
continue
|
|
333
|
+
|
|
334
|
+
src_idx = src_row * tile_width + src_col
|
|
335
|
+
dst_idx = dst_row * tile_width + dst_col
|
|
336
|
+
|
|
337
|
+
if src_idx < len(src_colors) and dst_idx < len(dst_colors):
|
|
338
|
+
dst_colors[dst_idx] = src_colors[src_idx]
|
|
339
|
+
pixels_copied += 1
|
|
340
|
+
|
|
341
|
+
logger.info(
|
|
342
|
+
f"Tile {tile_index} copied {pixels_copied} pixels from "
|
|
343
|
+
f"FB{src_fb_index}({src_x},{src_y}) to "
|
|
344
|
+
f"FB{dst_fb_index}({dst_x},{dst_y}), "
|
|
345
|
+
f"size={width}x{height}, duration={packet.duration}ms"
|
|
346
|
+
)
|
|
347
|
+
|
|
221
348
|
return []
|
|
222
349
|
|
|
223
350
|
|
|
@@ -15,13 +15,13 @@ lifx_emulator/api/services/__init__.py,sha256=ttjjZfAxbDQC_Ep0LkXjopNiVZOFPsFDSO
|
|
|
15
15
|
lifx_emulator/api/services/device_service.py,sha256=r3uFWApC8sVQMCuuzkyjm27K4LDpZnnHmQNgXWX40ok,6294
|
|
16
16
|
lifx_emulator/api/templates/dashboard.html,sha256=YXQ9jrs30DZIxtMWFE4E2HqmsgHQ-NeWTTQxQ-7BfHk,33800
|
|
17
17
|
lifx_emulator/devices/__init__.py,sha256=QlBTPnFErJcSKLvGyeDwemh7xcpjYvB_L5siKsjr3s8,1089
|
|
18
|
-
lifx_emulator/devices/device.py,sha256=
|
|
18
|
+
lifx_emulator/devices/device.py,sha256=LIVXURglYsYMC6_88sAWzoJKkq_HSZEOu4xruRtcZKs,13650
|
|
19
19
|
lifx_emulator/devices/manager.py,sha256=XDrT82um5sgNpNihLj5RsNvHqdVI1bK9YY2eBzWIcf0,8162
|
|
20
20
|
lifx_emulator/devices/observers.py,sha256=-KnUgFcKdhlNo7CNVstP-u0wU2W0JAGg055ZPV15Sj0,3874
|
|
21
21
|
lifx_emulator/devices/persistence.py,sha256=9Mhj46-xrweOmyzjORCi2jKIwa8XJWpQ5CgaKcw6U98,10513
|
|
22
22
|
lifx_emulator/devices/state_restorer.py,sha256=eDsRSW-2RviP_0Qlk2DHqMaB-zhV0X1cNQECv2lD1qc,9809
|
|
23
|
-
lifx_emulator/devices/state_serializer.py,sha256=
|
|
24
|
-
lifx_emulator/devices/states.py,sha256=
|
|
23
|
+
lifx_emulator/devices/state_serializer.py,sha256=aws4LUmXBJS8oBrQziJtlV0XMvCTm5X4dGkGlO_QHcM,6281
|
|
24
|
+
lifx_emulator/devices/states.py,sha256=O__VtgK97-ZHxZ2qgOKp9-fDG8HcmlTVkGYONwot8iQ,12094
|
|
25
25
|
lifx_emulator/factories/__init__.py,sha256=yN8i_Hu_cFEryWZmh0TiOQvWEYFVIApQSs4xeb0EfBk,1170
|
|
26
26
|
lifx_emulator/factories/builder.py,sha256=OaDqQDGkAyZCSO-4HAsFSd5UzsHpHvRyBk-Fotl1mAY,12056
|
|
27
27
|
lifx_emulator/factories/default_config.py,sha256=FTcxKDfeTmO49GTSki8nxnEIZQzR0Lg0hL_PwHUrkVQ,4828
|
|
@@ -34,7 +34,7 @@ lifx_emulator/handlers/device_handlers.py,sha256=1AmslA4Ut6L7b3SfduDdvnQizTpzUB3
|
|
|
34
34
|
lifx_emulator/handlers/light_handlers.py,sha256=Ryz-_fzoVCT6DBkXhW9YCOYJYaMRcBOIguL3HrQXhAw,11471
|
|
35
35
|
lifx_emulator/handlers/multizone_handlers.py,sha256=2dYsitq0KzEaxEAJmz7ixtir1tvFMOAnfkBQqslqbPM,7914
|
|
36
36
|
lifx_emulator/handlers/registry.py,sha256=s1ht4PmPhXhAcwu1hoY4yW39wy3SPJBMY-9Uxd0FWuE,3292
|
|
37
|
-
lifx_emulator/handlers/tile_handlers.py,sha256=
|
|
37
|
+
lifx_emulator/handlers/tile_handlers.py,sha256=tniYndUbtWPTu7YznfMKsWUBu2UmGsSuOYRws5IBL0s,17239
|
|
38
38
|
lifx_emulator/products/__init__.py,sha256=qcNop_kRYFF3zSjNemzQEgu3jPrIxfyQyLv9GsnaLEI,627
|
|
39
39
|
lifx_emulator/products/generator.py,sha256=5zcq0iKgwjtg0gePnBEOdIkumesvfzEcKRdBZFPyGtk,33538
|
|
40
40
|
lifx_emulator/products/registry.py,sha256=qkm2xgGZo_ds3wAbYplLu4gb0cxhjZXjnCc1V8etpHw,46517
|
|
@@ -55,8 +55,8 @@ lifx_emulator/scenarios/__init__.py,sha256=CGjudoWvyysvFj2xej11N2cr3mYROGtRb9zVH
|
|
|
55
55
|
lifx_emulator/scenarios/manager.py,sha256=1esxRdz74UynNk1wb86MGZ2ZFAuMzByuu74nRe3D-Og,11163
|
|
56
56
|
lifx_emulator/scenarios/models.py,sha256=BKS_fGvrbkGe-vK3arZ0w2f9adS1UZhiOoKpu7GENnc,4099
|
|
57
57
|
lifx_emulator/scenarios/persistence.py,sha256=3vjtPNFYfag38tUxuqxkGpWhQ7uBitc1rLroSAuw9N8,8881
|
|
58
|
-
lifx_emulator-2.
|
|
59
|
-
lifx_emulator-2.
|
|
60
|
-
lifx_emulator-2.
|
|
61
|
-
lifx_emulator-2.
|
|
62
|
-
lifx_emulator-2.
|
|
58
|
+
lifx_emulator-2.3.0.dist-info/METADATA,sha256=PsbeOthCdD824wzYnw8vf_rKKze3Yk1DPC6NtpkZv1Q,4549
|
|
59
|
+
lifx_emulator-2.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
60
|
+
lifx_emulator-2.3.0.dist-info/entry_points.txt,sha256=R9C_K_tTgt6yXEmhzH4r2Yx2Tu1rLlnYzeG4RFUVzSc,62
|
|
61
|
+
lifx_emulator-2.3.0.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
|
|
62
|
+
lifx_emulator-2.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|