From 48081324365a42b0cb31ffc2b74648de499c3baf Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 01:56:13 +0000 Subject: [PATCH] docs: correct semantically stale content across the user and developer guides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A second-pass content audit checked the guides' substantive claims against the code (the first pass only fixed mechanical drift). Fixes: - GETTING_STARTED: described booting a prebuilt SD image and seeing default clock/weather plugins — neither exists. Now documents the real install (Pi OS Lite + one-shot installer / first_time_install.sh) and that displays come from the Plugin Store. Duration and ordering instructions moved to the Rotation tab where the controls actually live. - WEB_INTERFACE_GUIDE: three whole tabs were undocumented (Rotation, Backup & Restore, Tools) and the Display tab's Vegas Scroll section was unmentioned. Fonts overrides are per display element (not per plugin); Logs has an Auto-scroll checkbox (not a Pause button); the aspirational keyboard-shortcut list and no-JS claim removed. - TROUBLESHOOTING: the hand-written service-file template (wrong user, wrong ExecStart, dropped the autostart gate) replaced with the real systemd/ units + install scripts; recovery steps no longer copy placeholder units verbatim; WiFi curl endpoint corrected to /api/v3/; cache-clearing advice now targets the real cache locations. - ADVANCED_FEATURES: removed a false claim that CacheManager has no delete(); fixed two example snippets that raise TypeError (BackgroundDataService and get_config_file_mode signatures); fixed cache paths, a 5-minute TTL that is actually 1 hour, and the vegas table now links the complete 26-key reference. - EMULATOR_SETUP_GUIDE: documented run.py flags that don't exist (--plugin/--test-plugins) removed in favor of dev_server.py and check_plugin.py; shipped emulator config values corrected (browser adapter default on :8888, not pygame). - PLUGIN_QUICK_REFERENCE: drag-and-drop reordering is shipped, not 'not yet supported'; discovery-fallback and registry-repo claims corrected. PLUGIN_API_REFERENCE: get_vegas_segment_width returns panels, not pixels. CONTRIBUTING: the repo uses flake8/mypy/bandit pre-commit hooks, not black/ruff, and tests need requirements-test.txt. - SKIN_SYSTEM/DEVELOPER_QUICK_REFERENCE: stale module paths. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr --- CONTRIBUTING.md | 11 ++- docs/ADVANCED_FEATURES.md | 64 +++++++----- docs/DEVELOPER_QUICK_REFERENCE.md | 3 +- docs/EMULATOR_SETUP_GUIDE.md | 157 ++++++++++++++++-------------- docs/GETTING_STARTED.md | 56 ++++++++--- docs/PLUGIN_API_REFERENCE.md | 5 +- docs/PLUGIN_QUICK_REFERENCE.md | 14 +-- docs/SKIN_SYSTEM.md | 2 +- docs/TROUBLESHOOTING.md | 98 +++++++++---------- docs/WEB_INTERFACE_GUIDE.md | 41 ++++---- 10 files changed, 255 insertions(+), 196 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 613b51e1..a802a89f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,7 @@ improvements, and code changes. ## Running the tests ```bash -pip install -r requirements.txt +pip install -r requirements.txt -r requirements-test.txt pytest ``` @@ -57,9 +57,12 @@ integration tests. `docs/`. 3. **Keep PRs focused.** One conceptual change per PR. If you find adjacent bugs while working, fix them in a separate PR. -4. **Follow the existing code style.** Python code uses standard - `black`/`ruff` conventions; HTML/JS in `web_interface/` follows the - patterns already in `templates/v3/` and `static/v3/`. +4. **Follow the existing code style.** The pre-commit hooks run + `flake8` (E9, F63, F7, F82 plus bugbear `B` checks), `mypy` on + `src/`, `bandit`, and `gitleaks` — install them with + `pre-commit install` so they run on every commit; HTML/JS in + `web_interface/` follows the patterns already in `templates/v3/` + and `static/v3/`. 5. **Update documentation** alongside code changes. If you add a config key, document it in the relevant `*.md` file (or, for plugins, in `config_schema.json` so the form is auto-generated). diff --git a/docs/ADVANCED_FEATURES.md b/docs/ADVANCED_FEATURES.md index a9742155..219b5952 100644 --- a/docs/ADVANCED_FEATURES.md +++ b/docs/ADVANCED_FEATURES.md @@ -47,6 +47,11 @@ Enable Vegas mode in `config/config.json`: } ``` +Vegas mode can also be configured entirely from the web UI — the +**Display** tab has a Vegas Scroll Mode section (enable toggle, scroll +speed, separator width, dynamic duration, and more), so hand-editing +JSON is optional. + **Configuration Options:** | Setting | Default | Description | @@ -57,7 +62,11 @@ Enable Vegas mode in `config/config.json`: | `plugin_order` | `[]` | Plugin display order (empty = auto) | | `excluded_plugins` | `[]` | Plugins to exclude from Vegas mode | | `target_fps` | `125` | Target frame rate | -| `buffer_ahead` | `2` | Number of panels to render ahead | +| `buffer_ahead` | `2` | Number of plugins buffered ahead | + +This table is a subset — `display.vegas_scroll` supports 26 keys in +total. See the full list in +[CONFIG_REFERENCE.md](CONFIG_REFERENCE.md#displayvegas_scroll--continuous-scroll-mode). ### Per-Plugin Configuration @@ -79,9 +88,13 @@ Override Vegas behavior for specific plugins: | Setting | Values | Description | |---------|--------|-------------| | `vegas_mode` | `scroll`, `fixed`, `static` | Display mode for this plugin | -| `vegas_panel_count` | `1-10` | Width in panels (1 panel = display width) | +| `vegas_panel_count` | any positive integer | Width in panels (1 panel = display width) | | `display_duration` | seconds | Pause duration for STATIC mode | +Plugins may also set `vegas_overflow` and `vegas_max_width_screens` in +their config section to control how oversized content is handled (see +`PluginManager` in `src/plugin_system/plugin_manager.py`). + ### Plugin Integration (Developer Guide) **1. Implement Content Method:** @@ -451,7 +464,7 @@ time when something is active. ### REST API Reference -The API is mounted at `/api/v3` (`web_interface/app.py:144`). +The API is mounted at `/api/v3` (`web_interface/app.py:199`). #### Start On-Demand Display @@ -518,13 +531,15 @@ curl http://localhost:5000/api/v3/display/on-demand/status > There is no public Python on-demand API. The display controller's > on-demand machinery is internal — drive it through the REST endpoints -> above (or the web UI buttons), which write a request into the cache -> manager under the `display_on_demand_request` key -> (`web_interface/blueprints/api_v3.py:1622,1687`) that the controller -> polls at `src/display_controller.py:921`. A separate +> above (or the web UI buttons). The API handlers +> (`start_on_demand_display()` / `stop_on_demand_display()` in +> `web_interface/blueprints/api_v3.py`) write a request into the cache +> manager under the `display_on_demand_request` key, which +> `DisplayController._poll_on_demand_requests()` +> (`src/display_controller.py`) picks up. A separate > `display_on_demand_config` key is used by the controller itself -> during activation to track what's currently running (written at -> `display_controller.py:1195`, cleared at `:1221`). +> during activation (`_activate_on_demand()`) to track what's +> currently running, and is cleared by `_clear_on_demand()`. ### Duration Modes @@ -646,13 +661,13 @@ keys helps troubleshoot stuck states. **When Set:** Every display loop iteration **Auto-Cleared:** Never (continuously updated) -**4. display_on_demand_processed_id** (TTL: 5 minutes) +**4. display_on_demand_processed_id** (TTL: 1 hour) ``` "uuid-string-of-last-processed-request" ``` **Purpose:** Prevents duplicate request processing **When Set:** After processing request -**Auto-Cleared:** After 5 minutes TTL +**Auto-Cleared:** After 1 hour TTL ### When Manual Clearing is Needed @@ -685,9 +700,9 @@ keys helps troubleshoot stuck states. The cache is stored as JSON files under one of: - `/var/cache/ledmatrix/` (preferred when the service has permission) -- `~/.cache/ledmatrix/` +- `~/.ledmatrix_cache/` - `/opt/ledmatrix/cache/` -- `/tmp/ledmatrix-cache/` (fallback) +- `$TMPDIR/ledmatrix_cache/` (fallback) ```bash # Find the cache dir actually in use @@ -711,8 +726,9 @@ cache.clear_cache('display_on_demand_request') cache.clear_cache('display_on_demand_processed_id') ``` -> The actual public method is `clear_cache(key=None)` — there is no -> `delete()` method on `CacheManager`. +> `CacheManager` also has a `delete(key)` method — a thin wrapper over +> `clear_cache(key)` — so `cache.delete('display_on_demand_config')` +> works equally well. ### Cache Impact on Running Service @@ -730,7 +746,7 @@ The display controller automatically handles cleanup: - **Config key**: Cleared when on-demand stops - **State key**: Updated every display loop iteration - **Request key**: Expires after 1 hour TTL (or after processing) -- **Processed ID**: Expires after 5 minutes TTL +- **Processed ID**: Expires after 1 hour TTL --- @@ -821,9 +837,6 @@ same shape as the example above. ### Testing ```bash -# Run background service test -python test_background_service.py - # Check logs for background operations sudo journalctl -u ledmatrix -f | grep "background" ``` @@ -832,9 +845,10 @@ sudo journalctl -u ledmatrix -f | grep "background" **View Statistics:** ```python -from src.background_data_service import BackgroundDataService +from src.background_data_service import get_background_service +from src.cache_manager import CacheManager -service = BackgroundDataService() +service = get_background_service(CacheManager()) stats = service.get_statistics() print(f"Active tasks: {stats['active_tasks']}") print(f"Completed: {stats['completed']}") @@ -875,6 +889,7 @@ from src.common.permission_utils import ( ensure_file_permissions, get_config_file_mode, get_assets_file_mode, + get_assets_dir_mode, get_plugin_file_mode, get_cache_dir_mode ) @@ -883,7 +898,10 @@ from src.common.permission_utils import ( ensure_directory_permissions(Path("assets/sports"), get_assets_dir_mode()) # Set file permissions after writing -ensure_file_permissions(Path("config/config.json"), get_config_file_mode()) +# (get_config_file_mode requires the file path — secrets files get a +# stricter mode than the main config) +config_path = Path("config/config.json") +ensure_file_permissions(config_path, get_config_file_mode(config_path)) ``` ### When to Use Utilities @@ -938,7 +956,7 @@ from src.common.permission_utils import ensure_file_permissions, get_config_file config_path = Path("config/config.json") with open(config_path, 'w') as f: json.dump(data, f) -ensure_file_permissions(config_path, get_config_file_mode()) +ensure_file_permissions(config_path, get_config_file_mode(config_path)) ``` **Pattern 3: Downloading Logo** diff --git a/docs/DEVELOPER_QUICK_REFERENCE.md b/docs/DEVELOPER_QUICK_REFERENCE.md index 3b05dcf9..7eefb0c9 100644 --- a/docs/DEVELOPER_QUICK_REFERENCE.md +++ b/docs/DEVELOPER_QUICK_REFERENCE.md @@ -190,7 +190,8 @@ def display(self, force_clear=False): ``` LEDMatrix/ -├── plugins/ # Installed plugins +├── plugin-repos/ # Installed plugins (default; plugins/ is only +│ # for dev symlinks via scripts/dev/dev_plugin_setup.sh) ├── config/ │ ├── config.json # Main configuration │ └── config_secrets.json # API keys and secrets diff --git a/docs/EMULATOR_SETUP_GUIDE.md b/docs/EMULATOR_SETUP_GUIDE.md index e30c3063..0f1ff98b 100644 --- a/docs/EMULATOR_SETUP_GUIDE.md +++ b/docs/EMULATOR_SETUP_GUIDE.md @@ -69,23 +69,24 @@ default configuration as it ships in the repo: ```json { "pixel_outline": 0, - "pixel_size": 5, + "pixel_size": 16, "pixel_style": "square", "pixel_glow": 6, - "display_adapter": "pygame", + "display_adapter": "browser", + "allow_adapter_fallback": true, "icon_path": null, "emulator_title": null, "suppress_font_warnings": false, - "suppress_adapter_load_errors": false, "browser": { "_comment": "For use with the browser adapter only.", "port": 8888, - "target_fps": 24, + "target_fps": 60, "fps_display": false, "quality": 70, "image_border": true, "debug_text": false, - "image_format": "JPEG" + "image_format": "JPEG", + "open_immediately": false }, "log_level": "info" } @@ -96,13 +97,13 @@ default configuration as it ships in the repo: | Option | Description | Default | Values | |--------|-------------|---------|--------| | `pixel_outline` | Pixel border thickness | 0 | 0-5 | -| `pixel_size` | Size of each pixel | 5 | 1-64 (8–16 is typical for testing) | +| `pixel_size` | Size of each pixel | 16 | 1-64 (8–16 is typical for testing) | | `pixel_style` | Pixel shape | "square" | "square", "circle" | | `pixel_glow` | Glow effect intensity | 6 | 0-20 | -| `display_adapter` | Display backend | "pygame" | "pygame", "browser" | +| `display_adapter` | Display backend | "browser" | "browser", "pygame" | +| `allow_adapter_fallback` | Fall back to another adapter if the configured one fails to load | true | true/false | | `emulator_title` | Window title | null | Any string | | `suppress_font_warnings` | Hide font warnings | false | true/false | -| `suppress_adapter_load_errors` | Hide adapter errors | false | true/false | ### 3. Browser Adapter Configuration @@ -111,18 +112,32 @@ When using the browser adapter, additional options are available: | Option | Description | Default | |--------|-------------|---------| | `port` | Web server port | 8888 | -| `target_fps` | Target frames per second | 24 | +| `target_fps` | Target frames per second | 60 | | `fps_display` | Show FPS counter | false | | `quality` | Image compression quality | 70 | | `image_border` | Show image border | true | | `debug_text` | Show debug information | false | | `image_format` | Image format | "JPEG" | +| `open_immediately` | Open the browser page automatically on start | false | ## Running the Emulator -### 1. Set Environment Variable +### 1. Use the `-e` Flag (Recommended) -Enable emulator mode by setting the `EMULATOR` environment variable: +`run.py` accepts exactly two flags: `-e`/`--emulator` and +`-d`/`--debug`. + +```bash +python3 run.py -e + +# With verbose logging +python3 run.py -e -d +``` + +### 2. Alternative: Set the Environment Variable + +You can also enable emulator mode via the `EMULATOR` environment +variable: **Windows (Command Prompt):** ```cmd @@ -137,15 +152,6 @@ python run.py ``` **Linux/macOS:** -```bash -export EMULATOR=true -python3 run.py -``` - -### 2. Alternative: Direct Python Execution - -You can also run the emulator directly: - ```bash EMULATOR=true python3 run.py ``` @@ -153,7 +159,8 @@ EMULATOR=true python3 run.py ### 3. Verify Emulator Mode When running in emulator mode, you should see: -- A window displaying the LED matrix simulation +- The emulated matrix — a web page at `http://localhost:8888` with the + default browser adapter, or a desktop window with the pygame adapter - Console output indicating emulator mode - No hardware initialization errors @@ -161,7 +168,36 @@ When running in emulator mode, you should see: LEDMatrix supports two display adapters for the emulator: -### 1. Pygame Adapter (Default) +### 1. Browser Adapter (Default) + +The browser adapter runs a web server and displays the matrix as a web +page at `http://localhost:8888`. This is the adapter the shipped +`emulator_config.json` uses. + +**Features:** +- Web-based interface +- Remote access capability +- Mobile-friendly +- Screenshot capture + +**Configuration:** +```json +{ + "display_adapter": "browser", + "browser": { + "port": 8888, + "target_fps": 60, + "quality": 70 + } +} +``` + +**Usage:** +1. Start the emulator (`python3 run.py -e`) +2. Open browser to `http://localhost:8888` +3. View the LED matrix display + +### 2. Pygame Adapter (Alternative) The pygame adapter provides a native desktop window with real-time display. @@ -186,33 +222,6 @@ The pygame adapter provides a native desktop window with real-time display. - `+/-` - Zoom in/out - `R` - Reset zoom -### 2. Browser Adapter - -The browser adapter runs a web server and displays the matrix in a web browser. - -**Features:** -- Web-based interface -- Remote access capability -- Mobile-friendly -- Screenshot capture - -**Configuration:** -```json -{ - "display_adapter": "browser", - "browser": { - "port": 8888, - "target_fps": 24, - "quality": 70 - } -} -``` - -**Usage:** -1. Start the emulator with browser adapter -2. Open browser to `http://localhost:8888` -3. View the LED matrix display - ## Troubleshooting ### Common Issues @@ -299,17 +308,18 @@ Modify the display dimensions in your main config: ### 2. Plugin Development -For plugin development with the emulator: +`run.py` always runs the full rotation — it has no single-plugin flag. +To preview or check one plugin in isolation, use the dev tools: ```bash -# Enable emulator mode -export EMULATOR=true +# Run the full display in emulator mode (optionally with debug logging) +python3 run.py -e -d -# Run with specific plugin -python run.py --plugin my-plugin +# Live single-plugin preview in the browser (port 5001) +python3 scripts/dev_server.py -# Debug mode -python run.py --debug +# Headless render/validation of one plugin +python3 scripts/check_plugin.py --plugin my-plugin ``` ### 3. Performance Tuning @@ -344,11 +354,10 @@ The emulator can work alongside the web interface: ```bash # Terminal 1: Start emulator -export EMULATOR=true -python run.py +python3 run.py -e -# Terminal 2: Start web interface -python web_interface/app.py +# Terminal 2: Start web interface (supported entry point) +python3 web_interface/start.py ``` Access the web interface at `http://localhost:5000` while the emulator runs. @@ -365,13 +374,14 @@ Access the web interface at `http://localhost:5000` while the emulator runs. ### 2. Plugin Testing ```bash -# Test specific plugin -export EMULATOR=true -python run.py --plugin clock-simple +# Test a specific plugin (headless check) +python3 scripts/check_plugin.py --plugin clock-simple -# Test all plugins -export EMULATOR=true -python run.py --test-plugins +# Preview a single plugin live in the browser (port 5001) +python3 scripts/dev_server.py + +# Test the full rotation in the emulator +python3 run.py -e ``` ### 3. Configuration Management @@ -385,9 +395,8 @@ python run.py --test-plugins ### Basic Clock Display ```bash -# Start emulator with clock -export EMULATOR=true -python run.py +# Start emulator with clock enabled in config.json +python3 run.py -e ``` ### Sports Scores @@ -395,16 +404,16 @@ python run.py ```bash # Configure for sports display # Edit config/config.json to enable sports plugins -export EMULATOR=true -python run.py +python3 run.py -e ``` ### Custom Text Display ```bash -# Use text display plugin -export EMULATOR=true -python run.py --plugin text-display --text "Hello World" +# Preview the text display plugin on its own +python3 scripts/check_plugin.py --plugin text-display +# or use the live dev preview server +python3 scripts/dev_server.py ``` ## Support diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index de6e15b6..e4ec54d0 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -21,18 +21,30 @@ This guide will help you set up your LEDMatrix display for the first time and ge --- -## Quick Start (5 Minutes) +## Quick Start -### 1. First Boot +### 1. Install LEDMatrix -1. Insert the MicroSD card with LEDMatrix installed -2. Connect the LED matrix to your Raspberry Pi -3. Plug in the power supply -4. Wait for the Pi to boot (about 60 seconds) +There is no prebuilt SD card image — you install LEDMatrix onto stock +Raspberry Pi OS Lite yourself: -**Expected Behavior:** +1. Flash Raspberry Pi OS Lite to the MicroSD card (Raspberry Pi Imager) +2. Connect the LED matrix to your Raspberry Pi, insert the card, and + power on +3. SSH into the Pi and run the one-shot installer: + ```bash + curl -fsSL https://raw.githubusercontent.com/ChuckBuilds/LEDMatrix/main/scripts/install/one-shot-install.sh | bash + ``` + or clone the repo and run `sudo ./first_time_install.sh` — see the + [README Installation Steps / Quick Install](../README.md#installation-steps) + for full details + +**Expected Behavior after install:** - LED matrix will light up -- Display will show default plugins (clock, weather, etc.) +- A fresh install ships only the bundled `starlark-apps` and + `web-ui-info` plugins — clock, weather, sports, etc. must be + installed from the Plugin Store (web UI → Plugin Manager) before + anything else displays - Pi creates WiFi network "LEDMatrix-Setup" if not connected ### 2. Connect to WiFi @@ -73,7 +85,7 @@ You should see: 2. Set your matrix configuration: - **Rows**: 32 or 64 (match your hardware) - **Columns**: commonly 64 or 96; the web UI accepts any integer - in the 16–128 range, but 64 and 96 are the values the bundled + in the 1–128 range, but 64 and 96 are the values the bundled panel hardware ships with - **Chain Length**: Number of panels chained horizontally - **Hardware Mapping**: usually `adafruit-hat-pwm` (with the PWM jumper @@ -115,11 +127,16 @@ You can also install community plugins straight from a GitHub URL using the 1. Each installed plugin gets its own tab in the second navigation row 2. Open that plugin's tab to edit its settings (favorite teams, API keys, - update intervals, display duration, etc.) + update intervals, etc.) 3. Click **Save** 4. Restart the display service from **Overview** so the new settings take effect +**Note:** how long each plugin stays on screen is not set in the +plugin's own tab — use the **Rotation** tab's **Screen Durations** +section instead (saved to `display.display_durations` in +`config.json`). + **Example: Weather Plugin** - Set your location (city, state, country) - Add an API key from OpenWeatherMap (free signup) to @@ -208,12 +225,14 @@ The fastest way to verify a plugin works without waiting for the rotation: ### Customize Your Display **Adjust display durations:** -- Each plugin's tab has a **Display Duration (seconds)** field — set how - long that plugin stays on screen each rotation. +- Open the **Rotation** tab and use the **Screen Durations** section to + set how long each plugin stays on screen per rotation (saved to + `display.display_durations`). **Organize plugin order:** -- Use the **Plugin Manager** tab to enable/disable plugins. The display - cycles through enabled plugins in the order they appear. +- The **Rotation** tab also has a drag-and-drop **Rotation Order** list + (saved to `display.plugin_rotation_order`). Enable/disable plugins + from the **Plugin Manager** tab. **Add more plugins:** - Check the **Plugin Store** section of **Plugin Manager** for new plugins. @@ -280,10 +299,14 @@ sudo journalctl -u ledmatrix-web -f │ ├── config_secrets.json # API keys and secrets │ └── wifi_config.json # WiFi settings ├── plugin-repos/ # Installed plugins (default location) -├── cache/ # Cached data └── web_interface/ # Web interface files ``` +> Cached data does not live in the project directory — the cache manager +> uses the first writable location among `/var/cache/ledmatrix`, +> `~/.ledmatrix_cache`, `/opt/ledmatrix/cache`, and +> `$TMPDIR/ledmatrix_cache`. + > The plugin install location is configurable via > `plugin_system.plugins_directory` in `config.json`. The default is > `plugin-repos/`. Plugin discovery (`PluginManager.discover_plugins()`) @@ -303,11 +326,14 @@ System tabs: - WiFi Network selection and AP-mode setup - Schedule Power and dim schedules - Display Matrix hardware configuration +- Rotation Rotation order (drag-and-drop) and screen durations - Config Editor Raw config.json editor +- Backup & Restore Config backup and restore - Fonts Upload and manage fonts - Logs Real-time log viewing - Cache Cached data inspection and cleanup - Operation History Recent service operations +- Tools System diagnostics, updates, dependencies, maintenance Plugin tabs (second row): - Plugin Manager Browse the Plugin Store, install/enable plugins diff --git a/docs/PLUGIN_API_REFERENCE.md b/docs/PLUGIN_API_REFERENCE.md index 751d5609..9c9d919b 100644 --- a/docs/PLUGIN_API_REFERENCE.md +++ b/docs/PLUGIN_API_REFERENCE.md @@ -201,8 +201,9 @@ the mode selector for this plugin. #### `get_vegas_segment_width() -> Optional[int]` -For `FIXED_SEGMENT` plugins, the width in pixels of the segment they -occupy in the scroll. `None` lets the controller pick a default. +For `FIXED_SEGMENT` plugins, the number of *panels* the segment +occupies in the scroll (pixel width = panels × `single_panel_width`, +from `display.hardware.cols`). `None` uses the default of 1 panel. > The full source for `BasePlugin` lives in > `src/plugin_system/base_plugin.py`. If a method here disagrees with the diff --git a/docs/PLUGIN_QUICK_REFERENCE.md b/docs/PLUGIN_QUICK_REFERENCE.md index 7f8c0bf0..850fbb22 100644 --- a/docs/PLUGIN_QUICK_REFERENCE.md +++ b/docs/PLUGIN_QUICK_REFERENCE.md @@ -14,8 +14,10 @@ and [PLUGIN_DEVELOPMENT_GUIDE.md](PLUGIN_DEVELOPMENT_GUIDE.md). ✅ **GitHub Store**: Discovery from `ledmatrix-plugins` registry plus any GitHub URL ✅ **Plugin Location**: configured by `plugin_system.plugins_directory` - in `config.json` (default `plugin-repos/`; the loader also searches - `plugins/` as a fallback) + in `config.json` (default `plugin-repos/`). Plugin discovery scans + only this directory — there is no loader fallback to `plugins/` + (only Plugin Store operations and schema lookup additionally probe + `plugins/`) ## File Structure @@ -109,7 +111,7 @@ git push -u origin main git tag v1.0.0 git push origin v1.0.0 -# Submit to registry (PR to ChuckBuilds/ledmatrix-plugin-registry) +# Submit to registry (PR to ChuckBuilds/ledmatrix-plugins) ``` ## Using Plugins @@ -120,12 +122,12 @@ git push origin v1.0.0 2. **Install**: Click **Install** in the plugin's row 3. **Configure**: open the plugin's tab in the second nav row 4. **Enable/Disable**: toggle switch in the **Installed Plugins** list -5. **Reorder**: order is set by the position in `display_modes` / - plugin order; rearranging via drag-and-drop is not yet supported +5. **Reorder**: use the drag-and-drop **Rotation Order** list in the + **Rotation** tab (saved to `display.plugin_rotation_order`) ### REST API -The API is mounted at `/api/v3` (`web_interface/app.py:144`). +The API is mounted at `/api/v3` (`web_interface/app.py:199`). ```bash # Install plugin from the registry diff --git a/docs/SKIN_SYSTEM.md b/docs/SKIN_SYSTEM.md index b10dbcff..f7f4861f 100644 --- a/docs/SKIN_SYSTEM.md +++ b/docs/SKIN_SYSTEM.md @@ -33,7 +33,7 @@ crashing) simply restores the built-in look. ## The render funnel Every sports scoreboard (baseball, football, basketball, hockey — anything -built on `src/base_classes/sports.py`) renders through exactly one seam: +built on the `src/base_classes/sports/` package, `core.py`) renders through exactly one seam: `SportsCore._render_game(game, force_clear)`. 1. The mode class's `display()` (live, `SportsUpcoming`, `SportsRecent`) diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 453b5556..fe3a1a74 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -330,8 +330,8 @@ sudo systemctl cat ledmatrix-web | grep User 6. **Manually enable AP mode:** ```bash - # Via API - curl -X POST http://localhost:5000/api/wifi/ap/enable + # Via API (the WiFi blueprint is mounted under /api/v3) + curl -X POST http://localhost:5000/api/v3/wifi/ap/enable # Via Python python3 -c " @@ -482,19 +482,19 @@ sudo systemctl cat ledmatrix-web | grep User 1. **Check plugin directory exists:** ```bash - ls -ld plugins/plugin-id/ + ls -ld plugin-repos/plugin-id/ ``` 2. **Verify manifest.json:** ```bash - cat plugins/plugin-id/manifest.json + cat plugin-repos/plugin-id/manifest.json # Verify all required fields present ``` 3. **Check dependencies installed:** ```bash - if [ -f plugins/plugin-id/requirements.txt ]; then - pip3 install --break-system-packages -r plugins/plugin-id/requirements.txt + if [ -f plugin-repos/plugin-id/requirements.txt ]; then + pip3 install --break-system-packages -r plugin-repos/plugin-id/requirements.txt fi ``` @@ -507,7 +507,7 @@ sudo systemctl cat ledmatrix-web | grep User ```bash python3 -c " import sys - sys.path.insert(0, 'plugins/plugin-id') + sys.path.insert(0, 'plugin-repos/plugin-id') from manager import PluginClass print('Plugin imports successfully') " @@ -523,12 +523,18 @@ sudo systemctl cat ledmatrix-web | grep User **Solutions:** 1. **Manual cache clearing:** - ```bash - # Remove plugin-specific cache - rm -rf cache/plugin-id* - # Or remove all cache - rm -rf cache/* + The cache does not live in the project directory. The cache manager + uses the first writable location among `/var/cache/ledmatrix`, + `~/.ledmatrix_cache`, `/opt/ledmatrix/cache`, and + `$TMPDIR/ledmatrix_cache`. The easiest option is the helper script: + + ```bash + # Clear the cache with the helper script + sudo python3 scripts/utils/clear_cache.py + + # Or remove files manually from the cache dir in use, e.g.: + sudo rm -rf /var/cache/ledmatrix/* # Restart display sudo systemctl restart ledmatrix @@ -536,8 +542,8 @@ sudo systemctl cat ledmatrix-web | grep User 2. **Check cache permissions:** ```bash - ls -ld cache/ - sudo chown -R ledpi:ledpi cache/ + ls -ld /var/cache/ledmatrix + sudo ./scripts/fix_perms/fix_cache_permissions.sh ``` --- @@ -772,11 +778,11 @@ nmcli device status ```bash # Check file exists ls -l config/config.json -ls -l plugins/plugin-id/manifest.json +ls -l plugin-repos/plugin-id/manifest.json # Check directory structure ls -la web_interface/ -ls -la plugins/ +ls -la plugin-repos/ # Check file permissions ls -l config/config_secrets.json @@ -804,7 +810,7 @@ python3 -c "from src.wifi_manager import WiFiManager; print('OK')" # Test plugin import python3 -c " import sys -sys.path.insert(0, 'plugins/plugin-id') +sys.path.insert(0, 'plugin-repos/plugin-id') from manager import PluginClass print('Plugin imports OK') " @@ -812,40 +818,29 @@ print('Plugin imports OK') --- -## Service File Template +## Reinstalling Service Files -If your systemd service file is corrupted or missing, use this template: - -```ini -[Unit] -Description=LEDMatrix Web Interface -After=network.target - -[Service] -Type=simple -User=ledpi -Group=ledpi -WorkingDirectory=/home/ledpi/LEDMatrix -Environment="PYTHONUNBUFFERED=1" -ExecStart=/usr/bin/python3 /home/ledpi/LEDMatrix/web_interface/start.py -Restart=on-failure -RestartSec=5s -StandardOutput=journal -StandardError=journal -SyslogIdentifier=ledmatrix-web - -[Install] -WantedBy=multi-user.target -``` - -Save to `/etc/systemd/system/ledmatrix-web.service` and run: +If a systemd service file is corrupted or missing, do NOT hand-write +one. The real unit files live in the repo's `systemd/` directory +(`ledmatrix.service`, `ledmatrix-web.service`, +`ledmatrix-wifi-monitor.service`) and contain a +`__PROJECT_ROOT_DIR__` placeholder that the install scripts substitute +with your actual checkout path: ```bash -sudo systemctl daemon-reload -sudo systemctl enable ledmatrix-web -sudo systemctl start ledmatrix-web +# Reinstall the display service unit +sudo ./scripts/install/install_service.sh + +# Reinstall the web interface service unit +sudo ./scripts/install/install_web_service.sh ``` +Note that `ledmatrix-web.service` runs as root via +`scripts/utils/start_web_conditionally.py` — root is needed for +system operations (service control, WiFi management), and the wrapper +honors the `web_display_autostart` config flag before actually +starting the web server. + --- ## Complete Diagnostic Script @@ -878,7 +873,7 @@ echo "" echo "5. File Structure:" ls -la web_interface/ | head -10 -ls -la plugins/ | head -10 +ls -la plugin-repos/ | head -10 echo "" echo "6. Python Imports:" @@ -954,12 +949,11 @@ sudo systemctl restart ledmatrix-web # Reinstall WiFi monitor sudo ./scripts/install/install_wifi_monitor.sh -# Recreate service files from templates -sudo cp templates/ledmatrix.service /etc/systemd/system/ -sudo cp templates/ledmatrix-web.service /etc/systemd/system/ +# Recreate service files (substitutes __PROJECT_ROOT_DIR__ in systemd/ units) +sudo ./scripts/install/install_service.sh +sudo ./scripts/install/install_web_service.sh -# Reload and restart -sudo systemctl daemon-reload +# Restart sudo systemctl restart ledmatrix ledmatrix-web ``` diff --git a/docs/WEB_INTERFACE_GUIDE.md b/docs/WEB_INTERFACE_GUIDE.md index 09afc494..c57691b9 100644 --- a/docs/WEB_INTERFACE_GUIDE.md +++ b/docs/WEB_INTERFACE_GUIDE.md @@ -39,12 +39,18 @@ present: - **WiFi** — Network selection and AP-mode setup - **Schedule** — Power and dim schedules - **Display** — Matrix hardware configuration (rows, cols, hardware - mapping, GPIO slowdown, brightness, PWM) + mapping, GPIO slowdown, brightness, PWM) and Vegas Scroll Mode + settings +- **Rotation** — drag-and-drop **Rotation Order** list and per-plugin + **Screen Durations** - **Config Editor** — Raw `config.json` editor with validation +- **Backup & Restore** — back up and restore your configuration - **Fonts** — Upload and manage fonts - **Logs** — Real-time log streaming - **Cache** — Cached data inspection and cleanup - **Operation History** — Recent service operations +- **Tools** — system diagnostics, git & updates, Python dependencies, + maintenance, power supply, network radio, services, and plugin health A second nav row holds plugin tabs: @@ -111,6 +117,12 @@ Configure your LED matrix hardware: - Dynamic Duration — global cap for plugins that extend their display time based on content +**Vegas Scroll Mode:** the Display tab also has a full Vegas Scroll +Mode section — enable toggle, scroll speed, separator width, dynamic +duration, and related settings — so you can configure Vegas mode +entirely from the web UI without hand-editing JSON. See +[ADVANCED_FEATURES.md](ADVANCED_FEATURES.md) for what the options do. + Changes require **Restart Display Service** from the Overview tab. ### Plugin Manager Tab @@ -159,9 +171,10 @@ Manage fonts for your display: - See font previews - Check font sizes and styles -**Plugin Font Overrides:** -- Set custom fonts for specific plugins -- Override default font choices +**Font Overrides:** +- Overrides are set per display *element* (e.g. a specific score or + clock text element), not per plugin +- Override default font choices for individual elements - Preview font changes **Delete Fonts:** @@ -183,9 +196,11 @@ View real-time system logs: - Filter by plugin or component **Actions:** +- **Refresh**: Reload the log view - **Clear**: Clear the current view - **Download**: Download logs for offline analysis -- **Pause**: Pause auto-scrolling +- **Auto-scroll** checkbox: toggle automatic scrolling to the latest + entries --- @@ -248,7 +263,8 @@ The web interface uses Server-Sent Events (SSE) for real-time updates: **Performance:** - Minimal bandwidth usage - Server-side rendering for fast load times -- Progressive enhancement - works without JavaScript +- The UI is built on Alpine.js and HTMX, so JavaScript must be enabled + in the browser --- @@ -267,17 +283,6 @@ The interface is fully responsive and works on mobile devices: --- -## Keyboard Shortcuts - -Use keyboard shortcuts for faster navigation: - -- **Tab**: Navigate between form fields -- **Enter**: Submit forms -- **Esc**: Close modals -- **Ctrl+F**: Search in logs - ---- - ## API Access The web interface is built on a REST API that you can access programmatically: @@ -288,7 +293,7 @@ http://your-pi-ip:5000/api/v3 ``` The API blueprint mounts at `/api/v3` (see -`web_interface/app.py:144`). All endpoints below are relative to that +`web_interface/app.py:199`). All endpoints below are relative to that base. **Common Endpoints:**