docs: fix ADVANCED_FEATURES and REST_API_REFERENCE

REST_API_REFERENCE.md
- Wrong path: /fonts/delete/<font_family> -> /fonts/<font_family>
  (verified the real DELETE route in
  web_interface/blueprints/api_v3.py).
- Diffed the documented routes against the real api_v3 blueprint
  (92 routes vs the 71 documented). Added missing sections:
  - Error tracking (/errors/summary, /errors/plugin/<id>, /errors/clear)
  - Health (/health)
  - Schedule dim/power (/config/dim-schedule GET/POST)
  - Plugin-specific endpoints (calendar/list-calendars,
    of-the-day/json/upload+delete, plugins/<id>/static/<path>)
  - Starlark Apps (12 endpoints: status, install-pixlet, apps CRUD,
    repository browse/install, upload)
  - Font preview (/fonts/preview)
- Updated table of contents with the new sections.
- Added a footer note that the API blueprint mounts at /api/v3
  (app.py:144) and that SSE stream endpoints are defined directly on
  the Flask app at app.py:607-615.

ADVANCED_FEATURES.md
- Vegas Scroll Mode section was actually accurate (verified all
  config keys match src/vegas_mode/config.py:15-30).

- On-Demand Display section had multiple bugs:
  - 5 occurrences of port 5050 -> 5000
  - All API paths missing /v3 (e.g. /api/display/on-demand/start
    should be /api/v3/display/on-demand/start)
  - "Settings -> Plugin Management -> Show Now Button" UI flow doesn't
    exist. Real flow: open the plugin's tab in the second nav row,
    click Run On-Demand / Stop On-Demand.
  - "Python API Methods" section showed
    controller.show_on_demand() / clear_on_demand() /
    is_on_demand_active() / get_on_demand_info() — none of these
    methods exist on DisplayController. The on-demand machinery is
    all internal (_set_on_demand_*, _activate_on_demand, etc) and
    is driven through the cache_manager. Replaced the section with
    a note pointing to the REST API.
  - All Use Case Examples used the same fictional Python calls.
    Replaced with curl examples against the real API.

- Cache Management section claimed "On-demand display uses Redis cache
  keys". LEDMatrix doesn't use Redis — verified with grep that
  src/cache_manager.py has no redis import. The cache is file-based,
  managed by CacheManager (file at /var/cache/ledmatrix/ or fallback
  paths). Rewrote the manual recovery section:
  - Removed redis-cli commands
  - Replaced cache.delete() Python calls with cache.clear_cache()
    (the real public method per the same bug already flagged in
    PLUGIN_API_REFERENCE.md)
  - Replaced "Settings -> Cache Management" with the real Cache tab
  - Documented the actual cache directory candidates

- Background Data Service section:
  - Used "nfl_scoreboard" as the plugin id in the example.
    The real plugin is "football-scoreboard" (handles both NFL and
    NCAA). Fixed.
  - "Implementation Status: Phase 1 NFL only / Phase 2 planned"
    section was severely outdated. The background service is now
    used by all sports scoreboards (football, hockey, baseball,
    basketball, soccer, lacrosse, F1, UFC), the odds ticker, and
    the leaderboard plugin. Replaced with a current "Plugins using
    the background service" note.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-04-06 21:55:34 -04:00
parent 1d31465df0
commit 49287bdd1a
2 changed files with 220 additions and 92 deletions

View File

