scrollkit 0.8.3__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.
- scrollkit/__init__.py +16 -0
- scrollkit/app/__init__.py +6 -0
- scrollkit/app/base.py +918 -0
- scrollkit/app/memory.py +70 -0
- scrollkit/config/__init__.py +1 -0
- scrollkit/config/settings_manager.py +215 -0
- scrollkit/config/transition_names.py +31 -0
- scrollkit/dev/__init__.py +41 -0
- scrollkit/dev/capabilities.py +374 -0
- scrollkit/dev/harness.py +383 -0
- scrollkit/dev/metrics.py +91 -0
- scrollkit/dev/performance.py +174 -0
- scrollkit/dev/validation.py +245 -0
- scrollkit/display/__init__.py +14 -0
- scrollkit/display/_graphics.py +299 -0
- scrollkit/display/_recording.py +165 -0
- scrollkit/display/_sim_backend.py +99 -0
- scrollkit/display/bitmap_text.py +408 -0
- scrollkit/display/boards.py +186 -0
- scrollkit/display/colors.py +176 -0
- scrollkit/display/content.py +604 -0
- scrollkit/display/gradient_text.py +167 -0
- scrollkit/display/interface.py +126 -0
- scrollkit/display/simulator.py +80 -0
- scrollkit/display/text_fill.py +59 -0
- scrollkit/display/text_pixels.py +250 -0
- scrollkit/display/unified.py +595 -0
- scrollkit/effects/__init__.py +28 -0
- scrollkit/effects/drip_splash.py +253 -0
- scrollkit/effects/easing.py +131 -0
- scrollkit/effects/overlay.py +92 -0
- scrollkit/effects/particles.py +355 -0
- scrollkit/effects/reveal_splash.py +132 -0
- scrollkit/effects/scrolling.py +363 -0
- scrollkit/effects/swarm_reveal.py +512 -0
- scrollkit/effects/text_render.py +25 -0
- scrollkit/effects/transitions.py +873 -0
- scrollkit/exceptions.py +55 -0
- scrollkit/network/__init__.py +1 -0
- scrollkit/network/http_client.py +505 -0
- scrollkit/network/mdns.py +44 -0
- scrollkit/network/wifi_manager.py +382 -0
- scrollkit/ota/__init__.py +13 -0
- scrollkit/ota/client.py +528 -0
- scrollkit/ota/display_progress.py +125 -0
- scrollkit/ota/manifest.py +206 -0
- scrollkit/ota/publish.py +379 -0
- scrollkit/simulator/ATTRIBUTION.md +20 -0
- scrollkit/simulator/CIRCUITPYTHON_COMPATIBILITY.md +364 -0
- scrollkit/simulator/LICENSE +176 -0
- scrollkit/simulator/README.md +87 -0
- scrollkit/simulator/__init__.py +11 -0
- scrollkit/simulator/adafruit_bitmap_font/__init__.py +5 -0
- scrollkit/simulator/adafruit_bitmap_font/bitmap_font.py +273 -0
- scrollkit/simulator/adafruit_bitmap_font/glyph_cache.py +70 -0
- scrollkit/simulator/adafruit_display_text/__init__.py +5 -0
- scrollkit/simulator/adafruit_display_text/label.py +336 -0
- scrollkit/simulator/bitmaptools.py +50 -0
- scrollkit/simulator/core/__init__.py +8 -0
- scrollkit/simulator/core/color_utils.py +62 -0
- scrollkit/simulator/core/device_benchmarks.json +254 -0
- scrollkit/simulator/core/feasibility.py +160 -0
- scrollkit/simulator/core/hardware_profile.py +191 -0
- scrollkit/simulator/core/led_matrix.py +307 -0
- scrollkit/simulator/core/matrixportal_s3_baseline.json +12 -0
- scrollkit/simulator/core/performance_manager.py +253 -0
- scrollkit/simulator/core/pixel_buffer.py +188 -0
- scrollkit/simulator/devices/__init__.py +7 -0
- scrollkit/simulator/devices/base_device.py +79 -0
- scrollkit/simulator/devices/matrixportal_s3.py +87 -0
- scrollkit/simulator/displayio/__init__.py +12 -0
- scrollkit/simulator/displayio/bitmap.py +158 -0
- scrollkit/simulator/displayio/display.py +195 -0
- scrollkit/simulator/displayio/fourwire.py +54 -0
- scrollkit/simulator/displayio/group.py +125 -0
- scrollkit/simulator/displayio/ondiskbitmap.py +109 -0
- scrollkit/simulator/displayio/palette.py +115 -0
- scrollkit/simulator/displayio/tilegrid.py +155 -0
- scrollkit/simulator/fonts/3x5.bdf +2474 -0
- scrollkit/simulator/fonts/Arial_16.bdf +7366 -0
- scrollkit/simulator/fonts/Arial_16.bdf.license +3 -0
- scrollkit/simulator/fonts/Arial_Bold_12.bdf +6131 -0
- scrollkit/simulator/fonts/Arial_Bold_12.bdf.license +2 -0
- scrollkit/simulator/fonts/Arial_Bold_18.bdf +32653 -0
- scrollkit/simulator/fonts/Arial_Bold_18.bdf.license +2 -0
- scrollkit/simulator/fonts/Junction_regular_24.bdf +8676 -0
- scrollkit/simulator/fonts/Junction_regular_24.bdf.license +3 -0
- scrollkit/simulator/fonts/LeagueSpartan-Bold-16.bdf +12458 -0
- scrollkit/simulator/fonts/LeagueSpartan-Bold-16.bdf.license +1921 -0
- scrollkit/simulator/fonts/LeagueSpartan_Bold_16.bdf +12458 -0
- scrollkit/simulator/fonts/LeagueSpartan_Bold_16.bdf.license +4 -0
- scrollkit/simulator/fonts/LibreBodoniv2002-Bold-27.bdf +16818 -0
- scrollkit/simulator/fonts/LibreBodoniv2002-Bold-27.bdf.license +1921 -0
- scrollkit/simulator/fonts/tom-thumb.bdf +2353 -0
- scrollkit/simulator/fonts/viii-bold.bdf +2673 -0
- scrollkit/simulator/fonts/viii.bdf +2659 -0
- scrollkit/simulator/terminalio/__init__.py +20 -0
- scrollkit/utils/__init__.py +1 -0
- scrollkit/utils/color_utils.py +54 -0
- scrollkit/utils/diagnostics.py +227 -0
- scrollkit/utils/error_handler.py +347 -0
- scrollkit/utils/system_utils.py +245 -0
- scrollkit/utils/url_utils.py +46 -0
- scrollkit/web/__init__.py +6 -0
- scrollkit/web/settings_server.py +328 -0
- scrollkit/web/wifi_setup.py +331 -0
- scrollkit-0.8.3.dist-info/METADATA +248 -0
- scrollkit-0.8.3.dist-info/RECORD +111 -0
- scrollkit-0.8.3.dist-info/WHEEL +5 -0
- scrollkit-0.8.3.dist-info/licenses/LICENSE +31 -0
- scrollkit-0.8.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# CircuitPython Compatibility Guide
|
|
2
|
+
|
|
3
|
+
This document outlines the CircuitPython compatibility considerations when using PyLEDSimulator and developing code that needs to run on both desktop (simulation) and CircuitPython hardware.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
PyLEDSimulator implements CircuitPython's display APIs to allow desktop development and testing. However, there are important differences between standard Python and CircuitPython that developers must be aware of.
|
|
8
|
+
|
|
9
|
+
## Core Compatibility Principles
|
|
10
|
+
|
|
11
|
+
### 1. Module Availability
|
|
12
|
+
|
|
13
|
+
CircuitPython has a limited subset of Python's standard library. Many common modules are not available or have limited functionality.
|
|
14
|
+
|
|
15
|
+
#### Available in CircuitPython:
|
|
16
|
+
- `os` (limited functionality)
|
|
17
|
+
- `time` (limited functionality)
|
|
18
|
+
- `json` (basic functionality only)
|
|
19
|
+
- `re` (basic regex support)
|
|
20
|
+
- `random` (limited functionality - no `shuffle()`)
|
|
21
|
+
- `asyncio` (cooperative multitasking only)
|
|
22
|
+
- `gc` (garbage collection)
|
|
23
|
+
- `sys` (limited functionality)
|
|
24
|
+
|
|
25
|
+
#### NOT Available in CircuitPython:
|
|
26
|
+
- `pathlib`
|
|
27
|
+
- `urllib`
|
|
28
|
+
- `threading`
|
|
29
|
+
- `subprocess`
|
|
30
|
+
- `typing` (type hints must be removed)
|
|
31
|
+
- `dataclasses`
|
|
32
|
+
- `collections` (except `namedtuple`)
|
|
33
|
+
- Most standard library modules
|
|
34
|
+
|
|
35
|
+
### 2. Exception Handling Differences
|
|
36
|
+
|
|
37
|
+
CircuitPython uses different exceptions than standard Python:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
# ❌ WRONG - Standard Python only
|
|
41
|
+
try:
|
|
42
|
+
data = json.loads(response)
|
|
43
|
+
except json.JSONDecodeError: # Not available in CircuitPython
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
# ✅ CORRECT - CircuitPython compatible
|
|
47
|
+
try:
|
|
48
|
+
data = json.loads(response)
|
|
49
|
+
except ValueError: # CircuitPython raises ValueError for invalid JSON
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
# ❌ WRONG - Standard Python only
|
|
53
|
+
try:
|
|
54
|
+
with open('file.txt') as f:
|
|
55
|
+
content = f.read()
|
|
56
|
+
except FileNotFoundError: # Not available in CircuitPython
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
# ✅ CORRECT - CircuitPython compatible
|
|
60
|
+
try:
|
|
61
|
+
with open('file.txt') as f:
|
|
62
|
+
content = f.read()
|
|
63
|
+
except OSError: # CircuitPython only has OSError
|
|
64
|
+
pass
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. String and Type Operations
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
# ❌ WRONG - f-string debug syntax not supported
|
|
71
|
+
print(f"{value=}")
|
|
72
|
+
|
|
73
|
+
# ✅ CORRECT - Use regular f-strings
|
|
74
|
+
print(f"value={value}")
|
|
75
|
+
|
|
76
|
+
# ❌ WRONG - match/case not available
|
|
77
|
+
match command:
|
|
78
|
+
case "start":
|
|
79
|
+
start()
|
|
80
|
+
|
|
81
|
+
# ✅ CORRECT - Use if/elif
|
|
82
|
+
if command == "start":
|
|
83
|
+
start()
|
|
84
|
+
elif command == "stop":
|
|
85
|
+
stop()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 4. Memory Management
|
|
89
|
+
|
|
90
|
+
CircuitPython has limited memory (typically 256KB-512KB RAM):
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
# ❌ WRONG - Loading large data structures
|
|
94
|
+
data = json.loads(large_file_content) # May cause MemoryError
|
|
95
|
+
|
|
96
|
+
# ✅ CORRECT - Process data in chunks or use generators
|
|
97
|
+
def process_json_lines(file_path):
|
|
98
|
+
with open(file_path) as f:
|
|
99
|
+
for line in f:
|
|
100
|
+
yield json.loads(line)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 5. File Operations
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# ❌ WRONG - Using pathlib
|
|
107
|
+
from pathlib import Path
|
|
108
|
+
if Path('config.json').exists():
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
# ✅ CORRECT - Use os or try/except
|
|
112
|
+
import os
|
|
113
|
+
try:
|
|
114
|
+
os.stat('config.json')
|
|
115
|
+
file_exists = True
|
|
116
|
+
except OSError:
|
|
117
|
+
file_exists = False
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 6. Time Operations
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# ❌ WRONG - time.time() not always available
|
|
124
|
+
start_time = time.time()
|
|
125
|
+
|
|
126
|
+
# ✅ CORRECT - Use time.monotonic()
|
|
127
|
+
start_time = time.monotonic()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 7. Random Module Limitations
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
# ❌ WRONG - random.shuffle() not available
|
|
134
|
+
import random
|
|
135
|
+
my_list = [1, 2, 3, 4, 5]
|
|
136
|
+
random.shuffle(my_list)
|
|
137
|
+
|
|
138
|
+
# ✅ CORRECT - Implement simple shuffle
|
|
139
|
+
import random
|
|
140
|
+
|
|
141
|
+
def simple_shuffle(lst):
|
|
142
|
+
"""Simple in-place shuffle for CircuitPython compatibility."""
|
|
143
|
+
for i in range(len(lst)):
|
|
144
|
+
j = random.randint(0, len(lst) - 1)
|
|
145
|
+
lst[i], lst[j] = lst[j], lst[i]
|
|
146
|
+
|
|
147
|
+
my_list = [1, 2, 3, 4, 5]
|
|
148
|
+
simple_shuffle(my_list)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 8. Async Operations
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
# ❌ WRONG - asyncio.run() at module level
|
|
155
|
+
import asyncio
|
|
156
|
+
asyncio.run(main())
|
|
157
|
+
|
|
158
|
+
# ✅ CORRECT - Use asyncio properly
|
|
159
|
+
import asyncio
|
|
160
|
+
|
|
161
|
+
async def main():
|
|
162
|
+
# Your async code here
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
# At the bottom of your main file:
|
|
166
|
+
if __name__ == "__main__":
|
|
167
|
+
asyncio.run(main())
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## displayio API Changes
|
|
171
|
+
|
|
172
|
+
### Display.show() Removed in CircuitPython 9.x
|
|
173
|
+
|
|
174
|
+
The `.show()` method has been removed from Display objects in CircuitPython 9.x:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
# ❌ WRONG - Old API (CircuitPython 8.x and earlier)
|
|
178
|
+
display.show(None) # Clear display
|
|
179
|
+
display.show(group) # Show group
|
|
180
|
+
|
|
181
|
+
# ✅ CORRECT - New API (CircuitPython 9.x)
|
|
182
|
+
display.root_group = None # Clear display
|
|
183
|
+
display.root_group = group # Show group
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### MatrixPortal Pixel Access
|
|
187
|
+
|
|
188
|
+
The MatrixPortal class doesn't provide direct pixel manipulation methods:
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
# ❌ WRONG - No set_pixel/get_pixel methods
|
|
192
|
+
matrixportal.set_pixel(x, y, color)
|
|
193
|
+
color = matrixportal.get_pixel(x, y)
|
|
194
|
+
|
|
195
|
+
# ✅ CORRECT - Use displayio.Bitmap
|
|
196
|
+
bitmap = displayio.Bitmap(width, height, num_colors)
|
|
197
|
+
palette = displayio.Palette(num_colors)
|
|
198
|
+
palette[0] = 0x000000 # Black
|
|
199
|
+
palette[1] = 0xFFFF00 # Yellow
|
|
200
|
+
|
|
201
|
+
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette)
|
|
202
|
+
group = displayio.Group()
|
|
203
|
+
group.append(tile_grid)
|
|
204
|
+
display.root_group = group
|
|
205
|
+
|
|
206
|
+
# Set pixels via bitmap
|
|
207
|
+
bitmap[x, y] = 1 # Set to color index 1 (yellow)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## PyLEDSimulator-Specific Compatibility
|
|
211
|
+
|
|
212
|
+
### 1. Conditional Imports
|
|
213
|
+
|
|
214
|
+
Always structure imports to support both environments:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
try:
|
|
218
|
+
# Try hardware imports first
|
|
219
|
+
import board
|
|
220
|
+
import displayio
|
|
221
|
+
import terminalio
|
|
222
|
+
from adafruit_display_text import label
|
|
223
|
+
HARDWARE_AVAILABLE = True
|
|
224
|
+
except ImportError:
|
|
225
|
+
# Fall back to simulator
|
|
226
|
+
from pyledsimulator import displayio
|
|
227
|
+
from pyledsimulator import terminalio
|
|
228
|
+
from pyledsimulator.adafruit_display_text import label
|
|
229
|
+
HARDWARE_AVAILABLE = False
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 2. Display Initialization
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
def get_display():
|
|
236
|
+
"""Get display for hardware or simulator."""
|
|
237
|
+
if HARDWARE_AVAILABLE:
|
|
238
|
+
return board.DISPLAY
|
|
239
|
+
else:
|
|
240
|
+
from pyledsimulator.devices import MatrixPortalS3
|
|
241
|
+
device = MatrixPortalS3()
|
|
242
|
+
device.initialize()
|
|
243
|
+
return device.display
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 3. Performance Differences
|
|
247
|
+
|
|
248
|
+
The simulator runs at desktop speeds, which is much faster than CircuitPython:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
# Add delays to simulate hardware timing
|
|
252
|
+
if not HARDWARE_AVAILABLE:
|
|
253
|
+
time.sleep(0.1) # Simulate hardware processing time
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 4. Memory Constraints Simulation
|
|
257
|
+
|
|
258
|
+
When developing with the simulator, be mindful of hardware memory limits:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
# Even though desktop has more memory, design for hardware constraints
|
|
262
|
+
MAX_SPRITES = 10 # Limit based on hardware capabilities
|
|
263
|
+
MAX_TEXT_LENGTH = 100 # Avoid long strings
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Common Pitfalls and Solutions
|
|
267
|
+
|
|
268
|
+
### 1. HTTP Libraries
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
# ❌ WRONG - Using requests
|
|
272
|
+
import requests
|
|
273
|
+
response = requests.get(url)
|
|
274
|
+
|
|
275
|
+
# ✅ CORRECT - Use adafruit_requests
|
|
276
|
+
import adafruit_requests
|
|
277
|
+
response = adafruit_requests.get(url)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 2. JSON Handling
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
# ❌ WRONG - Expecting specific exceptions
|
|
284
|
+
try:
|
|
285
|
+
data = json.loads(text)
|
|
286
|
+
except json.JSONDecodeError as e:
|
|
287
|
+
print(f"JSON error at position {e.pos}")
|
|
288
|
+
|
|
289
|
+
# ✅ CORRECT - Handle generic ValueError
|
|
290
|
+
try:
|
|
291
|
+
data = json.loads(text)
|
|
292
|
+
except ValueError as e:
|
|
293
|
+
print(f"JSON error: {e}")
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 3. Type Hints
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
# ❌ WRONG - Using type hints
|
|
300
|
+
def process_data(data: dict[str, Any]) -> list[str]:
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
# ✅ CORRECT - Remove type hints or use comments
|
|
304
|
+
def process_data(data): # type: (dict) -> list
|
|
305
|
+
"""Process data dictionary and return list of strings."""
|
|
306
|
+
pass
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Testing for Compatibility
|
|
310
|
+
|
|
311
|
+
### 1. Linting for CircuitPython
|
|
312
|
+
|
|
313
|
+
Use the project's linting tools to catch compatibility issues:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
make lint-errors # Catches undefined names and syntax errors
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### 2. Import Testing
|
|
320
|
+
|
|
321
|
+
Test imports in both environments:
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
# test_imports.py
|
|
325
|
+
def test_imports():
|
|
326
|
+
"""Verify all imports work in current environment."""
|
|
327
|
+
try:
|
|
328
|
+
import json
|
|
329
|
+
import time
|
|
330
|
+
import os
|
|
331
|
+
print("✓ Core imports successful")
|
|
332
|
+
except ImportError as e:
|
|
333
|
+
print(f"✗ Import failed: {e}")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 3. Memory Testing
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
import gc
|
|
340
|
+
|
|
341
|
+
def check_memory():
|
|
342
|
+
"""Check available memory (CircuitPython only)."""
|
|
343
|
+
gc.collect()
|
|
344
|
+
if hasattr(gc, 'mem_free'):
|
|
345
|
+
print(f"Free memory: {gc.mem_free()} bytes")
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Best Practices
|
|
349
|
+
|
|
350
|
+
1. **Always test on hardware**: The simulator is for development, but final testing must be on actual hardware
|
|
351
|
+
2. **Use minimal dependencies**: Stick to CircuitPython built-ins when possible
|
|
352
|
+
3. **Handle errors gracefully**: Assume operations can fail due to memory or hardware constraints
|
|
353
|
+
4. **Keep it simple**: Complex Python features are often not available
|
|
354
|
+
5. **Check CircuitPython docs**: When in doubt, consult https://docs.circuitpython.org/
|
|
355
|
+
|
|
356
|
+
## Useful Resources
|
|
357
|
+
|
|
358
|
+
- [CircuitPython API Reference](https://docs.circuitpython.org/en/latest/docs/library/index.html)
|
|
359
|
+
- [CircuitPython vs MicroPython](https://docs.circuitpython.org/en/latest/docs/design_guide.html)
|
|
360
|
+
- [Adafruit Learn Guides](https://learn.adafruit.com/category/circuitpython)
|
|
361
|
+
|
|
362
|
+
## Version Compatibility
|
|
363
|
+
|
|
364
|
+
PyLEDSimulator targets CircuitPython 8.x and 9.x compatibility. Features specific to newer versions should be avoided or have fallbacks.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# LED Simulator
|
|
2
|
+
|
|
3
|
+
A standalone Python library for simulating LED matrix displays used with CircuitPython boards. The library provides a visual representation of LED hardware using Pygame, allowing developers to test their code on desktop platforms before deploying to actual hardware.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Pixel-Perfect LED Simulation**: Realistic LED rendering with configurable pitch (2.5, 3, 4, 5, 6mm)
|
|
8
|
+
- **CircuitPython API Compatibility**: Implements displayio, terminalio, and adafruit_display_text APIs
|
|
9
|
+
- **Multi-Display Support**: Tile multiple displays together (up to 4x4 grid)
|
|
10
|
+
- **Font Support**: BDF font loading with bundled fonts
|
|
11
|
+
- **Performance Simulation**: Optional hardware performance characteristics simulation
|
|
12
|
+
- **Device Emulation**: Pre-configured device profiles (MatrixPortal S3, etc.)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install led_simulator
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from led_simulator.devices import MatrixPortalS3
|
|
24
|
+
from led_simulator.displayio import Group
|
|
25
|
+
from led_simulator.adafruit_display_text import Label
|
|
26
|
+
from led_simulator.terminalio import FONT
|
|
27
|
+
|
|
28
|
+
# Create device
|
|
29
|
+
device = MatrixPortalS3()
|
|
30
|
+
device.initialize()
|
|
31
|
+
|
|
32
|
+
# Create text label
|
|
33
|
+
text_group = Group()
|
|
34
|
+
label = Label(font=FONT, text="Hello LED!")
|
|
35
|
+
label.x = 0
|
|
36
|
+
label.y = 15
|
|
37
|
+
text_group.append(label)
|
|
38
|
+
|
|
39
|
+
# Show on display
|
|
40
|
+
device.display.show(text_group)
|
|
41
|
+
|
|
42
|
+
# Run the simulation
|
|
43
|
+
device.run()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Compatibility
|
|
47
|
+
|
|
48
|
+
PyLEDSimulator aims for "sufficient API compatibility" with CircuitPython's displayio module. This means:
|
|
49
|
+
- Your CircuitPython code should work with minimal or no modifications
|
|
50
|
+
- The visual output closely matches real hardware
|
|
51
|
+
- Some advanced features may have behavioral differences (documented below)
|
|
52
|
+
|
|
53
|
+
### Known Limitations
|
|
54
|
+
|
|
55
|
+
- Rendering order nuances may differ slightly from hardware
|
|
56
|
+
- Memory management follows Python's model, not CircuitPython's
|
|
57
|
+
- Some rotation/scaling transforms may have minor differences
|
|
58
|
+
- Font rendering may have slight metric differences
|
|
59
|
+
|
|
60
|
+
### CircuitPython Compatibility
|
|
61
|
+
|
|
62
|
+
For detailed information about writing code that works in both the simulator and on CircuitPython hardware, see [CIRCUITPYTHON_COMPATIBILITY.md](CIRCUITPYTHON_COMPATIBILITY.md). This guide covers:
|
|
63
|
+
- Module availability differences
|
|
64
|
+
- Exception handling in CircuitPython
|
|
65
|
+
- Memory constraints
|
|
66
|
+
- Common pitfalls and solutions
|
|
67
|
+
|
|
68
|
+
## Examples
|
|
69
|
+
|
|
70
|
+
See the `examples/` directory for various usage examples:
|
|
71
|
+
- `matrixportal_s3_example.py` - Basic MatrixPortal S3 simulation
|
|
72
|
+
- `scrolling_text_example.py` - Text scrolling demonstration
|
|
73
|
+
- `dual_zone_example.py` - Multi-zone display example
|
|
74
|
+
- `multi_display_example.py` - Multiple display coordination
|
|
75
|
+
- `rainbow_text.py` - Colorful text effects
|
|
76
|
+
- `pixel_dust.py` - Particle effects simulation
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
Apache License 2.0
|
|
81
|
+
|
|
82
|
+
## Attribution
|
|
83
|
+
|
|
84
|
+
Portions of this project are adapted from CircuitPython:
|
|
85
|
+
- Copyright (c) 2016-2024 Adafruit Industries
|
|
86
|
+
- Licensed under MIT License
|
|
87
|
+
- See ATTRIBUTION.md for details
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026 Michael Winslow Czeiszperger
|
|
2
|
+
"""SLDK LED Matrix Simulator."""
|
|
3
|
+
|
|
4
|
+
# Make simulator modules available at package level
|
|
5
|
+
from . import core
|
|
6
|
+
from . import devices
|
|
7
|
+
from . import displayio
|
|
8
|
+
from . import adafruit_display_text
|
|
9
|
+
from . import terminalio
|
|
10
|
+
|
|
11
|
+
__version__ = "0.8.1"
|