lifx-emulator 2.4.0__py3-none-any.whl → 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. lifx_emulator-3.1.0.dist-info/METADATA +103 -0
  2. lifx_emulator-3.1.0.dist-info/RECORD +19 -0
  3. {lifx_emulator-2.4.0.dist-info → lifx_emulator-3.1.0.dist-info}/WHEEL +1 -1
  4. lifx_emulator-3.1.0.dist-info/entry_points.txt +2 -0
  5. lifx_emulator_app/__init__.py +10 -0
  6. {lifx_emulator → lifx_emulator_app}/__main__.py +2 -3
  7. {lifx_emulator → lifx_emulator_app}/api/__init__.py +1 -1
  8. {lifx_emulator → lifx_emulator_app}/api/app.py +9 -4
  9. {lifx_emulator → lifx_emulator_app}/api/mappers/__init__.py +1 -1
  10. {lifx_emulator → lifx_emulator_app}/api/mappers/device_mapper.py +1 -1
  11. {lifx_emulator → lifx_emulator_app}/api/models.py +1 -2
  12. lifx_emulator_app/api/routers/__init__.py +11 -0
  13. {lifx_emulator → lifx_emulator_app}/api/routers/devices.py +2 -2
  14. {lifx_emulator → lifx_emulator_app}/api/routers/monitoring.py +1 -1
  15. {lifx_emulator → lifx_emulator_app}/api/routers/scenarios.py +1 -1
  16. lifx_emulator_app/api/services/__init__.py +8 -0
  17. {lifx_emulator → lifx_emulator_app}/api/services/device_service.py +3 -2
  18. lifx_emulator_app/api/static/dashboard.js +588 -0
  19. lifx_emulator_app/api/templates/dashboard.html +357 -0
  20. lifx_emulator/__init__.py +0 -31
  21. lifx_emulator/api/routers/__init__.py +0 -11
  22. lifx_emulator/api/services/__init__.py +0 -8
  23. lifx_emulator/api/templates/dashboard.html +0 -899
  24. lifx_emulator/constants.py +0 -33
  25. lifx_emulator/devices/__init__.py +0 -37
  26. lifx_emulator/devices/device.py +0 -395
  27. lifx_emulator/devices/manager.py +0 -256
  28. lifx_emulator/devices/observers.py +0 -139
  29. lifx_emulator/devices/persistence.py +0 -308
  30. lifx_emulator/devices/state_restorer.py +0 -259
  31. lifx_emulator/devices/state_serializer.py +0 -157
  32. lifx_emulator/devices/states.py +0 -381
  33. lifx_emulator/factories/__init__.py +0 -39
  34. lifx_emulator/factories/builder.py +0 -375
  35. lifx_emulator/factories/default_config.py +0 -158
  36. lifx_emulator/factories/factory.py +0 -252
  37. lifx_emulator/factories/firmware_config.py +0 -77
  38. lifx_emulator/factories/serial_generator.py +0 -82
  39. lifx_emulator/handlers/__init__.py +0 -39
  40. lifx_emulator/handlers/base.py +0 -49
  41. lifx_emulator/handlers/device_handlers.py +0 -322
  42. lifx_emulator/handlers/light_handlers.py +0 -503
  43. lifx_emulator/handlers/multizone_handlers.py +0 -249
  44. lifx_emulator/handlers/registry.py +0 -110
  45. lifx_emulator/handlers/tile_handlers.py +0 -488
  46. lifx_emulator/products/__init__.py +0 -28
  47. lifx_emulator/products/generator.py +0 -1079
  48. lifx_emulator/products/registry.py +0 -1530
  49. lifx_emulator/products/specs.py +0 -284
  50. lifx_emulator/products/specs.yml +0 -386
  51. lifx_emulator/protocol/__init__.py +0 -1
  52. lifx_emulator/protocol/base.py +0 -446
  53. lifx_emulator/protocol/const.py +0 -8
  54. lifx_emulator/protocol/generator.py +0 -1384
  55. lifx_emulator/protocol/header.py +0 -159
  56. lifx_emulator/protocol/packets.py +0 -1351
  57. lifx_emulator/protocol/protocol_types.py +0 -817
  58. lifx_emulator/protocol/serializer.py +0 -379
  59. lifx_emulator/repositories/__init__.py +0 -22
  60. lifx_emulator/repositories/device_repository.py +0 -155
  61. lifx_emulator/repositories/storage_backend.py +0 -107
  62. lifx_emulator/scenarios/__init__.py +0 -22
  63. lifx_emulator/scenarios/manager.py +0 -322
  64. lifx_emulator/scenarios/models.py +0 -112
  65. lifx_emulator/scenarios/persistence.py +0 -241
  66. lifx_emulator/server.py +0 -464
  67. lifx_emulator-2.4.0.dist-info/METADATA +0 -107
  68. lifx_emulator-2.4.0.dist-info/RECORD +0 -62
  69. lifx_emulator-2.4.0.dist-info/entry_points.txt +0 -2
  70. lifx_emulator-2.4.0.dist-info/licenses/LICENSE +0 -35
