lifx-emulator 1.0.2__py3-none-any.whl → 2.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 +1 -1
- lifx_emulator/__main__.py +26 -51
- lifx_emulator/api/__init__.py +18 -0
- lifx_emulator/api/app.py +154 -0
- lifx_emulator/api/mappers/__init__.py +5 -0
- lifx_emulator/api/mappers/device_mapper.py +114 -0
- lifx_emulator/api/models.py +133 -0
- lifx_emulator/api/routers/__init__.py +11 -0
- lifx_emulator/api/routers/devices.py +130 -0
- lifx_emulator/api/routers/monitoring.py +52 -0
- lifx_emulator/api/routers/scenarios.py +247 -0
- lifx_emulator/api/services/__init__.py +8 -0
- lifx_emulator/api/services/device_service.py +198 -0
- lifx_emulator/{api.py → api/templates/dashboard.html} +0 -942
- lifx_emulator/devices/__init__.py +37 -0
- lifx_emulator/devices/device.py +333 -0
- lifx_emulator/devices/manager.py +256 -0
- lifx_emulator/{async_storage.py → devices/persistence.py} +3 -3
- lifx_emulator/{state_restorer.py → devices/state_restorer.py} +2 -2
- lifx_emulator/devices/states.py +333 -0
- lifx_emulator/factories/__init__.py +37 -0
- lifx_emulator/factories/builder.py +371 -0
- lifx_emulator/factories/default_config.py +158 -0
- lifx_emulator/factories/factory.py +221 -0
- lifx_emulator/factories/firmware_config.py +59 -0
- lifx_emulator/factories/serial_generator.py +82 -0
- lifx_emulator/handlers/base.py +1 -1
- lifx_emulator/handlers/device_handlers.py +10 -28
- lifx_emulator/handlers/light_handlers.py +5 -9
- lifx_emulator/handlers/multizone_handlers.py +1 -1
- lifx_emulator/handlers/tile_handlers.py +1 -1
- lifx_emulator/products/generator.py +389 -170
- lifx_emulator/products/registry.py +52 -40
- lifx_emulator/products/specs.py +12 -13
- lifx_emulator/protocol/base.py +115 -61
- lifx_emulator/protocol/generator.py +18 -5
- lifx_emulator/protocol/packets.py +7 -7
- lifx_emulator/repositories/__init__.py +22 -0
- lifx_emulator/repositories/device_repository.py +155 -0
- lifx_emulator/repositories/storage_backend.py +107 -0
- lifx_emulator/scenarios/__init__.py +22 -0
- lifx_emulator/{scenario_manager.py → scenarios/manager.py} +11 -91
- lifx_emulator/scenarios/models.py +112 -0
- lifx_emulator/{scenario_persistence.py → scenarios/persistence.py} +82 -47
- lifx_emulator/server.py +38 -64
- {lifx_emulator-1.0.2.dist-info → lifx_emulator-2.0.0.dist-info}/METADATA +1 -1
- lifx_emulator-2.0.0.dist-info/RECORD +62 -0
- lifx_emulator/device.py +0 -750
- lifx_emulator/device_states.py +0 -114
- lifx_emulator/factories.py +0 -380
- lifx_emulator/storage_protocol.py +0 -100
- lifx_emulator-1.0.2.dist-info/RECORD +0 -40
- /lifx_emulator/{observers.py → devices/observers.py} +0 -0
- /lifx_emulator/{state_serializer.py → devices/state_serializer.py} +0 -0
- {lifx_emulator-1.0.2.dist-info → lifx_emulator-2.0.0.dist-info}/WHEEL +0 -0
- {lifx_emulator-1.0.2.dist-info → lifx_emulator-2.0.0.dist-info}/entry_points.txt +0 -0
- {lifx_emulator-1.0.2.dist-info → lifx_emulator-2.0.0.dist-info}/licenses/LICENSE +0 -0
lifx_emulator/server.py
CHANGED
|
@@ -9,17 +9,18 @@ from collections import defaultdict
|
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
11
|
from lifx_emulator.constants import LIFX_HEADER_SIZE, LIFX_UDP_PORT
|
|
12
|
-
from lifx_emulator.
|
|
13
|
-
from lifx_emulator.observers import (
|
|
12
|
+
from lifx_emulator.devices import (
|
|
14
13
|
ActivityLogger,
|
|
15
14
|
ActivityObserver,
|
|
15
|
+
EmulatedLifxDevice,
|
|
16
|
+
IDeviceManager,
|
|
16
17
|
NullObserver,
|
|
17
18
|
PacketEvent,
|
|
18
19
|
)
|
|
19
20
|
from lifx_emulator.protocol.header import LifxHeader
|
|
20
21
|
from lifx_emulator.protocol.packets import get_packet_class
|
|
21
|
-
from lifx_emulator.
|
|
22
|
-
from lifx_emulator.
|
|
22
|
+
from lifx_emulator.repositories import IScenarioStorageBackend
|
|
23
|
+
from lifx_emulator.scenarios import HierarchicalScenarioManager
|
|
23
24
|
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
25
26
|
|
|
@@ -91,6 +92,7 @@ class EmulatedLifxServer:
|
|
|
91
92
|
def __init__(
|
|
92
93
|
self,
|
|
93
94
|
devices: list[EmulatedLifxDevice],
|
|
95
|
+
device_manager: IDeviceManager,
|
|
94
96
|
bind_address: str = "127.0.0.1",
|
|
95
97
|
port: int = LIFX_UDP_PORT,
|
|
96
98
|
track_activity: bool = True,
|
|
@@ -98,30 +100,35 @@ class EmulatedLifxServer:
|
|
|
98
100
|
activity_observer: ActivityObserver | None = None,
|
|
99
101
|
scenario_manager: HierarchicalScenarioManager | None = None,
|
|
100
102
|
persist_scenarios: bool = False,
|
|
103
|
+
scenario_storage: IScenarioStorageBackend | None = None,
|
|
101
104
|
):
|
|
102
|
-
|
|
105
|
+
# Device manager (required dependency injection)
|
|
106
|
+
self._device_manager = device_manager
|
|
103
107
|
self.bind_address = bind_address
|
|
104
108
|
self.port = port
|
|
105
109
|
self.transport = None
|
|
106
110
|
self.storage = storage
|
|
107
111
|
|
|
108
|
-
# Scenario
|
|
109
|
-
self.scenario_persistence:
|
|
112
|
+
# Scenario storage backend (optional - only needed for persistence)
|
|
113
|
+
self.scenario_persistence: IScenarioStorageBackend | None = None
|
|
110
114
|
if persist_scenarios:
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
if scenario_storage is None:
|
|
116
|
+
raise ValueError(
|
|
117
|
+
"scenario_storage is required when persist_scenarios=True"
|
|
118
|
+
)
|
|
113
119
|
if scenario_manager is None:
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
raise ValueError(
|
|
121
|
+
"scenario_manager is required when persist_scenarios=True "
|
|
122
|
+
"(must be pre-loaded from storage before server initialization)"
|
|
123
|
+
)
|
|
124
|
+
self.scenario_persistence = scenario_storage
|
|
116
125
|
|
|
117
126
|
# Scenario manager (shared across all devices for runtime updates)
|
|
118
127
|
self.scenario_manager = scenario_manager or HierarchicalScenarioManager()
|
|
119
128
|
|
|
120
|
-
#
|
|
129
|
+
# Add initial devices to the device manager
|
|
121
130
|
for device in devices:
|
|
122
|
-
|
|
123
|
-
device.scenario_manager = self.scenario_manager
|
|
124
|
-
device.invalidate_scenario_cache()
|
|
131
|
+
self._device_manager.add_device(device, self.scenario_manager)
|
|
125
132
|
|
|
126
133
|
# Activity observer - defaults to ActivityLogger if track_activity=True
|
|
127
134
|
if activity_observer is not None:
|
|
@@ -320,18 +327,8 @@ class EmulatedLifxServer:
|
|
|
320
327
|
)
|
|
321
328
|
)
|
|
322
329
|
|
|
323
|
-
# Determine target devices
|
|
324
|
-
target_devices =
|
|
325
|
-
if header.tagged or header.target == b"\x00" * 8:
|
|
326
|
-
# Broadcast to all devices
|
|
327
|
-
target_devices = list(self.devices.values())
|
|
328
|
-
else:
|
|
329
|
-
# Specific device - convert target bytes to serial string
|
|
330
|
-
# Target is 8 bytes: 6-byte MAC + 2 null bytes
|
|
331
|
-
target_serial = header.target[:6].hex()
|
|
332
|
-
device = self.devices.get(target_serial)
|
|
333
|
-
if device:
|
|
334
|
-
target_devices = [device]
|
|
330
|
+
# Determine target devices using device manager
|
|
331
|
+
target_devices = self._device_manager.resolve_target_devices(header)
|
|
335
332
|
|
|
336
333
|
# Process packet for each target device
|
|
337
334
|
# Use parallel processing for broadcasts to improve scalability
|
|
@@ -361,18 +358,7 @@ class EmulatedLifxServer:
|
|
|
361
358
|
Returns:
|
|
362
359
|
True if added, False if device with same serial already exists
|
|
363
360
|
"""
|
|
364
|
-
|
|
365
|
-
if serial in self.devices:
|
|
366
|
-
return False
|
|
367
|
-
|
|
368
|
-
# If device is using HierarchicalScenarioManager, share the server's manager
|
|
369
|
-
if isinstance(device.scenario_manager, HierarchicalScenarioManager):
|
|
370
|
-
device.scenario_manager = self.scenario_manager
|
|
371
|
-
device.invalidate_scenario_cache()
|
|
372
|
-
|
|
373
|
-
self.devices[serial] = device
|
|
374
|
-
logger.info("Added device: %s (product=%s)", serial, device.state.product)
|
|
375
|
-
return True
|
|
361
|
+
return self._device_manager.add_device(device, self.scenario_manager)
|
|
376
362
|
|
|
377
363
|
def remove_device(self, serial: str) -> bool:
|
|
378
364
|
"""Remove a device from the server.
|
|
@@ -383,16 +369,7 @@ class EmulatedLifxServer:
|
|
|
383
369
|
Returns:
|
|
384
370
|
True if removed, False if device not found
|
|
385
371
|
"""
|
|
386
|
-
|
|
387
|
-
return False
|
|
388
|
-
self.devices.pop(serial)
|
|
389
|
-
logger.info("Removed device: %s", serial)
|
|
390
|
-
|
|
391
|
-
# Delete persistent storage if enabled
|
|
392
|
-
if self.storage:
|
|
393
|
-
self.storage.delete_device_state(serial)
|
|
394
|
-
|
|
395
|
-
return True
|
|
372
|
+
return self._device_manager.remove_device(serial, self.storage)
|
|
396
373
|
|
|
397
374
|
def remove_all_devices(self, delete_storage: bool = False) -> int:
|
|
398
375
|
"""Remove all devices from the server.
|
|
@@ -403,18 +380,7 @@ class EmulatedLifxServer:
|
|
|
403
380
|
Returns:
|
|
404
381
|
Number of devices removed
|
|
405
382
|
"""
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
# Clear devices dict
|
|
409
|
-
self.devices.clear()
|
|
410
|
-
logger.info("Removed all %s device(s) from server", device_count)
|
|
411
|
-
|
|
412
|
-
# Delete persistent storage if requested
|
|
413
|
-
if delete_storage and self.storage:
|
|
414
|
-
deleted = self.storage.delete_all_device_states()
|
|
415
|
-
logger.info("Deleted %s device state(s) from persistent storage", deleted)
|
|
416
|
-
|
|
417
|
-
return device_count
|
|
383
|
+
return self._device_manager.remove_all_devices(delete_storage, self.storage)
|
|
418
384
|
|
|
419
385
|
def get_device(self, serial: str) -> EmulatedLifxDevice | None:
|
|
420
386
|
"""Get a device by serial number.
|
|
@@ -425,7 +391,7 @@ class EmulatedLifxServer:
|
|
|
425
391
|
Returns:
|
|
426
392
|
Device if found, None otherwise
|
|
427
393
|
"""
|
|
428
|
-
return self.
|
|
394
|
+
return self._device_manager.get_device(serial)
|
|
429
395
|
|
|
430
396
|
def get_all_devices(self) -> list[EmulatedLifxDevice]:
|
|
431
397
|
"""Get all devices.
|
|
@@ -433,7 +399,15 @@ class EmulatedLifxServer:
|
|
|
433
399
|
Returns:
|
|
434
400
|
List of all devices
|
|
435
401
|
"""
|
|
436
|
-
return
|
|
402
|
+
return self._device_manager.get_all_devices()
|
|
403
|
+
|
|
404
|
+
def invalidate_all_scenario_caches(self) -> None:
|
|
405
|
+
"""Invalidate scenario cache for all devices.
|
|
406
|
+
|
|
407
|
+
This should be called when scenario configuration changes to ensure
|
|
408
|
+
devices reload their scenario settings from the scenario manager.
|
|
409
|
+
"""
|
|
410
|
+
self._device_manager.invalidate_all_scenario_caches()
|
|
437
411
|
|
|
438
412
|
def get_stats(self) -> dict[str, Any]:
|
|
439
413
|
"""Get server statistics.
|
|
@@ -445,7 +419,7 @@ class EmulatedLifxServer:
|
|
|
445
419
|
return {
|
|
446
420
|
"uptime_seconds": uptime,
|
|
447
421
|
"start_time": self.start_time,
|
|
448
|
-
"device_count":
|
|
422
|
+
"device_count": self._device_manager.count_devices(),
|
|
449
423
|
"packets_received": self.packets_received,
|
|
450
424
|
"packets_sent": self.packets_sent,
|
|
451
425
|
"packets_received_by_type": dict(self.packets_received_by_type),
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
lifx_emulator/__init__.py,sha256=vjhtpAQRSsUZtaUGCQKbmPALvwZ_BF8Mko8w6jzVqBw,819
|
|
2
|
+
lifx_emulator/__main__.py,sha256=zaul9OQhN5csqOqxGWXkVrlurfo2R_-YvM6URk4QAME,21680
|
|
3
|
+
lifx_emulator/constants.py,sha256=DFZkUsdewE-x_3MgO28tMGkjUCWPeYc3xLj_EXViGOw,1032
|
|
4
|
+
lifx_emulator/server.py,sha256=0bn7oDIlC6TTOJj9ULXLp9rCFAFcW4vM4whor7VTuRU,16391
|
|
5
|
+
lifx_emulator/api/__init__.py,sha256=FoEPw_In5-H_BDQ-XIIONvgj-UqIDVtejIEVRv9qmV8,647
|
|
6
|
+
lifx_emulator/api/app.py,sha256=IxK8sC7MgdtkoLz8iXcEt02nPDaVgdKJgEiGnzTs-YE,4880
|
|
7
|
+
lifx_emulator/api/models.py,sha256=eBx80Ece_4Wv6aqxb1CsZEob9CF0WmR9oJGz3hh14x8,3973
|
|
8
|
+
lifx_emulator/api/mappers/__init__.py,sha256=ZPCOQR9odcwn0C58AjFW6RvBXe5gOll_QS5lAabgorQ,152
|
|
9
|
+
lifx_emulator/api/mappers/device_mapper.py,sha256=EGOpdao9ZS-vT4T8IoV-AoN5WucTnqpQO92dYizo3vw,4151
|
|
10
|
+
lifx_emulator/api/routers/__init__.py,sha256=kbMefnuXrEsYeMA9J4YK_wVs87_XcH7hwkEifR-zgMc,369
|
|
11
|
+
lifx_emulator/api/routers/devices.py,sha256=i0hFxb9-yA3bbNsk1HyDhHfpAB61o5rObH_vC9gDEpk,4210
|
|
12
|
+
lifx_emulator/api/routers/monitoring.py,sha256=qgVBNm6iMESf1W6EE22DvLalMnxkr0pRbGKu_JDDkPw,1456
|
|
13
|
+
lifx_emulator/api/routers/scenarios.py,sha256=0axSQ9r6rByvXLvqRqOU2ma5nTvZgZ0IIzEXdtzoPnM,9743
|
|
14
|
+
lifx_emulator/api/services/__init__.py,sha256=ttjjZfAxbDQC_Ep0LkXjopNiVZOFPsFDSOHhBN98v5s,277
|
|
15
|
+
lifx_emulator/api/services/device_service.py,sha256=r3uFWApC8sVQMCuuzkyjm27K4LDpZnnHmQNgXWX40ok,6294
|
|
16
|
+
lifx_emulator/api/templates/dashboard.html,sha256=YXQ9jrs30DZIxtMWFE4E2HqmsgHQ-NeWTTQxQ-7BfHk,33800
|
|
17
|
+
lifx_emulator/devices/__init__.py,sha256=QlBTPnFErJcSKLvGyeDwemh7xcpjYvB_L5siKsjr3s8,1089
|
|
18
|
+
lifx_emulator/devices/device.py,sha256=LMdg__95n6geG_32j7qp5yl51WNS3ZbCXn-xMfVVikE,13294
|
|
19
|
+
lifx_emulator/devices/manager.py,sha256=XDrT82um5sgNpNihLj5RsNvHqdVI1bK9YY2eBzWIcf0,8162
|
|
20
|
+
lifx_emulator/devices/observers.py,sha256=-KnUgFcKdhlNo7CNVstP-u0wU2W0JAGg055ZPV15Sj0,3874
|
|
21
|
+
lifx_emulator/devices/persistence.py,sha256=9Mhj46-xrweOmyzjORCi2jKIwa8XJWpQ5CgaKcw6U98,10513
|
|
22
|
+
lifx_emulator/devices/state_restorer.py,sha256=eDsRSW-2RviP_0Qlk2DHqMaB-zhV0X1cNQECv2lD1qc,9809
|
|
23
|
+
lifx_emulator/devices/state_serializer.py,sha256=O4Cp3bbGkd4eZf5jzb0MKzWDTgiNhrSGgypmMWaB4dg,5097
|
|
24
|
+
lifx_emulator/devices/states.py,sha256=ealrShXAqEeKYnyNclTGgWxV9uDf3VYyw4SbRHe1xEk,10205
|
|
25
|
+
lifx_emulator/factories/__init__.py,sha256=yN8i_Hu_cFEryWZmh0TiOQvWEYFVIApQSs4xeb0EfBk,1170
|
|
26
|
+
lifx_emulator/factories/builder.py,sha256=ZSz5apcorsKpuPsdjFE4VLC1p41jVY8MWs1-nRBOLMk,11996
|
|
27
|
+
lifx_emulator/factories/default_config.py,sha256=FTcxKDfeTmO49GTSki8nxnEIZQzR0Lg0hL_PwHUrkVQ,4828
|
|
28
|
+
lifx_emulator/factories/factory.py,sha256=VQfU5M8zrpFyNHjpGP1q-3bpek9MltBdoAUSvIvt7Bs,7583
|
|
29
|
+
lifx_emulator/factories/firmware_config.py,sha256=AzvPvR4pfwjK1yNsaua1L9V1gLVItUVySjcGrXIWnEw,1932
|
|
30
|
+
lifx_emulator/factories/serial_generator.py,sha256=MbaXoommsj76ho8_ZoKuUDnffDf98YvwQiXZSWsUsEs,2507
|
|
31
|
+
lifx_emulator/handlers/__init__.py,sha256=3Hj1hRo3yL3E7GKwG9TaYh33ymk_N3bRiQ8nvqSQULA,1306
|
|
32
|
+
lifx_emulator/handlers/base.py,sha256=0avCLXY_rNlw16PpJ5JrRCwXNE4uMpBqF3PfSfNJ0b8,1654
|
|
33
|
+
lifx_emulator/handlers/device_handlers.py,sha256=1AmslA4Ut6L7b3SfduDdvnQizTpzUB3KKWBXmp4WYLQ,9462
|
|
34
|
+
lifx_emulator/handlers/light_handlers.py,sha256=Ryz-_fzoVCT6DBkXhW9YCOYJYaMRcBOIguL3HrQXhAw,11471
|
|
35
|
+
lifx_emulator/handlers/multizone_handlers.py,sha256=2dYsitq0KzEaxEAJmz7ixtir1tvFMOAnfkBQqslqbPM,7914
|
|
36
|
+
lifx_emulator/handlers/registry.py,sha256=s1ht4PmPhXhAcwu1hoY4yW39wy3SPJBMY-9Uxd0FWuE,3292
|
|
37
|
+
lifx_emulator/handlers/tile_handlers.py,sha256=D23dQVwukfKccryNEFrojMFhubcg4p-onMCXEDRyTlc,10039
|
|
38
|
+
lifx_emulator/products/__init__.py,sha256=qcNop_kRYFF3zSjNemzQEgu3jPrIxfyQyLv9GsnaLEI,627
|
|
39
|
+
lifx_emulator/products/generator.py,sha256=NYInVSGyYIxAYMpTihqBtXP06lAYVfbSYe0Wv5Hg9vQ,31758
|
|
40
|
+
lifx_emulator/products/registry.py,sha256=qkm2xgGZo_ds3wAbYplLu4gb0cxhjZXjnCc1V8etpHw,46517
|
|
41
|
+
lifx_emulator/products/specs.py,sha256=pfmQMrQxlCGqORs3MbsH_vmCvxdaDwjVzXUCVZCjFCI,7093
|
|
42
|
+
lifx_emulator/products/specs.yml,sha256=uxzdKFREAHphk8XSPiCHvQE2vwoPfT2m1xy-zC4ZIl4,8552
|
|
43
|
+
lifx_emulator/protocol/__init__.py,sha256=-wjC-wBcb7fxi5I-mJr2Ad8K2YRflJFdLLdobfD-W1Q,56
|
|
44
|
+
lifx_emulator/protocol/base.py,sha256=8DyJBhJi9k5LH4qRe-9P-XBC0iUEH01lGodoADH6Za8,13209
|
|
45
|
+
lifx_emulator/protocol/const.py,sha256=ilhv-KcQpHtKh2MDCaIbMLQAsxKO_uTaxyR63v1W8cc,226
|
|
46
|
+
lifx_emulator/protocol/generator.py,sha256=LUkf-1Z5570Vg5iA1QhDZDWQOrABqmukUgk9qH-IJmg,49524
|
|
47
|
+
lifx_emulator/protocol/header.py,sha256=RXMJ5YZG1jyxl4Mz46ZGJBYX41Jdp7J95BHuY-scYC0,5499
|
|
48
|
+
lifx_emulator/protocol/packets.py,sha256=Yv4O-Uqbj0CR7n04vXhfalJVCmTTvJTWkvZBkcwPx-U,41553
|
|
49
|
+
lifx_emulator/protocol/protocol_types.py,sha256=2Mccm9717EuTXQYaW44W_yReI4EtnlPp3-WEVASgdGY,24820
|
|
50
|
+
lifx_emulator/protocol/serializer.py,sha256=2bZz7TddxaMRO4_6LujRGCS1w7GxD4E3rRk3r-hpEIE,10738
|
|
51
|
+
lifx_emulator/repositories/__init__.py,sha256=x-ncM6T_Q7jNrwhK4a1uAyMrTGHHGeUzPSLC4O-kEUw,645
|
|
52
|
+
lifx_emulator/repositories/device_repository.py,sha256=KsXVg2sg7PGSTsK_PvDYeHHwEPM9Qx2ZZF_ORncBrYQ,3929
|
|
53
|
+
lifx_emulator/repositories/storage_backend.py,sha256=wEgjhnBvAxl6aO1ZGL3ou0dW9P2hBPnK8jEE03sOlL4,3264
|
|
54
|
+
lifx_emulator/scenarios/__init__.py,sha256=CGjudoWvyysvFj2xej11N2cr3mYROGtRb9zVHcOHGrQ,665
|
|
55
|
+
lifx_emulator/scenarios/manager.py,sha256=1esxRdz74UynNk1wb86MGZ2ZFAuMzByuu74nRe3D-Og,11163
|
|
56
|
+
lifx_emulator/scenarios/models.py,sha256=BKS_fGvrbkGe-vK3arZ0w2f9adS1UZhiOoKpu7GENnc,4099
|
|
57
|
+
lifx_emulator/scenarios/persistence.py,sha256=3vjtPNFYfag38tUxuqxkGpWhQ7uBitc1rLroSAuw9N8,8881
|
|
58
|
+
lifx_emulator-2.0.0.dist-info/METADATA,sha256=u29qYpMQ0IbZju5mormUZu6Nye04gpQnxBMWnmSYNiM,4549
|
|
59
|
+
lifx_emulator-2.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
60
|
+
lifx_emulator-2.0.0.dist-info/entry_points.txt,sha256=R9C_K_tTgt6yXEmhzH4r2Yx2Tu1rLlnYzeG4RFUVzSc,62
|
|
61
|
+
lifx_emulator-2.0.0.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
|
|
62
|
+
lifx_emulator-2.0.0.dist-info/RECORD,,
|