lifx-emulator 4.0.0__py3-none-any.whl → 4.2.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 (42) hide show
  1. {lifx_emulator-4.0.0.dist-info → lifx_emulator-4.2.0.dist-info}/METADATA +2 -1
  2. lifx_emulator-4.2.0.dist-info/RECORD +43 -0
  3. lifx_emulator_app/__main__.py +35 -7
  4. lifx_emulator_app/api/__init__.py +0 -4
  5. lifx_emulator_app/api/app.py +122 -16
  6. lifx_emulator_app/api/models.py +32 -1
  7. lifx_emulator_app/api/routers/__init__.py +5 -1
  8. lifx_emulator_app/api/routers/devices.py +64 -10
  9. lifx_emulator_app/api/routers/products.py +42 -0
  10. lifx_emulator_app/api/routers/scenarios.py +55 -52
  11. lifx_emulator_app/api/routers/websocket.py +70 -0
  12. lifx_emulator_app/api/services/__init__.py +21 -4
  13. lifx_emulator_app/api/services/device_service.py +188 -1
  14. lifx_emulator_app/api/services/event_bridge.py +234 -0
  15. lifx_emulator_app/api/services/scenario_service.py +153 -0
  16. lifx_emulator_app/api/services/websocket_manager.py +326 -0
  17. lifx_emulator_app/api/static/_app/env.js +1 -0
  18. lifx_emulator_app/api/static/_app/immutable/assets/0.DOQLX7EM.css +1 -0
  19. lifx_emulator_app/api/static/_app/immutable/assets/2.CU0O2Xrb.css +1 -0
  20. lifx_emulator_app/api/static/_app/immutable/chunks/BORyfda6.js +1 -0
  21. lifx_emulator_app/api/static/_app/immutable/chunks/BTLkiQR5.js +1 -0
  22. lifx_emulator_app/api/static/_app/immutable/chunks/BaoxLdOF.js +2 -0
  23. lifx_emulator_app/api/static/_app/immutable/chunks/Binc8JbE.js +1 -0
  24. lifx_emulator_app/api/static/_app/immutable/chunks/CDSQEL5N.js +1 -0
  25. lifx_emulator_app/api/static/_app/immutable/chunks/DfIkQq0Y.js +1 -0
  26. lifx_emulator_app/api/static/_app/immutable/chunks/MAGDeS2Z.js +1 -0
  27. lifx_emulator_app/api/static/_app/immutable/chunks/N3z8axFy.js +1 -0
  28. lifx_emulator_app/api/static/_app/immutable/chunks/yhjkpkcN.js +1 -0
  29. lifx_emulator_app/api/static/_app/immutable/entry/app.Dhwm664s.js +2 -0
  30. lifx_emulator_app/api/static/_app/immutable/entry/start.Nqz6UJJT.js +1 -0
  31. lifx_emulator_app/api/static/_app/immutable/nodes/0.CPncm6RP.js +1 -0
  32. lifx_emulator_app/api/static/_app/immutable/nodes/1.x-f3libw.js +1 -0
  33. lifx_emulator_app/api/static/_app/immutable/nodes/2.BP5Yvqf4.js +6 -0
  34. lifx_emulator_app/api/static/_app/version.json +1 -0
  35. lifx_emulator_app/api/static/index.html +38 -0
  36. lifx_emulator_app/api/static/robots.txt +3 -0
  37. lifx_emulator_app/config.py +2 -0
  38. lifx_emulator-4.0.0.dist-info/RECORD +0 -20
  39. lifx_emulator_app/api/static/dashboard.js +0 -588
  40. lifx_emulator_app/api/templates/dashboard.html +0 -357
  41. {lifx_emulator-4.0.0.dist-info → lifx_emulator-4.2.0.dist-info}/WHEEL +0 -0
  42. {lifx_emulator-4.0.0.dist-info → lifx_emulator-4.2.0.dist-info}/entry_points.txt +0 -0
@@ -1,357 +0,0 @@
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>