@@ -0,0 +1,357 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>LIFX Emulator Monitor</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+ body {
14
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
15
+ Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
16
+ background: #0a0a0a;
17
+ color: #e0e0e0;
18
+ line-height: 1.6;
19
+ padding: 20px;
20
+ }
21
+ .container {
22
+ max-width: 1400px;
23
+ margin: 0 auto;
24
+ }
25
+ h1 {
26
+ color: #fff;
27
+ margin-bottom: 10px;
28
+ font-size: 2em;
29
+ }
30
+ .subtitle {
31
+ color: #888;
32
+ margin-bottom: 30px;
33
+ }
34
+ .grid {
35
+ display: grid;
36
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
37
+ gap: 15px;
38
+ margin-bottom: 25px;
39
+ }
40
+ .devices-grid {
41
+ display: grid;
42
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
43
+ gap: 10px;
44
+ }
45
+ .card {
46
+ background: #1a1a1a;
47
+ border: 1px solid #333;
48
+ border-radius: 8px;
49
+ padding: 20px;
50
+ }
51
+ .card h2 {
52
+ color: #fff;
53
+ font-size: 1.2em;
54
+ margin-bottom: 15px;
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 10px;
58
+ }
59
+ .stat {
60
+ display: flex;
61
+ justify-content: space-between;
62
+ padding: 8px 0;
63
+ border-bottom: 1px solid #2a2a2a;
64
+ }
65
+ .stat:last-child {
66
+ border-bottom: none;
67
+ }
68
+ .stat-label {
69
+ color: #888;
70
+ }
71
+ .stat-value {
72
+ color: #fff;
73
+ font-weight: 600;
74
+ }
75
+ .device {
76
+ background: #252525;
77
+ border: 1px solid #333;
78
+ border-radius: 6px;
79
+ padding: 8px;
80
+ margin-bottom: 8px;
81
+ font-size: 0.85em;
82
+ }
83
+ .device-header {
84
+ display: flex;
85
+ justify-content: space-between;
86
+ align-items: center;
87
+ margin-bottom: 6px;
88
+ }
89
+ .device-serial {
90
+ font-family: 'Monaco', 'Courier New', monospace;
91
+ color: #4a9eff;
92
+ font-weight: bold;
93
+ font-size: 0.9em;
94
+ }
95
+ .device-label {
96
+ color: #aaa;
97
+ font-size: 0.85em;
98
+ }
99
+ .zones-container {
100
+ margin-top: 8px;
101
+ padding-top: 8px;
102
+ border-top: 1px solid #333;
103
+ }
104
+ .zones-toggle, .metadata-toggle {
105
+ cursor: pointer;
106
+ color: #4a9eff;
107
+ font-size: 0.8em;
108
+ margin-top: 4px;
109
+ user-select: none;
110
+ }
111
+ .zones-toggle:hover, .metadata-toggle:hover {
112
+ color: #6bb0ff;
113
+ }
114
+ .zones-display, .metadata-display {
115
+ display: none;
116
+ margin-top: 6px;
117
+ }
118
+ .zones-display.show, .metadata-display.show {
119
+ display: block;
120
+ }
121
+ .metadata-display {
122
+ font-size: 0.75em;
123
+ color: #888;
124
+ padding: 6px;
125
+ background: #1a1a1a;
126
+ border-radius: 3px;
127
+ border: 1px solid #333;
128
+ }
129
+ .metadata-row {
130
+ display: flex;
131
+ justify-content: space-between;
132
+ padding: 2px 0;
133
+ }
134
+ .metadata-label {
135
+ color: #666;
136
+ }
137
+ .metadata-value {
138
+ color: #aaa;
139
+ font-family: 'Monaco', 'Courier New', monospace;
140
+ }
141
+ .zone-strip {
142
+ display: flex;
143
+ height: 20px;
144
+ border-radius: 3px;
145
+ overflow: hidden;
146
+ margin-bottom: 4px;
147
+ }
148
+ .zone-segment {
149
+ flex: 1;
150
+ min-width: 4px;
151
+ }
152
+ .color-swatch {
153
+ display: inline-block;
154
+ width: 16px;
155
+ height: 16px;
156
+ border-radius: 3px;
157
+ border: 1px solid #333;
158
+ vertical-align: middle;
159
+ margin-right: 4px;
160
+ }
161
+ .tile-grid {
162
+ display: grid;
163
+ gap: 2px;
164
+ margin-top: 4px;
165
+ }
166
+ .tile-zone {
167
+ width: 8px;
168
+ height: 8px;
169
+ border-radius: 1px;
170
+ }
171
+ .tiles-container {
172
+ display: flex;
173
+ flex-wrap: wrap;
174
+ gap: 8px;
175
+ margin-top: 4px;
176
+ }
177
+ .tile-item {
178
+ display: inline-block;
179
+ }
180
+ .badge {
181
+ display: inline-block;
182
+ padding: 2px 6px;
183
+ border-radius: 3px;
184
+ font-size: 0.7em;
185
+ font-weight: 600;
186
+ margin-right: 4px;
187
+ margin-bottom: 2px;
188
+ }
189
+ .badge-power-on {
190
+ background: #2d5;
191
+ color: #000;
192
+ }
193
+ .badge-power-off {
194
+ background: #555;
195
+ color: #aaa;
196
+ }
197
+ .badge-capability {
198
+ background: #333;
199
+ color: #4a9eff;
200
+ }
201
+ .badge-extended-mz {
202
+ background: #2d4a2d;
203
+ color: #5dff5d;
204
+ }
205
+ .activity-log {
206
+ background: #0d0d0d;
207
+ border: 1px solid #333;
208
+ border-radius: 6px;
209
+ padding: 15px;
210
+ max-height: 400px;
211
+ overflow-y: auto;
212
+ font-family: 'Monaco', 'Courier New', monospace;
213
+ font-size: 0.85em;
214
+ }
215
+ .activity-item {
216
+ padding: 6px 0;
217
+ border-bottom: 1px solid #1a1a1a;
218
+ display: flex;
219
+ gap: 10px;
220
+ }
221
+ .activity-item:last-child {
222
+ border-bottom: none;
223
+ }
224
+ .activity-time {
225
+ color: #666;
226
+ min-width: 80px;
227
+ }
228
+ .activity-rx {
229
+ color: #4a9eff;
230
+ }
231
+ .activity-tx {
232
+ color: #f9a825;
233
+ }
234
+ .activity-packet {
235
+ color: #aaa;
236
+ }
237
+ .btn {
238
+ background: #4a9eff;
239
+ color: #000;
240
+ border: none;
241
+ padding: 4px 8px;
242
+ border-radius: 3px;
243
+ cursor: pointer;
244
+ font-weight: 600;
245
+ font-size: 0.75em;
246
+ }
247
+ .btn:hover {
248
+ background: #6bb0ff;
249
+ }
250
+ .btn-delete {
251
+ background: #d32f2f;
252
+ color: #fff;
253
+ }
254
+ .btn-delete:hover {
255
+ background: #e57373;
256
+ }
257
+ .form-group {
258
+ margin-bottom: 15px;
259
+ }
260
+ .form-group label {
261
+ display: block;
262
+ color: #aaa;
263
+ margin-bottom: 5px;
264
+ font-size: 0.9em;
265
+ }
266
+ .form-group input, .form-group select {
267
+ width: 100%;
268
+ background: #0d0d0d;
269
+ border: 1px solid #333;
270
+ color: #fff;
271
+ padding: 8px;
272
+ border-radius: 4px;
273
+ }
274
+ .status-indicator {
275
+ display: inline-block;
276
+ width: 8px;
277
+ height: 8px;
278
+ border-radius: 50%;
279
+ background: #2d5;
280
+ animation: pulse 2s infinite;
281
+ }
282
+ @keyframes pulse {
283
+ 0%, 100% { opacity: 1; }
284
+ 50% { opacity: 0.5; }
285
+ }
286
+ .no-devices {
287
+ text-align: center;
288
+ color: #666;
289
+ padding: 40px;
290
+ }
291
+ </style>
292
+ </head>
293
+ <body>
294
+ <div class="container">
295
+ <h1>LIFX Emulator Monitor</h1>
296
+ <p class="subtitle">Real-time monitoring and device management</p>
297
+
298
+ <div class="grid">
299
+ <div class="card">
300
+ <h2><span class="status-indicator"></span> Server Statistics</h2>
301
+ <div id="stats">
302
+ <div class="stat">
303
+ <span class="stat-label">Loading...</span>
304
+ <span class="stat-value"></span>
305
+ </div>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="card">
310
+ <h2>Add Device</h2>
311
+ <form id="add-device-form">
312
+ <div class="form-group">
313
+ <label>Product ID</label>
314
+ <select id="product-id" required>
315
+ <option value="27">27 - LIFX A19</option>
316
+ <option value="29">29 - LIFX A19 Night Vision</option>
317
+ <option value="32">32 - LIFX Z (Strip)</option>
318
+ <option value="38">38 - LIFX Beam</option>
319
+ <option value="50">50 - LIFX Mini White to Warm</option>
320
+ <option value="55">55 - LIFX Tile</option>
321
+ <option value="90">90 - LIFX Clean (HEV)</option>
322
+ </select>
323
+ </div>
324
+ <button type="submit" class="btn">Add Device</button>
325
+ </form>
326
+ </div>
327
+ </div>
328
+
329
+ <div class="card">
330
+ <h2>
331
+ Devices (<span id="device-count">0</span>)
332
+ <span style="float: right; display: flex; gap: 8px;">
333
+ <button
334
+ class="btn btn-delete"
335
+ onclick="removeAllDevices()"
336
+ title="Remove all devices from server (runtime only)"
337
+ >Remove All</button>
338
+ <button
339
+ class="btn btn-delete"
340
+ onclick="clearStorage()"
341
+ id="clear-storage-btn"
342
+ title="Delete all persistent device state files"
343
+ >Clear Storage</button>
344
+ </span>
345
+ </h2>
346
+ <div id="devices" class="devices-grid"></div>
347
+ </div>
348
+
349
+ <div class="card" id="activity-card">
350
+ <h2>Recent Activity</h2>
351
+ <div class="activity-log" id="activity-log"></div>
352
+ </div>
353
+ </div>
354
+
355
+ <script src="/static/dashboard.js"></script>
356
+ </body>
357
+ </html>
lifx_emulator/__init__.py DELETED
@@ -1,31 +0,0 @@
1
- """LIFX Emulator
2
-
3
- A comprehensive LIFX emulator for testing LIFX LAN protocol libraries.
4
- Implements the binary UDP protocol documented at https://lan.developer.lifx.com
5
- """
6
-
7
- from importlib.metadata import version as get_version
8
-
9
- from lifx_emulator.devices import EmulatedLifxDevice
10
- from lifx_emulator.factories import (
11
- create_color_light,
12
- create_color_temperature_light,
13
- create_hev_light,
14
- create_infrared_light,
15
- create_multizone_light,
16
- create_tile_device,
17
- )
18
- from lifx_emulator.server import EmulatedLifxServer
19
-
20
- __version__ = get_version("lifx_emulator")
21
-
22
- __all__ = [
23
- "EmulatedLifxServer",
24
- "EmulatedLifxDevice",
25
- "create_color_light",
26
- "create_color_temperature_light",
27
- "create_hev_light",
28
- "create_infrared_light",
29
- "create_multizone_light",
30
- "create_tile_device",
31
- ]
@@ -1,11 +0,0 @@
1
- """API routers for LIFX emulator endpoints."""
2
-
3
- from lifx_emulator.api.routers.devices import create_devices_router
4
- from lifx_emulator.api.routers.monitoring import create_monitoring_router
5
- from lifx_emulator.api.routers.scenarios import create_scenarios_router
6
-
7
- __all__ = [
8
- "create_monitoring_router",
9
- "create_devices_router",
10
- "create_scenarios_router",
11
- ]
@@ -1,8 +0,0 @@
1
- """Business logic services for API endpoints."""
2
-
3
- from lifx_emulator.api.services.device_service import DeviceService
4
-
5
- # TODO: Create ScenarioService (Phase 1.1b completion)
6
- # from lifx_emulator.api.services.scenario_service import ScenarioService
7
-
8
- __all__ = ["DeviceService"]