@@ -437,26 +437,26 @@ When on-demand expires or is cleared, the display returns to the next highest pr
### Web Interface Controls ### Web Interface Controls
**Access:** Navigate to Settings → Plugin Management Each installed plugin has its own tab in the second nav row of the web
UI. Inside the plugin's tab, scroll to **On-Demand Controls**:
**Controls:** - **Run On-Demand** — triggers the plugin immediately, even if it's
- **Show Now Button** - Triggers plugin immediately disabled in the rotation
- **Duration Slider** - Set display time (0 = indefinite) - **Stop On-Demand** — clears on-demand and returns to the normal
- **Pin Checkbox** - Keep showing until manually cleared rotation
- **Stop Button** - Clear on-demand and return to rotation
- **Shift+Click Stop** - Stop the entire display service
**Status Card:** The display service must be running. The status banner at the top of
- Real-time status updates the plugin tab shows the active on-demand plugin, mode, and remaining
- Shows active plugin and remaining time time when something is active.
- Pin status indicator
### REST API Reference ### REST API Reference
The API is mounted at `/api/v3` (`web_interface/app.py:144`).
#### Start On-Demand Display #### Start On-Demand Display
```bash ```bash
POST /api/display/on-demand/start POST /api/v3/display/on-demand/start
# Body: # Body:
{ {
@@ -467,20 +467,20 @@ POST /api/display/on-demand/start
# Examples: # Examples:
# 30-second preview # 30-second preview
curl -X POST http://localhost:5050/api/display/on-demand/start \ curl -X POST http://localhost:5000/api/v3/display/on-demand/start \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"plugin_id": "weather", "duration": 30}' -d '{"plugin_id": "weather", "duration": 30}'
# Pin indefinitely # Pin indefinitely
curl -X POST http://localhost:5050/api/display/on-demand/start \ curl -X POST http://localhost:5000/api/v3/display/on-demand/start \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"plugin_id": "hockey-scores", "pinned": true}' -d '{"plugin_id": "hockey-scoreboard", "pinned": true}'
``` ```
#### Stop On-Demand Display #### Stop On-Demand Display
```bash ```bash
POST /api/display/on-demand/stop POST /api/v3/display/on-demand/stop
# Body: # Body:
{ {
@@ -489,10 +489,10 @@ POST /api/display/on-demand/stop
# Examples: # Examples:
# Clear on-demand # Clear on-demand
curl -X POST http://localhost:5050/api/display/on-demand/stop curl -X POST http://localhost:5000/api/v3/display/on-demand/stop
# Stop service too # Stop service too
curl -X POST http://localhost:5050/api/display/on-demand/stop \ curl -X POST http://localhost:5000/api/v3/display/on-demand/stop \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"stop_service": true}' -d '{"stop_service": true}'
``` ```
@@ -500,10 +500,10 @@ curl -X POST http://localhost:5050/api/display/on-demand/stop \
#### Get On-Demand Status #### Get On-Demand Status
```bash ```bash
GET /api/display/on-demand/status GET /api/v3/display/on-demand/status
# Example: # Example:
curl http://localhost:5050/api/display/on-demand/status curl http://localhost:5000/api/v3/display/on-demand/status
# Response: # Response:
{ {
@@ -516,35 +516,10 @@ curl http://localhost:5050/api/display/on-demand/status
} }
``` ```
### Python API Methods > There is no public Python on-demand API. The display controller's
> on-demand machinery is internal — drive it through the REST endpoints
```python > above (or the web UI buttons), which write a request into the cache
from src.display_controller import DisplayController > manager (`display_on_demand_config` key) that the controller polls.
controller = DisplayController()
# Show plugin for 30 seconds
controller.show_on_demand('weather', duration=30)
# Pin plugin until manually cleared
controller.show_on_demand('hockey-scores', pinned=True)
# Show indefinitely (not pinned, clears on expiry if duration set later)
controller.show_on_demand('weather', duration=0)
# Use plugin's default duration
controller.show_on_demand('weather')
# Clear on-demand
controller.clear_on_demand()
# Check status
is_active = controller.is_on_demand_active()
# Get detailed info
info = controller.get_on_demand_info()
# Returns: {'active': bool, 'mode': str, 'duration': float, 'remaining': float, 'pinned': bool}
```
### Duration Modes ### Duration Modes
@@ -557,27 +532,31 @@ info = controller.get_on_demand_info()
### Use Case Examples ### Use Case Examples
**Quick Check (30-second preview):** **Quick check (30-second preview):**
```python ```bash
controller.show_on_demand('weather', duration=30) curl -X POST http://localhost:5000/api/v3/display/on-demand/start \
-H "Content-Type: application/json" \
-d '{"plugin_id": "ledmatrix-weather", "duration": 30}'
``` ```
**Pin Important Information:** **Pin important information:**
```python ```bash
controller.show_on_demand('game-score', pinned=True) curl -X POST http://localhost:5000/api/v3/display/on-demand/start \
-H "Content-Type: application/json" \
-d '{"plugin_id": "hockey-scoreboard", "pinned": true}'
# ... later ... # ... later ...
controller.clear_on_demand() curl -X POST http://localhost:5000/api/v3/display/on-demand/stop
``` ```
**Indefinite Display:** **Indefinite display:**
```python ```bash
controller.show_on_demand('welcome-message', duration=0) curl -X POST http://localhost:5000/api/v3/display/on-demand/start \
-H "Content-Type: application/json" \
-d '{"plugin_id": "text-display", "duration": 0}'
``` ```
**Testing Plugin:** **Testing a plugin during development:** the same call works, or just
```python click **Run On-Demand** in the plugin's tab.
controller.show_on_demand('my-new-plugin', duration=60)
```
### Best Practices ### Best Practices
@@ -613,7 +592,10 @@ controller.show_on_demand('my-new-plugin', duration=60)
### Overview ### Overview
On-demand display uses Redis cache keys to manage state across service restarts and coordinate between web interface and display controller. Understanding these keys helps troubleshoot stuck states. On-demand display uses cache keys (managed by `src/cache_manager.py`
file-based, not Redis) to coordinate state between the web interface
and the display controller across service restarts. Understanding these
keys helps troubleshoot stuck states.
### Cache Keys ### Cache Keys
@@ -688,19 +670,26 @@ On-demand display uses Redis cache keys to manage state across service restarts
### Manual Recovery Procedures ### Manual Recovery Procedures
**Via Web Interface (Recommended):** **Via Web Interface (Recommended):**
1. Navigate to Settings → Cache Management 1. Open the **Cache** tab in the web UI
2. Search for "on_demand" keys 2. Find the `display_on_demand_*` entries
3. Select keys to delete 3. Delete them
4. Click "Delete Selected" 4. Restart display: `sudo systemctl restart ledmatrix`
5. Restart display: `sudo systemctl restart ledmatrix`
**Via Command Line:** **Via Command Line:**
```bash
# Clear specific key
redis-cli DEL display_on_demand_config
# Clear all on-demand keys The cache is stored as JSON files under one of:
redis-cli KEYS "display_on_demand_*" | xargs redis-cli DEL
- `/var/cache/ledmatrix/` (preferred when the service has permission)
- `~/.cache/ledmatrix/`
- `/opt/ledmatrix/cache/`
- `/tmp/ledmatrix-cache/` (fallback)
```bash
# Find the cache dir actually in use
journalctl -u ledmatrix | grep -i "cache directory" | tail -1
# Clear all on-demand keys (replace path with the one above)
rm /var/cache/ledmatrix/display_on_demand_*
# Restart service # Restart service
sudo systemctl restart ledmatrix sudo systemctl restart ledmatrix
@@ -711,19 +700,22 @@ sudo systemctl restart ledmatrix
from src.cache_manager import CacheManager from src.cache_manager import CacheManager
cache = CacheManager() cache = CacheManager()
cache.delete('display_on_demand_config') cache.clear_cache('display_on_demand_config')
cache.delete('display_on_demand_state') cache.clear_cache('display_on_demand_state')
cache.delete('display_on_demand_request') cache.clear_cache('display_on_demand_request')
cache.delete('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
> `delete()` method on `CacheManager`.
### Cache Impact on Running Service ### Cache Impact on Running Service
**IMPORTANT:** Clearing cache keys does NOT immediately affect the running controller in memory. **IMPORTANT:** Clearing cache keys does NOT immediately affect the running controller in memory.
**To fully reset:** **To fully reset:**
1. Stop the service: `sudo systemctl stop ledmatrix` 1. Stop the service: `sudo systemctl stop ledmatrix`
2. Clear cache keys (web UI or redis-cli) 2. Clear cache keys (web UI Cache tab or `rm` from the cache directory)
3. Clear systemd environment: `sudo systemctl daemon-reload` 3. Clear systemd environment: `sudo systemctl daemon-reload`
4. Start the service: `sudo systemctl start ledmatrix` 4. Start the service: `sudo systemctl start ledmatrix`
@@ -767,7 +759,7 @@ Enable background service per plugin in `config/config.json`:
```json ```json
{ {
"nfl_scoreboard": { "football-scoreboard": {
"enabled": true, "enabled": true,
"background_service": { "background_service": {
"enabled": true, "enabled": true,
@@ -801,18 +793,13 @@ Enable background service per plugin in `config/config.json`:
- Returns immediately: < 0.1 seconds - Returns immediately: < 0.1 seconds
- Background refresh (if stale): async, no blocking - Background refresh (if stale): async, no blocking
### Implementation Status ### Plugins using the background service
**Phase 1 (Complete):** The background data service is now used by all of the sports scoreboard
- ✅ NFL scoreboard implemented plugins (football, hockey, baseball, basketball, soccer, lacrosse, F1,
- ✅ Background threading architecture UFC), the odds ticker, and the leaderboard plugin. Each plugin's
- ✅ Cache integration `background_service` block (under its own config namespace) follows the
- ✅ Error handling and retry logic same shape as the example above.
**Phase 2 (Planned):**
- ⏳ NCAAFB (college football)
- ⏳ NBA (basketball)
- ⏳ NHL (hockey)
- ⏳ MLB (baseball) - ⏳ MLB (baseball)
### Error Handling & Fallback ### Error Handling & Fallback

View File

@@ -24,6 +24,17 @@ All endpoints return JSON responses with a standard format:
- [Cache](#cache) - [Cache](#cache)
- [WiFi](#wifi) - [WiFi](#wifi)
- [Streams](#streams) - [Streams](#streams)
- [Logs](#logs)
- [Error tracking](#error-tracking)
- [Health](#health)
- [Schedule (dim/power)](#schedule-dimpower)
- [Plugin-specific endpoints](#plugin-specific-endpoints)
- [Starlark Apps](#starlark-apps)
> The API blueprint is mounted at `/api/v3` (`web_interface/app.py:144`).
> SSE stream endpoints (`/api/v3/stream/*`) are defined directly on the
> Flask app at `app.py:607-615`. There are about 92 routes total — see
> `web_interface/blueprints/api_v3.py` for the canonical list.
--- ---
@@ -1201,10 +1212,16 @@ Upload a custom font file.
### Delete Font ### Delete Font
**DELETE** `/api/v3/fonts/delete/<font_family>` **DELETE** `/api/v3/fonts/<font_family>`
Delete an uploaded font. Delete an uploaded font.
### Font Preview
**GET** `/api/v3/fonts/preview?family=<font_family>&text=<sample>`
Render a small preview image of a font for use in the web UI font picker.
--- ---
## Cache ## Cache
@@ -1439,6 +1456,130 @@ Get recent log entries.
--- ---
## Error tracking
### Get Error Summary
**GET** `/api/v3/errors/summary`
Aggregated counts of recent errors across all plugins and core
components, used by the web UI's error indicator.
### Get Plugin Errors
**GET** `/api/v3/errors/plugin/<plugin_id>`
Recent errors for a specific plugin.
### Clear Errors
**POST** `/api/v3/errors/clear`
Clear the in-memory error aggregator.
---
## Health
### Health Check
**GET** `/api/v3/health`
Lightweight liveness check used by the WiFi monitor and external
monitoring tools.
---
## Schedule (dim/power)
### Get Dim Schedule
**GET** `/api/v3/config/dim-schedule`
Read the dim/power schedule that automatically reduces brightness or
turns the display off at configured times.
### Update Dim Schedule
**POST** `/api/v3/config/dim-schedule`
Update the dim schedule. Body matches the structure returned by GET.
---
## Plugin-specific endpoints
A handful of endpoints belong to individual built-in or shipped plugins.
### Calendar
**GET** `/api/v3/plugins/calendar/list-calendars`
List the calendars available on the authenticated Google account.
Used by the calendar plugin's config UI.
### Of The Day
**POST** `/api/v3/plugins/of-the-day/json/upload`
Upload a JSON data file for the Of-The-Day plugin's category data.
**POST** `/api/v3/plugins/of-the-day/json/delete`
Delete a previously uploaded Of-The-Day data file.
### Plugin Static Assets
**GET** `/api/v3/plugins/<plugin_id>/static/<path:file_path>`
Serve a static asset (image, font, etc.) from a plugin's directory.
Used internally by the web UI to render plugin previews and icons.
---
## Starlark Apps
The Starlark plugin lets you run [Tronbyt](https://github.com/tronbyt/apps)
Starlark apps on the matrix. These endpoints expose its UI.
### Status
**GET** `/api/v3/starlark/status`
Returns whether the Pixlet binary is installed and the Starlark plugin
is operational.
### Install Pixlet
**POST** `/api/v3/starlark/install-pixlet`
Download and install the Pixlet binary on the Pi.
### Apps
**GET** `/api/v3/starlark/apps` — list installed Starlark apps
**GET** `/api/v3/starlark/apps/<app_id>` — get app details
**DELETE** `/api/v3/starlark/apps/<app_id>` — uninstall an app
**GET** `/api/v3/starlark/apps/<app_id>/config` — get app config schema
**PUT** `/api/v3/starlark/apps/<app_id>/config` — update app config
**POST** `/api/v3/starlark/apps/<app_id>/render` — render app to a frame
**POST** `/api/v3/starlark/apps/<app_id>/toggle` — enable/disable app
### Repository (Tronbyt community apps)
**GET** `/api/v3/starlark/repository/categories` — browse categories
**GET** `/api/v3/starlark/repository/browse?category=<cat>` — browse apps
**POST** `/api/v3/starlark/repository/install` — install an app from the
community repository
### Upload custom app
**POST** `/api/v3/starlark/upload`
Upload a custom Starlark `.star` file as a new app.
---
## Error Responses ## Error Responses
All endpoints may return error responses in the following format: All endpoints may return error responses in the following format: