IS-Matrix-Forge 1.0.0.dev5__tar.gz → 1.0.0.dev6__tar.gz
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.
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/PKG-INFO +3 -1
- is_matrix_forge-1.0.0.dev6/is_matrix_forge/common/decorators/__init__.py +12 -0
- is_matrix_forge-1.0.0.dev5/is_matrix_forge/common/decorators/__init__.py → is_matrix_forge-1.0.0.dev6/is_matrix_forge/common/decorators/freeze_setter.py +2 -12
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/controller.py +77 -30
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/__init__.py +9 -0
- is_matrix_forge-1.0.0.dev6/is_matrix_forge/led_matrix/display/animations/audio_visualizer.py +124 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/breather.py +1 -1
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/grid.py +43 -8
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/device.py +1 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/pyproject.toml +5 -2
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/LICENSE.md +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/README.md +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/files/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/files/plugged.wav +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/files/unplugged.wav +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/char_map.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/font_map.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/dirs.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/helpers/github_api.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/button_grid/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/button_grid/column.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/button_grid/grid.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/streamlit_app.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/debug.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/presets.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/b1display.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/c1minimal.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/font.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/ledmatrix.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/battery_monitor.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/identify_matrices.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/install_presets/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/install_presets/arguments.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/install_presets/main.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/commands/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/commands/map.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/constants.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/helpers/threading.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/multiton.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/threaded.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/animation.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/effects/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/font/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/font/font.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/font/map_builder.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/frame/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/frame/base.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/frame/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/keep_awake.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/plugged.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/text_scroller.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/fade.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/scroller/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/scroller/base.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/scroller/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/presets/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/presets/manifest.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/helpers/columns.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/media.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/commands.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/constants.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/res.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/text/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/text/scroller.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/base.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/grid.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/matrix.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/misc.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/fonts.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/hardware.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/core/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/core/lazy_mod_load.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/status_handler.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/stream/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/stream/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/led_matrix.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/status.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/tools/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/tools/identify.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/utils/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/log_engine.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/events.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/collection.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/event.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/layout/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/layout/base.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/metaclasses/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/base.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/main/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/main/layout.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/monitor.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/sounds/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/sounds/base.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/progress.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/scripts/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/scripts/preset_installer.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/answer.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/message.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/request.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/exchange.py +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/blank.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/manifest.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/shock_face.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test1.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test2.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test3.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test4.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test5.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test6.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test7.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/x_animation II.json +0 -0
- {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/x_animation.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: IS-Matrix-Forge
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev6
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: led,matrix,framework,hardware
|
|
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Provides-Extra: clipboard-support
|
|
15
|
+
Requires-Dist: aliaser (>=1.0.0.dev4,<2.0.0)
|
|
15
16
|
Requires-Dist: chime (>=0.7.0,<0.8.0)
|
|
16
17
|
Requires-Dist: clipboard (>=0.0.4,<0.0.5) ; extra == "clipboard-support"
|
|
17
18
|
Requires-Dist: easy-exit-calls (>=1.0.0.dev1,<2.0.0)
|
|
@@ -23,6 +24,7 @@ Requires-Dist: pillow (>=11.2.1,<12.0.0)
|
|
|
23
24
|
Requires-Dist: pyserial (>=3.5,<4.0)
|
|
24
25
|
Requires-Dist: pysimplegui-4-foss (==4.60.4.1)
|
|
25
26
|
Requires-Dist: pysimpleguiweb (==0.39.0)
|
|
27
|
+
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
26
28
|
Project-URL: Homepage, https://github.com/Inspyre-Softworks/IS-Matrix-Forge
|
|
27
29
|
Project-URL: Repository, https://github.com/Inspyre-Softworks/IS-Matrix-Forge
|
|
28
30
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from inspyre_toolbox.syntactic_sweets.classes.decorators import validate_type
|
|
2
|
+
from is_matrix_forge.common.decorators.freeze_setter import freeze_setter
|
|
3
|
+
from is_matrix_forge.led_matrix.errors.misc import ImplicitNameDerivationError
|
|
4
|
+
from aliaser import Aliases
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
'Aliases',
|
|
9
|
+
'ImplicitNameDerivationError',
|
|
10
|
+
'freeze_setter',
|
|
11
|
+
'validate_type',
|
|
12
|
+
]
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
from typing import Optional, Type, Callable, Any
|
|
3
3
|
|
|
4
|
-
import functools
|
|
5
|
-
from typing import Optional, Type, Callable, Any
|
|
6
|
-
from inspyre_toolbox.syntactic_sweets.classes.decorators import validate_type
|
|
7
|
-
from is_matrix_forge.led_matrix.errors.misc import ImplicitNameDerivationError
|
|
8
|
-
|
|
9
4
|
|
|
10
5
|
def freeze_setter(
|
|
11
6
|
attr_name: Optional[str] = None,
|
|
@@ -94,6 +89,8 @@ def freeze_setter(
|
|
|
94
89
|
- `ImplicitNameDerivationError`: Raised for configuration issues with underscore-prefixed setters.
|
|
95
90
|
- `AttributeError`: Default exception for reassigning a frozen attribute.
|
|
96
91
|
"""
|
|
92
|
+
from is_matrix_forge.led_matrix.errors.misc import ImplicitNameDerivationError
|
|
93
|
+
|
|
97
94
|
def decorator(setter: Callable) -> Callable:
|
|
98
95
|
setter_name = setter.__name__
|
|
99
96
|
|
|
@@ -143,10 +140,3 @@ def freeze_setter(
|
|
|
143
140
|
return wrapper
|
|
144
141
|
|
|
145
142
|
return decorator
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
__all__ = [
|
|
149
|
-
'ImplicitNameDerivationError',
|
|
150
|
-
'freeze_setter',
|
|
151
|
-
'validate_type',
|
|
152
|
-
]
|
|
@@ -26,20 +26,20 @@ from inspyre_toolbox.syntactic_sweets.classes.decorators.aliases import add_alia
|
|
|
26
26
|
from serial.tools.list_ports_common import ListPortInfo
|
|
27
27
|
|
|
28
28
|
from is_matrix_forge.common.helpers import coerce_to_int
|
|
29
|
+
from aliaser.metaclass import AliasMeta
|
|
29
30
|
from is_matrix_forge.led_matrix.constants import SLOT_MAP
|
|
30
31
|
from is_matrix_forge.led_matrix.display.text import show_string as _show_string_raw
|
|
31
32
|
from is_matrix_forge.led_matrix.controller import MultitonMeta
|
|
32
33
|
from is_matrix_forge.led_matrix.controller.helpers.threading import synchronized
|
|
33
34
|
from is_matrix_forge.led_matrix.commands.map import CommandVals
|
|
34
|
-
from is_matrix_forge.led_matrix.hardware import
|
|
35
|
+
from is_matrix_forge.led_matrix.hardware import send_command
|
|
35
36
|
from is_matrix_forge.led_matrix.display.effects.breather import Breather
|
|
36
37
|
from is_matrix_forge.led_matrix.display.text import show_string
|
|
37
38
|
|
|
38
39
|
COMMANDS = CommandVals
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
class LEDMatrixController(metaclass=MultitonMeta):
|
|
42
|
+
class LEDMatrixController(metaclass=AliasMeta):
|
|
43
43
|
"""
|
|
44
44
|
Controller class for LED Matrix devices.
|
|
45
45
|
|
|
@@ -115,6 +115,8 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
115
115
|
self.__show_grid_on_init = None
|
|
116
116
|
self._thread_safe = None
|
|
117
117
|
self._cmd_lock = None
|
|
118
|
+
self._keep_alive = False
|
|
119
|
+
self._KEEP_ALIVE_INTERVAL = 50
|
|
118
120
|
|
|
119
121
|
self.hold_all = hold_all or False
|
|
120
122
|
|
|
@@ -129,6 +131,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
129
131
|
self.__init_clear = not skip_init_clear
|
|
130
132
|
|
|
131
133
|
if init_grid is not None:
|
|
134
|
+
from is_matrix_forge.led_matrix.display.grid import Grid
|
|
132
135
|
if not isinstance(init_grid, Grid):
|
|
133
136
|
raise TypeError(f'init_grid must be of type `Grid`, not {type(init_grid)}')
|
|
134
137
|
|
|
@@ -145,13 +148,75 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
145
148
|
|
|
146
149
|
self.__post_init__()
|
|
147
150
|
|
|
151
|
+
# ---------------------------------------------------------------------
|
|
152
|
+
# Keep‑alive internal worker
|
|
153
|
+
# ---------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
@synchronized
|
|
156
|
+
def __keep_alive_worker(self):
|
|
157
|
+
"""Loop until signalled, polling :pyattr:`animating` every 50 s."""
|
|
158
|
+
# Lazily create the stop event (should already exist, but be safe)
|
|
159
|
+
stop_evt = self._keep_alive_stop_evt or threading.Event()
|
|
160
|
+
self._keep_alive_stop_evt = stop_evt
|
|
161
|
+
|
|
162
|
+
while not stop_evt.is_set():
|
|
163
|
+
try:
|
|
164
|
+
_ = self.animating # A simple query is enough to keep FW awake
|
|
165
|
+
except Exception: # pragma: no cover – we don't crash the thread
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
# Wait with timeout so the thread can exit early when stop_evt is set
|
|
169
|
+
stop_evt.wait(self._KEEP_ALIVE_INTERVAL)
|
|
170
|
+
|
|
171
|
+
# ---------------------------------------------------------------------
|
|
172
|
+
# Property controlling the keep‑alive thread
|
|
173
|
+
# ---------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def keep_alive(self) -> bool:
|
|
177
|
+
"""Whether the background keep‑alive thread is active."""
|
|
178
|
+
return self._keep_alive
|
|
179
|
+
|
|
180
|
+
@keep_alive.setter
|
|
181
|
+
def keep_alive(self, enable: bool):
|
|
182
|
+
if not isinstance(enable, bool):
|
|
183
|
+
raise TypeError('keep_alive must be a boolean.')
|
|
184
|
+
|
|
185
|
+
# No change ➜ nothing to do
|
|
186
|
+
if enable == self._keep_alive:
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
if enable:
|
|
190
|
+
# Start background thread
|
|
191
|
+
self._keep_alive_stop_evt = threading.Event()
|
|
192
|
+
self._keep_alive_thread = threading.Thread(
|
|
193
|
+
target=self.__keep_alive_worker,
|
|
194
|
+
name=f"{self.__class__.__name__}-KeepAlive-{self.device.name}",
|
|
195
|
+
daemon=True,
|
|
196
|
+
)
|
|
197
|
+
self._keep_alive_thread.start()
|
|
198
|
+
self._keep_alive = True
|
|
199
|
+
else:
|
|
200
|
+
# Signal thread to exit and wait (briefly) for it
|
|
201
|
+
if self._keep_alive_stop_evt is not None:
|
|
202
|
+
self._keep_alive_stop_evt.set()
|
|
203
|
+
if (
|
|
204
|
+
self._keep_alive_thread is not None
|
|
205
|
+
and self._keep_alive_thread.is_alive()
|
|
206
|
+
):
|
|
207
|
+
self._keep_alive_thread.join(timeout=self._KEEP_ALIVE_INTERVAL + 1)
|
|
208
|
+
self._keep_alive_thread = None
|
|
209
|
+
self._keep_alive_stop_evt = None
|
|
210
|
+
self._keep_alive = False
|
|
211
|
+
self.__post_init__()
|
|
212
|
+
|
|
148
213
|
def __post_init__(self):
|
|
149
214
|
from is_matrix_forge.led_matrix.display.effects.breather import Breather
|
|
150
215
|
|
|
151
216
|
self.__breather = Breather(self)
|
|
152
217
|
|
|
153
218
|
if self.clear_on_init:
|
|
154
|
-
self.
|
|
219
|
+
self.clear_matrix()
|
|
155
220
|
|
|
156
221
|
if self.set_brightness_on_init:
|
|
157
222
|
self.set_brightness(self.__default_brightness)
|
|
@@ -184,7 +249,6 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
184
249
|
bool: True if the device is animating, False otherwise.
|
|
185
250
|
"""
|
|
186
251
|
return bool(send_command(self.device, COMMANDS.Animate, with_response=True)[0])
|
|
187
|
-
# return animate(self.device)
|
|
188
252
|
|
|
189
253
|
@property
|
|
190
254
|
def breather(self) -> Breather:
|
|
@@ -321,7 +385,10 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
321
385
|
|
|
322
386
|
@property
|
|
323
387
|
def name(self) -> str:
|
|
324
|
-
|
|
388
|
+
if self.__name is None:
|
|
389
|
+
self.__name = self.device.name
|
|
390
|
+
|
|
391
|
+
return self.__name
|
|
325
392
|
|
|
326
393
|
def play_animation(self, animation):
|
|
327
394
|
from is_matrix_forge.led_matrix.display.animations.animation import Animation
|
|
@@ -344,9 +411,6 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
344
411
|
text_animation.loop = True
|
|
345
412
|
return self.play_animation(text_animation)
|
|
346
413
|
|
|
347
|
-
def show_text(self, text: str):
|
|
348
|
-
self.draw_text(text)
|
|
349
|
-
|
|
350
414
|
@property
|
|
351
415
|
def set_brightness_on_init(self):
|
|
352
416
|
"""
|
|
@@ -405,6 +469,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
405
469
|
animate(self.device, enable)
|
|
406
470
|
|
|
407
471
|
@synchronized
|
|
472
|
+
@method_alias('clear')
|
|
408
473
|
def clear_matrix(self) -> None:
|
|
409
474
|
"""
|
|
410
475
|
Clear the LED matrix display.
|
|
@@ -419,12 +484,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
419
484
|
grid = Grid(init_grid=data)
|
|
420
485
|
self.draw_grid(grid)
|
|
421
486
|
|
|
422
|
-
|
|
423
|
-
self.clear_matrix()
|
|
424
|
-
|
|
425
|
-
def draw(self, grid: 'Grid' = None) -> None:
|
|
426
|
-
return self.draw_grid(grid)
|
|
427
|
-
|
|
487
|
+
@alias('draw')
|
|
428
488
|
@synchronized
|
|
429
489
|
def draw_grid(self, grid: 'Grid' = None) -> None:
|
|
430
490
|
"""
|
|
@@ -443,7 +503,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
443
503
|
render_matrix(self.device, grid.grid)
|
|
444
504
|
|
|
445
505
|
@synchronized
|
|
446
|
-
@
|
|
506
|
+
@alias('pattern', 'show_pattern')
|
|
447
507
|
def draw_pattern(self, pattern: str) -> None:
|
|
448
508
|
"""
|
|
449
509
|
Draw a pattern on the LED matrix.
|
|
@@ -476,12 +536,6 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
476
536
|
|
|
477
537
|
_show_percentage_raw(self.device, percentage)
|
|
478
538
|
|
|
479
|
-
def draw_string(self, text: str):
|
|
480
|
-
self.show_text(text)
|
|
481
|
-
|
|
482
|
-
def draw_text(self, text: str):
|
|
483
|
-
self.show_text(text)
|
|
484
|
-
|
|
485
539
|
@synchronized
|
|
486
540
|
def display_location(self):
|
|
487
541
|
"""
|
|
@@ -613,15 +667,8 @@ class LEDMatrixController(metaclass=MultitonMeta):
|
|
|
613
667
|
if not __from_setter:
|
|
614
668
|
self.__brightness = brightness
|
|
615
669
|
|
|
616
|
-
def show_string(self, text: str) -> None:
|
|
617
|
-
"""
|
|
618
|
-
Alias for LEDMatrixController.show_text.
|
|
619
|
-
|
|
620
|
-
See Also:
|
|
621
|
-
LEDMatrixController.show_text
|
|
622
|
-
"""
|
|
623
|
-
self.show_text(text)
|
|
624
670
|
|
|
671
|
+
@method_alias('draw_text', 'show_string', 'draw_string')
|
|
625
672
|
@synchronized
|
|
626
673
|
def show_text(self, text: str) -> None:
|
|
627
674
|
"""
|
|
@@ -2,6 +2,7 @@ from time import sleep
|
|
|
2
2
|
|
|
3
3
|
from is_matrix_forge.led_matrix.hardware import brightness
|
|
4
4
|
from is_matrix_forge.led_matrix.display.text import show_string
|
|
5
|
+
from .audio_visualizer import AudioVisualizer
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def clear(dev):
|
|
@@ -26,3 +27,11 @@ def goodbye_animation(dev):
|
|
|
26
27
|
checkerboard_cycle(dev)
|
|
27
28
|
sleep(.5)
|
|
28
29
|
show_string(dev, 'Bye')
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
'AudioVisualizer',
|
|
34
|
+
'clear',
|
|
35
|
+
'checkerboard_cycle',
|
|
36
|
+
'goodbye_animation',
|
|
37
|
+
]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Real-time audio visualizer for the LED matrix.
|
|
2
|
+
|
|
3
|
+
This module provides a small utility that streams audio data and renders simple
|
|
4
|
+
bar style visualizations on one or more LED matrix controllers. By default it
|
|
5
|
+
uses the system microphone for input, however an audio file may also be used as
|
|
6
|
+
the source allowing "regular" audio to be visualized. ``sounddevice`` and
|
|
7
|
+
``soundfile`` are optional dependencies and the visualiser gracefully degrades
|
|
8
|
+
if they are unavailable.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import threading
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Iterable, List, Optional, Union
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
try: # ``sounddevice`` is an optional dependency
|
|
20
|
+
import sounddevice as sd
|
|
21
|
+
except Exception: # pragma: no cover - optional dependency missing
|
|
22
|
+
sd = None # type: ignore
|
|
23
|
+
|
|
24
|
+
try: # ``soundfile`` is also optional
|
|
25
|
+
import soundfile as sf
|
|
26
|
+
except Exception: # pragma: no cover - optional dependency missing
|
|
27
|
+
sf = None # type: ignore
|
|
28
|
+
|
|
29
|
+
from is_matrix_forge.led_matrix.controller.controller import LEDMatrixController
|
|
30
|
+
from is_matrix_forge.led_matrix.display.animations.frame.base import Frame
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AudioVisualizer:
|
|
34
|
+
"""Stream audio data and render a simple bar visualisation."""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
controllers: Iterable[LEDMatrixController],
|
|
39
|
+
sample_rate: int = 44_100,
|
|
40
|
+
chunk_size: int = 1_024,
|
|
41
|
+
audio_source: Union[str, Path, None] = None,
|
|
42
|
+
loop_file: bool = True,
|
|
43
|
+
) -> None:
|
|
44
|
+
self.controllers: List[LEDMatrixController] = list(controllers)
|
|
45
|
+
self.sample_rate = sample_rate
|
|
46
|
+
self.chunk_size = chunk_size
|
|
47
|
+
self._stream: Optional[sd.InputStream] = None # type: ignore[var-annotated]
|
|
48
|
+
self._thread: Optional[threading.Thread] = None
|
|
49
|
+
self._running = False
|
|
50
|
+
self._audio_source: Optional[Path] = Path(audio_source) if audio_source else None
|
|
51
|
+
self._loop_file = loop_file
|
|
52
|
+
|
|
53
|
+
# ------------------------------------------------------------------ utils --
|
|
54
|
+
def _process_chunk(self, data: np.ndarray) -> None: # pragma: no cover - real time
|
|
55
|
+
"""Render a frame based on ``data`` samples."""
|
|
56
|
+
amplitude = float(np.linalg.norm(data) / len(data))
|
|
57
|
+
bar_height = min(int(amplitude * 34), 34)
|
|
58
|
+
|
|
59
|
+
grid = [[0 for _ in range(34)] for _ in range(9)]
|
|
60
|
+
for x in range(9):
|
|
61
|
+
for y in range(bar_height):
|
|
62
|
+
grid[x][33 - y] = 1
|
|
63
|
+
|
|
64
|
+
frame = Frame(grid=grid, duration=0.01)
|
|
65
|
+
|
|
66
|
+
for ctrl in self.controllers:
|
|
67
|
+
ctrl.draw_grid(frame.grid)
|
|
68
|
+
|
|
69
|
+
def _audio_callback(self, indata, frames, time, status) -> None: # pragma: no cover - real time
|
|
70
|
+
if not self._running:
|
|
71
|
+
return
|
|
72
|
+
self._process_chunk(indata[:, 0])
|
|
73
|
+
|
|
74
|
+
def _file_loop(self) -> None: # pragma: no cover - requires soundfile
|
|
75
|
+
assert sf is not None and self._audio_source is not None
|
|
76
|
+
while self._running:
|
|
77
|
+
with sf.SoundFile(self._audio_source) as f:
|
|
78
|
+
while self._running:
|
|
79
|
+
data = f.read(self.chunk_size, dtype='float32')
|
|
80
|
+
if len(data) == 0:
|
|
81
|
+
break
|
|
82
|
+
self._process_chunk(data)
|
|
83
|
+
if not self._loop_file:
|
|
84
|
+
break
|
|
85
|
+
|
|
86
|
+
# ------------------------------------------------------------------- API --
|
|
87
|
+
def start(self) -> None:
|
|
88
|
+
if sd is None: # pragma: no cover - environment without sounddevice
|
|
89
|
+
raise RuntimeError("sounddevice is required for AudioVisualizer")
|
|
90
|
+
|
|
91
|
+
if self._running:
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
self._running = True
|
|
95
|
+
if self._audio_source is not None:
|
|
96
|
+
if sf is None:
|
|
97
|
+
raise RuntimeError("soundfile is required for file playback")
|
|
98
|
+
self._thread = threading.Thread(target=self._file_loop, daemon=True)
|
|
99
|
+
self._thread.start()
|
|
100
|
+
else:
|
|
101
|
+
self._stream = sd.InputStream(
|
|
102
|
+
channels=1,
|
|
103
|
+
samplerate=self.sample_rate,
|
|
104
|
+
blocksize=self.chunk_size,
|
|
105
|
+
callback=self._audio_callback,
|
|
106
|
+
)
|
|
107
|
+
self._stream.start()
|
|
108
|
+
|
|
109
|
+
def stop(self) -> None:
|
|
110
|
+
if not self._running:
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
self._running = False
|
|
114
|
+
if self._stream is not None:
|
|
115
|
+
self._stream.stop()
|
|
116
|
+
self._stream.close()
|
|
117
|
+
self._stream = None
|
|
118
|
+
if self._thread is not None:
|
|
119
|
+
self._thread.join(timeout=1)
|
|
120
|
+
self._thread = None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
__all__ = ["AudioVisualizer"]
|
|
124
|
+
|
|
@@ -22,6 +22,7 @@ from pathlib import Path
|
|
|
22
22
|
from typing import List, Optional, Union, ClassVar, Type, Any, Dict # Added Any, Dict
|
|
23
23
|
from ...constants import WIDTH as __WIDTH, HEIGHT as __HEIGHT, PRESETS_DIR
|
|
24
24
|
from .helpers import is_valid_grid, generate_blank_grid
|
|
25
|
+
from ...helpers import load_from_file as _helpers_load_from_file
|
|
25
26
|
from is_matrix_forge.common.helpers import coerce_to_int
|
|
26
27
|
|
|
27
28
|
MATRIX_HEIGHT = __HEIGHT
|
|
@@ -35,6 +36,24 @@ This constant defines the default width for new Grid instances and for loading o
|
|
|
35
36
|
"""
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
def load_from_file(
|
|
40
|
+
path: Union[str, Path],
|
|
41
|
+
expected_width: Optional[int] | None = None,
|
|
42
|
+
expected_height: Optional[int] | None = None,
|
|
43
|
+
fallback_duration: Optional[Union[int, float]] = None,
|
|
44
|
+
) -> Any:
|
|
45
|
+
"""Wrapper around :func:`is_matrix_forge.led_matrix.helpers.load_from_file`.
|
|
46
|
+
|
|
47
|
+
Exists primarily for unit tests which monkeypatch this function directly.
|
|
48
|
+
"""
|
|
49
|
+
return _helpers_load_from_file(
|
|
50
|
+
path,
|
|
51
|
+
expected_width,
|
|
52
|
+
expected_height,
|
|
53
|
+
fallback_duration,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
38
57
|
class Grid:
|
|
39
58
|
"""
|
|
40
59
|
Represents a 2D column-major grid for the LED display (grid[x][y], 9×34).
|
|
@@ -127,8 +146,18 @@ class Grid:
|
|
|
127
146
|
cls,
|
|
128
147
|
spec: List[List[int]]
|
|
129
148
|
) -> 'Grid':
|
|
130
|
-
"""Instantiate directly from a column-major spec list.
|
|
131
|
-
|
|
149
|
+
"""Instantiate directly from a column-major spec list.
|
|
150
|
+
|
|
151
|
+
The dimensions of the grid are inferred from ``spec`` so tests can
|
|
152
|
+
provide arbitrary sized grids.
|
|
153
|
+
"""
|
|
154
|
+
width = len(spec)
|
|
155
|
+
height = len(spec[0]) if spec else 0
|
|
156
|
+
if not is_valid_grid(spec, width, height):
|
|
157
|
+
raise ValueError(
|
|
158
|
+
f"init_grid must be {width}×{height} column-major 0/1 list"
|
|
159
|
+
)
|
|
160
|
+
return cls(width=width, height=height, init_grid=spec)
|
|
132
161
|
|
|
133
162
|
@classmethod
|
|
134
163
|
def from_file(
|
|
@@ -141,10 +170,16 @@ class Grid:
|
|
|
141
170
|
"""
|
|
142
171
|
Load a column-major grid from file (single grid or frames of grids).
|
|
143
172
|
"""
|
|
144
|
-
from ...helpers import load_from_file
|
|
145
173
|
raw = load_from_file(str(filename))
|
|
146
174
|
# Single-grid JSON: list of lists
|
|
147
|
-
if
|
|
175
|
+
if (
|
|
176
|
+
isinstance(raw, list)
|
|
177
|
+
and raw
|
|
178
|
+
and isinstance(raw[0], list)
|
|
179
|
+
and is_valid_grid(raw[0], width, height)
|
|
180
|
+
):
|
|
181
|
+
grid_data = raw[0]
|
|
182
|
+
elif isinstance(raw, list) and raw and isinstance(raw[0], list):
|
|
148
183
|
grid_data = raw
|
|
149
184
|
# Frame-list JSON: list of dicts
|
|
150
185
|
elif isinstance(raw, list) and all(isinstance(f, dict) for f in raw):
|
|
@@ -187,11 +222,11 @@ class Grid:
|
|
|
187
222
|
new = generate_blank_grid(self._width, self._height, self._fill_value)
|
|
188
223
|
|
|
189
224
|
for c, r in itertools.product(range(self._width), range(self._height)):
|
|
190
|
-
|
|
191
|
-
|
|
225
|
+
dest_c = (c + dx) % self._width if wrap else c + dx
|
|
226
|
+
dest_r = (r + dy) % self._height if wrap else r + dy
|
|
192
227
|
|
|
193
|
-
if 0 <=
|
|
194
|
-
new[
|
|
228
|
+
if 0 <= dest_c < self._width and 0 <= dest_r < self._height:
|
|
229
|
+
new[dest_c][dest_r] = self._grid[c][r]
|
|
195
230
|
|
|
196
231
|
return Grid(width=self._width, height=self._height, fill_value=self._fill_value, init_grid=new)
|
|
197
232
|
|
|
@@ -7,6 +7,7 @@ including functions to convert between different device location formats.
|
|
|
7
7
|
from serial import Serial, SerialException
|
|
8
8
|
from serial.tools import list_ports
|
|
9
9
|
from is_matrix_forge.log_engine import ROOT_LOGGER
|
|
10
|
+
from is_matrix_forge.led_matrix.constants import VID as EXPECTED_VID, PID as EXPECTED_PID
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
MOD_LOGGER = ROOT_LOGGER.get_child('led_matrix.helpers.device')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "IS-Matrix-Forge"
|
|
3
|
-
version = "1.0.0-dev.
|
|
3
|
+
version = "1.0.0-dev.6"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Taylor B. <t.blackstone@inspyre.tech>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -31,6 +31,8 @@ clipboard = { version = "^0.0.4", optional = true }
|
|
|
31
31
|
pysimplegui-4-foss = "==4.60.4.1"
|
|
32
32
|
pysimpleguiweb = "==0.39.0"
|
|
33
33
|
imapclient = "==3.0.1"
|
|
34
|
+
requests = "^2.32.4"
|
|
35
|
+
aliaser = "^1.0.0.dev4"
|
|
34
36
|
|
|
35
37
|
[tool.poetry.extras]
|
|
36
38
|
clipboard_support = ["clipboard"]
|
|
@@ -44,7 +46,8 @@ ipyboost = { version = "1.0.0.a3", source = "testpypi" }
|
|
|
44
46
|
[tool.poetry.scripts]
|
|
45
47
|
python-path = "Scripts.python_path:main"
|
|
46
48
|
led-matrix-identify = "is_matrix_forge.led_matrix.Scripts.identify_matrices:main"
|
|
47
|
-
install-presets = "Scripts.install_presets:main"
|
|
49
|
+
install-presets = "is_matrix_forge.led_matrix.Scripts.install_presets.main:main"
|
|
50
|
+
pixel-grid = "is_matrix_forge.designer_gui.main_window:main"
|
|
48
51
|
|
|
49
52
|
[[tool.poetry.include]]
|
|
50
53
|
path = "presets/**"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/__init__.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/char_map.json
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/font_map.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/helpers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/__init__.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/debug.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/presets.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/__init__.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/b1display.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/c1minimal.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/font.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/ledmatrix.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/commands/map.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/base.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/grid.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/misc.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/fonts.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/hardware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/led_matrix.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/__init__.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/errors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/event.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/layout/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/helpers.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/monitor.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/__init__.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/sounds/__init__.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/sounds/base.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/scripts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/answer.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/message.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/request.py
RENAMED
|
File without changes
|
{is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/exchange.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|