mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-06 11:18:06 +00:00
docs: correct semantically stale content across the user and developer guides
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr
This commit is contained in:
+7
-4
@@ -40,7 +40,7 @@ improvements, and code changes.
|
|||||||
## Running the tests
|
## Running the tests
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt -r requirements-test.txt
|
||||||
pytest
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -57,9 +57,12 @@ integration tests.
|
|||||||
`docs/<short-description>`.
|
`docs/<short-description>`.
|
||||||
3. **Keep PRs focused.** One conceptual change per PR. If you find
|
3. **Keep PRs focused.** One conceptual change per PR. If you find
|
||||||
adjacent bugs while working, fix them in a separate PR.
|
adjacent bugs while working, fix them in a separate PR.
|
||||||
4. **Follow the existing code style.** Python code uses standard
|
4. **Follow the existing code style.** The pre-commit hooks run
|
||||||
`black`/`ruff` conventions; HTML/JS in `web_interface/` follows the
|
`flake8` (E9, F63, F7, F82 plus bugbear `B` checks), `mypy` on
|
||||||
patterns already in `templates/v3/` and `static/v3/`.
|
`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
|
5. **Update documentation** alongside code changes. If you add a
|
||||||
config key, document it in the relevant `*.md` file (or, for
|
config key, document it in the relevant `*.md` file (or, for
|
||||||
plugins, in `config_schema.json` so the form is auto-generated).
|
plugins, in `config_schema.json` so the form is auto-generated).
|
||||||
|
|||||||
+41
-23
@@ -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:**
|
**Configuration Options:**
|
||||||
|
|
||||||
| Setting | Default | Description |
|
| Setting | Default | Description |
|
||||||
@@ -57,7 +62,11 @@ Enable Vegas mode in `config/config.json`:
|
|||||||
| `plugin_order` | `[]` | Plugin display order (empty = auto) |
|
| `plugin_order` | `[]` | Plugin display order (empty = auto) |
|
||||||
| `excluded_plugins` | `[]` | Plugins to exclude from Vegas mode |
|
| `excluded_plugins` | `[]` | Plugins to exclude from Vegas mode |
|
||||||
| `target_fps` | `125` | Target frame rate |
|
| `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
|
### Per-Plugin Configuration
|
||||||
|
|
||||||
@@ -79,9 +88,13 @@ Override Vegas behavior for specific plugins:
|
|||||||
| Setting | Values | Description |
|
| Setting | Values | Description |
|
||||||
|---------|--------|-------------|
|
|---------|--------|-------------|
|
||||||
| `vegas_mode` | `scroll`, `fixed`, `static` | Display mode for this plugin |
|
| `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 |
|
| `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)
|
### Plugin Integration (Developer Guide)
|
||||||
|
|
||||||
**1. Implement Content Method:**
|
**1. Implement Content Method:**
|
||||||
@@ -451,7 +464,7 @@ time when something is active.
|
|||||||
|
|
||||||
### REST API Reference
|
### 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
|
#### 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
|
> There is no public Python on-demand API. The display controller's
|
||||||
> on-demand machinery is internal — drive it through the REST endpoints
|
> on-demand machinery is internal — drive it through the REST endpoints
|
||||||
> above (or the web UI buttons), which write a request into the cache
|
> above (or the web UI buttons). The API handlers
|
||||||
> manager under the `display_on_demand_request` key
|
> (`start_on_demand_display()` / `stop_on_demand_display()` in
|
||||||
> (`web_interface/blueprints/api_v3.py:1622,1687`) that the controller
|
> `web_interface/blueprints/api_v3.py`) write a request into the cache
|
||||||
> polls at `src/display_controller.py:921`. A separate
|
> 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
|
> `display_on_demand_config` key is used by the controller itself
|
||||||
> during activation to track what's currently running (written at
|
> during activation (`_activate_on_demand()`) to track what's
|
||||||
> `display_controller.py:1195`, cleared at `:1221`).
|
> currently running, and is cleared by `_clear_on_demand()`.
|
||||||
|
|
||||||
### Duration Modes
|
### Duration Modes
|
||||||
|
|
||||||
@@ -646,13 +661,13 @@ keys helps troubleshoot stuck states.
|
|||||||
**When Set:** Every display loop iteration
|
**When Set:** Every display loop iteration
|
||||||
**Auto-Cleared:** Never (continuously updated)
|
**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"
|
"uuid-string-of-last-processed-request"
|
||||||
```
|
```
|
||||||
**Purpose:** Prevents duplicate request processing
|
**Purpose:** Prevents duplicate request processing
|
||||||
**When Set:** After processing request
|
**When Set:** After processing request
|
||||||
**Auto-Cleared:** After 5 minutes TTL
|
**Auto-Cleared:** After 1 hour TTL
|
||||||
|
|
||||||
### When Manual Clearing is Needed
|
### When Manual Clearing is Needed
|
||||||
|
|
||||||
@@ -685,9 +700,9 @@ keys helps troubleshoot stuck states.
|
|||||||
The cache is stored as JSON files under one of:
|
The cache is stored as JSON files under one of:
|
||||||
|
|
||||||
- `/var/cache/ledmatrix/` (preferred when the service has permission)
|
- `/var/cache/ledmatrix/` (preferred when the service has permission)
|
||||||
- `~/.cache/ledmatrix/`
|
- `~/.ledmatrix_cache/`
|
||||||
- `/opt/ledmatrix/cache/`
|
- `/opt/ledmatrix/cache/`
|
||||||
- `/tmp/ledmatrix-cache/` (fallback)
|
- `$TMPDIR/ledmatrix_cache/` (fallback)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Find the cache dir actually in use
|
# 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')
|
cache.clear_cache('display_on_demand_processed_id')
|
||||||
```
|
```
|
||||||
|
|
||||||
> The actual public method is `clear_cache(key=None)` — there is no
|
> `CacheManager` also has a `delete(key)` method — a thin wrapper over
|
||||||
> `delete()` method on `CacheManager`.
|
> `clear_cache(key)` — so `cache.delete('display_on_demand_config')`
|
||||||
|
> works equally well.
|
||||||
|
|
||||||
### Cache Impact on Running Service
|
### Cache Impact on Running Service
|
||||||
|
|
||||||
@@ -730,7 +746,7 @@ The display controller automatically handles cleanup:
|
|||||||
- **Config key**: Cleared when on-demand stops
|
- **Config key**: Cleared when on-demand stops
|
||||||
- **State key**: Updated every display loop iteration
|
- **State key**: Updated every display loop iteration
|
||||||
- **Request key**: Expires after 1 hour TTL (or after processing)
|
- **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
|
### Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run background service test
|
|
||||||
python test_background_service.py
|
|
||||||
|
|
||||||
# Check logs for background operations
|
# Check logs for background operations
|
||||||
sudo journalctl -u ledmatrix -f | grep "background"
|
sudo journalctl -u ledmatrix -f | grep "background"
|
||||||
```
|
```
|
||||||
@@ -832,9 +845,10 @@ sudo journalctl -u ledmatrix -f | grep "background"
|
|||||||
|
|
||||||
**View Statistics:**
|
**View Statistics:**
|
||||||
```python
|
```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()
|
stats = service.get_statistics()
|
||||||
print(f"Active tasks: {stats['active_tasks']}")
|
print(f"Active tasks: {stats['active_tasks']}")
|
||||||
print(f"Completed: {stats['completed']}")
|
print(f"Completed: {stats['completed']}")
|
||||||
@@ -875,6 +889,7 @@ from src.common.permission_utils import (
|
|||||||
ensure_file_permissions,
|
ensure_file_permissions,
|
||||||
get_config_file_mode,
|
get_config_file_mode,
|
||||||
get_assets_file_mode,
|
get_assets_file_mode,
|
||||||
|
get_assets_dir_mode,
|
||||||
get_plugin_file_mode,
|
get_plugin_file_mode,
|
||||||
get_cache_dir_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())
|
ensure_directory_permissions(Path("assets/sports"), get_assets_dir_mode())
|
||||||
|
|
||||||
# Set file permissions after writing
|
# 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
|
### 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")
|
config_path = Path("config/config.json")
|
||||||
with open(config_path, 'w') as f:
|
with open(config_path, 'w') as f:
|
||||||
json.dump(data, 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**
|
**Pattern 3: Downloading Logo**
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ def display(self, force_clear=False):
|
|||||||
|
|
||||||
```
|
```
|
||||||
LEDMatrix/
|
LEDMatrix/
|
||||||
├── plugins/ # Installed plugins
|
├── plugin-repos/ # Installed plugins (default; plugins/ is only
|
||||||
|
│ # for dev symlinks via scripts/dev/dev_plugin_setup.sh)
|
||||||
├── config/
|
├── config/
|
||||||
│ ├── config.json # Main configuration
|
│ ├── config.json # Main configuration
|
||||||
│ └── config_secrets.json # API keys and secrets
|
│ └── config_secrets.json # API keys and secrets
|
||||||
|
|||||||
@@ -69,23 +69,24 @@ default configuration as it ships in the repo:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"pixel_outline": 0,
|
"pixel_outline": 0,
|
||||||
"pixel_size": 5,
|
"pixel_size": 16,
|
||||||
"pixel_style": "square",
|
"pixel_style": "square",
|
||||||
"pixel_glow": 6,
|
"pixel_glow": 6,
|
||||||
"display_adapter": "pygame",
|
"display_adapter": "browser",
|
||||||
|
"allow_adapter_fallback": true,
|
||||||
"icon_path": null,
|
"icon_path": null,
|
||||||
"emulator_title": null,
|
"emulator_title": null,
|
||||||
"suppress_font_warnings": false,
|
"suppress_font_warnings": false,
|
||||||
"suppress_adapter_load_errors": false,
|
|
||||||
"browser": {
|
"browser": {
|
||||||
"_comment": "For use with the browser adapter only.",
|
"_comment": "For use with the browser adapter only.",
|
||||||
"port": 8888,
|
"port": 8888,
|
||||||
"target_fps": 24,
|
"target_fps": 60,
|
||||||
"fps_display": false,
|
"fps_display": false,
|
||||||
"quality": 70,
|
"quality": 70,
|
||||||
"image_border": true,
|
"image_border": true,
|
||||||
"debug_text": false,
|
"debug_text": false,
|
||||||
"image_format": "JPEG"
|
"image_format": "JPEG",
|
||||||
|
"open_immediately": false
|
||||||
},
|
},
|
||||||
"log_level": "info"
|
"log_level": "info"
|
||||||
}
|
}
|
||||||
@@ -96,13 +97,13 @@ default configuration as it ships in the repo:
|
|||||||
| Option | Description | Default | Values |
|
| Option | Description | Default | Values |
|
||||||
|--------|-------------|---------|--------|
|
|--------|-------------|---------|--------|
|
||||||
| `pixel_outline` | Pixel border thickness | 0 | 0-5 |
|
| `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_style` | Pixel shape | "square" | "square", "circle" |
|
||||||
| `pixel_glow` | Glow effect intensity | 6 | 0-20 |
|
| `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 |
|
| `emulator_title` | Window title | null | Any string |
|
||||||
| `suppress_font_warnings` | Hide font warnings | false | true/false |
|
| `suppress_font_warnings` | Hide font warnings | false | true/false |
|
||||||
| `suppress_adapter_load_errors` | Hide adapter errors | false | true/false |
|
|
||||||
|
|
||||||
### 3. Browser Adapter Configuration
|
### 3. Browser Adapter Configuration
|
||||||
|
|
||||||
@@ -111,18 +112,32 @@ When using the browser adapter, additional options are available:
|
|||||||
| Option | Description | Default |
|
| Option | Description | Default |
|
||||||
|--------|-------------|---------|
|
|--------|-------------|---------|
|
||||||
| `port` | Web server port | 8888 |
|
| `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 |
|
| `fps_display` | Show FPS counter | false |
|
||||||
| `quality` | Image compression quality | 70 |
|
| `quality` | Image compression quality | 70 |
|
||||||
| `image_border` | Show image border | true |
|
| `image_border` | Show image border | true |
|
||||||
| `debug_text` | Show debug information | false |
|
| `debug_text` | Show debug information | false |
|
||||||
| `image_format` | Image format | "JPEG" |
|
| `image_format` | Image format | "JPEG" |
|
||||||
|
| `open_immediately` | Open the browser page automatically on start | false |
|
||||||
|
|
||||||
## Running the Emulator
|
## 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):**
|
**Windows (Command Prompt):**
|
||||||
```cmd
|
```cmd
|
||||||
@@ -137,15 +152,6 @@ python run.py
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Linux/macOS:**
|
**Linux/macOS:**
|
||||||
```bash
|
|
||||||
export EMULATOR=true
|
|
||||||
python3 run.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Alternative: Direct Python Execution
|
|
||||||
|
|
||||||
You can also run the emulator directly:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
EMULATOR=true python3 run.py
|
EMULATOR=true python3 run.py
|
||||||
```
|
```
|
||||||
@@ -153,7 +159,8 @@ EMULATOR=true python3 run.py
|
|||||||
### 3. Verify Emulator Mode
|
### 3. Verify Emulator Mode
|
||||||
|
|
||||||
When running in emulator mode, you should see:
|
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
|
- Console output indicating emulator mode
|
||||||
- No hardware initialization errors
|
- No hardware initialization errors
|
||||||
|
|
||||||
@@ -161,7 +168,36 @@ When running in emulator mode, you should see:
|
|||||||
|
|
||||||
LEDMatrix supports two display adapters for the emulator:
|
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.
|
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
|
- `+/-` - Zoom in/out
|
||||||
- `R` - Reset zoom
|
- `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
|
## Troubleshooting
|
||||||
|
|
||||||
### Common Issues
|
### Common Issues
|
||||||
@@ -299,17 +308,18 @@ Modify the display dimensions in your main config:
|
|||||||
|
|
||||||
### 2. Plugin Development
|
### 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
|
```bash
|
||||||
# Enable emulator mode
|
# Run the full display in emulator mode (optionally with debug logging)
|
||||||
export EMULATOR=true
|
python3 run.py -e -d
|
||||||
|
|
||||||
# Run with specific plugin
|
# Live single-plugin preview in the browser (port 5001)
|
||||||
python run.py --plugin my-plugin
|
python3 scripts/dev_server.py
|
||||||
|
|
||||||
# Debug mode
|
# Headless render/validation of one plugin
|
||||||
python run.py --debug
|
python3 scripts/check_plugin.py --plugin my-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Performance Tuning
|
### 3. Performance Tuning
|
||||||
@@ -344,11 +354,10 @@ The emulator can work alongside the web interface:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Terminal 1: Start emulator
|
# Terminal 1: Start emulator
|
||||||
export EMULATOR=true
|
python3 run.py -e
|
||||||
python run.py
|
|
||||||
|
|
||||||
# Terminal 2: Start web interface
|
# Terminal 2: Start web interface (supported entry point)
|
||||||
python web_interface/app.py
|
python3 web_interface/start.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Access the web interface at `http://localhost:5000` while the emulator runs.
|
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
|
### 2. Plugin Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Test specific plugin
|
# Test a specific plugin (headless check)
|
||||||
export EMULATOR=true
|
python3 scripts/check_plugin.py --plugin clock-simple
|
||||||
python run.py --plugin clock-simple
|
|
||||||
|
|
||||||
# Test all plugins
|
# Preview a single plugin live in the browser (port 5001)
|
||||||
export EMULATOR=true
|
python3 scripts/dev_server.py
|
||||||
python run.py --test-plugins
|
|
||||||
|
# Test the full rotation in the emulator
|
||||||
|
python3 run.py -e
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Configuration Management
|
### 3. Configuration Management
|
||||||
@@ -385,9 +395,8 @@ python run.py --test-plugins
|
|||||||
### Basic Clock Display
|
### Basic Clock Display
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start emulator with clock
|
# Start emulator with clock enabled in config.json
|
||||||
export EMULATOR=true
|
python3 run.py -e
|
||||||
python run.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Sports Scores
|
### Sports Scores
|
||||||
@@ -395,16 +404,16 @@ python run.py
|
|||||||
```bash
|
```bash
|
||||||
# Configure for sports display
|
# Configure for sports display
|
||||||
# Edit config/config.json to enable sports plugins
|
# Edit config/config.json to enable sports plugins
|
||||||
export EMULATOR=true
|
python3 run.py -e
|
||||||
python run.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom Text Display
|
### Custom Text Display
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Use text display plugin
|
# Preview the text display plugin on its own
|
||||||
export EMULATOR=true
|
python3 scripts/check_plugin.py --plugin text-display
|
||||||
python run.py --plugin text-display --text "Hello World"
|
# or use the live dev preview server
|
||||||
|
python3 scripts/dev_server.py
|
||||||
```
|
```
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|||||||
+41
-15
@@ -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
|
There is no prebuilt SD card image — you install LEDMatrix onto stock
|
||||||
2. Connect the LED matrix to your Raspberry Pi
|
Raspberry Pi OS Lite yourself:
|
||||||
3. Plug in the power supply
|
|
||||||
4. Wait for the Pi to boot (about 60 seconds)
|
|
||||||
|
|
||||||
**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
|
- 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
|
- Pi creates WiFi network "LEDMatrix-Setup" if not connected
|
||||||
|
|
||||||
### 2. Connect to WiFi
|
### 2. Connect to WiFi
|
||||||
@@ -73,7 +85,7 @@ You should see:
|
|||||||
2. Set your matrix configuration:
|
2. Set your matrix configuration:
|
||||||
- **Rows**: 32 or 64 (match your hardware)
|
- **Rows**: 32 or 64 (match your hardware)
|
||||||
- **Columns**: commonly 64 or 96; the web UI accepts any integer
|
- **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
|
panel hardware ships with
|
||||||
- **Chain Length**: Number of panels chained horizontally
|
- **Chain Length**: Number of panels chained horizontally
|
||||||
- **Hardware Mapping**: usually `adafruit-hat-pwm` (with the PWM jumper
|
- **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
|
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,
|
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**
|
3. Click **Save**
|
||||||
4. Restart the display service from **Overview** so the new settings take
|
4. Restart the display service from **Overview** so the new settings take
|
||||||
effect
|
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**
|
**Example: Weather Plugin**
|
||||||
- Set your location (city, state, country)
|
- Set your location (city, state, country)
|
||||||
- Add an API key from OpenWeatherMap (free signup) to
|
- 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
|
### Customize Your Display
|
||||||
|
|
||||||
**Adjust display durations:**
|
**Adjust display durations:**
|
||||||
- Each plugin's tab has a **Display Duration (seconds)** field — set how
|
- Open the **Rotation** tab and use the **Screen Durations** section to
|
||||||
long that plugin stays on screen each rotation.
|
set how long each plugin stays on screen per rotation (saved to
|
||||||
|
`display.display_durations`).
|
||||||
|
|
||||||
**Organize plugin order:**
|
**Organize plugin order:**
|
||||||
- Use the **Plugin Manager** tab to enable/disable plugins. The display
|
- The **Rotation** tab also has a drag-and-drop **Rotation Order** list
|
||||||
cycles through enabled plugins in the order they appear.
|
(saved to `display.plugin_rotation_order`). Enable/disable plugins
|
||||||
|
from the **Plugin Manager** tab.
|
||||||
|
|
||||||
**Add more plugins:**
|
**Add more plugins:**
|
||||||
- Check the **Plugin Store** section of **Plugin Manager** for new 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
|
│ ├── config_secrets.json # API keys and secrets
|
||||||
│ └── wifi_config.json # WiFi settings
|
│ └── wifi_config.json # WiFi settings
|
||||||
├── plugin-repos/ # Installed plugins (default location)
|
├── plugin-repos/ # Installed plugins (default location)
|
||||||
├── cache/ # Cached data
|
|
||||||
└── web_interface/ # Web interface files
|
└── 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
|
> The plugin install location is configurable via
|
||||||
> `plugin_system.plugins_directory` in `config.json`. The default is
|
> `plugin_system.plugins_directory` in `config.json`. The default is
|
||||||
> `plugin-repos/`. Plugin discovery (`PluginManager.discover_plugins()`)
|
> `plugin-repos/`. Plugin discovery (`PluginManager.discover_plugins()`)
|
||||||
@@ -303,11 +326,14 @@ System tabs:
|
|||||||
- WiFi Network selection and AP-mode setup
|
- WiFi Network selection and AP-mode setup
|
||||||
- Schedule Power and dim schedules
|
- Schedule Power and dim schedules
|
||||||
- Display Matrix hardware configuration
|
- Display Matrix hardware configuration
|
||||||
|
- Rotation Rotation order (drag-and-drop) and screen durations
|
||||||
- Config Editor Raw config.json editor
|
- Config Editor Raw config.json editor
|
||||||
|
- Backup & Restore Config backup and restore
|
||||||
- Fonts Upload and manage fonts
|
- Fonts Upload and manage fonts
|
||||||
- Logs Real-time log viewing
|
- Logs Real-time log viewing
|
||||||
- Cache Cached data inspection and cleanup
|
- Cache Cached data inspection and cleanup
|
||||||
- Operation History Recent service operations
|
- Operation History Recent service operations
|
||||||
|
- Tools System diagnostics, updates, dependencies, maintenance
|
||||||
|
|
||||||
Plugin tabs (second row):
|
Plugin tabs (second row):
|
||||||
- Plugin Manager Browse the Plugin Store, install/enable plugins
|
- Plugin Manager Browse the Plugin Store, install/enable plugins
|
||||||
|
|||||||
@@ -201,8 +201,9 @@ the mode selector for this plugin.
|
|||||||
|
|
||||||
#### `get_vegas_segment_width() -> Optional[int]`
|
#### `get_vegas_segment_width() -> Optional[int]`
|
||||||
|
|
||||||
For `FIXED_SEGMENT` plugins, the width in pixels of the segment they
|
For `FIXED_SEGMENT` plugins, the number of *panels* the segment
|
||||||
occupy in the scroll. `None` lets the controller pick a default.
|
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
|
> The full source for `BasePlugin` lives in
|
||||||
> `src/plugin_system/base_plugin.py`. If a method here disagrees with the
|
> `src/plugin_system/base_plugin.py`. If a method here disagrees with the
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ and [PLUGIN_DEVELOPMENT_GUIDE.md](PLUGIN_DEVELOPMENT_GUIDE.md).
|
|||||||
✅ **GitHub Store**: Discovery from `ledmatrix-plugins` registry plus
|
✅ **GitHub Store**: Discovery from `ledmatrix-plugins` registry plus
|
||||||
any GitHub URL
|
any GitHub URL
|
||||||
✅ **Plugin Location**: configured by `plugin_system.plugins_directory`
|
✅ **Plugin Location**: configured by `plugin_system.plugins_directory`
|
||||||
in `config.json` (default `plugin-repos/`; the loader also searches
|
in `config.json` (default `plugin-repos/`). Plugin discovery scans
|
||||||
`plugins/` as a fallback)
|
only this directory — there is no loader fallback to `plugins/`
|
||||||
|
(only Plugin Store operations and schema lookup additionally probe
|
||||||
|
`plugins/`)
|
||||||
|
|
||||||
## File Structure
|
## File Structure
|
||||||
|
|
||||||
@@ -109,7 +111,7 @@ git push -u origin main
|
|||||||
git tag v1.0.0
|
git tag v1.0.0
|
||||||
git push origin 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
|
## Using Plugins
|
||||||
@@ -120,12 +122,12 @@ git push origin v1.0.0
|
|||||||
2. **Install**: Click **Install** in the plugin's row
|
2. **Install**: Click **Install** in the plugin's row
|
||||||
3. **Configure**: open the plugin's tab in the second nav row
|
3. **Configure**: open the plugin's tab in the second nav row
|
||||||
4. **Enable/Disable**: toggle switch in the **Installed Plugins** list
|
4. **Enable/Disable**: toggle switch in the **Installed Plugins** list
|
||||||
5. **Reorder**: order is set by the position in `display_modes` /
|
5. **Reorder**: use the drag-and-drop **Rotation Order** list in the
|
||||||
plugin order; rearranging via drag-and-drop is not yet supported
|
**Rotation** tab (saved to `display.plugin_rotation_order`)
|
||||||
|
|
||||||
### REST API
|
### 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
|
```bash
|
||||||
# Install plugin from the registry
|
# Install plugin from the registry
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ crashing) simply restores the built-in look.
|
|||||||
## The render funnel
|
## The render funnel
|
||||||
|
|
||||||
Every sports scoreboard (baseball, football, basketball, hockey — anything
|
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)`.
|
`SportsCore._render_game(game, force_clear)`.
|
||||||
|
|
||||||
1. The mode class's `display()` (live, `SportsUpcoming`, `SportsRecent`)
|
1. The mode class's `display()` (live, `SportsUpcoming`, `SportsRecent`)
|
||||||
|
|||||||
+46
-52
@@ -330,8 +330,8 @@ sudo systemctl cat ledmatrix-web | grep User
|
|||||||
|
|
||||||
6. **Manually enable AP mode:**
|
6. **Manually enable AP mode:**
|
||||||
```bash
|
```bash
|
||||||
# Via API
|
# Via API (the WiFi blueprint is mounted under /api/v3)
|
||||||
curl -X POST http://localhost:5000/api/wifi/ap/enable
|
curl -X POST http://localhost:5000/api/v3/wifi/ap/enable
|
||||||
|
|
||||||
# Via Python
|
# Via Python
|
||||||
python3 -c "
|
python3 -c "
|
||||||
@@ -482,19 +482,19 @@ sudo systemctl cat ledmatrix-web | grep User
|
|||||||
|
|
||||||
1. **Check plugin directory exists:**
|
1. **Check plugin directory exists:**
|
||||||
```bash
|
```bash
|
||||||
ls -ld plugins/plugin-id/
|
ls -ld plugin-repos/plugin-id/
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Verify manifest.json:**
|
2. **Verify manifest.json:**
|
||||||
```bash
|
```bash
|
||||||
cat plugins/plugin-id/manifest.json
|
cat plugin-repos/plugin-id/manifest.json
|
||||||
# Verify all required fields present
|
# Verify all required fields present
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Check dependencies installed:**
|
3. **Check dependencies installed:**
|
||||||
```bash
|
```bash
|
||||||
if [ -f plugins/plugin-id/requirements.txt ]; then
|
if [ -f plugin-repos/plugin-id/requirements.txt ]; then
|
||||||
pip3 install --break-system-packages -r plugins/plugin-id/requirements.txt
|
pip3 install --break-system-packages -r plugin-repos/plugin-id/requirements.txt
|
||||||
fi
|
fi
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -507,7 +507,7 @@ sudo systemctl cat ledmatrix-web | grep User
|
|||||||
```bash
|
```bash
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, 'plugins/plugin-id')
|
sys.path.insert(0, 'plugin-repos/plugin-id')
|
||||||
from manager import PluginClass
|
from manager import PluginClass
|
||||||
print('Plugin imports successfully')
|
print('Plugin imports successfully')
|
||||||
"
|
"
|
||||||
@@ -523,12 +523,18 @@ sudo systemctl cat ledmatrix-web | grep User
|
|||||||
**Solutions:**
|
**Solutions:**
|
||||||
|
|
||||||
1. **Manual cache clearing:**
|
1. **Manual cache clearing:**
|
||||||
```bash
|
|
||||||
# Remove plugin-specific cache
|
|
||||||
rm -rf cache/plugin-id*
|
|
||||||
|
|
||||||
# Or remove all cache
|
The cache does not live in the project directory. The cache manager
|
||||||
rm -rf cache/*
|
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
|
# Restart display
|
||||||
sudo systemctl restart ledmatrix
|
sudo systemctl restart ledmatrix
|
||||||
@@ -536,8 +542,8 @@ sudo systemctl cat ledmatrix-web | grep User
|
|||||||
|
|
||||||
2. **Check cache permissions:**
|
2. **Check cache permissions:**
|
||||||
```bash
|
```bash
|
||||||
ls -ld cache/
|
ls -ld /var/cache/ledmatrix
|
||||||
sudo chown -R ledpi:ledpi cache/
|
sudo ./scripts/fix_perms/fix_cache_permissions.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -772,11 +778,11 @@ nmcli device status
|
|||||||
```bash
|
```bash
|
||||||
# Check file exists
|
# Check file exists
|
||||||
ls -l config/config.json
|
ls -l config/config.json
|
||||||
ls -l plugins/plugin-id/manifest.json
|
ls -l plugin-repos/plugin-id/manifest.json
|
||||||
|
|
||||||
# Check directory structure
|
# Check directory structure
|
||||||
ls -la web_interface/
|
ls -la web_interface/
|
||||||
ls -la plugins/
|
ls -la plugin-repos/
|
||||||
|
|
||||||
# Check file permissions
|
# Check file permissions
|
||||||
ls -l config/config_secrets.json
|
ls -l config/config_secrets.json
|
||||||
@@ -804,7 +810,7 @@ python3 -c "from src.wifi_manager import WiFiManager; print('OK')"
|
|||||||
# Test plugin import
|
# Test plugin import
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, 'plugins/plugin-id')
|
sys.path.insert(0, 'plugin-repos/plugin-id')
|
||||||
from manager import PluginClass
|
from manager import PluginClass
|
||||||
print('Plugin imports OK')
|
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:
|
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
|
||||||
```ini
|
(`ledmatrix.service`, `ledmatrix-web.service`,
|
||||||
[Unit]
|
`ledmatrix-wifi-monitor.service`) and contain a
|
||||||
Description=LEDMatrix Web Interface
|
`__PROJECT_ROOT_DIR__` placeholder that the install scripts substitute
|
||||||
After=network.target
|
with your actual checkout path:
|
||||||
|
|
||||||
[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:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl daemon-reload
|
# Reinstall the display service unit
|
||||||
sudo systemctl enable ledmatrix-web
|
sudo ./scripts/install/install_service.sh
|
||||||
sudo systemctl start ledmatrix-web
|
|
||||||
|
# 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
|
## Complete Diagnostic Script
|
||||||
@@ -878,7 +873,7 @@ echo ""
|
|||||||
|
|
||||||
echo "5. File Structure:"
|
echo "5. File Structure:"
|
||||||
ls -la web_interface/ | head -10
|
ls -la web_interface/ | head -10
|
||||||
ls -la plugins/ | head -10
|
ls -la plugin-repos/ | head -10
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "6. Python Imports:"
|
echo "6. Python Imports:"
|
||||||
@@ -954,12 +949,11 @@ sudo systemctl restart ledmatrix-web
|
|||||||
# Reinstall WiFi monitor
|
# Reinstall WiFi monitor
|
||||||
sudo ./scripts/install/install_wifi_monitor.sh
|
sudo ./scripts/install/install_wifi_monitor.sh
|
||||||
|
|
||||||
# Recreate service files from templates
|
# Recreate service files (substitutes __PROJECT_ROOT_DIR__ in systemd/ units)
|
||||||
sudo cp templates/ledmatrix.service /etc/systemd/system/
|
sudo ./scripts/install/install_service.sh
|
||||||
sudo cp templates/ledmatrix-web.service /etc/systemd/system/
|
sudo ./scripts/install/install_web_service.sh
|
||||||
|
|
||||||
# Reload and restart
|
# Restart
|
||||||
sudo systemctl daemon-reload
|
|
||||||
sudo systemctl restart ledmatrix ledmatrix-web
|
sudo systemctl restart ledmatrix ledmatrix-web
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+23
-18
@@ -39,12 +39,18 @@ present:
|
|||||||
- **WiFi** — Network selection and AP-mode setup
|
- **WiFi** — Network selection and AP-mode setup
|
||||||
- **Schedule** — Power and dim schedules
|
- **Schedule** — Power and dim schedules
|
||||||
- **Display** — Matrix hardware configuration (rows, cols, hardware
|
- **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
|
- **Config Editor** — Raw `config.json` editor with validation
|
||||||
|
- **Backup & Restore** — back up and restore your configuration
|
||||||
- **Fonts** — Upload and manage fonts
|
- **Fonts** — Upload and manage fonts
|
||||||
- **Logs** — Real-time log streaming
|
- **Logs** — Real-time log streaming
|
||||||
- **Cache** — Cached data inspection and cleanup
|
- **Cache** — Cached data inspection and cleanup
|
||||||
- **Operation History** — Recent service operations
|
- **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:
|
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
|
- Dynamic Duration — global cap for plugins that extend their display
|
||||||
time based on content
|
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.
|
Changes require **Restart Display Service** from the Overview tab.
|
||||||
|
|
||||||
### Plugin Manager Tab
|
### Plugin Manager Tab
|
||||||
@@ -159,9 +171,10 @@ Manage fonts for your display:
|
|||||||
- See font previews
|
- See font previews
|
||||||
- Check font sizes and styles
|
- Check font sizes and styles
|
||||||
|
|
||||||
**Plugin Font Overrides:**
|
**Font Overrides:**
|
||||||
- Set custom fonts for specific plugins
|
- Overrides are set per display *element* (e.g. a specific score or
|
||||||
- Override default font choices
|
clock text element), not per plugin
|
||||||
|
- Override default font choices for individual elements
|
||||||
- Preview font changes
|
- Preview font changes
|
||||||
|
|
||||||
**Delete Fonts:**
|
**Delete Fonts:**
|
||||||
@@ -183,9 +196,11 @@ View real-time system logs:
|
|||||||
- Filter by plugin or component
|
- Filter by plugin or component
|
||||||
|
|
||||||
**Actions:**
|
**Actions:**
|
||||||
|
- **Refresh**: Reload the log view
|
||||||
- **Clear**: Clear the current view
|
- **Clear**: Clear the current view
|
||||||
- **Download**: Download logs for offline analysis
|
- **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:**
|
**Performance:**
|
||||||
- Minimal bandwidth usage
|
- Minimal bandwidth usage
|
||||||
- Server-side rendering for fast load times
|
- 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
|
## API Access
|
||||||
|
|
||||||
The web interface is built on a REST API that you can access programmatically:
|
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
|
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.
|
base.
|
||||||
|
|
||||||
**Common Endpoints:**
|
**Common Endpoints:**
|
||||||
|
|||||||
Reference in New Issue
Block a user