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

View File

@@ -24,6 +24,17 @@ All endpoints return JSON responses with a standard format:
- [Cache](#cache)
- [WiFi](#wifi)
- [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** `/api/v3/fonts/delete/<font_family>`
**DELETE** `/api/v3/fonts/<font_family>`
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
@@ -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
All endpoints may return error responses in the following format: