mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-16 07:03:00 +00:00
Compare commits
3 Commits
40fcd1ed9f
...
eba2d4a711
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eba2d4a711 | ||
|
|
ef579dd191 | ||
|
|
b15bbb6f4b |
@@ -53,7 +53,8 @@ cp ../../.cursor/plugin_templates/*.template .
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Emulator mode (development, no hardware required)
|
# Emulator mode (development, no hardware required)
|
||||||
EMULATOR=true python3 run.py
|
python3 run.py --emulator
|
||||||
|
# (equivalent: EMULATOR=true python3 run.py)
|
||||||
|
|
||||||
# Hardware (production, requires the rpi-rgb-led-matrix submodule built)
|
# Hardware (production, requires the rpi-rgb-led-matrix submodule built)
|
||||||
python3 run.py
|
python3 run.py
|
||||||
@@ -65,9 +66,10 @@ sudo systemctl start ledmatrix
|
|||||||
python3 scripts/dev_server.py # then open http://localhost:5001
|
python3 scripts/dev_server.py # then open http://localhost:5001
|
||||||
```
|
```
|
||||||
|
|
||||||
There is no `--emulator` flag — the emulator is selected via the
|
The `-e`/`--emulator` CLI flag is defined in `run.py:19-20` and
|
||||||
`EMULATOR=true` environment variable, which `src/display_manager.py:2`
|
sets `os.environ["EMULATOR"] = "true"` before any display imports,
|
||||||
checks at import time.
|
which `src/display_manager.py:2` then reads to switch between the
|
||||||
|
hardware and emulator backends.
|
||||||
|
|
||||||
### Managing Plugins
|
### Managing Plugins
|
||||||
|
|
||||||
|
|||||||
@@ -403,7 +403,10 @@ cd /path/to/LEDMatrix
|
|||||||
2. **Test with the dev preview server**:
|
2. **Test with the dev preview server**:
|
||||||
`python3 scripts/dev_server.py` (then open `http://localhost:5001`).
|
`python3 scripts/dev_server.py` (then open `http://localhost:5001`).
|
||||||
Or run the full display in emulator mode with
|
Or run the full display in emulator mode with
|
||||||
`EMULATOR=true python3 run.py`. There is no `--emulator` flag.
|
`python3 run.py --emulator` (or equivalently
|
||||||
|
`EMULATOR=true python3 run.py`). The `-e`/`--emulator` CLI flag is
|
||||||
|
defined in `run.py:19-20` and sets the same `EMULATOR` environment
|
||||||
|
variable internally.
|
||||||
3. **Check logs** for errors or warnings
|
3. **Check logs** for errors or warnings
|
||||||
4. **Update configuration** in `config/config.json` if needed
|
4. **Update configuration** in `config/config.json` if needed
|
||||||
5. **Iterate** until plugin works correctly
|
5. **Iterate** until plugin works correctly
|
||||||
|
|||||||
29
.cursorrules
29
.cursorrules
@@ -6,9 +6,27 @@ The LEDMatrix project uses a plugin-based architecture. All display
|
|||||||
functionality (except core calendar) is implemented as plugins that are
|
functionality (except core calendar) is implemented as plugins that are
|
||||||
dynamically loaded from the directory configured by
|
dynamically loaded from the directory configured by
|
||||||
`plugin_system.plugins_directory` in `config.json` — the default is
|
`plugin_system.plugins_directory` in `config.json` — the default is
|
||||||
`plugin-repos/` (per `config/config.template.json:130`), and the loader
|
`plugin-repos/` (per `config/config.template.json:130`).
|
||||||
also falls back to `plugins/` (used by `scripts/dev/dev_plugin_setup.sh`
|
|
||||||
for symlinks).
|
> **Fallback note (scoped):** `PluginManager.discover_plugins()`
|
||||||
|
> (`src/plugin_system/plugin_manager.py:154`) only scans the
|
||||||
|
> configured directory — there is no fallback to `plugins/` in the
|
||||||
|
> main discovery path. A fallback to `plugins/` does exist in two
|
||||||
|
> narrower places:
|
||||||
|
> - `store_manager.py:1700-1718` — store operations (install/update/
|
||||||
|
> uninstall) check `plugins/` if the plugin isn't found in the
|
||||||
|
> configured directory, so plugin-store flows work even when your
|
||||||
|
> dev symlinks live in `plugins/`.
|
||||||
|
> - `schema_manager.py:70-80` — `get_schema_path()` probes both
|
||||||
|
> `plugins/` and `plugin-repos/` for `config_schema.json` so the
|
||||||
|
> web UI form generation finds the schema regardless of where the
|
||||||
|
> plugin lives.
|
||||||
|
>
|
||||||
|
> The dev workflow in `scripts/dev/dev_plugin_setup.sh` creates
|
||||||
|
> symlinks under `plugins/`, which is why the store and schema
|
||||||
|
> fallbacks exist. For day-to-day development, set
|
||||||
|
> `plugin_system.plugins_directory` to `plugins` so the main
|
||||||
|
> discovery path picks up your symlinks.
|
||||||
|
|
||||||
## Plugin Structure
|
## Plugin Structure
|
||||||
|
|
||||||
@@ -74,8 +92,9 @@ Plugins are configured in `config/config.json`:
|
|||||||
open `http://localhost:5001`) — renders plugins in the browser
|
open `http://localhost:5001`) — renders plugins in the browser
|
||||||
without running the full display loop
|
without running the full display loop
|
||||||
- Or run the full display in emulator mode:
|
- Or run the full display in emulator mode:
|
||||||
`EMULATOR=true python3 run.py` (or `./scripts/dev/run_emulator.sh`).
|
`python3 run.py --emulator` (or equivalently
|
||||||
There is no `--emulator` flag.
|
`EMULATOR=true python3 run.py`, or `./scripts/dev/run_emulator.sh`).
|
||||||
|
The `-e`/`--emulator` CLI flag is defined in `run.py:19-20`.
|
||||||
- Test plugin loading: Check logs for plugin discovery and loading
|
- Test plugin loading: Check logs for plugin discovery and loading
|
||||||
- Validate configuration: Ensure config matches `config_schema.json`
|
- Validate configuration: Ensure config matches `config_schema.json`
|
||||||
|
|
||||||
|
|||||||
@@ -519,7 +519,12 @@ 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), which write a request into the cache
|
||||||
> manager (`display_on_demand_config` key) that the controller polls.
|
> 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
|
||||||
|
> `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`).
|
||||||
|
|
||||||
### Duration Modes
|
### Duration Modes
|
||||||
|
|
||||||
@@ -795,12 +800,11 @@ Enable background service per plugin in `config/config.json`:
|
|||||||
|
|
||||||
### Plugins using the background service
|
### Plugins using the background service
|
||||||
|
|
||||||
The background data service is now used by all of the sports scoreboard
|
The background data service is used by all of the sports scoreboard
|
||||||
plugins (football, hockey, baseball, basketball, soccer, lacrosse, F1,
|
plugins (football, hockey, baseball/MLB, basketball, soccer, lacrosse,
|
||||||
UFC), the odds ticker, and the leaderboard plugin. Each plugin's
|
F1, UFC), the odds ticker, and the leaderboard plugin. Each plugin's
|
||||||
`background_service` block (under its own config namespace) follows the
|
`background_service` block (under its own config namespace) follows the
|
||||||
same shape as the example above.
|
same shape as the example above.
|
||||||
- ⏳ MLB (baseball)
|
|
||||||
|
|
||||||
### Error Handling & Fallback
|
### Error Handling & Fallback
|
||||||
|
|
||||||
|
|||||||
@@ -144,13 +144,21 @@ font = self.font_manager.resolve_font(
|
|||||||
> `"fonts"` block to your plugin's `manifest.json` will silently have
|
> `"fonts"` block to your plugin's `manifest.json` will silently have
|
||||||
> no effect — the FontManager method exists but nothing calls it.
|
> no effect — the FontManager method exists but nothing calls it.
|
||||||
>
|
>
|
||||||
> Until that's connected, plugin authors should ship custom fonts as
|
> Until that's connected, plugin authors who need a custom font
|
||||||
> regular files inside the plugin directory (e.g., `assets/myfont.ttf`)
|
> should load it directly with PIL (or `freetype-py` for BDF) in
|
||||||
> and reference them by relative path from the plugin's `manager.py`
|
> their plugin's `manager.py` — `FontManager.resolve_font(family=…,
|
||||||
> via `display_manager.font_manager.resolve_font(...)` or by loading
|
> size_px=…)` takes a **family name**, not a file path, so it can't
|
||||||
> with PIL directly. The user-facing font override system in the
|
> be used to pull a font from your plugin directory. The
|
||||||
> **Fonts** tab still works for any element that's been registered via
|
> `plugin://…` source URIs described below are only honored by
|
||||||
> `register_manager_font()`.
|
> `register_plugin_fonts()` itself, which isn't wired up.
|
||||||
|
>
|
||||||
|
> The `/api/v3/fonts/overrides` endpoints and the **Fonts** tab in
|
||||||
|
> the web UI are currently **placeholder implementations** — they
|
||||||
|
> return empty arrays and contain "would integrate with the actual
|
||||||
|
> font system" comments. Manually registered manager fonts do
|
||||||
|
> **not** yet flow into that tab. If you need an override today,
|
||||||
|
> load the font directly in your plugin and skip the
|
||||||
|
> override system.
|
||||||
|
|
||||||
### Plugin Font Registration (planned)
|
### Plugin Font Registration (planned)
|
||||||
|
|
||||||
@@ -373,5 +381,8 @@ self.font = self.font_manager.resolve_font(
|
|||||||
|
|
||||||
## Example: Complete Manager Implementation
|
## Example: Complete Manager Implementation
|
||||||
|
|
||||||
See `test/font_manager_example.py` for a complete working example.
|
For a working example of the font manager API in use, see
|
||||||
|
`src/font_manager.py` itself and the bundled scoreboard base classes
|
||||||
|
in `src/base_classes/` (e.g., `hockey.py`, `football.py`) which
|
||||||
|
register and resolve fonts via the patterns documented above.
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ You should see:
|
|||||||
1. Open the **Display** tab
|
1. Open the **Display** tab
|
||||||
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**: 64 or 96 (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
|
||||||
|
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
|
||||||
mod) or `adafruit-hat` (without). See the root README for the full list.
|
mod) or `adafruit-hat` (without). See the root README for the full list.
|
||||||
@@ -284,7 +286,11 @@ sudo journalctl -u ledmatrix-web -f
|
|||||||
|
|
||||||
> 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/`; the loader also searches `plugins/` as a fallback.
|
> `plugin-repos/`. Plugin discovery (`PluginManager.discover_plugins()`)
|
||||||
|
> only scans the configured directory — it does not fall back to
|
||||||
|
> `plugins/`. However, the Plugin Store install/update path and the
|
||||||
|
> web UI's schema loader do also probe `plugins/` so the dev symlinks
|
||||||
|
> created by `scripts/dev/dev_plugin_setup.sh` keep working.
|
||||||
|
|
||||||
### Web Interface
|
### Web Interface
|
||||||
|
|
||||||
|
|||||||
@@ -336,11 +336,15 @@ pytest --cov=src --cov-report=html
|
|||||||
|
|
||||||
## Continuous Integration
|
## Continuous Integration
|
||||||
|
|
||||||
Tests are configured to run automatically in CI/CD. The GitHub Actions workflow (`.github/workflows/tests.yml`) runs:
|
There is currently no CI test workflow in this repo — `pytest` runs
|
||||||
|
locally but is not gated on PRs. The only GitHub Actions workflow is
|
||||||
|
[`.github/workflows/security-audit.yml`](../.github/workflows/security-audit.yml),
|
||||||
|
which runs bandit and semgrep on every push.
|
||||||
|
|
||||||
- All tests on multiple Python versions (3.10, 3.11, 3.12)
|
If you'd like to add a test workflow, the recommended setup is a
|
||||||
- Coverage reporting
|
`.github/workflows/tests.yml` that runs `pytest` against the
|
||||||
- Uploads coverage to Codecov (if configured)
|
supported Python versions (3.10, 3.11, 3.12, 3.13 per
|
||||||
|
`requirements.txt`). Open an issue or PR if you want to contribute it.
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ If you encounter issues during migration:
|
|||||||
|
|
||||||
1. Check the [README.md](README.md) for current installation and usage instructions
|
1. Check the [README.md](README.md) for current installation and usage instructions
|
||||||
2. Review script README files:
|
2. Review script README files:
|
||||||
- `scripts/install/README.md` - Installation scripts documentation
|
- [`scripts/install/README.md`](../scripts/install/README.md) - Installation scripts documentation
|
||||||
- `scripts/fix_perms/README.md` (if exists) - Permission scripts documentation
|
- [`scripts/fix_perms/README.md`](../scripts/fix_perms/README.md) - Permission scripts documentation
|
||||||
3. Check system logs: `journalctl -u ledmatrix -f` or `journalctl -u ledmatrix-web -f`
|
3. Check system logs: `journalctl -u ledmatrix -f` or `journalctl -u ledmatrix-web -f`
|
||||||
4. Review the troubleshooting section in the main README
|
4. Review the troubleshooting section in the main README
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,17 @@ The solution uses **symbolic links** to connect plugin repositories to the `plug
|
|||||||
> **Plugin directory note:** the dev workflow described here puts
|
> **Plugin directory note:** the dev workflow described here puts
|
||||||
> symlinks in `plugins/`. The plugin loader's *production* default is
|
> symlinks in `plugins/`. The plugin loader's *production* default is
|
||||||
> `plugin-repos/` (set by `plugin_system.plugins_directory` in
|
> `plugin-repos/` (set by `plugin_system.plugins_directory` in
|
||||||
> `config.json`), but it falls back to `plugins/` so the dev symlinks
|
> `config.json`). Importantly, the main discovery path
|
||||||
> are picked up automatically. The Plugin Store installs to
|
> (`PluginManager.discover_plugins()`) only scans the configured
|
||||||
> `plugin-repos/`. If you want both your dev symlinks *and* store
|
> directory — it does **not** fall back to `plugins/`. Two narrower
|
||||||
> installs to share the same directory, set `plugins_directory` to
|
> paths do: the Plugin Store install/update logic in `store_manager.py`,
|
||||||
> `plugins` in the General tab of the web UI.
|
> and `schema_manager.get_schema_path()` (which the web UI form
|
||||||
|
> generator uses to find `config_schema.json`). That's why plugins
|
||||||
|
> installed via the Plugin Store still work even with symlinks in
|
||||||
|
> `plugins/`, but your own dev plugin won't appear in the rotation
|
||||||
|
> until you either move it to `plugin-repos/` or change
|
||||||
|
> `plugin_system.plugins_directory` to `plugins` in the General tab
|
||||||
|
> of the web UI. The latter is the smoother dev setup.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
|||||||
@@ -399,7 +399,10 @@ The web interface uses modern web technologies:
|
|||||||
**Plugins:**
|
**Plugins:**
|
||||||
- Plugin directory: configurable via
|
- Plugin directory: configurable via
|
||||||
`plugin_system.plugins_directory` in `config.json` (default
|
`plugin_system.plugins_directory` in `config.json` (default
|
||||||
`plugin-repos/`); the loader also searches `plugins/` as a fallback
|
`plugin-repos/`). Main plugin discovery only scans this directory;
|
||||||
|
the Plugin Store install flow and the schema loader additionally
|
||||||
|
probe `plugins/` so dev symlinks created by
|
||||||
|
`scripts/dev/dev_plugin_setup.sh` keep working.
|
||||||
- Plugin config: `/config/config.json` (per-plugin sections)
|
- Plugin config: `/config/config.json` (per-plugin sections)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -48,3 +48,25 @@ pytest>=7.4.0,<8.0.0
|
|||||||
pytest-cov>=4.1.0,<5.0.0
|
pytest-cov>=4.1.0,<5.0.0
|
||||||
pytest-mock>=3.11.0,<4.0.0
|
pytest-mock>=3.11.0,<4.0.0
|
||||||
mypy>=1.5.0,<2.0.0
|
mypy>=1.5.0,<2.0.0
|
||||||
|
|
||||||
|
# ───────────────────────────────────────────────────────────────────────
|
||||||
|
# Optional dependencies — the code imports these inside try/except
|
||||||
|
# blocks and gracefully degrades when missing. Install them for the
|
||||||
|
# full feature set, or skip them for a minimal install.
|
||||||
|
# ───────────────────────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# scipy — sub-pixel interpolation in
|
||||||
|
# src/common/scroll_helper.py for smoother
|
||||||
|
# scrolling. Falls back to a simpler shift algorithm.
|
||||||
|
# pip install 'scipy>=1.10.0,<2.0.0'
|
||||||
|
#
|
||||||
|
# psutil — per-plugin resource monitoring in
|
||||||
|
# src/plugin_system/resource_monitor.py. The monitor
|
||||||
|
# silently no-ops when missing (PSUTIL_AVAILABLE = False).
|
||||||
|
# pip install 'psutil>=5.9.0,<6.0.0'
|
||||||
|
#
|
||||||
|
# Flask-Limiter — request rate limiting in web_interface/app.py
|
||||||
|
# (accidental-abuse protection, not security). The
|
||||||
|
# web interface starts without rate limiting when
|
||||||
|
# this is missing.
|
||||||
|
# pip install 'Flask-Limiter>=3.5.0,<4.0.0'
|
||||||
|
|||||||
70
scripts/fix_perms/README.md
Normal file
70
scripts/fix_perms/README.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Permission Fix Scripts
|
||||||
|
|
||||||
|
This directory contains shell scripts for repairing file/directory
|
||||||
|
permissions on a LEDMatrix installation. They're typically only needed
|
||||||
|
when something has gone wrong — for example, after running parts of the
|
||||||
|
install as the wrong user, after a manual file copy that didn't preserve
|
||||||
|
ownership, or after a permissions-related error from the display or
|
||||||
|
web service.
|
||||||
|
|
||||||
|
Most of these scripts require `sudo` since they touch directories
|
||||||
|
owned by the `ledmatrix` service user or by `root`.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
- **`fix_assets_permissions.sh`** — Fixes ownership and write
|
||||||
|
permissions on the `assets/` tree so plugins can download and cache
|
||||||
|
team logos, fonts, and other static content.
|
||||||
|
|
||||||
|
- **`fix_cache_permissions.sh`** — Fixes permissions on every cache
|
||||||
|
directory the project may use (`/var/cache/ledmatrix/`,
|
||||||
|
`~/.cache/ledmatrix/`, `/opt/ledmatrix/cache/`, project-local
|
||||||
|
`cache/`). Also creates placeholder logo subdirectories used by the
|
||||||
|
sports plugins.
|
||||||
|
|
||||||
|
- **`fix_plugin_permissions.sh`** — Fixes ownership on the plugins
|
||||||
|
directory so both the root display service and the web service user
|
||||||
|
can read and write plugin files (manifests, configs, requirements
|
||||||
|
installs).
|
||||||
|
|
||||||
|
- **`fix_web_permissions.sh`** — Fixes permissions on log files,
|
||||||
|
systemd journal access, and the sudoers entries the web interface
|
||||||
|
needs to control the display service.
|
||||||
|
|
||||||
|
- **`fix_nhl_cache.sh`** — Targeted fix for NHL plugin cache issues
|
||||||
|
(clears the NHL cache and restarts the display service).
|
||||||
|
|
||||||
|
- **`safe_plugin_rm.sh`** — Validates that a plugin removal path is
|
||||||
|
inside an allowed base directory before deleting it. Used by the web
|
||||||
|
interface (via sudo) when a user clicks **Uninstall** on a plugin —
|
||||||
|
prevents path-traversal abuse from the web UI.
|
||||||
|
|
||||||
|
## When to use these
|
||||||
|
|
||||||
|
Most users never need to run these directly. The first-time installer
|
||||||
|
(`first_time_install.sh`) sets up permissions correctly, and the web
|
||||||
|
interface manages plugin install/uninstall through the sudoers entries
|
||||||
|
the installer creates.
|
||||||
|
|
||||||
|
Run these scripts only when:
|
||||||
|
|
||||||
|
- You see "Permission denied" errors in `journalctl -u ledmatrix` or
|
||||||
|
the web UI Logs tab.
|
||||||
|
- You manually copied files into the project directory as the wrong
|
||||||
|
user.
|
||||||
|
- You restored from a backup that didn't preserve ownership.
|
||||||
|
- You moved the LEDMatrix directory and need to re-anchor permissions.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run from the project root
|
||||||
|
sudo ./scripts/fix_perms/fix_cache_permissions.sh
|
||||||
|
sudo ./scripts/fix_perms/fix_assets_permissions.sh
|
||||||
|
sudo ./scripts/fix_perms/fix_plugin_permissions.sh
|
||||||
|
sudo ./scripts/fix_perms/fix_web_permissions.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're not sure which one you need, run `fix_cache_permissions.sh`
|
||||||
|
first — it's the most commonly needed and creates several directories
|
||||||
|
the other scripts assume exist.
|
||||||
@@ -86,7 +86,8 @@ reference for the most common endpoints:
|
|||||||
- `GET /api/v3/system/status` - System status
|
- `GET /api/v3/system/status` - System status
|
||||||
- `POST /api/v3/system/action` - Control display (action body:
|
- `POST /api/v3/system/action` - Control display (action body:
|
||||||
`start_display`, `stop_display`, `restart_display_service`,
|
`start_display`, `stop_display`, `restart_display_service`,
|
||||||
`restart_web_service`, `git_pull`, `reboot_system`, `shutdown_system`)
|
`restart_web_service`, `git_pull`, `reboot_system`, `shutdown_system`,
|
||||||
|
`enable_autostart`, `disable_autostart`)
|
||||||
- `GET /api/v3/display/current` - Current display frame
|
- `GET /api/v3/display/current` - Current display frame
|
||||||
- `GET /api/v3/display/on-demand/status` - On-demand status
|
- `GET /api/v3/display/on-demand/status` - On-demand status
|
||||||
- `POST /api/v3/display/on-demand/start` - Trigger on-demand display
|
- `POST /api/v3/display/on-demand/start` - Trigger on-demand display
|
||||||
@@ -105,11 +106,13 @@ reference for the most common endpoints:
|
|||||||
|
|
||||||
### Plugin Store
|
### Plugin Store
|
||||||
- `GET /api/v3/plugins/store/list` - List available registry plugins
|
- `GET /api/v3/plugins/store/list` - List available registry plugins
|
||||||
|
- `GET /api/v3/plugins/store/github-status` - GitHub authentication status
|
||||||
- `POST /api/v3/plugins/store/refresh` - Refresh registry from GitHub
|
- `POST /api/v3/plugins/store/refresh` - Refresh registry from GitHub
|
||||||
|
|
||||||
### Real-time Streams (SSE)
|
### Real-time Streams (SSE)
|
||||||
SSE stream endpoints are defined directly on the Flask app
|
SSE stream endpoints are defined directly on the Flask app
|
||||||
(`app.py:607-615`), not on the api_v3 blueprint:
|
(`app.py:607-619` — includes the CSRF exemption and rate-limit hookup
|
||||||
|
alongside the three route definitions), not on the api_v3 blueprint:
|
||||||
- `GET /api/v3/stream/stats` - System statistics stream
|
- `GET /api/v3/stream/stats` - System statistics stream
|
||||||
- `GET /api/v3/stream/display` - Display preview stream
|
- `GET /api/v3/stream/display` - Display preview stream
|
||||||
- `GET /api/v3/stream/logs` - Service logs stream
|
- `GET /api/v3/stream/logs` - Service logs stream
|
||||||
|
|||||||
Reference in New Issue
Block a user