diff --git a/docs/ADVANCED_FEATURES.md b/docs/ADVANCED_FEATURES.md index 7da07602..ae3958c3 100644 --- a/docs/ADVANCED_FEATURES.md +++ b/docs/ADVANCED_FEATURES.md @@ -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 diff --git a/docs/REST_API_REFERENCE.md b/docs/REST_API_REFERENCE.md index 01b9bc30..132547b0 100644 --- a/docs/REST_API_REFERENCE.md +++ b/docs/REST_API_REFERENCE.md @@ -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/` +**DELETE** `/api/v3/fonts/` Delete an uploaded font. +### Font Preview + +**GET** `/api/v3/fonts/preview?family=&text=` + +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/` + +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//static/` + +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/` — get app details +**DELETE** `/api/v3/starlark/apps/` — uninstall an app +**GET** `/api/v3/starlark/apps//config` — get app config schema +**PUT** `/api/v3/starlark/apps//config` — update app config +**POST** `/api/v3/starlark/apps//render` — render app to a frame +**POST** `/api/v3/starlark/apps//toggle` — enable/disable app + +### Repository (Tronbyt community apps) + +**GET** `/api/v3/starlark/repository/categories` — browse categories +**GET** `/api/v3/starlark/repository/browse?category=` — 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: