From 11db5bb7e521632ea2c81f78efaacf40e7d504a1 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 6 Apr 2026 20:46:07 -0400 Subject: [PATCH 01/15] docs: refresh plugin READMEs and fix manifest bugs Walked every plugin against its manifest.json + config_schema.json + manager.py and corrected stale documentation. Two real loader-breaking bugs found and fixed; the rest is README accuracy work. Loader-breaking manifest bugs (would AttributeError at load time) - plugins/hello-world/manifest.json: class_name was "HelloWorld Plugin" (with a space) but the actual class in manager.py:19 is HelloWorldPlugin. The plugin loader does getattr(module, class_name) (LEDMatrix:src/plugin_system/ plugin_loader.py:444) so this would have always failed. Also bumped the versions[] array to include 1.0.2 to match the version field. - plugins/stock-news/manifest.json: missing both entry_point and class_name entirely. Loader requires class_name (loader.py:537-538). Added entry_point: "manager.py" and class_name: "StockNewsTickerPlugin" (verified from manager.py:33). Schema-vs-README mismatches that would silently mislead users - ledmatrix-weather: README claimed "location" was a single string; reality is three keys (location_city/state/country). Added the 5 display modes (was 3) including the previously undocumented radar and almanac modes, plus the radar customization keys. Verified against config_schema.json (167 lines). - ledmatrix-stocks: README documented top-level keys (display_duration, scroll_speed, font_size, stock_symbols, etc) but the real schema nests them under display.* / stocks.symbols / customization.*. Also: README said "Future Implementation: API integration with Alpha Vantage / Yahoo Finance" but data_fetcher.py has been using Yahoo Finance directly with no API key for a long time. Full rewrite. - hockey-scoreboard: documented update_interval (15-300, default 60) as a top-level key; reality is defaults.update_interval_seconds (default 3600) plus per-league update_intervals.{base,live,recent, upcoming,odds}. Rewrote the Display Settings section to match the real config_schema.json structure. - text-display: scroll_speed documented as "1-200 px/sec" but it's a multiplier (default 1). Added 4 missing keys: update_interval, target_fps, scroll_loop, scroll_delay. - static-image: README documented only the legacy single-image_path form. The current schema/manager use an images array with image_config.* and rotation_settings.* (verified at manager.py:79-101). Added multi-image example. - news: every "Global Settings" key was at the top level in the README but actually nested under global.* in the schema. Fixed. - ledmatrix-music: Spotify credentials were documented under the legacy "music" key with SPOTIFY_CLIENT_ID (uppercase). Canonical form per spotify_client.py:50-53 is "ledmatrix-music" key with lowercase spotify_client_id/spotify_client_secret/spotify_redirect_uri. - calendar: README told users to choose "TV and Limited Input Device" OAuth client type (and contradicted itself with "Desktop application" one section later). The plugin uses InstalledAppFlow.run_local_server (manager.py:346-348) which requires Desktop application. Fixed. UI navigation - README files in 11 plugins referenced a "Plugin Store tab" or "Plugins -> Foo -> Configuration" UI that doesn't exist. Real flow: open Plugin Manager tab -> find plugin in Plugin Store section -> click Install -> open the plugin's tab in the second nav row to configure. Fixed in: 7-segment-clock, clock-simple, countdown, football-scoreboard, hello-world, hockey-scoreboard, ledmatrix-flights, masters-tournament, olympics, calendar (and previously hockey/clock-simple). Repo-root README - Plugin count badge said 27; actually 30. Three plugins were missing from the index entirely: f1-scoreboard, lacrosse-scoreboard, masters-tournament. Added them. - API curl example used port 5050; real port is 5000. - "python run.py --emulator" was wrong (no such flag). Replaced with the real options: scripts/dev_server.py for dev preview, or EMULATOR=true python3 run.py for the full emulator path. Plugin Store docs (docs/PLUGIN_STORE_*.md) - 27 occurrences of port 5050 across all three docs. Bulk-fixed to 5000. - "Navigate to Plugin Store tab" -> real Plugin Manager tab + Plugin Store section. - Updated "Install from URL" UI nav to match the real "Install from GitHub" section name. Submission/verification - SUBMISSION.md: same port fix. - VERIFICATION.md: extended manifest checklist to require class_name matches the actual class (would have caught the hello-world bug), entry_point file existence, id matches directory name, and last_updated matches the latest version's release date. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 31 ++- SUBMISSION.md | 3 +- VERIFICATION.md | 12 +- docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md | 14 +- docs/PLUGIN_STORE_QUICK_REFERENCE.md | 18 +- docs/PLUGIN_STORE_USER_GUIDE.md | 47 ++-- plugins/7-segment-clock/README.md | 5 +- plugins/calendar/README.md | 33 +-- plugins/clock-simple/README.md | 52 ++-- plugins/countdown/README.md | 8 +- plugins/football-scoreboard/README.md | 17 +- plugins/hello-world/README.md | 184 ++++++-------- plugins/hello-world/manifest.json | 7 +- plugins/hockey-scoreboard/README.md | 70 ++++-- plugins/hockey-scoreboard/manifest.json | 2 +- plugins/ledmatrix-flights/README.md | 5 +- plugins/ledmatrix-music/README.md | 13 +- plugins/ledmatrix-stocks/README.md | 266 ++++++-------------- plugins/ledmatrix-weather/README.md | 127 ++++++---- plugins/masters-tournament/README.md | 11 +- plugins/news/README.md | 32 ++- plugins/olympics/README.md | 5 +- plugins/static-image/README.md | 61 ++++- plugins/stock-news/manifest.json | 2 + plugins/text-display/README.md | 61 +++-- 25 files changed, 565 insertions(+), 521 deletions(-) diff --git a/README.md b/README.md index fb4bb1a..d2a0b73 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # LEDMatrix Official Plugins -[![Plugins](https://img.shields.io/badge/plugins-27-blue)](./plugins.json) +[![Plugins](https://img.shields.io/badge/plugins-30-blue)](./plugins.json) [![License](https://img.shields.io/badge/license-GPL--3.0-green)](LICENSE) [![Discord](https://img.shields.io/badge/Discord-community-5865F2?logo=discord&logoColor=white)](https://discord.gg/uW36dVAtcT) [![GitHub Stars](https://img.shields.io/github/stars/ChuckBuilds/ledmatrix-plugins?style=flat&color=yellow)](https://github.com/ChuckBuilds/ledmatrix-plugins) @@ -64,12 +64,13 @@ **Web Interface (Recommended):** 1. Open `http://your-pi-ip:5000` -2. Go to **Plugin Store** tab -3. Browse & click **Install** +2. Open the **Plugin Manager** tab +3. Find the plugin you want in the **Plugin Store** section and click + **Install** **API:** ```bash -curl -X POST http://your-pi-ip:5050/api/plugins/install \ +curl -X POST http://your-pi-ip:5000/api/plugins/install \ -H "Content-Type: application/json" \ -d '{"plugin_id": "football-scoreboard"}' ``` @@ -78,7 +79,7 @@ curl -X POST http://your-pi-ip:5050/api/plugins/install \ ## Available Plugins -### Sports (9) +### Sports (12) | Plugin | Description | |--------|-------------| @@ -87,7 +88,10 @@ curl -X POST http://your-pi-ip:5050/api/plugins/install \ | [Basketball Scoreboard](./plugins/basketball-scoreboard/) | NBA, NCAA & WNBA live scores and schedules | | [Baseball Scoreboard](./plugins/baseball-scoreboard/) | MLB, MiLB & NCAA Baseball live scores | | [Soccer Scoreboard](./plugins/soccer-scoreboard/) | Premier League, La Liga, Bundesliga, Serie A, Ligue 1, MLS | +| [Lacrosse Scoreboard](./plugins/lacrosse-scoreboard/) | NCAA lacrosse live scores and schedules | +| [F1 Scoreboard](./plugins/f1-scoreboard/) | Formula 1 race results, schedules, and standings | | [UFC Scoreboard](./plugins/ufc-scoreboard/) | UFC/MMA live fights, fighter headshots, records, odds & results — *by [LegoGuy1000](https://github.com/legoguy1000)* | +| [Masters Tournament](./plugins/masters-tournament/) | Live Masters golf leaderboard, hole tracking, player cards | | [Odds Ticker](./plugins/odds-ticker/) | Betting odds & lines across NFL, NBA, MLB, NCAA | | [Sports Leaderboard](./plugins/ledmatrix-leaderboard/) | League standings, rankings, conference records | | [Olympics Countdown](./plugins/olympics/) | Countdown to next Olympics with live medal counts | @@ -196,14 +200,20 @@ The **Plugin Store** in the LEDMatrix web interface automatically fetches the la ### Manual Installation -Clone this repository and copy the plugin you want: +Clone this repository and copy the plugin you want into your LEDMatrix +installation's configured plugins directory (default `plugin-repos/`): ```bash git clone https://github.com/ChuckBuilds/ledmatrix-plugins.git cp -r ledmatrix-plugins/plugins/football-scoreboard /path/to/LEDMatrix/plugin-repos/ ``` -> **Note:** See individual plugin README files for detailed setup instructions and configuration. +The directory name on the destination must match the plugin's `id` in +its `manifest.json`. Restart the LEDMatrix display service afterwards +so the loader picks up the new plugin. + +> **Note:** See individual plugin README files for detailed setup +> instructions and configuration. --- @@ -308,7 +318,12 @@ See the [manifest schema](https://github.com/ChuckBuilds/LEDMatrix/blob/main/sch 1. Review the [Plugin Development Guide](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/PLUGIN_DEVELOPMENT_GUIDE.md) 2. Start with the [Hello World plugin](./plugins/hello-world/) as a template -3. Test with the emulator: `python run.py --emulator` +3. Test without hardware: run the LEDMatrix dev preview server + (`python3 scripts/dev_server.py` from the LEDMatrix repo, then open + `http://localhost:5001`) — see + [`docs/DEV_PREVIEW.md`](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/DEV_PREVIEW.md). + Or run the full display in emulator mode with + `EMULATOR=true python3 run.py`. ### Submitting a Plugin diff --git a/SUBMISSION.md b/SUBMISSION.md index eac970e..409f8b4 100644 --- a/SUBMISSION.md +++ b/SUBMISSION.md @@ -47,7 +47,8 @@ If you prefer to maintain your own repo: 1. **Test Your Plugin** ```bash # Install via URL on your Pi - curl -X POST http://your-pi:5050/api/plugins/install-from-url \ + curl -X POST http://your-pi:5000/api/plugins/install-from-url \ + -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/you/ledmatrix-your-plugin"}' ``` diff --git a/VERIFICATION.md b/VERIFICATION.md index b6bff4a..fd1570f 100644 --- a/VERIFICATION.md +++ b/VERIFICATION.md @@ -14,9 +14,19 @@ Use this checklist when reviewing plugin submissions. ## Manifest Validation -- [ ] All required fields present +- [ ] All required fields present (`id`, `name`, `version`, `class_name`, + `display_modes`) +- [ ] `class_name` matches the actual class name in the entry point + (case-sensitive, no spaces) — the loader does + `getattr(module, class_name)` and will fail with `AttributeError` + otherwise +- [ ] `entry_point` either matches the real file name or is omitted + (defaults to `manager.py`) +- [ ] `id` matches the directory name - [ ] Valid JSON syntax - [ ] Correct version format (semver) +- [ ] `version` field matches the latest entry in the `versions[]` array +- [ ] `last_updated` matches the release date of the latest version - [ ] Category is valid - [ ] Tags are descriptive diff --git a/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md b/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md index 176e4c0..d6bdf45 100644 --- a/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md +++ b/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md @@ -90,7 +90,7 @@ This is the **key feature** that enables community participation: 3. **Or via API:** ```bash - curl -X POST http://your-pi-ip:5050/api/plugins/install-from-url \ + curl -X POST http://your-pi-ip:5000/api/plugins/install-from-url \ -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/developer/ledmatrix-awesome-display"}' ``` @@ -149,12 +149,12 @@ This is the **key feature** that enables community participation: # 1. Develop plugin locally # 2. Push to GitHub # 3. Test on Pi via URL install -curl -X POST http://pi:5050/api/plugins/install-from-url \ +curl -X POST http://pi:5000/api/plugins/install-from-url \ -d '{"repo_url": "https://github.com/me/my-plugin"}' # 4. Make changes, push # 5. Update on Pi -curl -X POST http://pi:5050/api/plugins/update \ +curl -X POST http://pi:5000/api/plugins/update \ -d '{"plugin_id": "my-plugin"}' ``` @@ -261,13 +261,13 @@ python3 test/test_install_from_url.py python3 web_interface_v2.py # 2. Test API endpoints -curl http://localhost:5050/api/plugins/store/list -curl http://localhost:5050/api/plugins/store/search?q=clock -curl http://localhost:5050/api/plugins/installed +curl http://localhost:5000/api/plugins/store/list +curl http://localhost:5000/api/plugins/store/search?q=clock +curl http://localhost:5000/api/plugins/installed # 3. Test installation (with existing hello-world plugin) # First, push hello-world to a test GitHub repo, then: -curl -X POST http://localhost:5050/api/plugins/install-from-url \ +curl -X POST http://localhost:5000/api/plugins/install-from-url \ -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/your-test-repo/ledmatrix-hello-world"}' ``` diff --git a/docs/PLUGIN_STORE_QUICK_REFERENCE.md b/docs/PLUGIN_STORE_QUICK_REFERENCE.md index a48ecdb..6918208 100644 --- a/docs/PLUGIN_STORE_QUICK_REFERENCE.md +++ b/docs/PLUGIN_STORE_QUICK_REFERENCE.md @@ -4,17 +4,17 @@ ### Install Plugin from Store ```bash -# Web UI: Plugin Store → Search → Click Install +# Web UI: Plugin Manager tab → Plugin Store section → Search → Click Install # API: -curl -X POST http://pi:5050/api/plugins/install \ +curl -X POST http://pi:5000/api/plugins/install \ -d '{"plugin_id": "clock-simple"}' ``` ### Install Plugin from GitHub URL ⭐ ```bash -# Web UI: Plugin Store → "Install from URL" → Paste URL +# Web UI: Plugin Manager tab → "Install from GitHub" section → Paste URL # API: -curl -X POST http://pi:5050/api/plugins/install-from-url \ +curl -X POST http://pi:5000/api/plugins/install-from-url \ -d '{"repo_url": "https://github.com/user/ledmatrix-plugin"}' ``` @@ -22,29 +22,29 @@ curl -X POST http://pi:5050/api/plugins/install-from-url \ ```bash # Web UI: Use search bar and filters # API: -curl "http://pi:5050/api/plugins/store/search?q=hockey&category=sports" +curl "http://pi:5000/api/plugins/store/search?q=hockey&category=sports" ``` ### List Installed ```bash -curl "http://pi:5050/api/plugins/installed" +curl "http://pi:5000/api/plugins/installed" ``` ### Enable/Disable ```bash -curl -X POST http://pi:5050/api/plugins/toggle \ +curl -X POST http://pi:5000/api/plugins/toggle \ -d '{"plugin_id": "clock-simple", "enabled": true}' ``` ### Update Plugin ```bash -curl -X POST http://pi:5050/api/plugins/update \ +curl -X POST http://pi:5000/api/plugins/update \ -d '{"plugin_id": "clock-simple"}' ``` ### Uninstall ```bash -curl -X POST http://pi:5050/api/plugins/uninstall \ +curl -X POST http://pi:5000/api/plugins/uninstall \ -d '{"plugin_id": "clock-simple"}' ``` diff --git a/docs/PLUGIN_STORE_USER_GUIDE.md b/docs/PLUGIN_STORE_USER_GUIDE.md index d77fd35..8dc470c 100644 --- a/docs/PLUGIN_STORE_USER_GUIDE.md +++ b/docs/PLUGIN_STORE_USER_GUIDE.md @@ -11,16 +11,17 @@ The LEDMatrix Plugin Store allows you to easily discover, install, and manage di The official plugin store contains curated, verified plugins that have been reviewed by maintainers. **Via Web UI:** -1. Open the web interface (http://your-pi-ip:5050) -2. Navigate to "Plugin Store" tab -3. Browse or search for plugins -4. Click "Install" on the plugin you want +1. Open the web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Scroll to the **Plugin Store** section and browse or search +4. Click **Install** on the plugin you want 5. Wait for installation to complete -6. Restart the display to activate the plugin +6. Toggle the plugin on, then click **Restart Display Service** on the + **Overview** tab **Via API:** ```bash -curl -X POST http://your-pi-ip:5050/api/plugins/install \ +curl -X POST http://your-pi-ip:5000/api/plugins/install \ -H "Content-Type: application/json" \ -d '{"plugin_id": "clock-simple", "version": "latest"}' ``` @@ -45,18 +46,20 @@ Install any plugin directly from a GitHub repository, even if it's not in the of **Via Web UI:** 1. Open the web interface -2. Navigate to "Plugin Store" tab -3. Find the "Install from URL" section at the bottom -4. Paste the GitHub repository URL (e.g., `https://github.com/user/ledmatrix-my-plugin`) -5. Click "Install from URL" +2. Open the **Plugin Manager** tab +3. Scroll to the **Install from GitHub** section +4. Paste the GitHub repository URL (e.g., + `https://github.com/user/ledmatrix-my-plugin`) +5. Click **Install Single Plugin** (or **Load Registry** if it's a + monorepo of multiple plugins) 6. Review the warning about unverified plugins 7. Confirm installation 8. Wait for installation to complete -9. Restart the display +9. Restart the display service from the **Overview** tab **Via API:** ```bash -curl -X POST http://your-pi-ip:5050/api/plugins/install-from-url \ +curl -X POST http://your-pi-ip:5000/api/plugins/install-from-url \ -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/user/ledmatrix-my-plugin"}' ``` @@ -84,13 +87,13 @@ else: **Via API:** ```bash # Search by query -curl "http://your-pi-ip:5050/api/plugins/store/search?q=hockey" +curl "http://your-pi-ip:5000/api/plugins/store/search?q=hockey" # Filter by category -curl "http://your-pi-ip:5050/api/plugins/store/search?category=sports" +curl "http://your-pi-ip:5000/api/plugins/store/search?category=sports" # Filter by tags -curl "http://your-pi-ip:5050/api/plugins/store/search?tags=nhl&tags=hockey" +curl "http://your-pi-ip:5000/api/plugins/store/search?tags=nhl&tags=hockey" ``` **Via Python:** @@ -119,7 +122,7 @@ results = store.search_plugins(tags=["nhl", "hockey"]) **Via API:** ```bash -curl "http://your-pi-ip:5050/api/plugins/installed" +curl "http://your-pi-ip:5000/api/plugins/installed" ``` **Via Python:** @@ -143,7 +146,7 @@ for plugin_id in installed: **Via API:** ```bash -curl -X POST http://your-pi-ip:5050/api/plugins/toggle \ +curl -X POST http://your-pi-ip:5000/api/plugins/toggle \ -H "Content-Type: application/json" \ -d '{"plugin_id": "clock-simple", "enabled": true}' ``` @@ -158,7 +161,7 @@ curl -X POST http://your-pi-ip:5050/api/plugins/toggle \ **Via API:** ```bash -curl -X POST http://your-pi-ip:5050/api/plugins/update \ +curl -X POST http://your-pi-ip:5000/api/plugins/update \ -H "Content-Type: application/json" \ -d '{"plugin_id": "clock-simple"}' ``` @@ -181,7 +184,7 @@ success = store.update_plugin('clock-simple') **Via API:** ```bash -curl -X POST http://your-pi-ip:5050/api/plugins/uninstall \ +curl -X POST http://your-pi-ip:5000/api/plugins/uninstall \ -H "Content-Type: application/json" \ -d '{"plugin_id": "clock-simple"}' ``` @@ -363,7 +366,7 @@ All API endpoints return JSON with this structure: ```bash # Install -curl -X POST http://192.168.1.100:5050/api/plugins/install \ +curl -X POST http://192.168.1.100:5000/api/plugins/install \ -H "Content-Type: application/json" \ -d '{"plugin_id": "clock-simple"}' @@ -386,12 +389,12 @@ sudo systemctl restart ledmatrix ```bash # Install your own plugin during development -curl -X POST http://192.168.1.100:5050/api/plugins/install-from-url \ +curl -X POST http://192.168.1.100:5000/api/plugins/install-from-url \ -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/myusername/ledmatrix-my-custom-plugin"}' # Enable it -curl -X POST http://192.168.1.100:5050/api/plugins/toggle \ +curl -X POST http://192.168.1.100:5000/api/plugins/toggle \ -H "Content-Type: application/json" \ -d '{"plugin_id": "my-custom-plugin", "enabled": true}' diff --git a/plugins/7-segment-clock/README.md b/plugins/7-segment-clock/README.md index 5e13faf..6cd22de 100644 --- a/plugins/7-segment-clock/README.md +++ b/plugins/7-segment-clock/README.md @@ -17,8 +17,9 @@ A retro-style 7-segment clock plugin for LEDMatrix that displays time using digi ### From Plugin Store (Recommended) 1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) -2. Go to **Plugin Store** -3. Find **7-Segment Clock** and click **Install** +2. Open the **Plugin Manager** tab +3. Find **7-Segment Clock** in the **Plugin Store** section and click + **Install** ### Manual Installation diff --git a/plugins/calendar/README.md b/plugins/calendar/README.md index 8f10610..7a3bb4f 100644 --- a/plugins/calendar/README.md +++ b/plugins/calendar/README.md @@ -36,29 +36,30 @@ Display upcoming events from Google Calendar with automatic updates, event rotat ### 1. Create Google Cloud Project 1. Go to [Google Cloud Console](https://console.cloud.google.com/) -2. Create a new project or select existing one -3. Enable the Google Calendar API -4. Create OAuth 2.0 credentials - * Application type: TV and Limited Input Device +2. Create a new project or select an existing one +3. Enable the **Google Calendar API** -### 2. Download Credentials +### 2. Create OAuth credentials and download them -1. In Cloud Console, go to "Credentials" -2. Click "Create Credentials" → "OAuth client ID" -3. Choose "Desktop application" +1. In Cloud Console, go to **APIs & Services → Credentials** +2. Click **Create Credentials → OAuth client ID** +3. Choose **Desktop application** — the plugin uses + `InstalledAppFlow.run_local_server()` + (`plugins/calendar/manager.py:346-348`), which requires this client + type. "TV and Limited Input Device" will not work. 4. Download the JSON file -5. Save as `credentials.json` in the **calendar plugin directory** - - Path: `plugins/calendar/credentials.json` +5. Save it as `credentials.json` in the calendar plugin directory + (typically `plugin-repos/calendar/credentials.json`) ### 3. First-Time Authentication **Option A: Use Web Interface (Recommended)** -1. Open the LEDMatrix web interface -2. Navigate to the Plugins tab -3. Find the "Google Calendar" plugin and click "Configure" -4. Click the "Authenticate Google Calendar" button -5. Follow the OAuth flow in your browser -6. Token will be saved automatically +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Calendar** tab in the second nav row (added once the + plugin is installed) +3. Click the **Authenticate Google Calendar** button +4. Follow the OAuth flow in your browser +5. The token is saved automatically into the plugin directory **Option B: Use Registration Script** ```bash diff --git a/plugins/clock-simple/README.md b/plugins/clock-simple/README.md index f9693b0..d2d68a5 100644 --- a/plugins/clock-simple/README.md +++ b/plugins/clock-simple/README.md @@ -25,12 +25,14 @@ A simple, customizable clock display plugin for LEDMatrix that shows the current ## Installation -### From Plugin Store (Recommended) +### From the Plugin Store (recommended) -1. Open the LEDMatrix web interface -2. Navigate to the Plugin Store tab -3. Search for "Simple Clock" or browse the "time" category -4. Click "Install" +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **Simple Clock** in the **Plugin Store** section (it's in the + `time` category) and click **Install** +4. Toggle the plugin on, then click **Restart Display Service** on the + **Overview** tab ### Manual Installation @@ -79,16 +81,18 @@ Add the following to your `config/config.json`: | Option | Type | Default | Description | |--------|------|---------|-------------| -| `enabled` | boolean | `true` | Enable or disable the plugin | -| `timezone` | string | Inherits from global config | Timezone for display (e.g., `"America/New_York"`). If not specified, inherits from LEDMatrix global timezone setting | -| `time_format` | string | `"12h"` | Time format: `"12h"` or `"24h"` | -| `show_seconds` | boolean | `false` | Show seconds in time display | +| `enabled` | boolean | `false` | Enable or disable the plugin | +| `display_duration` | number | `15` | Seconds to hold the screen each rotation (1–300) | +| `update_interval` | integer | `1` | How often to redraw the clock, in seconds (1–60) | +| `timezone` | string \| null | `null` | IANA timezone name (e.g. `"America/New_York"`). When null, inherits the global LEDMatrix timezone | +| `time_format` | string | `"12h"` | `"12h"` or `"24h"` | +| `center_time_with_ampm` | boolean | `false` | Center the time + AM/PM as one block (12h only) | +| `show_seconds` | boolean | `false` | Include seconds in the time | | `show_date` | boolean | `true` | Show date below the time | -| `date_format` | string | `"OLD_CLOCK"` | Date format: `"MM/DD/YYYY"`, `"DD/MM/YYYY"`, `"YYYY-MM-DD"`, or `"OLD_CLOCK"` | -| `display_duration` | number | `15` | Display duration in seconds | -| `position_x` | integer | `0` | X position offset for display (pixels) | -| `position_y` | integer | `0` | Y position offset for display (pixels) | -| `customization` | object | See below | Nested configuration for display customization | +| `date_format` | string | `"OLD_CLOCK"` | One of `"MM/DD/YYYY"`, `"DD/MM/YYYY"`, `"YYYY-MM-DD"`, `"OLD_CLOCK"` (e.g. `Monday, January 1st`) | +| `position_x` | integer | `0` | X offset in pixels | +| `position_y` | integer | `0` | Y offset in pixels | +| `customization` | object | See below | Per-element font and color overrides | ### Customization Options @@ -172,21 +176,21 @@ plugins/clock-simple/ ### Testing -Test the plugin by running: +The fastest way to verify a change without restarting the full display +service is the LEDMatrix dev preview server, which renders this plugin in +your browser without any hardware: ```bash cd /path/to/LEDMatrix -python3 -c " -from src.plugin_system.plugin_manager import PluginManager -pm = PluginManager() -pm.discover_plugins() -pm.load_plugin('clock-simple') -plugin = pm.get_plugin('clock-simple') -plugin.update() -plugin.display() -" +python3 scripts/dev_server.py --extra-dir /path/to/ledmatrix-plugins/plugins/clock-simple +# then open http://localhost:5001 ``` +You can also render a single still frame to a PNG with +`scripts/render_plugin.py` — see +[`docs/DEV_PREVIEW.md`](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/DEV_PREVIEW.md) +for details. + ## License GPL-3.0 License - feel free to modify and distribute. diff --git a/plugins/countdown/README.md b/plugins/countdown/README.md index 42a70f8..c1f0c6e 100644 --- a/plugins/countdown/README.md +++ b/plugins/countdown/README.md @@ -18,8 +18,9 @@ Display customizable countdowns with images on your LED matrix. Perfect for birt ### From Plugin Store (Recommended) 1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) -2. Go to **Plugin Store** -3. Find **Countdown Display** and click **Install** +2. Open the **Plugin Manager** tab +3. Find **Countdown Display** in the **Plugin Store** section and click + **Install** ### Manual Installation @@ -35,7 +36,8 @@ Display customizable countdowns with images on your LED matrix. Perfect for birt ### Adding a Countdown 1. Open the LEDMatrix web UI -2. Navigate to Settings > Plugins > Countdown Display +2. Open the **Countdown Display** tab (second nav row, added once the + plugin is installed) 3. Click "Add Countdown" 4. Fill in the details: - **Name**: Display name (e.g., "Birthday", "Vacation") diff --git a/plugins/football-scoreboard/README.md b/plugins/football-scoreboard/README.md index c59ca01..ee0c52d 100644 --- a/plugins/football-scoreboard/README.md +++ b/plugins/football-scoreboard/README.md @@ -264,7 +264,7 @@ The plugin supports fine-tuning element positioning for custom display sizes. Al #### Accessing Layout Settings Layout customization is available in the web UI under the plugin configuration section: -1. Navigate to **Plugins** → **Football Scoreboard** → **Configuration** +1. Open the **Football Scoreboard** tab (second nav row) 2. Expand the **Customization** section 3. Find the **Layout Positioning** subsection @@ -331,7 +331,7 @@ The plugin supports fine-tuning element positioning for custom display sizes. Al #### Accessing Layout Settings Layout customization is available in the web UI under the plugin configuration section: -1. Navigate to **Plugins** → **Football Scoreboard** → **Configuration** +1. Open the **Football Scoreboard** tab (second nav row) 2. Expand the **Customization** section 3. Find the **Layout Positioning** subsection @@ -431,12 +431,13 @@ This plugin reuses the proven code from the main LEDMatrix project: ## 📦 Installation -### From Plugin Store (Recommended) -1. Open LEDMatrix web interface -2. Navigate to Plugin Store -3. Search for "Football Scoreboard" -4. Click Install -5. Configure your favorite teams and preferences +### From the Plugin Store (recommended) +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **Football Scoreboard** in the **Plugin Store** section and click + **Install** +4. Open the **Football Scoreboard** tab in the second nav row to configure + your favorite teams and per-league preferences ## ⚙️ Configuration diff --git a/plugins/hello-world/README.md b/plugins/hello-world/README.md index 5098108..adae164 100644 --- a/plugins/hello-world/README.md +++ b/plugins/hello-world/README.md @@ -1,61 +1,55 @@ # Hello World Plugin -A simple test plugin for the LEDMatrix plugin system. Displays a customizable greeting message with optional time display. +A minimal LEDMatrix plugin that displays a customizable greeting and the +current time. It's primarily here as a working starter template you can +copy when building your own plugin. -## Purpose +## What it does -This plugin serves as: -- **Test plugin** for validating the plugin system works correctly -- **Example plugin** for developers creating their own plugins -- **Simple demonstration** of the BasePlugin interface - -## Features - -- ✅ Customizable greeting message -- ✅ Optional time display -- ✅ Configurable text colors -- ✅ Proper error handling -- ✅ Configuration validation +- Displays a configurable message +- Optionally shows the current time underneath +- Lets you set the colors of both lines ## Installation -This plugin is included as a test plugin. To enable it: +The Hello World plugin ships with the default Plugin Store, so the easiest +way to install it is from the LEDMatrix web UI: -1. Edit `config/config.json` and add: +1. Open the web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **Hello World** in the **Plugin Store** section and click **Install** +4. Toggle it on, then click **Restart Display Service** on the **Overview** + tab -```json -{ - "hello-world": { - "enabled": true, - "message": "Hello, World!", - "show_time": true, - "color": [255, 255, 255], - "time_color": [0, 255, 255], - "display_duration": 10 - } -} -``` - -2. Restart the display: +If you'd rather install it from source for local development, copy this +directory into your LEDMatrix installation's `plugins/` folder: ```bash +cp -r plugins/hello-world ~/LEDMatrix/plugins/ sudo systemctl restart ledmatrix ``` -## Configuration Options +## Configuration + +Once installed, configuration lives in the plugin's tab in the web UI. +Under the hood it's stored in `config/config.json` under the `hello-world` +key. | Option | Type | Default | Description | -|--------|------|---------|-------------| +|---|---|---|---| | `enabled` | boolean | `true` | Enable/disable the plugin | -| `message` | string | `"Hello, World!"` | The greeting message to display | +| `message` | string | `"Hello, World!"` | The greeting message (1–50 chars) | | `show_time` | boolean | `true` | Show current time below message | -| `color` | array | `[255, 255, 255]` | RGB color for message (white) | -| `time_color` | array | `[0, 255, 255]` | RGB color for time (cyan) | -| `display_duration` | number | `10` | Display time in seconds | +| `color` | `[r, g, b]` | `[255, 255, 255]` | RGB color for the message (white) | +| `time_color` | `[r, g, b]` | `[0, 255, 255]` | RGB color for the time (cyan) | +| `display_duration` | number | `10` | Seconds the plugin holds the screen (1–300) | + +The full schema lives in [`config_schema.json`](config_schema.json) and is +what the web UI's form is generated from. -## Examples +### Examples -### Minimal Configuration +**Minimal:** ```json { "hello-world": { @@ -64,7 +58,7 @@ sudo systemctl restart ledmatrix } ``` -### Custom Message +**Custom message and color:** ```json { "hello-world": { @@ -76,7 +70,7 @@ sudo systemctl restart ledmatrix } ``` -### Message Only (No Time) +**Message only, no time:** ```json { "hello-world": { @@ -88,98 +82,70 @@ sudo systemctl restart ledmatrix } ``` -## Testing the Plugin +## Verifying the plugin loaded -### 1. Check Plugin Discovery +The fastest way is the **Plugin Manager** tab — installed plugins show up +under **Installed Plugins** and a tab for `hello-world` appears in the +plugin row at the top. -After adding the configuration, check the logs: +From SSH you can also tail the display log: ```bash sudo journalctl -u ledmatrix -f | grep hello-world ``` -You should see: +You should see something like: + ``` -Discovered plugin: hello-world v1.0.0 +Discovered plugin: hello-world v1.0.2 Loaded plugin: hello-world Hello World plugin initialized with message: 'Hello, World!' ``` -### 2. Test via Web API +To run the plugin once on demand instead of waiting for it in the +rotation, open its tab in the web UI and click **Run On-Demand**. -Check if the plugin is installed: -```bash -curl http://localhost:5001/api/plugins/installed | jq '.plugins[] | select(.id=="hello-world")' -``` - -### 3. Watch It Display +## Using this as a template -The plugin will appear in the normal display rotation based on your `display_duration` setting. +Hello World is intentionally tiny so you can read the whole thing in one +sitting. -## Development Notes +- [`manager.py`](manager.py) — `HelloWorldPlugin` class implementing + `update()` and `display()` from `BasePlugin` +- [`manifest.json`](manifest.json) — plugin metadata, entry point, and + class name (must match the class in `manager.py` exactly) +- [`config_schema.json`](config_schema.json) — JSON Schema that drives + the web UI configuration form +- [`requirements.txt`](requirements.txt) — Python dependencies the + plugin loader will install on first run -This plugin demonstrates: +To start a new plugin, copy this directory, rename it, update +`manifest.json` (especially `id`, `class_name`, and `entry_point`), and +replace the body of `update()` / `display()`. -### BasePlugin Interface -```python -class HelloWorldPlugin(BasePlugin): - def __init__(self, plugin_id, config, display_manager, cache_manager, plugin_manager): - super().__init__(plugin_id, config, display_manager, cache_manager, plugin_manager) - # Initialize your plugin - - def update(self): - # Fetch/update data - pass - - def display(self, force_clear=False): - # Render to display - pass -``` - -### Configuration Validation -```python -def validate_config(self): - # Validate configuration values - return True -``` +For deeper details see the LEDMatrix docs: -### Error Handling -```python -try: - # Plugin logic -except Exception as e: - self.logger.error(f"Error: {e}", exc_info=True) -``` +- [Plugin Development Guide](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/PLUGIN_DEVELOPMENT_GUIDE.md) +- [Plugin API Reference](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/PLUGIN_API_REFERENCE.md) +- [Plugin Architecture Spec](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/PLUGIN_ARCHITECTURE_SPEC.md) ## Troubleshooting -### Plugin Not Loading -- Check that `manifest.json` is valid JSON -- Verify `enabled: true` in config.json -- Check logs for error messages -- Ensure Python path is correct +**Plugin doesn't appear in the rotation** +- Make sure it's enabled in **Plugin Manager** and that you restarted the + display service afterward. +- Check the **Logs** tab in the web UI (or `journalctl -u ledmatrix`) for + errors mentioning `hello-world`. -### Display Issues -- Verify display_manager is initialized -- Check that colors are valid RGB arrays -- Ensure message isn't too long for display +**`Class HelloWorldPlugin not found in module`** +- The `class_name` field in `manifest.json` must exactly match the class + defined in `manager.py`. They are case-sensitive and must not contain + spaces. -### Configuration Errors -- Validate JSON syntax in config.json -- Check that all color arrays have 3 values (RGB) -- Ensure display_duration is a positive number +**Colors look wrong** +- Each color value must be a 3-element array of integers from `0` to + `255`. The form rejects anything else. ## License -GPL-3.0 License - Same as LEDMatrix project - -## Contributing - -This is a reference plugin included with LEDMatrix. Feel free to use it as a template for your own plugins! - -## Support - -For plugin system questions, see: -- [LEDMatrix Plugin Documentation](https://github.com/ChuckBuilds/LEDMatrix) -- [Plugin Architecture Spec](https://github.com/ChuckBuilds/LEDMatrix/blob/main/PLUGIN_ARCHITECTURE_SPEC.md) - +GPL-3.0, same as the LEDMatrix project. diff --git a/plugins/hello-world/manifest.json b/plugins/hello-world/manifest.json index 7421596..d143392 100644 --- a/plugins/hello-world/manifest.json +++ b/plugins/hello-world/manifest.json @@ -5,7 +5,7 @@ "author": "ChuckBuilds", "description": "A simple test plugin that displays a customizable message", "entry_point": "manager.py", - "class_name": "HelloWorld Plugin", + "class_name": "HelloWorldPlugin", "category": "demo", "tags": [ "demo", @@ -20,6 +20,11 @@ "released": "2025-10-19", "version": "1.0.1", "ledmatrix_min": "2.0.0" + }, + { + "released": "2026-04-06", + "version": "1.0.2", + "ledmatrix_min": "2.0.0" } ], "last_updated": "2025-10-19", diff --git a/plugins/hockey-scoreboard/README.md b/plugins/hockey-scoreboard/README.md index 42f5a11..61ad9b2 100644 --- a/plugins/hockey-scoreboard/README.md +++ b/plugins/hockey-scoreboard/README.md @@ -241,12 +241,35 @@ Specify team abbreviations for each league: #### Display Settings -- **`prioritize_favorites`**: Show favorite team games first (default: true) -- **`show_shots_on_goal`**: Display SOG statistics (default: false) -- **`show_powerplay`**: Highlight power play situations (default: true) -- **`update_interval`**: Data refresh interval in seconds (15-300, default: 60) -- **`display_duration`**: How long to show each game in seconds (5-60, default: 15) -- **`request_priority`**: Set the request priority from 1 to 5, where 1 is highest (default: 2) +The full set of options lives in +[`config_schema.json`](config_schema.json) — the schema is the source of +truth and is what generates the web UI. The most commonly tweaked keys: + +- **`enabled`** (boolean, default `false`) — master switch for the plugin +- **`defaults.display_duration`** (5–60s, default `15`) — fallback per-game + duration when a league doesn't override it +- **`defaults.show_records`** (boolean, default `false`) — show team + records (W-L) +- **`defaults.show_shots_on_goal`** (boolean, default `false`) — show SOG + during live games +- **`defaults.show_powerplay`** (boolean, default `true`) — highlight power + play situations +- **`defaults.update_interval_seconds`** (30–86400s, default `3600`) — + default base poll interval. Per-league `update_intervals.*` overrides + this. + +Each league (`nhl`, `ncaa_mens`, `ncaa_womens`) then has its own block with +finer-grained controls: + +- `.update_intervals.{base,live,recent,upcoming,odds}` — how often + to poll ESPN for each kind of data. Live games default to 30s; recent + and upcoming default to 3600s. +- `.display_durations.{base,live,recent,upcoming}` — per-mode + display duration overrides for that league. +- `.display_options.{show_records,show_ranking,show_odds,...}` — + per-league overrides of the cross-league defaults. +- `.live_priority` (boolean) — let this league's live games take + over the rotation when one is in progress. ## Display Mode Details @@ -277,12 +300,14 @@ Shows scheduled games for the next X hours with: ### 1. Install Plugin -Install from the Plugin Store in the LEDMatrix Web UI: +Install from the Plugin Store in the LEDMatrix web UI: -1. Go to Plugin Store tab -2. Search for "Hockey Scoreboard" -3. Click Install -4. Configure via Plugin Configuration page +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Hockey Scoreboard** in the **Plugin Store** section and click + **Install** +4. The plugin appears in **Installed Plugins** above and gets its own tab + in the second nav row — open that tab to configure it ### 2. Configure Leagues @@ -372,8 +397,8 @@ The plugin supports fine-tuning element positioning for custom display sizes. Al #### Accessing Layout Settings -Layout customization is available in the web UI under the plugin configuration section: -1. Navigate to **Plugins** → **Hockey Scoreboard** → **Configuration** +Layout customization is available in the plugin's tab in the web UI: +1. Open the **Hockey Scoreboard** tab (second nav row) 2. Expand the **Customization** section 3. Find the **Layout Positioning** subsection @@ -591,9 +616,12 @@ Uses LEDMatrix's `BackgroundDataService` for: ### Resource Usage - **CPU**: Low (background fetching, cached data) -- **Memory**: ~5-10MB for game data -- **Network**: ~1-5 KB per API call per league -- **API Calls**: 3 leagues × 12 calls/hour = 36 calls/hour (max) +- **Memory**: ~5–10 MB for game data +- **Network**: ~1–5 KB per API call per league +- **API calls**: depends on how many leagues are enabled and which + `update_intervals` you set. With defaults (NHL only, base 60s, live 30s, + recent/upcoming 3600s) and no live games, expect about one ESPN call per + minute per enabled league. ### Optimization Tips @@ -609,13 +637,13 @@ GPL-3.0 License - see main LEDMatrix repository for details. ## Support - **Issues**: [GitHub Issues](https://github.com/ChuckBuilds/ledmatrix-plugins/issues) -- **Documentation**: [LEDMatrix Wiki](https://github.com/ChuckBuilds/LEDMatrix/wiki) +- **Documentation**: see the LEDMatrix + [`docs/`](https://github.com/ChuckBuilds/LEDMatrix/tree/main/docs) directory - **Community**: [Discussions](https://github.com/ChuckBuilds/LEDMatrix/discussions) --- -**Version**: 1.0.0 -**Author**: ChuckBuilds -**Category**: Sports -**Tags**: hockey, nhl, ncaa, sports, scoreboard, live-scores +For the current version, author, category and tags see +[`manifest.json`](manifest.json) — that's the source of truth and is +what the Plugin Store reads. diff --git a/plugins/hockey-scoreboard/manifest.json b/plugins/hockey-scoreboard/manifest.json index ab22236..2cca3a6 100644 --- a/plugins/hockey-scoreboard/manifest.json +++ b/plugins/hockey-scoreboard/manifest.json @@ -131,7 +131,7 @@ "ledmatrix_min": "2.0.0" } ], - "last_updated": "2026-02-24", + "last_updated": "2026-03-02", "stars": 0, "downloads": 0, "verified": true, diff --git a/plugins/ledmatrix-flights/README.md b/plugins/ledmatrix-flights/README.md index 06229cf..29f235f 100644 --- a/plugins/ledmatrix-flights/README.md +++ b/plugins/ledmatrix-flights/README.md @@ -35,8 +35,9 @@ Real-time aircraft tracking plugin for LEDMatrix with ADS-B data, map background ### From Plugin Store (Recommended) 1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) -2. Go to **Plugin Store** -3. Find **Flight Tracker** and click **Install** +2. Open the **Plugin Manager** tab +3. Find **Flight Tracker** in the **Plugin Store** section and click + **Install** ### Manual Installation diff --git a/plugins/ledmatrix-music/README.md b/plugins/ledmatrix-music/README.md index a837e2b..dc6073d 100644 --- a/plugins/ledmatrix-music/README.md +++ b/plugins/ledmatrix-music/README.md @@ -66,14 +66,19 @@ Use Web Ui to configure Add to `config/config_secrets.json`: ```json { - "music": { - "SPOTIFY_CLIENT_ID": "your_client_id_here", - "SPOTIFY_CLIENT_SECRET": "your_client_secret_here", - "SPOTIFY_REDIRECT_URI": "http://localhost:8080/callback" + "ledmatrix-music": { + "spotify_client_id": "your_client_id_here", + "spotify_client_secret": "your_client_secret_here", + "spotify_redirect_uri": "http://localhost:8080/callback" } } ``` + > Older configs that put these under a `"music"` key with + > `SPOTIFY_CLIENT_ID` (uppercase) still work — `spotify_client.py` + > falls back to that legacy form — but new installs should use the + > `"ledmatrix-music"` key with lowercase names shown above. + 3. **Run Authentication**: ```bash cd plugins/ledmatrix-music diff --git a/plugins/ledmatrix-stocks/README.md b/plugins/ledmatrix-stocks/README.md index 652a096..e63c32e 100644 --- a/plugins/ledmatrix-stocks/README.md +++ b/plugins/ledmatrix-stocks/README.md @@ -1,215 +1,111 @@ ------------------------------------------------------------------------------------ -### Connect with ChuckBuilds +# Stock & Crypto Ticker Plugin -- Show support on Youtube: https://www.youtube.com/@ChuckBuilds -- Stay in touch on Instagram: https://www.instagram.com/ChuckBuilds/ -- Want to chat or need support? Reach out on the ChuckBuilds Discord: https://discord.com/invite/uW36dVAtcT -- Feeling Generous? Support the project: - - Github Sponsorship: https://github.com/sponsors/ChuckBuilds - - Buy Me a Coffee: https://buymeacoffee.com/chuckbuilds - - Ko-fi: https://ko-fi.com/chuckbuilds/ - ------------------------------------------------------------------------------------ - -# Stocks Ticker Plugin - -A plugin for LEDMatrix that displays scrolling stock tickers with prices, changes, and optional charts for stocks and cryptocurrencies. +A scrolling ticker for the LEDMatrix display showing live stock and +cryptocurrency prices, percent changes, and optional inline price charts. +Data comes from Yahoo Finance — no API key required. ## Features -- **Stock Price Tracking**: Real-time stock prices and changes -- **Cryptocurrency Support**: Bitcoin, Ethereum, and other crypto prices -- **Change Indicators**: Color-coded positive/negative changes -- **Percentage Display**: Show percentage changes alongside dollar amounts -- **Optional Charts**: Toggle chart display for visual price trends -- **Market Data**: Volume and market cap information -- **Configurable Display**: Adjustable scroll speed, colors, and timing -- **Background Data Fetching**: Efficient API calls without blocking display - -## Configuration - -### Global Settings - -- `display_duration`: How long to show the ticker (10-300 seconds, default: 30) -- `scroll_speed`: Scrolling speed multiplier (0.5-5, default: 1) -- `scroll_delay`: Delay between scroll steps (0.001-0.1 seconds, default: 0.01) -- `dynamic_duration`: Enable dynamic duration based on content width (default: true) -- `min_duration`: Minimum display duration (10-300 seconds, default: 30) -- `max_duration`: Maximum display duration (30-600 seconds, default: 300) -- `toggle_chart`: Enable chart display toggle (default: false) -- `font_size`: Font size for stock information (8-16, default: 10) - -### Stock Settings - -#### Stock Symbols - -```json -{ - "stocks": { - "stock_symbols": ["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN", "META"] - } -} -``` +- Live stock and crypto prices via Yahoo Finance (no API key) +- Color-coded gain/loss with positive/negative colors +- Optional inline mini chart per symbol (`display.toggle_chart`) +- Two display modes: continuous scroll, or one symbol at a time +- Independent stock and crypto symbol lists +- Per-element font and color customization -#### Display Options - -```json -{ - "stocks": { - "show_change": true, - "show_percentage": true, - "show_volume": false, - "show_market_cap": false, - "text_color": [255, 255, 255], - "positive_color": [0, 255, 0], - "negative_color": [255, 0, 0] - } -} -``` - -### Cryptocurrency Settings +## Installation -#### Enable Crypto Tracking +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **Stock Ticker** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure it -```json -{ - "crypto": { - "enabled": true, - "crypto_symbols": ["BTC", "ETH", "ADA", "SOL", "DOT"] - } -} -``` +## Configuration -#### Crypto Display Options +The full schema lives in +[`config_schema.json`](config_schema.json) — what you see in the web UI is +generated from it. The most-used keys, with their actual nesting: -```json -{ - "crypto": { - "show_change": true, - "show_percentage": true, - "text_color": [255, 215, 0], - "positive_color": [0, 255, 0], - "negative_color": [255, 0, 0] - } -} -``` +### Top level -## Display Format +| Key | Default | Notes | +|---|---|---| +| `enabled` | `false` | Master switch | +| `update_interval` | `600` | Seconds between Yahoo Finance fetches for stocks | -The stocks ticker displays information in a scrolling format showing: +### `display.*` — how the ticker scrolls -- **Symbol**: Stock/crypto ticker symbol -- **Price**: Current price (e.g., "$150.25") -- **Change**: Dollar change with color coding (green for positive, red for negative) -- **Percentage**: Percentage change (e.g., "+2.5%") -- **Additional Info**: Volume and market cap (if enabled) +| Key | Default | Notes | +|---|---|---| +| `display.display_mode` | `"scroll"` | `"scroll"` or `"switch"` | +| `display.switch_duration` | `15` | Seconds per symbol in switch mode | +| `display.scroll_speed` | `1.0` | Scroll speed multiplier | +| `display.scroll_delay` | `0.02` | Per-step delay (smaller = smoother but more CPU) | +| `display.toggle_chart` | `true` | Show an inline mini-chart per symbol | +| `display.dynamic_duration` | `true` | Let the controller pick a duration based on content width | +| `display.min_duration` | `30` | Floor for dynamic duration (seconds) | +| `display.max_duration` | `300` | Ceiling for dynamic duration (seconds) | +| `display.duration_buffer` | `0.1` | Padding factor on dynamic duration | +| `display.stock_gap` | `32` | Pixels of empty space between symbols | -## Stock Symbol Format +### `stocks.*` -Stock symbols should be in uppercase format: +| Key | Default | Notes | +|---|---|---| +| `stocks.enabled` | `true` | Enable the stocks list | +| `stocks.symbols` | `["ASTS","SCHD","INTC","NVDA","T","VOO","SMCI"]` | Yahoo Finance ticker symbols | +| `stocks.display_format` | `"{symbol}: ${price} ({change}%)"` | Placeholders: `{symbol}`, `{price}`, `{change}` | -- **AAPL**: Apple Inc. -- **GOOGL**: Alphabet Inc. -- **MSFT**: Microsoft Corporation -- **TSLA**: Tesla Inc. -- **AMZN**: Amazon.com Inc. -- **META**: Meta Platforms Inc. -- **NFLX**: Netflix Inc. +### `crypto.*` -## Cryptocurrency Symbols +| Key | Default | Notes | +|---|---|---| +| `crypto.enabled` | `false` | Enable the crypto list | +| `crypto.update_interval` | `600` | Seconds between crypto fetches | +| `crypto.symbols` | `["BTC-USD","ETH-USD"]` | Yahoo Finance pair symbols (always end in `-USD` etc.) | +| `crypto.display_format` | `"{symbol}: ${price} ({change}%)"` | Same placeholders as stocks | -Common cryptocurrency symbols: +### `customization.*` -- **BTC**: Bitcoin -- **ETH**: Ethereum -- **ADA**: Cardano -- **SOL**: Solana -- **DOT**: Polkadot -- **AVAX**: Avalanche -- **MATIC**: Polygon -- **LINK**: Chainlink - -## Background Service - -The plugin uses background data fetching for efficient API calls: - -- Requests timeout after 30 seconds (configurable) -- Up to 5 retries for failed requests -- Priority level 2 (medium priority) -- Updates every minute by default (configurable) +Per-element font, size, and color overrides for stocks and crypto. Each +of `symbol`, `price`, and `price_delta` has its own `font`, `font_size`, +and color settings. Defaults use `PressStart2P-Regular.ttf` at size 8, +with green for positive deltas and red for negative. -## Data Sources +## Symbol format -The plugin can fetch from: - -1. **Financial APIs**: Stock and crypto price data (requires API keys in practice) -2. **Market Data Feeds**: Real-time market information -3. **Placeholder Data**: Mock data for demonstration (current implementation) - -## Dependencies +The plugin uses Yahoo Finance symbols directly: -This plugin requires the main LEDMatrix installation and uses the cache manager for data storage. +- **Stocks**: plain ticker, e.g. `AAPL`, `GOOGL`, `MSFT`, `TSLA`, + `AMZN`, `META`, `NVDA` +- **Crypto**: pair with the quote currency, e.g. `BTC-USD`, `ETH-USD`, + `SOL-USD`, `DOGE-USD`. Without the `-USD` suffix Yahoo returns no data. -## Installation +## Pairing with the Stock News plugin -1. Copy this plugin directory to your `ledmatrix-plugins/plugins/` folder -2. Ensure the plugin is enabled in your LEDMatrix configuration -3. Configure your stock symbols and display preferences -4. Restart LEDMatrix to load the new plugin +This plugin pairs naturally with the [`stock-news`](../stock-news/) +plugin: prices on one rotation slot, related headlines on another. ## Troubleshooting -- **No data showing**: Check if symbols are valid and APIs are accessible -- **API errors**: Verify API keys and rate limits (for real implementations) -- **Slow scrolling**: Adjust scroll speed and delay settings -- **Network errors**: Check your internet connection and API availability - -## Advanced Features - -- **Chart Toggle**: Option to display price charts alongside tickers -- **Color Coding**: Visual indicators for price movements -- **Volume Display**: Show trading volume information -- **Market Cap**: Display market capitalization -- **Dual Mode**: Separate display modes for stocks and crypto - -## Integration Notes - -This plugin is designed to work alongside the stock-news plugin for comprehensive financial display: - -- **Stocks Plugin**: Price tickers and market data -- **Stock News Plugin**: Financial headlines and updates -- **Combined Use**: Show tickers while news scrolls in background - -## Performance Notes - -- The plugin is designed to be lightweight and not impact display performance -- Price data fetching happens in background to avoid blocking -- Configurable update intervals balance freshness vs. API load -- Caching reduces unnecessary network requests - -## Chart Display (Future Feature) - -When chart toggle is enabled, the plugin can display: - -- **Price Charts**: Simple line charts showing price trends -- **Candlestick Charts**: OHLC candlestick representations -- **Volume Bars**: Trading volume visualization -- **Time Periods**: Multiple timeframe options - -## API Integration (Future Implementation) +**No data showing** +- Confirm the symbols are valid on + [finance.yahoo.com](https://finance.yahoo.com) — typos return empty data. +- Check the **Logs** tab for HTTP errors. Yahoo occasionally rate-limits; + raising `update_interval` usually fixes it. -For production use, this plugin would integrate with: +**Scroll feels choppy** +- Lower `display.scroll_delay` (default 0.02) toward 0.01 for smoother + motion at the cost of CPU. +- Or switch `display.display_mode` to `"switch"` to step through one + symbol at a time instead of scrolling. -- **Alpha Vantage API**: Stock and forex data -- **CoinGecko API**: Cryptocurrency data -- **Yahoo Finance API**: Financial market data -- **Twelve Data API**: Real-time and historical data +**Chart isn't drawing** +- Set `display.toggle_chart` to `true`. +- Charts need enough horizontal room next to each symbol. On a 64×32 + panel they may be cropped — try a wider chain. -## Example Display +## License -``` -AAPL: $150.25 +2.50 (+1.7%) -GOOGL: $2750.80 -15.20 (-0.5%) -BTC: $43250.00 +1250.00 (+3.0%) -ETH: $2850.75 -75.25 (-2.6%) -``` +GPL-3.0, same as the LEDMatrix project. diff --git a/plugins/ledmatrix-weather/README.md b/plugins/ledmatrix-weather/README.md index 490c728..358d09b 100644 --- a/plugins/ledmatrix-weather/README.md +++ b/plugins/ledmatrix-weather/README.md @@ -31,60 +31,88 @@ Daily Forecast: ## Features -- **Current Weather**: Temperature, conditions, humidity, wind speed -- **Hourly Forecast**: Next 24-48 hours of weather data -- **Daily Forecast**: 7-day forecast with high/low temperatures -- **Weather Icons**: Beautiful icons matching current conditions -- **UV Index**: UV radiation levels for sun safety -- **Automatic Updates**: Configurable update intervals -- **Error Handling**: Robust retry logic and error recovery +- **Current conditions**: temperature, conditions icon, humidity, wind, + feels-like, dew point, visibility, pressure (extra metrics need height ≥48px) +- **Hourly forecast**: next 24 hours +- **Daily forecast**: 3–7 day high/low +- **Almanac**: sunrise/sunset, moon phase, day length +- **Precipitation radar**: live RainViewer imagery — no API key required for this part +- **Weather alerts**: when active, takes priority in the rotation ## Requirements -- OpenWeatherMap API key (free tier available) -- Internet connection for API access -- Display size: minimum 64x32 pixels recommended +- A **One Call API 3.0** subscription from OpenWeatherMap (free tier + available) — see API Key below +- Internet connection for OpenWeatherMap and RainViewer +- Display size: 64x32 minimum; 64x48 or larger to see the extra current- + conditions metrics ## Configuration ### API Key -This plugin requires a **One Call API 3.0** subscription from [OpenWeatherMap](https://openweathermap.org/api) (free tier: 1,000 calls/day): - -1. Sign up for an account at https://openweathermap.org -2. Navigate to API Keys section and generate a new API key -3. **Subscribe to One Call API 3.0** — this is a separate step from getting an API key: - - Go to https://openweathermap.org/api - - Find "One Call API 3.0" and click Subscribe - - The free tier requires adding payment info but will not charge you - - A standard API key alone will **not** work; you must subscribe to One Call 3.0 -4. Add the API key to your plugin configuration - - -### Configuration Options - -- `enabled`: Enable/disable the plugin -- `api_key`: Your OpenWeatherMap API key (required) -- `location`: City, state, and country for weather data -- `units`: Temperature units (`imperial` for Fahrenheit, `metric` for Celsius) -- `update_interval`: Seconds between API updates (minimum 300, recommended 1800) -- `display_modes`: Enable/disable specific display modes -- `display_duration`: Seconds to display each mode - -## Display Modes - -### weather -Shows current conditions with temperature, condition text, and humidity. - -### hourly_forecast -Displays next 4-24 hours of forecasted weather with temperatures. - -### daily_forecast -Shows 3-7 day forecast with daily high/low temperatures. +This plugin requires the **One Call API 3.0** product from OpenWeatherMap. +A standard OpenWeatherMap API key on its own will **not** work — One Call 3.0 +is a separate subscription you must enable on your account. + +1. Sign up at https://openweathermap.org +2. Generate an API key under **API Keys** +3. Go to https://openweathermap.org/api, find **One Call API 3.0**, click + **Subscribe**. The free tier requires entering payment info but does not + charge you below 1,000 calls/day. +4. Open the **Weather** tab in the LEDMatrix web UI (or edit + `config/config_secrets.json`) and paste the key into `api_key`. + +### Configuration options + +The plugin's full schema lives in +[`config_schema.json`](config_schema.json) — what you see in the web UI is +generated from it. The keys you'll touch most often: + +| Key | Default | Notes | +|---|---|---| +| `enabled` | `false` | Master switch | +| `api_key` | _required_ | One Call 3.0 key (store in `config_secrets.json`) | +| `location_city` | `"Dallas"` | City name | +| `location_state` | `"Texas"` | State/province (optional, helps US disambiguation) | +| `location_country` | `"US"` | ISO 3166-1 alpha-2 code | +| `units` | `"imperial"` | `"imperial"` (°F) or `"metric"` (°C) | +| `display_duration` | `30` | Seconds per mode (5–300) | +| `update_interval` | `1800` | Seconds between OpenWeatherMap fetches (min 300) | +| `display_format` | `"{temp}°F\n{condition}"` | Placeholders: `{temp}`, `{condition}`, `{humidity}`, `{wind}` | +| `show_current_weather` | `true` | Toggle current conditions mode | +| `show_hourly_forecast` | `true` | Toggle hourly mode | +| `show_daily_forecast` | `true` | Toggle daily mode | +| `show_almanac` | `true` | Toggle almanac mode (sun/moon) | +| `show_radar` | `true` | Toggle precipitation radar mode | +| `show_alerts` | `true` | Show active weather alerts (preempts rotation) | +| `show_feels_like` / `show_dew_point` / `show_visibility` / `show_pressure` | `true` | Extra current-conditions metrics (need height ≥ 48px) | +| `radar_zoom` | `6` | 4 (regional) to 8 (very close) | +| `radar_line_color` | `[0, 130, 70]` | RGB for state outlines | +| `radar_fill_color` | `[15, 25, 15]` | RGB for land fill (`[0,0,0]` = outlines only) | +| `radar_update_interval` | `600` | RainViewer refresh seconds (300–1800) | + +## Display modes + +The plugin registers these modes in `manifest.json` and the display +controller rotates through them in order: + +| Mode | Description | +|---|---| +| `weather` | Current conditions: temperature, icon, humidity, wind, plus optional feels-like / dew point / visibility / pressure on taller displays | +| `hourly_forecast` | Next ~24 hours | +| `daily_forecast` | 3–7 day high/low forecast | +| `almanac` | Sunrise, sunset, moon phase, day length | +| `radar` | Live precipitation radar from RainViewer | + +When an active weather alert is available and `show_alerts` is true, the +alert takes priority over the normal rotation. ## Usage -The plugin automatically rotates through enabled display modes based on the `display_duration` setting. +The plugin auto-rotates through enabled display modes based on +`display_duration`. Toggle individual modes on or off with the +`show_*` keys above (or the matching toggles in the web UI). ## Troubleshooting @@ -100,13 +128,18 @@ The plugin automatically rotates through enabled display modes based on the `dis - API has rate limits, respect the minimum update interval - Free tier allows 1000 calls/day -## API Rate Limits +## API rate limits -OpenWeatherMap free tier provides: -- 1,000 API calls per day +OpenWeatherMap One Call 3.0 free tier: +- 1,000 calls per day - 60 calls per minute -With default settings (1800s = 30 min intervals), this plugin uses ~48 calls per day. +With the default `update_interval` of 1800s (30 minutes), this plugin +makes about 48 calls per day. Lower the interval if you want fresher +data — just keep it ≥ 300s and watch your daily total. + +The radar mode uses RainViewer separately and has no API key, but obeys +`radar_update_interval` (default 600s) to avoid hammering their CDN. ## License diff --git a/plugins/masters-tournament/README.md b/plugins/masters-tournament/README.md index 209eeb1..3e16fdd 100644 --- a/plugins/masters-tournament/README.md +++ b/plugins/masters-tournament/README.md @@ -48,11 +48,12 @@ Authentic Augusta National visual identity: ### Via Plugin Store (Recommended) -1. Open LEDMatrix Web UI -2. Navigate to **Plugins** → **Plugin Store** -3. Find "Masters Tournament" -4. Click **Install** -5. Configure and enable +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **Masters Tournament** in the **Plugin Store** section and click + **Install** +4. Open the **Masters Tournament** tab in the second nav row to enable + and configure it ### Manual Installation diff --git a/plugins/news/README.md b/plugins/news/README.md index 8f134d1..03251b7 100644 --- a/plugins/news/README.md +++ b/plugins/news/README.md @@ -30,19 +30,25 @@ A plugin for LEDMatrix that displays scrolling news headlines from RSS feeds inc ### Global Settings -- `display_duration`: How long to show the ticker (10-300 seconds, default: 30) -- `display.scroll_speed`: Scrolling speed in pixels per frame (0.5-5.0, default: 1.0) - **Recommended format** -- `display.scroll_delay`: Delay between scroll steps in seconds (0.001-0.1, default: 0.01) - **Recommended format** -- `target_fps`: Target frames per second for scrolling (30-200, default: 100) -- `dynamic_duration`: Enable dynamic duration based on content width (default: true) - - `enabled`: Enable/disable dynamic duration (default: true) - - `min_duration_seconds`: Minimum display duration (10-300 seconds, default: 30) - - `max_duration_seconds`: Maximum display duration (30-600 seconds, default: 300) - - `buffer_ratio`: Extra buffer applied to calculated duration (0.01-1.0, default: 0.1) -- `rotation_enabled`: Enable headline rotation (default: true) -- `rotation_threshold`: Cycles before rotating headlines (1-10, default: 3) -- `headlines_per_feed`: Headlines to fetch per feed (1-10, default: 2) -- `font_size`: Font size for headlines (8-20, default: 12) +All scrolling/timing/font settings live under the `global.*` namespace +in [`config_schema.json`](config_schema.json) — that file is the source +of truth. The keys you'll touch most often: + +- `global.display_duration`: How long to show the ticker (10–300s, default 30) +- `global.update_interval`: Seconds between RSS fetches (default 300) +- `global.display.scroll_speed`: Pixels per frame (0.5–5.0, default 1.0) +- `global.display.scroll_delay`: Sleep between scroll steps in seconds (0.001–0.1, default 0.01) +- `global.target_fps`: Target frames per second cap (30–200, default 100) +- `global.font_size`: Headline font size (8–20, default 12) +- `global.font_path`: Path to TTF/BDF font (default `assets/fonts/PressStart2P-Regular.ttf`) +- `global.dynamic_duration`: Object — `enabled` (default `true`), + `min_duration_seconds` (default `30`), `max_duration_seconds` + (default `300`), `buffer_ratio` (default `0.1`) +- `global.rotation_enabled`: Enable headline rotation (default `true`) +- `global.rotation_threshold`: Cycles before rotating headlines (1–10, default 3) +- `global.headlines_per_feed`: Headlines to fetch per feed (1–10, default 2) +- `global.background_service.*`: Background fetch tuning — + `enabled`, `request_timeout`, `max_retries`, `priority` ### Feed Settings diff --git a/plugins/olympics/README.md b/plugins/olympics/README.md index a1f5ad8..1bbc952 100644 --- a/plugins/olympics/README.md +++ b/plugins/olympics/README.md @@ -35,8 +35,9 @@ Screenshot Preview: ### From Plugin Store (Recommended) 1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) -2. Go to **Plugin Store** -3. Find **Olympics Countdown** and click **Install** +2. Open the **Plugin Manager** tab +3. Find **Olympics Countdown** in the **Plugin Store** section and click + **Install** ### Manual Installation diff --git a/plugins/static-image/README.md b/plugins/static-image/README.md index 8110f99..0c76629 100644 --- a/plugins/static-image/README.md +++ b/plugins/static-image/README.md @@ -26,12 +26,12 @@ Display static images on your LED matrix with automatic scaling, aspect ratio pr ## Configuration -### Example Configuration +### Single image ```json { "enabled": true, - "image_path": "assets/static_images/my_logo.png", + "images": ["assets/static_images/my_logo.png"], "fit_to_display": true, "preserve_aspect_ratio": true, "background_color": [0, 0, 0], @@ -39,14 +39,55 @@ Display static images on your LED matrix with automatic scaling, aspect ratio pr } ``` +### Multiple images with rotation + +```json +{ + "enabled": true, + "images": [ + "assets/static_images/logo_a.png", + "assets/static_images/logo_b.png", + "assets/static_images/logo_c.png" + ], + "image_config": { + "mode": "single", + "rotation_mode": "sequential" + }, + "rotation_settings": { + "sequential_loop": true + }, + "image_rotation_interval": 15, + "fit_to_display": true, + "preserve_aspect_ratio": true, + "background_color": [0, 0, 0], + "display_duration": 30 +} +``` + ### Configuration Options -- `enabled`: Enable/disable the plugin -- `image_path`: Path to image file (relative or absolute) -- `fit_to_display`: Automatically fit image to display dimensions -- `preserve_aspect_ratio`: Maintain image proportions when scaling -- `background_color`: RGB color for transparent areas [R, G, B] -- `display_duration`: Seconds to display the image +The full schema lives in +[`config_schema.json`](config_schema.json) — the web UI form is generated +from it. Key options: + +| Key | Default | Notes | +|---|---|---| +| `enabled` | `false` | Master switch | +| `images` | `[]` | Array of image paths (relative to LEDMatrix root or absolute) | +| `image_config.mode` | `"single"` | How images are presented | +| `image_config.rotation_mode` | `"sequential"` | `"sequential"` or `"random"` when multiple images | +| `rotation_settings.sequential_loop` | `true` | Loop back to the first image after the last | +| `rotation_settings.random_seed` | `null` | Optional fixed seed for reproducible random order | +| `rotation_settings.time_intervals.enabled` | `false` | Tie image changes to wall-clock intervals | +| `rotation_settings.time_intervals.interval_seconds` | `3600` | Wall-clock interval when enabled | +| `image_rotation_interval` | `15` | Seconds between images during rotation | +| `fit_to_display` | `true` | Scale image to display dimensions | +| `preserve_aspect_ratio` | `true` | Don't stretch when scaling | +| `background_color` | `[0, 0, 0]` | RGB fill behind transparent pixels | +| `display_duration` | `10` | Seconds the plugin holds the screen each rotation | + +> **Legacy:** the plugin still accepts a single `image_path` string for +> backward compatibility, but new configs should use the `images` array. ## Usage @@ -93,7 +134,9 @@ plugin.reload_image() ### Multiple Images -To rotate through multiple images, create multiple plugin instances with different IDs: +Put all the images you want to cycle through into the `images` array (see +the multi-image example above). For older configs, you can still create +multiple plugin instances with different IDs: ```json { diff --git a/plugins/stock-news/manifest.json b/plugins/stock-news/manifest.json index 1c89c42..b96fed5 100644 --- a/plugins/stock-news/manifest.json +++ b/plugins/stock-news/manifest.json @@ -4,6 +4,8 @@ "version": "1.0.2", "author": "ChuckBuilds", "description": "Displays scrolling stock-specific news headlines and financial updates from RSS feeds, focused on market news and company updates", + "entry_point": "manager.py", + "class_name": "StockNewsTickerPlugin", "category": "financial", "tags": [ "stock", diff --git a/plugins/text-display/README.md b/plugins/text-display/README.md index 72cfced..ec1d78d 100644 --- a/plugins/text-display/README.md +++ b/plugins/text-display/README.md @@ -36,8 +36,11 @@ Display custom scrolling or static text messages on your LED matrix with configu "font_path": "assets/fonts/PressStart2P-Regular.ttf", "font_size": 8, "scroll": true, - "scroll_speed": 30, + "scroll_speed": 1, + "scroll_delay": 0.01, + "scroll_loop": true, "scroll_gap_width": 32, + "target_fps": 120, "text_color": [255, 0, 0], "background_color": [0, 0, 0], "display_duration": 10 @@ -46,16 +49,26 @@ Display custom scrolling or static text messages on your LED matrix with configu ### Configuration Options -- `enabled`: Enable/disable the plugin -- `text`: The message to display -- `font_path`: Path to TTF or BDF font file -- `font_size`: Font size in pixels (4-32) -- `scroll`: Enable scrolling animation -- `scroll_speed`: Scroll speed in pixels per second (1-200) -- `scroll_gap_width`: Gap between scroll repetitions in pixels -- `text_color`: RGB text color [R, G, B] -- `background_color`: RGB background color [R, G, B] -- `display_duration`: Display duration in seconds +The full schema lives in +[`config_schema.json`](config_schema.json) — the web UI form is generated +from it. Key options: + +| Key | Default | Notes | +|---|---|---| +| `enabled` | `false` | Master switch | +| `text` | `"Subscribe to ChuckBuilds"` | The message to display | +| `font_path` | `assets/fonts/PressStart2P-Regular.ttf` | Path to TTF or BDF font file | +| `font_size` | `8` | Font size in pixels | +| `scroll` | `true` | Enable horizontal scrolling animation | +| `scroll_speed` | `1` | Speed multiplier (≈ pixels per frame). Higher = faster. | +| `scroll_delay` | `0.01` | Sleep between scroll steps in seconds. Lower = smoother but more CPU | +| `scroll_loop` | `true` | Loop the text instead of stopping after one pass | +| `scroll_gap_width` | `32` | Pixels of empty space between scroll loops | +| `target_fps` | `120` | Target frames per second cap for scroll rendering | +| `text_color` | `[255, 255, 255]` | RGB text color | +| `background_color` | `[0, 0, 0]` | RGB background color | +| `display_duration` | `10` | Seconds the plugin holds the screen | +| `update_interval` | `60` | Seconds between plugin update ticks | ## Usage @@ -119,9 +132,14 @@ Optimized for LED matrices: ### For Scrolling Text -1. **Adjust speed for readability**: Slower speeds (20-40) are more readable -2. **Set appropriate gap**: Use gap equal to display width for smooth loops -3. **Test message length**: Very long messages may need speed adjustment +1. **Adjust speed for readability**: `scroll_speed` is a multiplier, not px/s. + Values around `1`–`2` are typical; higher values scroll faster. +2. **Tune smoothness with `scroll_delay`**: lower (0.005) = smoother but + more CPU; higher (0.05) = choppier but lighter. +3. **Set appropriate gap**: a `scroll_gap_width` equal to your display width + produces clean loops. +4. **Test message length**: very long messages benefit from a higher + `target_fps` cap and lower `scroll_delay`. ### For Static Text @@ -152,7 +170,7 @@ Optimized for LED matrices: { "text": "Breaking News: LED matrices are awesome! Stay tuned for more...", "scroll": true, - "scroll_speed": 35 + "scroll_speed": 1.5 } ``` @@ -161,7 +179,7 @@ Optimized for LED matrices: { "text": "Subscribe to ChuckBuilds on YouTube!", "scroll": true, - "scroll_speed": 40, + "scroll_speed": 2, "text_color": [255, 0, 0] } ``` @@ -174,8 +192,8 @@ Optimized for LED matrices: - Check font_path points to valid font file **Scrolling too fast/slow:** -- Adjust scroll_speed value -- Try values between 20-50 for best readability +- Adjust `scroll_speed` (multiplier, default `1`). Try values between `0.5` and `3`. +- For finer control, also tune `scroll_delay` and `target_fps`. **Font not loading:** - Verify font_path is correct @@ -190,9 +208,10 @@ Optimized for LED matrices: ## Performance Notes -- Scrolling text uses pre-rendered cache for smooth animation -- Update interval is 0.033s (~30 FPS) for smooth scrolling -- Text cache is created once and reused for efficiency +- Scrolling text uses a pre-rendered cache for smooth animation +- The render loop targets `target_fps` (default 120) and sleeps + `scroll_delay` between steps +- Text cache is created once at first render and reused - Font loading happens once at initialization ## License From 5d29ce4d3d90b266b85d10667ea0ad6ca9ef01ce Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 6 Apr 2026 21:39:40 -0400 Subject: [PATCH 02/15] docs: audit remaining plugin READMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round 2 of the docs refresh — covering the 13 plugin READMEs that weren't touched in the first PR commit, plus two plugins that were shipping without any README at all. Created from scratch (the plugins had no README) - plugins/f1-scoreboard/README.md: documents all 8 display modes (driver/constructor standings, recent_races, upcoming, qualifying, practice, sprint, calendar) and the full nested config from config_schema.json. Uses ESPN F1 endpoints; no API key. - plugins/ufc-scoreboard/README.md: documents the 3 modes (live/recent/ upcoming), favorite-fighters/weight-classes config, headshot auto-download to assets/sports/ufc_fighters/, and the switch/scroll display_mode toggle. Credits the original LegoGuy1000 PR #137. Schema-vs-README bug fixes - baseball-scoreboard: documented display modes were baseball_live/baseball_recent/baseball_upcoming. Real modes per manifest are 9 per-league granular modes (mlb_live/mlb_recent/ mlb_upcoming, milb_*, ncaa_baseball_*). Rewrote. - baseball-scoreboard: all 3 league config examples used display_modes: { live, recent, upcoming } but the real schema uses show_live/show_recent/show_upcoming with the show_ prefix. Fixed. - christmas-countdown: options section listed 3 keys but the schema has 10. Added a complete table including transition.{enabled,type, speed}, text_color, tree_color, tree_size, and high_performance_transitions. Also fixed a malformed code fence (orphan ``` with no opening pair). - mqtt-notifications: heading was "##This plugin is still under heavy development" (broken markdown - ## ran into the text). Promoted to a clean alpha warning. UI navigation fixes (real flow: Plugin Manager tab -> Plugin Store section -> Install -> open the plugin's tab in the second nav row) - baseball-scoreboard: replaced "Copy to ledmatrix-plugins/plugins/" - basketball-scoreboard: same - soccer-scoreboard: same - lacrosse-scoreboard: was using cp ... plugins/ (LEDMatrix dev-time fallback path) instead of the canonical plugin-repos/. Fixed. - odds-ticker: same - ledmatrix-leaderboard: same - mqtt-notifications: replaced "automatically discovered" install language with the real Plugin Manager flow - of-the-day: replaced fictional "Plugins tab -> Configure button" with the real per-plugin tab in the second nav row - web-ui-info: same fix Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/baseball-scoreboard/README.md | 46 +++++++----- plugins/basketball-scoreboard/README.md | 16 +++- plugins/christmas-countdown/README.md | 24 ++++-- plugins/f1-scoreboard/README.md | 98 +++++++++++++++++++++++++ plugins/lacrosse-scoreboard/README.md | 20 ++++- plugins/ledmatrix-leaderboard/README.md | 16 +++- plugins/mqtt-notifications/README.md | 18 +++-- plugins/odds-ticker/README.md | 16 +++- plugins/of-the-day/README.md | 23 +++--- plugins/soccer-scoreboard/README.md | 16 +++- plugins/ufc-scoreboard/README.md | 78 ++++++++++++++++++++ plugins/web-ui-info/README.md | 7 +- 12 files changed, 313 insertions(+), 65 deletions(-) create mode 100644 plugins/f1-scoreboard/README.md create mode 100644 plugins/ufc-scoreboard/README.md diff --git a/plugins/baseball-scoreboard/README.md b/plugins/baseball-scoreboard/README.md index a02477a..6471075 100644 --- a/plugins/baseball-scoreboard/README.md +++ b/plugins/baseball-scoreboard/README.md @@ -43,9 +43,9 @@ A plugin for LEDMatrix that displays live, recent, and upcoming baseball games a "enabled": true, "favorite_teams": ["NYY", "BOS", "LAD"], "display_modes": { - "live": true, - "recent": true, - "upcoming": true + "show_live": true, + "show_recent": true, + "show_upcoming": true }, "recent_games_to_show": 5, "upcoming_games_to_show": 10 @@ -61,9 +61,9 @@ A plugin for LEDMatrix that displays live, recent, and upcoming baseball games a "enabled": true, "favorite_teams": ["DUR", "SWB", "MEM"], "display_modes": { - "live": true, - "recent": true, - "upcoming": true + "show_live": true, + "show_recent": true, + "show_upcoming": true }, "recent_games_to_show": 5, "upcoming_games_to_show": 10 @@ -79,9 +79,9 @@ A plugin for LEDMatrix that displays live, recent, and upcoming baseball games a "enabled": true, "favorite_teams": ["LSU", "FLA", "VANDY"], "display_modes": { - "live": true, - "recent": true, - "upcoming": true + "show_live": true, + "show_recent": true, + "show_upcoming": true }, "recent_games_to_show": 5, "upcoming_games_to_show": 10 @@ -91,11 +91,15 @@ A plugin for LEDMatrix that displays live, recent, and upcoming baseball games a ## Display Modes -The plugin supports three display modes: +The plugin registers per-league granular modes in `manifest.json`. The +display controller rotates through any that are enabled: -1. **baseball_live**: Shows currently active games -2. **baseball_recent**: Shows recently completed games -3. **baseball_upcoming**: Shows scheduled upcoming games +**MLB:** `mlb_live`, `mlb_recent`, `mlb_upcoming` +**MiLB:** `milb_live`, `milb_recent`, `milb_upcoming` +**NCAA Baseball:** `ncaa_baseball_live`, `ncaa_baseball_recent`, `ncaa_baseball_upcoming` + +Toggle individual modes per league with the `show_live` / `show_recent` +/ `show_upcoming` flags inside each league's `display_modes` block. ## Team Abbreviations @@ -126,10 +130,18 @@ This plugin requires the main LEDMatrix installation and inherits functionality ## Installation -1. Copy this plugin directory to your `ledmatrix-plugins/plugins/` folder -2. Ensure the plugin is enabled in your LEDMatrix configuration -3. Configure your favorite teams and display preferences -4. Restart LEDMatrix to load the new plugin +The easiest way is the Plugin Store in the LEDMatrix web UI: + +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Baseball Scoreboard** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure favorite + teams and per-league preferences + +Manual install: copy this directory into your LEDMatrix +`plugins_directory` (default `plugin-repos/`) and restart the display +service. ## Troubleshooting diff --git a/plugins/basketball-scoreboard/README.md b/plugins/basketball-scoreboard/README.md index cf62aed..f2e34b1 100644 --- a/plugins/basketball-scoreboard/README.md +++ b/plugins/basketball-scoreboard/README.md @@ -304,10 +304,18 @@ This plugin requires the main LEDMatrix installation and inherits functionality ## Installation -1. Copy this plugin directory to your `ledmatrix-plugins/plugins/` folder -2. Ensure the plugin is enabled in your LEDMatrix configuration -3. Configure your favorite teams and display preferences -4. Restart LEDMatrix to load the new plugin +The easiest way is the Plugin Store in the LEDMatrix web UI: + +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Basketball Scoreboard** in the **Plugin Store** section and + click **Install** +4. Open the plugin's tab in the second nav row to configure favorite + teams and per-league preferences + +Manual install: copy this directory into your LEDMatrix +`plugins_directory` (default `plugin-repos/`) and restart the display +service. ## Game Limits Behavior diff --git a/plugins/christmas-countdown/README.md b/plugins/christmas-countdown/README.md index ebc8206..2267578 100644 --- a/plugins/christmas-countdown/README.md +++ b/plugins/christmas-countdown/README.md @@ -34,14 +34,22 @@ Screenshot of Christmas Countdown: The plugin supports the following configuration options: -### Basic Settings - -- `enabled` (boolean, default: `false`): Enable or disable the plugin -- `display_duration` (number, default: `15`): How long to display the countdown in seconds (1-300) -- `update_interval` (integer, default: `3600`): How often to update the countdown in seconds (60-86400). Default is 1 hour since the countdown changes daily. - - -``` +### Configuration options + +Full schema lives in [`config_schema.json`](config_schema.json): + +| Key | Default | Notes | +|---|---|---| +| `enabled` | `false` | Master switch | +| `display_duration` | `15` | Seconds the plugin holds the screen (1–300) | +| `update_interval` | `3600` | Seconds between updates (60–86400). Default 1 hour since the countdown only changes daily. | +| `high_performance_transitions` | `false` | Use a faster path for transitions on weaker Pis | +| `transition.enabled` | `true` | Toggle transition animation between displays | +| `transition.type` | `"redraw"` | Transition style | +| `transition.speed` | `2` | Animation speed | +| `text_color` | `[255, 0, 0]` | RGB color for the countdown text (default red) | +| `tree_color` | `[0, 128, 0]` | RGB color for the programmatically-drawn tree (default green) | +| `tree_size` | _auto_ | Override the auto-sized tree height in pixels | ## Display Behavior diff --git a/plugins/f1-scoreboard/README.md b/plugins/f1-scoreboard/README.md new file mode 100644 index 0000000..3e97a99 --- /dev/null +++ b/plugins/f1-scoreboard/README.md @@ -0,0 +1,98 @@ +# F1 Scoreboard Plugin + +A Formula 1 plugin for LEDMatrix that displays driver and constructor +standings, race results, qualifying and practice times, sprint results, +upcoming races, and the season calendar — with team-colored visuals and +favorite-driver/team highlighting. + +Data comes from the public ESPN F1 endpoints; no API key is required. + +## Features + +- **Driver standings** with optional always-show-favorite +- **Constructor standings** with team colors +- **Recent races** with podium and your favorite's finish +- **Upcoming race** card with countdown and session times +- **Qualifying** results (Q1 / Q2 / Q3 with gaps) +- **Practice** sessions (FP1 / FP2 / FP3) with configurable depth +- **Sprint** results +- **Season calendar** with optional sprint/qualifying flags +- Per-element font and color customization +- No API key required + +## Installation + +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **F1 Scoreboard** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure your + favorite driver/team and toggle which sections appear + +## Display Modes + +The plugin registers eight granular modes in `manifest.json`. The +display controller rotates through any that are enabled in your config: + +| Mode | Section | +|---|---| +| `f1_driver_standings` | Driver standings | +| `f1_constructor_standings` | Constructor standings | +| `f1_recent_races` | Recent race results | +| `f1_upcoming` | Next race card with countdown | +| `f1_qualifying` | Qualifying session results | +| `f1_practice` | Practice session standings | +| `f1_sprint` | Sprint race results | +| `f1_calendar` | Season schedule overview | + +## Configuration + +The full schema lives in +[`config_schema.json`](config_schema.json) — the web UI form is generated +from it. The most-used keys: + +| Key | Default | Notes | +|---|---|---| +| `enabled` | `true` | Master switch | +| `display_duration` | `30` | Seconds per section | +| `update_interval` | `3600` | Seconds between data fetches | +| `favorite_team` | `""` | Constructor abbreviation (e.g. `MER`, `RBR`) | +| `favorite_driver` | `""` | Driver code (e.g. `VER`, `HAM`, `LEC`) | +| `driver_standings.enabled` | `true` | Toggle driver standings mode | +| `driver_standings.top_n` | `10` | How many drivers to show | +| `driver_standings.always_show_favorite` | `true` | Always include your favorite even if outside top N | +| `constructor_standings.*` | mirrors `driver_standings.*` | | +| `recent_races.number_of_races` | `3` | How many past races to cycle through | +| `recent_races.top_finishers` | `3` | Top N finishers per race | +| `upcoming.show_session_times` | `true` | Show practice/qualifying/race times | +| `upcoming.countdown_enabled` | `true` | Live countdown to next race | +| `qualifying.show_q1` / `show_q2` / `show_q3` | `true` | Toggle each Q session | +| `qualifying.show_gaps` | `true` | Show gap to pole | +| `practice.sessions_to_show` | `["FP1","FP2","FP3"]` | Which practice sessions to render | +| `practice.top_n` | `10` | Drivers per practice session | +| `sprint.top_finishers` | `10` | Sprint result depth | +| `calendar.max_events` | `5` | Races per calendar view | +| `calendar.show_practice` / `show_qualifying` / `show_sprint` | varies | Calendar detail toggles | +| `dynamic_duration.enabled` | `true` | Cycle through more content per slot | +| `dynamic_duration.max_duration_seconds` | `120` | Cap for dynamic-duration sessions | +| `scroll.scroll_speed` / `scroll.scroll_delay` | `1` / `0.03` | Scroll tuning | +| `customization.*` | various | Per-element font and color overrides | + +### Driver / team codes + +Use the standard F1 three-letter codes: + +- **Drivers**: `VER`, `HAM`, `LEC`, `NOR`, `RUS`, `SAI`, `PER`, `ALO`, etc. +- **Constructors**: `MER` (Mercedes), `RBR` (Red Bull), `FER` (Ferrari), + `MCL` (McLaren), `AST` (Aston Martin), `ALP` (Alpine), `WIL` (Williams), + `STA` (Stake), `RB`, `HAA` (Haas) + +## Data source + +ESPN's public Formula 1 endpoints. No API key required. Cached locally +to keep request volume low — adjust `update_interval` if you need fresher +data. + +## License + +GPL-3.0, same as the LEDMatrix project. diff --git a/plugins/lacrosse-scoreboard/README.md b/plugins/lacrosse-scoreboard/README.md index 335e3b4..a4d45b0 100644 --- a/plugins/lacrosse-scoreboard/README.md +++ b/plugins/lacrosse-scoreboard/README.md @@ -27,17 +27,29 @@ No API key is required. ## Installation -The plugin is installable from the LEDMatrix plugin store — search for **Lacrosse Scoreboard** and enable it. On first launch, team logos for any teams appearing in the current scoreboard window will be downloaded to `assets/sports/ncaa_logos/` automatically. +The easiest way is the Plugin Store in the LEDMatrix web UI: -To install manually from source: +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Lacrosse Scoreboard** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure favorite + teams + +On first launch, team logos for any teams in the current scoreboard +window will be downloaded to `assets/sports/ncaa_logos/` automatically. + +Manual install from source: ```bash cd /path/to/LEDMatrix python -m pip install --user pillow requests pytz # see requirements.txt -cp -r /path/to/ledmatrix-plugins/plugins/lacrosse-scoreboard plugins/ +cp -r /path/to/ledmatrix-plugins/plugins/lacrosse-scoreboard plugin-repos/ +sudo systemctl restart ledmatrix ``` -Then add a `lacrosse-scoreboard` entry to your LEDMatrix `config.json` (see **Configuration** below) and restart the LEDMatrix service. +Then add a `lacrosse-scoreboard` entry to your LEDMatrix `config.json` +(see **Configuration** below) — or just use the web UI to configure it. ## Dependencies diff --git a/plugins/ledmatrix-leaderboard/README.md b/plugins/ledmatrix-leaderboard/README.md index 90b264d..74dfe28 100644 --- a/plugins/ledmatrix-leaderboard/README.md +++ b/plugins/ledmatrix-leaderboard/README.md @@ -183,10 +183,18 @@ This plugin requires the main LEDMatrix installation and uses the cache manager ## Installation -1. Copy this plugin directory to your `ledmatrix-plugins/plugins/` folder -2. Ensure the plugin is enabled in your LEDMatrix configuration -3. Configure your preferred leagues and display options -4. Restart LEDMatrix to load the new plugin +The easiest way is the Plugin Store in the LEDMatrix web UI: + +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Sports Leaderboard** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure leagues and + display options + +Manual install: copy this directory into your LEDMatrix +`plugins_directory` (default `plugin-repos/`) and restart the display +service. ## Troubleshooting diff --git a/plugins/mqtt-notifications/README.md b/plugins/mqtt-notifications/README.md index f707116..6948e8b 100644 --- a/plugins/mqtt-notifications/README.md +++ b/plugins/mqtt-notifications/README.md @@ -13,9 +13,13 @@ # MQTT Notifications Plugin -##This plugin is still under heavy development and may not work. +> ⚠️ **Alpha**: This plugin is still under active development and may not +> work reliably yet. Expect rough edges and configuration changes. -Display text or images from HomeAssistant via MQTT. This plugin supports dynamic topic configuration with wildcard support, allowing you to send notifications from any MQTT topic that interrupt the normal display rotation to show important messages. +Display text or images from Home Assistant (or any MQTT publisher) by +subscribing to configurable MQTT topics. Incoming notifications interrupt +the normal display rotation via the on-demand display system to show +important messages. ## Features @@ -28,9 +32,13 @@ Display text or images from HomeAssistant via MQTT. This plugin supports dynamic ## Installation -1. The plugin will be automatically discovered by LEDMatrix -2. Dependencies will be installed automatically from `requirements.txt` -3. Configure the plugin in `config/config.json` +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **MQTT Notifications** in the **Plugin Store** section and click + **Install**. Dependencies (`paho-mqtt`, etc.) install automatically + from `requirements.txt` on first load. +4. Open the plugin's tab in the second nav row to configure your MQTT + broker, credentials, and topic subscriptions. ## Configuration diff --git a/plugins/odds-ticker/README.md b/plugins/odds-ticker/README.md index 3e5c2bb..96fcca3 100644 --- a/plugins/odds-ticker/README.md +++ b/plugins/odds-ticker/README.md @@ -162,10 +162,18 @@ This plugin requires the main LEDMatrix installation and uses the OddsManager fo ## Installation -1. Copy this plugin directory to your `ledmatrix-plugins/plugins/` folder -2. Ensure the plugin is enabled in your LEDMatrix configuration -3. Configure your favorite teams and display preferences -4. Restart LEDMatrix to load the new plugin +The easiest way is the Plugin Store in the LEDMatrix web UI: + +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Odds Ticker** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure leagues, + favorite teams, and display preferences + +Manual install: copy this directory into your LEDMatrix +`plugins_directory` (default `plugin-repos/`) and restart the display +service. ## Troubleshooting diff --git a/plugins/of-the-day/README.md b/plugins/of-the-day/README.md index f811e9b..e9f2f0d 100644 --- a/plugins/of-the-day/README.md +++ b/plugins/of-the-day/README.md @@ -17,18 +17,17 @@ Display daily featured content like Word of the Day, Bible verses, or custom dai This plugin is fully configurable through the LEDMatrix web interface: -1. Navigate to the **Plugins** tab in the web UI -2. Find "Of The Day Display" in the installed plugins list -3. Click **Configure** to open the plugin's configuration tab -4. Adjust settings using the auto-generated form: - - Enable/disable the plugin - - Configure update intervals - - Set display rotation timings - - Manage categories (enable/disable, set display names) - - Adjust display duration -5. Click **Save Configuration** to apply changes - -The web UI automatically generates a configuration form from the plugin's `config_schema.json`, including support for nested category configurations with collapsible sections. +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab and install **Of The Day Display** + from the **Plugin Store** section if it isn't already +3. Open the **Of The Day Display** tab in the second nav row +4. Adjust settings using the auto-generated form (enable/disable + categories, update intervals, rotation timings, display duration) +5. Click **Save** + +The web UI form is generated directly from +[`config_schema.json`](config_schema.json), including the nested +category configurations with collapsible sections. ### Example Configuration diff --git a/plugins/soccer-scoreboard/README.md b/plugins/soccer-scoreboard/README.md index e38b4e6..7a81f0d 100644 --- a/plugins/soccer-scoreboard/README.md +++ b/plugins/soccer-scoreboard/README.md @@ -217,10 +217,18 @@ This plugin requires the main LEDMatrix installation and uses the plugin system ## Installation -1. Copy this plugin directory to your `ledmatrix-plugins/plugins/` folder -2. Ensure the plugin is enabled in your LEDMatrix configuration -3. Configure your favorite teams and display preferences -4. Restart LEDMatrix to load the new plugin +The easiest way is the Plugin Store in the LEDMatrix web UI: + +1. Open `http://your-pi-ip:5000` +2. Open the **Plugin Manager** tab +3. Find **Soccer Scoreboard** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure leagues and + favorite teams + +Manual install: copy this directory into your LEDMatrix +`plugins_directory` (default `plugin-repos/`) and restart the display +service. ## Troubleshooting diff --git a/plugins/ufc-scoreboard/README.md b/plugins/ufc-scoreboard/README.md new file mode 100644 index 0000000..ba42dad --- /dev/null +++ b/plugins/ufc-scoreboard/README.md @@ -0,0 +1,78 @@ +# UFC Scoreboard Plugin + +A UFC/MMA plugin for LEDMatrix that displays live, recent, and upcoming +fights with fighter headshots, records, odds, and results. + +> Originally contributed by Alex Resnick +> ([@legoguy1000](https://github.com/legoguy1000)) — see +> [PR #137](https://github.com/ChuckBuilds/LEDMatrix/pull/137). + +## Features + +- **Live fight tracking** — current fights with round and time remaining +- **Recent fights** — results from completed events +- **Upcoming fights** — scheduled cards with start times +- **Fighter headshots** downloaded automatically on first display +- **Records and odds** alongside fighter info +- **Favorite fighters and weight classes** for prioritized display +- No API key required + +## Installation + +1. Open the LEDMatrix web interface (`http://your-pi-ip:5000`) +2. Open the **Plugin Manager** tab +3. Find **UFC Scoreboard** in the **Plugin Store** section and click + **Install** +4. Open the plugin's tab in the second nav row to configure favorite + fighters and weight classes + +## Display Modes + +The plugin registers three modes in `manifest.json`: + +| Mode | Description | +|---|---| +| `ufc_live` | Currently active fights with round/time remaining | +| `ufc_recent` | Recently completed fights with method/round of finish | +| `ufc_upcoming` | Scheduled fights with cards and start times | + +## Configuration + +The full schema lives in +[`config_schema.json`](config_schema.json) — the web UI form is generated +from it. The most-used keys: + +| Key | Default | Notes | +|---|---|---| +| `enabled` | `true` | Master switch | +| `display_duration` | `30` | Seconds per mode | +| `update_interval` | `3600` | Seconds between data fetches | +| `game_display_duration` | `15` | Seconds per individual fight in switch mode | +| `ufc.enabled` | `true` | Toggle UFC content | +| `ufc.favorite_fighters` | `[]` | Array of fighter names to prioritize (e.g. `["Jon Jones", "Islam Makhachev"]`) | +| `ufc.favorite_weight_classes` | `[]` | Weight classes to prioritize (e.g. `["Heavyweight", "Lightweight"]`) | +| `ufc.display_modes.show_live` | `true` | Toggle live mode | +| `ufc.display_modes.show_recent` | `true` | Toggle recent mode | +| `ufc.display_modes.show_upcoming` | `true` | Toggle upcoming mode | +| `ufc.display_modes.live_display_mode` | `"switch"` | `"switch"` (one fight at a time) or `"scroll"` | +| `ufc.display_modes.recent_display_mode` | `"switch"` | Same options for recent mode | + +For the full set of nested keys (scroll tuning, display durations, +update intervals, customization fonts/colors), see +[`config_schema.json`](config_schema.json). + +## Fighter headshots + +On first display the plugin downloads fighter headshots into +`assets/sports/ufc_fighters/`. This requires write access to the +LEDMatrix assets directory and an internet connection. If a headshot +fails to download, the plugin falls back to a placeholder icon. + +## Data source + +ESPN's public MMA endpoints. No API key required. Be mindful of +`update_interval` — the default of 3600s is suitable for normal use. + +## License + +GPL-3.0, same as the LEDMatrix project. diff --git a/plugins/web-ui-info/README.md b/plugins/web-ui-info/README.md index 14ed9ab..414864f 100644 --- a/plugins/web-ui-info/README.md +++ b/plugins/web-ui-info/README.md @@ -39,9 +39,10 @@ The plugin will automatically be discovered and loaded when the LEDMatrix system To enable/disable the plugin: 1. Open the web UI at `http://[your-device]:5000` -2. Navigate to the Plugins tab -3. Find "Web UI Info" in the plugin list -4. Toggle the enable/disable checkbox +2. Open the **Plugin Manager** tab +3. Find **Web UI Info** in the **Installed Plugins** list and toggle it + on or off +4. Restart the display service from the **Overview** tab ## Device ID From b2f76c1e3d9a1e48fea004afa85c5d68fb987b24 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 09:53:49 -0400 Subject: [PATCH 03/15] docs: fix plugin sub-docs (QUICK_START, STANDALONE, TESTING) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are the non-README docs that ship inside individual plugin directories. Triaged with grep, deep-audited the ones with hits or that I knew were likely to have stale class names. plugins/hello-world/QUICK_START.md - Port 5001 -> 5000 (×2 in curl examples) - /api/plugins/* -> /api/v3/plugins/* (×2) - "Discovered plugin: hello-world v1.0.0" example log -> v1.0.2 to match the current manifest version (after the iter 1 fix) - "python test/test_plugin_system.py" referenced a LEDMatrix-repo test file from inside a plugin's QUICK_START — that doesn't make sense (the user is on the plugins repo). Removed the section, replaced with the simpler journalctl + curl flow that actually works from a fresh install. - "ssh pi@your-pi-ip" -> "ssh ledpi@your-pi-ip" (the documented default username throughout the rest of LEDMatrix) - Broken link to ../../docs/PLUGIN_PHASE_1_SUMMARY.md (file doesn't exist anywhere in LEDMatrix). Replaced with an absolute link to docs/PLUGIN_DEVELOPMENT_GUIDE.md. - Added a one-line install-via-Plugin-Manager intro before the manual config-editing example, since the Plugin Store is now the recommended path. plugins/basketball-scoreboard/STANDALONE.md - Class name was wrong throughout: "BasketballPluginManager" vs the actual "BasketballScoreboardPlugin" in manager.py:50. The wrong name was the same bug pattern as hello-world's manifest issue — if anyone copied the name to register the class, it would AttributeError at load. Fixed all 4 occurrences via replace_all. - "Configuration" example used flat top-level keys (nba_enabled, nba_favorite_teams, nba_display_modes_live). The real schema nests them under nba.{enabled, favorite_teams, display_modes.show_*} (verified in manager.py:94 reads config.get("nba", {}).get("enabled")). Replaced with the real nested form. plugins/basketball-scoreboard/TESTING.md - Same wrong class name in expected test output. Fixed. - "Multiple inheritance works correctly (BasePlugin + Basketball)" — contradicts STANDALONE.md and reality. The plugin only inherits from BasePlugin (no Basketball base class). Fixed and pointed at STANDALONE.md. Verified clean (no fixes needed): - baseball-scoreboard/CHANGELOG.md (historical, leave as-is) - football-scoreboard/CHANGELOG.md (historical, leave as-is) - football-scoreboard/DYNAMIC_DURATION.md (uses flat keys early but shows real nested examples further down — internally consistent) - ledmatrix-weather/CHANGELOG.md (historical) Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/basketball-scoreboard/STANDALONE.md | 27 ++++++++++++------ plugins/basketball-scoreboard/TESTING.md | 4 +-- plugins/hello-world/QUICK_START.md | 31 +++++++++++---------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/plugins/basketball-scoreboard/STANDALONE.md b/plugins/basketball-scoreboard/STANDALONE.md index d5b32f9..069cb4f 100644 --- a/plugins/basketball-scoreboard/STANDALONE.md +++ b/plugins/basketball-scoreboard/STANDALONE.md @@ -8,7 +8,7 @@ The basketball plugin has been redesigned to be completely independent and not r ### Core Components -1. **`manager.py`** - Main plugin class (BasketballPluginManager) +1. **`manager.py`** - Main plugin class (BasketballScoreboardPlugin) - Only inherits from `BasePlugin` (plugin system requirement) - Contains all basketball-specific logic - Handles data fetching, game filtering, and display @@ -32,7 +32,7 @@ The basketball plugin has been redesigned to be completely independent and not r ### Before (with base classes) ```python -class BasketballPluginManager(BasePlugin, Basketball): +class BasketballScoreboardPlugin(BasePlugin, Basketball): # Inherited from Basketball base class: # - Font loading # - Logo loading @@ -43,7 +43,7 @@ class BasketballPluginManager(BasePlugin, Basketball): ### Now (standalone) ```python -class BasketballPluginManager(BasePlugin): +class BasketballScoreboardPlugin(BasePlugin): # Uses BasketballHelpers for: # - Font loading # - Logo loading @@ -73,7 +73,7 @@ python3 test_plugin_syntax.py Expected output: ``` ✓ Plugin imported successfully -✓ Class name: BasketballPluginManager +✓ Class name: BasketballScoreboardPlugin ✓ Base classes: (,) Plugin structure is valid! ``` @@ -108,13 +108,22 @@ All functionality from the old basketball managers is preserved: ## Configuration -Works exactly like the original, with per-league configuration: +Works with per-league nested configuration. The full schema lives in +[`config_schema.json`](config_schema.json); a minimal example: ```json { - "nba_enabled": true, - "nba_favorite_teams": ["LAL", "BOS"], - "nba_display_modes_live": true, - "ncaam_basketball_enabled": false + "nba": { + "enabled": true, + "favorite_teams": ["LAL", "BOS"], + "display_modes": { + "show_live": true, + "show_recent": true, + "show_upcoming": true + } + }, + "ncaam": { + "enabled": false + } } ``` diff --git a/plugins/basketball-scoreboard/TESTING.md b/plugins/basketball-scoreboard/TESTING.md index 9f970a1..7216f7c 100644 --- a/plugins/basketball-scoreboard/TESTING.md +++ b/plugins/basketball-scoreboard/TESTING.md @@ -16,7 +16,7 @@ python3 test_plugin_syntax.py Expected output: ``` ✓ Plugin imported successfully -✓ Class name: BasketballPluginManager +✓ Class name: BasketballScoreboardPlugin ✓ Base classes: (...) Plugin structure is valid! ``` @@ -49,7 +49,7 @@ The plugin is now **standalone** and does not depend on Basketball or Sports bas ## Plugin Features Tested - ✅ Plugin imports without errors -- ✅ Multiple inheritance works correctly (BasePlugin + Basketball) +- ✅ Inherits from BasePlugin only (no Basketball base class — see STANDALONE.md) - ✅ Configuration loading for all leagues (NBA, WNBA, NCAA M/W) - ✅ Display mode configuration (live, recent, upcoming) - ✅ League enable/disable functionality diff --git a/plugins/hello-world/QUICK_START.md b/plugins/hello-world/QUICK_START.md index 0fc447b..451defc 100644 --- a/plugins/hello-world/QUICK_START.md +++ b/plugins/hello-world/QUICK_START.md @@ -2,7 +2,13 @@ ## 🚀 Enable the Plugin -Add this to your `config/config.json`: +The easiest way is the Plugin Store in the LEDMatrix web UI: open the +**Plugin Manager** tab, find **Hello World** in the **Plugin Store** +section, and click **Install**. The configuration form for the plugin +then appears in the second nav row. + +If you prefer to edit the config file directly, add this to your +`config/config.json`: ```json { @@ -28,31 +34,26 @@ All plugin system tests passed: ## 📋 Verify Plugin is Working -### 1. Check Plugin Discovery (Windows) -```bash -python test/test_plugin_system.py -``` - -### 2. Check on Raspberry Pi +### 1. Check on Raspberry Pi ```bash # SSH into your Pi -ssh pi@your-pi-ip +ssh ledpi@your-pi-ip # Check if plugin is discovered sudo journalctl -u ledmatrix -n 50 | grep "hello-world" -# Should see: -# Discovered plugin: hello-world v1.0.0 +# Should see something like: +# Discovered plugin: hello-world v1.0.2 # Loaded plugin: hello-world ``` -### 3. Via Web API +### 2. Via Web API ```bash # List installed plugins -curl http://localhost:5001/api/plugins/installed +curl http://localhost:5000/api/v3/plugins/installed # Enable the plugin -curl -X POST http://localhost:5001/api/plugins/toggle \ +curl -X POST http://localhost:5000/api/v3/plugins/toggle \ -H "Content-Type: application/json" \ -d '{"plugin_id": "hello-world", "enabled": true}' ``` @@ -127,5 +128,7 @@ plugins/hello-world/ --- -**Need Help?** Check the main [README.md](README.md) or [Plugin System Documentation](../../docs/PLUGIN_PHASE_1_SUMMARY.md) +**Need Help?** Check the main [README.md](README.md) or the +[Plugin Development Guide](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/PLUGIN_DEVELOPMENT_GUIDE.md) +in the LEDMatrix repo. From 64ce9aa9b730fc8ffc5287eb065d8aa5c3bb1ead Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 13:08:26 -0400 Subject: [PATCH 04/15] Add CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, PR template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tier 1 organizational files mirroring the set added to the LEDMatrix repo. Additive — no existing content was rewritten. The plugins repo already has a LICENSE (GPL-3.0), so no LICENSE file is needed here. CONTRIBUTING.md - The repository had no CONTRIBUTING file. New plugin authors had to reconstruct the dev workflow from SUBMISSION.md, VERIFICATION.md, and the LEDMatrix repo's plugin development guide. - Covers: repo layout, dev environment setup (cloning both repos, the symlink + dev_server flow), the per-plugin update workflow (especially the version bump requirement that the Plugin Store relies on), the new-plugin submission flow, commit message convention, and license terms. CODE_OF_CONDUCT.md - Contributor Covenant 2.1, the de facto standard for open-source projects. Same content as the one added to LEDMatrix. SECURITY.md - Plugin-specific framing: routes core LEDMatrix issues to the LEDMatrix repo's SECURITY.md and keeps this file scoped to plugin code in this repo. Documents the same "no sandboxing" reality that LEDMatrix's SECURITY.md flags — plugins run in the same process as the display loop with full file/network access. - Out-of-scope section explicitly routes Python dep vulnerabilities to the upstream package maintainer and third-party plugin issues to the plugin's own repo. .github/PULL_REQUEST_TEMPLATE.md - More plugin-aware than the LEDMatrix template. Calls out the exact bugs found earlier in this PR series: - "Bumped version in manifest.json" (the Plugin Store only ships updates when the version increases, so forgetting this means the fix never reaches users) - "class_name matches the actual class in manager.py exactly, case-sensitive, no spaces" (the hello-world bug) - "entry_point matches the real file or is omitted" (the stock-news bug) - "config_schema.json is the source of truth" (the source of drift in many of the plugin READMEs I rewrote) - Has a separate SUBMISSION checklist block for new-plugin PRs. README.md - Added pointers to CONTRIBUTING.md, SECURITY.md, and SUBMISSION.md in the Support & Community section. The license section already existed. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/PULL_REQUEST_TEMPLATE.md | 81 +++++++++++++++++ CODE_OF_CONDUCT.md | 137 +++++++++++++++++++++++++++++ CONTRIBUTING.md | 145 +++++++++++++++++++++++++++++++ README.md | 5 ++ SECURITY.md | 84 ++++++++++++++++++ 5 files changed, 452 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..eddfc65 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,81 @@ +# Pull Request + +## Summary + + + +## Type of change + + + +- [ ] Bug fix in an existing plugin +- [ ] New plugin (also fill out the SUBMISSION.md checklist below) +- [ ] New feature for an existing plugin +- [ ] Documentation only +- [ ] Repo-wide change (registry script, hook, top-level docs) + +## Plugin(s) affected + + + +## Related issues + + + +## Test plan + + + +- [ ] Loaded the plugin in LEDMatrix on real hardware +- [ ] Loaded the plugin in LEDMatrix emulator mode + (`EMULATOR=true python3 run.py`) +- [ ] Rendered the plugin in the dev preview server + (`scripts/dev_server.py`) +- [ ] Verified the web UI configuration form against the schema +- [ ] N/A — repo-wide / docs-only change + +## Required for plugin changes + +- [ ] **Bumped `version` in `plugins//manifest.json`** + (the Plugin Store uses version comparison to ship updates — + forgetting this means users won't receive the change) +- [ ] `class_name` in `manifest.json` matches the actual class in + `manager.py` exactly (case-sensitive, no spaces) +- [ ] `entry_point` matches the real file (or is omitted to use + the `manager.py` default) +- [ ] Updated the plugin's `README.md` if config keys changed +- [ ] `config_schema.json` is the source of truth for the web UI + form — any new option is in the schema with a `default`, + `description`, and constraints +- [ ] Pre-commit hook ran successfully (auto-syncs `plugins.json`) + +## SUBMISSION checklist (new plugins only) + + + +- [ ] Plugin id matches the directory name and is unique +- [ ] `manifest.json` has all required fields (`id`, `name`, + `version`, `class_name`, `display_modes`) +- [ ] `manager.py` inherits from `BasePlugin` and implements + `update()` and `display()` +- [ ] `config_schema.json` exists and validates as JSON Schema Draft-7 +- [ ] `requirements.txt` lists all Python dependencies +- [ ] `README.md` documents what the plugin does, how to install, + and the configuration options +- [ ] `LICENSE` is GPL-3.0 (or compatible) +- [ ] No hardcoded API keys or secrets — secrets go in + `config/config_secrets.json` under the plugin id +- [ ] Tested on a real LEDMatrix setup (or in the emulator) + +## Checklist + +- [ ] My commits follow the message convention in `CONTRIBUTING.md` +- [ ] I read `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` +- [ ] I've not committed any secrets + +## Notes for reviewer + + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a1594b7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,137 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +This includes the LEDMatrix Discord server, GitHub repositories owned by +ChuckBuilds, and any other forums hosted by or affiliated with the project. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement on the +[LEDMatrix Discord](https://discord.gg/uW36dVAtcT) (DM a moderator or +ChuckBuilds directly) or by opening a private GitHub Security Advisory if +the issue involves account safety. All complaints will be reviewed and +investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available +at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..df0afe3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,145 @@ +# Contributing to ledmatrix-plugins + +This is the official plugin monorepo for +[LEDMatrix](https://github.com/ChuckBuilds/LEDMatrix). Contributions are +welcome — bug reports, plugin updates, brand-new plugins, and +documentation fixes all help. + +## Quick links + +- **Plugin submission flow**: see [SUBMISSION.md](SUBMISSION.md) +- **Plugin verification checklist**: see [VERIFICATION.md](VERIFICATION.md) +- **Real-time discussion**: the + [LEDMatrix Discord](https://discord.gg/uW36dVAtcT) +- **Bugs / feature requests**: + [open an issue](https://github.com/ChuckBuilds/ledmatrix-plugins/issues) +- **Security issues**: see [SECURITY.md](SECURITY.md). Don't open + public issues for vulnerabilities. + +## Repository layout + +``` +ledmatrix-plugins/ +├── plugins/ +│ └── / +│ ├── manifest.json # Plugin metadata, entry point, class name +│ ├── manager.py # Plugin class (inherits from BasePlugin) +│ ├── config_schema.json # JSON Schema for the web UI form +│ ├── requirements.txt # Python deps +│ ├── README.md # User-facing docs +│ └── LICENSE # Per-plugin license (usually GPL-3.0) +├── plugins.json # Auto-generated registry consumed by the Plugin Store +├── update_registry.py # Syncs plugins.json from manifests +├── scripts/ +│ └── pre-commit # Git hook that auto-runs update_registry.py +└── docs/ # Plugin Store and contributor docs +``` + +## Setting up a development environment + +You'll typically work on a plugin alongside the main LEDMatrix repo: + +```bash +# Clone both repos +git clone https://github.com/ChuckBuilds/LEDMatrix.git +git clone https://github.com/ChuckBuilds/ledmatrix-plugins.git + +# Symlink the plugin you want to work on into LEDMatrix's +# plugin loader path. Default plugin location in LEDMatrix is +# plugin-repos/ (or plugins/ as a fallback for the dev workflow). +cd LEDMatrix +ln -s ../ledmatrix-plugins/plugins/ plugin-repos/ + +# Test without hardware +python3 scripts/dev_server.py # then open http://localhost:5001 +# Or test the plugin in the full emulator path +EMULATOR=true python3 run.py +``` + +For a more managed dev setup, LEDMatrix ships +`scripts/dev/dev_plugin_setup.sh` which automates the symlink + clone +flow. See LEDMatrix's +[`docs/PLUGIN_DEVELOPMENT_GUIDE.md`](https://github.com/ChuckBuilds/LEDMatrix/blob/main/docs/PLUGIN_DEVELOPMENT_GUIDE.md). + +## Working on an existing plugin + +1. **Open an issue first** if the change is non-trivial. This avoids + wasted work on PRs that don't fit the project direction. +2. **Branch off `main`**: `fix/-` or + `feat/-`. +3. **Make your changes** in `plugins//`. +4. **Bump the version in `manifest.json`.** This is critical — the + Plugin Store uses version comparison (manifest version vs + `plugins.json` `latest_version`) to decide whether to ship updates + to users. If you forget, users won't receive your fix. + - **Patch** (1.0.0 → 1.0.1): bug fixes, doc tweaks + - **Minor** (1.0.0 → 1.1.0): new features, schema additions + - **Major** (1.0.0 → 2.0.0): breaking config changes +5. **Update the plugin's README** if you added/changed config keys. + The web UI form is generated from `config_schema.json`, so the + schema is the source of truth — README tables should match. +6. **Commit.** The pre-commit hook automatically runs + `update_registry.py` and stages `plugins.json`. If the hook isn't + installed, run `cp scripts/pre-commit .git/hooks/pre-commit`. +7. **Open a PR** using the template in + `.github/PULL_REQUEST_TEMPLATE.md`. + +## Adding a new plugin + +See [SUBMISSION.md](SUBMISSION.md) for the full submission flow. The +short version: + +1. Copy the + [`plugins/hello-world/`](plugins/hello-world/) directory as a + starting template — it's intentionally tiny and well-commented. +2. Rename the directory to your plugin id (lowercase, hyphens, e.g. + `my-cool-plugin`). +3. Update `manifest.json`: + - `id` must match the directory name + - `class_name` must match the actual class name in `manager.py` + **exactly** (case-sensitive, no spaces — see + [VERIFICATION.md](VERIFICATION.md) for why this matters) + - Set `entry_point` (defaults to `manager.py` if omitted) + - Set `version`, `author`, `category`, `tags`, `display_modes` +4. Implement `update()` and `display()` in your plugin class. +5. Define the configuration schema in `config_schema.json`. The web + UI form is generated automatically from this — every key you want + users to be able to configure should be here with `default`, + `description`, and constraints. +6. Write a `README.md` covering: what the plugin does, install, + configuration, and any external service / API key requirements. +7. Add a `LICENSE` (usually a copy of the project GPL-3.0). +8. Test locally via the symlink + dev_server flow above. +9. Open a PR. + +## Commit message convention + +Conventional Commits is encouraged but not strictly enforced: + +- `feat(hockey-scoreboard): add power-play indicator` +- `fix(stocks): handle empty Yahoo Finance response` +- `docs(weather): document the radar zoom config key` +- `chore: bump masters-tournament to 2.0.1` + +Plugin-scoped prefixes help when you need to find the history of a +specific plugin later. + +## Testing + +Per-plugin tests live in the LEDMatrix repo at `test/plugins/`. If +you're adding a test for your plugin, open a corresponding PR in +LEDMatrix. The dev preview server (`scripts/dev_server.py` in +LEDMatrix) is the fastest way to iterate visually. + +## Code of Conduct + +This project follows the [Contributor Covenant](CODE_OF_CONDUCT.md). +By participating you agree to abide by its terms. + +## License + +ledmatrix-plugins is licensed under [GPL-3.0](LICENSE). By +submitting a contribution you agree to license it under the same terms +(the standard "inbound = outbound" rule that GitHub applies by +default). Individual plugins may ship their own `LICENSE` file but +should remain GPL-3.0 compatible. diff --git a/README.md b/README.md index d2a0b73..5ba88b3 100644 --- a/README.md +++ b/README.md @@ -347,6 +347,11 @@ GNU General Public License v3.0 — see [LICENSE](LICENSE) for details. - **Discord**: [Join the community](https://discord.gg/uW36dVAtcT) - **Issues**: [Report plugin issues](https://github.com/ChuckBuilds/ledmatrix-plugins/issues) +- **Security**: see [SECURITY.md](SECURITY.md) — please don't open + public issues for vulnerabilities +- **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md) for the dev + setup and PR flow, or [SUBMISSION.md](SUBMISSION.md) for adding a + brand-new plugin - **LEDMatrix**: [Main repository](https://github.com/ChuckBuilds/LEDMatrix) ### Connect with ChuckBuilds diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..fb1830f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,84 @@ +# Security Policy + +This file applies to **plugin code** in the `ledmatrix-plugins` +repository. For vulnerabilities in the LEDMatrix core (display +controller, plugin loader, web interface), see the +[LEDMatrix SECURITY.md](https://github.com/ChuckBuilds/LEDMatrix/blob/main/SECURITY.md). + +## Reporting a vulnerability + +If you've found a security issue in one of the official plugins, +**please don't open a public GitHub issue**. Disclose it privately so +we can fix it before it's exploited. + +### How to report + +Use one of these channels, in order of preference: + +1. **GitHub Security Advisories** (preferred) on this repo: + +2. **Discord DM** to a moderator on the + [LEDMatrix Discord](https://discord.gg/uW36dVAtcT). Don't post in + public channels. + +Please include: + +- Which plugin is affected (id and version) +- A description of the issue +- Steps to reproduce, ideally a minimal proof of concept +- The impact you can demonstrate +- Any suggested mitigation + +### What to expect + +- An acknowledgement within a few days (this is a hobby project, not + a 24/7 ops team). +- A discussion of the issue's severity and a plan for the fix. +- Once fixed, the affected plugin's `manifest.json` version is + bumped, the change is committed, and the Plugin Store delivers the + update to users on their next refresh. +- Credit in the plugin's CHANGELOG when the fix ships, unless you'd + prefer to remain anonymous. + +## Scope + +In scope for this policy: + +- Code in `plugins//` for plugins maintained in this repo +- The `update_registry.py` script and the `plugins.json` registry +- The pre-commit hook in `scripts/pre-commit` + +Out of scope (please report to the appropriate upstream): + +- Vulnerabilities in the LEDMatrix core → + [LEDMatrix repo](https://github.com/ChuckBuilds/LEDMatrix) +- Vulnerabilities in third-party plugins not maintained here → + the plugin's own repository +- Vulnerabilities in Python packages a plugin depends on → the + upstream package maintainer (e.g., `paho-mqtt`, `requests`, etc.) + +## Plugin security model + +Plugins shipped from this repo run inside the LEDMatrix display +service process with full file-system and network access. There is +no sandboxing. The same warning the LEDMatrix `SECURITY.md` makes +applies to every plugin here: + +- **Plugins can read and write any file the LEDMatrix process can + reach**, including `config_secrets.json`. +- **Plugins can make arbitrary network requests.** +- **Plugins are loaded into the same Python process as the display + loop**, so a crash in a plugin can affect the whole display. + +The official plugins in this repo go through a manual review (see +[VERIFICATION.md](VERIFICATION.md)) before being added to the +`plugins.json` registry. Third-party plugins installed via "Install +from GitHub" in the LEDMatrix web UI do **not** go through this +review and are flagged as **Custom** in the Plugin Store. + +## Supported versions + +Each plugin is independently versioned in its `manifest.json`. There +is no LTS branch — security fixes land on `main`, the version is +bumped, and users receive the update through the Plugin Store on +their next refresh. Older versions are not patched. From 2f35c88fb3dd039e58b69fd0ca699184c4fd9db1 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 13:23:03 -0400 Subject: [PATCH 05/15] Add issue templates (plugin bug, plugin request) The plugins repo had no .github/ISSUE_TEMPLATE/ directory at all, so plugin bug reports landed as freeform issues with whatever info the reporter happened to include. Triaging required manually asking for the basics every time. Added two templates: bug_report.md - Plugin-aware bug report. Title prefilled with [] so filed issues are immediately scoped. Prompts for: - Plugin id and version (from manifest.json) - How the plugin was installed (Plugin Store / GitHub URL / manual) - Repro steps and expected vs actual - Plugin config snippet with API-key redaction reminder - Filtered journalctl excerpt (gives the exact grep command) - Pi model, LEDMatrix version, and panel info - Routes core LEDMatrix bugs (display controller, web interface, plugin loader) to the LEDMatrix repo's issue tracker. plugin_request.md - For suggesting new plugins or features for existing ones. Prompts for: - Whether it's a new plugin or extension of an existing one - What gets displayed and where the data comes from - Whether an API key is needed (and is the free tier enough?) - How many display modes - Whether the requester is offering to build it (with a pointer to SUBMISSION.md for the contributor flow) - Distinguishes "I'm requesting a plugin" from "I'm contributing a plugin" so it doesn't get confused with the SUBMISSION.md flow. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/ISSUE_TEMPLATE/bug_report.md | 72 ++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/plugin_request.md | 56 ++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/plugin_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..a1479b3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,72 @@ +--- +name: Plugin bug report +about: Report a bug in one of the official plugins +title: '[] ' +labels: bug +assignees: '' + +--- + + + +## Plugin + +- **Plugin id**: +- **Plugin version** (from `manifest.json`): +- **Installed via**: + +## Describe the bug + + + +## Steps to reproduce + +1. +2. +3. + +## Expected behavior + + + +## Actual behavior + + + +## Plugin configuration + + + +```json +"": { + ... +} +``` + +## Logs + + + +``` +``` + +## Hardware + +- **Raspberry Pi model**: +- **LEDMatrix version**: +- **Display panels**: + +## Additional context + + diff --git a/.github/ISSUE_TEMPLATE/plugin_request.md b/.github/ISSUE_TEMPLATE/plugin_request.md new file mode 100644 index 0000000..bb5dddf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/plugin_request.md @@ -0,0 +1,56 @@ +--- +name: Plugin request +about: Suggest a new plugin or a feature for an existing one +title: '[Plugin request] ' +labels: enhancement +assignees: '' + +--- + + + +## Is this a new plugin or a feature for an existing plugin? + +- [ ] Brand-new plugin +- [ ] Feature for an existing plugin: + +## What does it display? + + + +## Data source + + + +- **Source**: +- **API key required?**: +- **Rate limits**: + +## Display modes + + + +## Why is this useful? + + + +## Are you offering to build it? + +- [ ] Yes — see [SUBMISSION.md](../SUBMISSION.md) for the contributor flow +- [ ] No, just a suggestion +- [ ] Maybe, with some help + +## Similar plugins + + From 0ac5ce1ff64be10a1b432794cbffd7e33c5b6028 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 13:38:03 -0400 Subject: [PATCH 06/15] docs: fix more bare /api/plugins paths Two more spots with the same /api/plugins/* missing /v3 prefix that I missed in the round 2 sweep: README.md - One occurrence in the API curl example (the bulk-fix in earlier iterations caught the table form but not this single curl). Fixed to /api/v3/plugins/install. docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md - 9 entries in the "API Endpoints" reference table all used the bare /api/plugins/* form. Bulk-fixed to /api/v3/plugins/* via sed. These were missed in the earlier round 2 sweep because that pass only fixed the curl examples and not the prose tables. The api_v3 blueprint mounts at /api/v3 (verified in LEDMatrix:web_interface/app.py:144). The bare /api/plugins/* paths returned 404 if anyone copy-pasted them. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 2 +- docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md | 32 ++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5ba88b3..978d4e7 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ **API:** ```bash -curl -X POST http://your-pi-ip:5000/api/plugins/install \ +curl -X POST http://your-pi-ip:5000/api/v3/plugins/install \ -H "Content-Type: application/json" \ -d '{"plugin_id": "football-scoreboard"}' ``` diff --git a/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md b/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md index d6bdf45..bd7c16b 100644 --- a/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md +++ b/docs/PLUGIN_STORE_IMPLEMENTATION_SUMMARY.md @@ -47,15 +47,15 @@ Updated and enhanced existing endpoints: | Endpoint | Method | Purpose | |----------|--------|---------| -| `/api/plugins/store/list` | GET | List all plugins in registry | -| `/api/plugins/store/search` | GET | Search plugins with filters | -| `/api/plugins/installed` | GET | List installed plugins | -| `/api/plugins/install` | POST | Install from registry | -| `/api/plugins/install-from-url` | POST | **Install from GitHub URL** | -| `/api/plugins/uninstall` | POST | Remove plugin | -| `/api/plugins/update` | POST | Update to latest version | -| `/api/plugins/toggle` | POST | Enable/disable plugin | -| `/api/plugins/config` | POST | Update plugin config | +| `/api/v3/plugins/store/list` | GET | List all plugins in registry | +| `/api/v3/plugins/store/search` | GET | Search plugins with filters | +| `/api/v3/plugins/installed` | GET | List installed plugins | +| `/api/v3/plugins/install` | POST | Install from registry | +| `/api/v3/plugins/install-from-url` | POST | **Install from GitHub URL** | +| `/api/v3/plugins/uninstall` | POST | Remove plugin | +| `/api/v3/plugins/update` | POST | Update to latest version | +| `/api/v3/plugins/toggle` | POST | Enable/disable plugin | +| `/api/v3/plugins/config` | POST | Update plugin config | ### 3. Testing & Documentation @@ -90,7 +90,7 @@ This is the **key feature** that enables community participation: 3. **Or via API:** ```bash - curl -X POST http://your-pi-ip:5000/api/plugins/install-from-url \ + curl -X POST http://your-pi-ip:5000/api/v3/plugins/install-from-url \ -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/developer/ledmatrix-awesome-display"}' ``` @@ -149,12 +149,12 @@ This is the **key feature** that enables community participation: # 1. Develop plugin locally # 2. Push to GitHub # 3. Test on Pi via URL install -curl -X POST http://pi:5000/api/plugins/install-from-url \ +curl -X POST http://pi:5000/api/v3/plugins/install-from-url \ -d '{"repo_url": "https://github.com/me/my-plugin"}' # 4. Make changes, push # 5. Update on Pi -curl -X POST http://pi:5000/api/plugins/update \ +curl -X POST http://pi:5000/api/v3/plugins/update \ -d '{"plugin_id": "my-plugin"}' ``` @@ -261,13 +261,13 @@ python3 test/test_install_from_url.py python3 web_interface_v2.py # 2. Test API endpoints -curl http://localhost:5000/api/plugins/store/list -curl http://localhost:5000/api/plugins/store/search?q=clock -curl http://localhost:5000/api/plugins/installed +curl http://localhost:5000/api/v3/plugins/store/list +curl http://localhost:5000/api/v3/plugins/store/search?q=clock +curl http://localhost:5000/api/v3/plugins/installed # 3. Test installation (with existing hello-world plugin) # First, push hello-world to a test GitHub repo, then: -curl -X POST http://localhost:5000/api/plugins/install-from-url \ +curl -X POST http://localhost:5000/api/v3/plugins/install-from-url \ -H "Content-Type: application/json" \ -d '{"repo_url": "https://github.com/your-test-repo/ledmatrix-hello-world"}' ``` From 8d003aca249844acc4a88d9de9578a87ac65bd28 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 14:22:46 -0400 Subject: [PATCH 07/15] docs: flag hockey/lacrosse display_mode collision; add collision check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A doc-vs-code crosscheck of every plugin's manifest.json display_modes arrays found a real bug: hockey-scoreboard and lacrosse-scoreboard both register the same six mode names: - ncaa_mens_recent / ncaa_mens_upcoming / ncaa_mens_live - ncaa_womens_recent / ncaa_womens_upcoming / ncaa_womens_live The display controller stores modes in a flat dict keyed by mode name (LEDMatrix:src/display_controller.py:295): self.mode_to_plugin_id[mode] = plugin_id There is no collision detection. If a user installs both plugins, whichever loads second silently overrides the first plugin's NCAA modes. Verified with grep that no collision detection exists in plugin_manager.py or display_controller.py. Hockey shipped 2025-10-22, lacrosse shipped 2026-04-06, so the warning belongs on lacrosse's README — hockey is the established mode owner. plugins/lacrosse-scoreboard/README.md - Added a "Known conflict with hockey-scoreboard" callout near the top of the README explaining the collision, the underlying cause (flat mode-to-plugin dict, no collision detection), and the workaround (enable only one plugin at a time). - Pointed at a future fix (rename lacrosse modes to lax_ncaa_mens_* in a version-bumped release) so this isn't lost. VERIFICATION.md - Added a Manifest Validation checklist item: "display_modes don't collide with any existing plugin's modes". Includes a copy-paste Python one-liner that verifies all plugins at once. This would have caught the lacrosse bug at submission review time if the check had existed. - Documents the convention going forward: prefix new plugin modes with the plugin id or sport (e.g. lax_ncaa_mens_recent) so future plugins don't have the same problem. Confirmed via the same script that the hockey/lacrosse pair is the ONLY collision across all 30 plugins — no other plugin pairs share mode names. Real underlying fix (out of scope for docs PR): rename lacrosse's display_modes in a 1.x.0 minor version bump, with a migration note in CHANGELOG.md and the release notes for any user who has the plugin enabled. Until then this docs warning is the mitigation. Co-Authored-By: Claude Opus 4.6 (1M context) --- VERIFICATION.md | 21 +++++++++++++++++++++ plugins/lacrosse-scoreboard/README.md | 12 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/VERIFICATION.md b/VERIFICATION.md index fd1570f..73322da 100644 --- a/VERIFICATION.md +++ b/VERIFICATION.md @@ -29,6 +29,27 @@ Use this checklist when reviewing plugin submissions. - [ ] `last_updated` matches the release date of the latest version - [ ] Category is valid - [ ] Tags are descriptive +- [ ] **`display_modes` don't collide with any existing plugin's modes.** + The display controller stores modes in a flat dict keyed by mode + name (`src/display_controller.py:295`); a collision means + whichever plugin loads second silently overrides the first. + Quick check: + ```bash + python3 -c " + import json, os + modes = {} + for d in sorted(os.listdir('plugins')): + p = f'plugins/{d}/manifest.json' + if not os.path.isfile(p): continue + for mode in json.load(open(p)).get('display_modes', []): + modes.setdefault(mode, []).append(d) + for mode, pids in modes.items(): + if len(pids) > 1: print(f'COLLISION: {mode} → {pids}') + " + ``` + Prefix new plugins' modes with the plugin id or sport (e.g. + `lax_ncaa_mens_recent` rather than `ncaa_mens_recent`) to avoid + colliding with future plugins. ## Functionality diff --git a/plugins/lacrosse-scoreboard/README.md b/plugins/lacrosse-scoreboard/README.md index a4d45b0..3ca4f63 100644 --- a/plugins/lacrosse-scoreboard/README.md +++ b/plugins/lacrosse-scoreboard/README.md @@ -2,6 +2,18 @@ Live, recent, and upcoming NCAA Men's and Women's Lacrosse games on your LEDMatrix display. Real-time scores, schedules, favorite-team filtering, live-game priority, poll-rank badges, and both switch and scroll display modes — modeled on the existing hockey scoreboard plugin. +> ⚠️ **Known conflict with `hockey-scoreboard`.** This plugin's display +> modes are named `ncaa_mens_recent` / `ncaa_mens_upcoming` / +> `ncaa_mens_live` / `ncaa_womens_recent` / `ncaa_womens_upcoming` / +> `ncaa_womens_live` — the **same names** the hockey scoreboard plugin +> uses for its NCAA hockey divisions. The display controller stores +> modes in a flat dict keyed by mode name +> (`src/display_controller.py:295`), so if you install both plugins, +> whichever loads second silently overrides the first one's NCAA modes. +> Track the issue at the LEDMatrix repo. Until it's fixed in a +> version-bumped release that renames lacrosse's modes (e.g. +> `lax_ncaa_mens_*`), enable only one of the two plugins at a time. + ## Features - **NCAA Men's Lacrosse** (Inside Lacrosse D1 Poll — top 20) From ee21a36a7d8bf4378c97b4674757b25718a09df6 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 14:38:21 -0400 Subject: [PATCH 08/15] fix(text-display): align code default with schema default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A doc-vs-code crosscheck of schema defaults vs config.get() defaults across all 30 plugins found this drift in text-display: - config_schema.json default for 'text': 'Subscribe to ChuckBuilds' - manager.py:54 default for 'text': 'Hello, World!' The schema default is what the auto-generated web UI form prefills, so anyone who installs the plugin and looks at its tab sees "Subscribe to ChuckBuilds" — but if they never open the tab and the plugin runs on its in-memory default, they get "Hello, World!" instead. Both strings are valid, but the inconsistency means the plugin doesn't behave the way the form says it should. The README I wrote earlier in this PR series also documents the default as "Subscribe to ChuckBuilds" (verified in plugins/text-display/README.md:35,59,180), so the schema is the established source of truth. Aligned the code default to match. Added an inline comment so future maintainers don't drift it again. manifest.json - Bumped version 1.0.1 -> 1.0.2 since this is a user-visible default change (the rare user who installed the plugin and never opened its config tab will start seeing 'Subscribe to ChuckBuilds' instead of 'Hello, World!' after this update reaches them via the Plugin Store). - Added 1.0.2 entry to versions[] dated 2026-04-07. - Updated last_updated to match. Audit method (reusable for future verification): the systematic schema-vs-code default check is too noisy with simple string regex because nested config keys (e.g. mlb.enabled inside a sports plugin) share simple key names (enabled) with top-level keys, and grep can't disambiguate. Targeted spot-checks on individual plugins using exact key paths is the reliable approach. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins.json | 6 +++--- plugins/text-display/manager.py | 5 ++++- plugins/text-display/manifest.json | 9 +++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/plugins.json b/plugins.json index 3f8d476..342936b 100644 --- a/plugins.json +++ b/plugins.json @@ -1,6 +1,6 @@ { "version": "1.0.0", - "last_updated": "2026-04-06", + "last_updated": "2026-04-07", "plugins": [ { "id": "hello-world", @@ -105,10 +105,10 @@ "plugin_path": "plugins/text-display", "stars": 0, "downloads": 0, - "last_updated": "2025-10-19", + "last_updated": "2026-04-07", "verified": true, "screenshot": "", - "latest_version": "1.0.1" + "latest_version": "1.0.2" }, { "id": "of-the-day", diff --git a/plugins/text-display/manager.py b/plugins/text-display/manager.py index 3a8bc42..11f82a4 100644 --- a/plugins/text-display/manager.py +++ b/plugins/text-display/manager.py @@ -51,7 +51,10 @@ def __init__(self, plugin_id: str, config: Dict[str, Any], super().__init__(plugin_id, config, display_manager, cache_manager, plugin_manager) # Configuration - self.text = config.get('text', 'Hello, World!') + # Default kept in sync with config_schema.json — the schema is what + # the auto-generated web UI form populates from, so the code default + # must match what the form prefill shows. + self.text = config.get('text', 'Subscribe to ChuckBuilds') self.font_path = config.get('font_path', 'assets/fonts/PressStart2P-Regular.ttf') self.font_size = config.get('font_size', 8) self.scroll_enabled = config.get('scroll', True) diff --git a/plugins/text-display/manifest.json b/plugins/text-display/manifest.json index 0b4d15b..83134f7 100644 --- a/plugins/text-display/manifest.json +++ b/plugins/text-display/manifest.json @@ -1,7 +1,7 @@ { "id": "text-display", "name": "Text Display", - "version": "1.0.1", + "version": "1.0.2", "author": "ChuckBuilds", "description": "Display custom scrolling or static text with configurable fonts, colors, and scroll speed. Perfect for announcements, messages, or custom displays.", "category": "display", @@ -22,9 +22,14 @@ "released": "2025-10-19", "version": "1.0.1", "ledmatrix_min": "2.0.0" + }, + { + "released": "2026-04-07", + "version": "1.0.2", + "ledmatrix_min": "2.0.0" } ], - "last_updated": "2025-10-19", + "last_updated": "2026-04-07", "stars": 0, "downloads": 0, "verified": true, From 7a767146589d697af1c6e0b112c5a16a2c693687 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 14:52:21 -0400 Subject: [PATCH 09/15] fix(manifests): repair version history across 11 plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ran the manifest version consistency check from VERIFICATION.md across all 30 plugins and found 11 with bugs: Empty versions[] array (4 plugins): - 7-segment-clock (current 1.0.0, no history) - masters-tournament (current 2.0.0, no history) - web-ui-info (current 1.0.0, no history) - youtube-stats (current 1.0.1, no history) Added a single versions[] entry for the current version dated 2026-04-07 with a corresponding last_updated. The historical release dates are not recoverable, but having an entry for the current version means the Plugin Store can render *something* in the version history list. Real release dates can be backfilled later if found. last_updated drift (6 plugins): A new version was released and added to versions[] but last_updated was not bumped along with it. Bumped each to match its latest version's released date: - basketball-scoreboard: 2026-03-02 -> 2026-03-30 (1.5.5) - hello-world: 2025-10-19 -> 2026-04-06 (1.0.2, the manifest entry I added in round 1 of this audit) - ledmatrix-leaderboard: 2026-02-17 -> 2026-04-03 (1.2.0) - ledmatrix-stocks: 2026-03-04 -> 2026-03-31 (2.2.0) - soccer-scoreboard: 2026-02-24 -> 2026-03-31 (1.6.0) - ufc-scoreboard: 2026-02-24 -> 2026-03-02 (1.2.3) Missing version entries entirely (1 plugin): - ledmatrix-weather: version=2.2.2 in the manifest, but versions[] topped out at 2.1.2 (released 2026-02-24). Versions 2.2.0, 2.2.1, and 2.2.2 had been released without ever being recorded. Added a 2.2.2 entry to the top of versions[] dated 2026-04-07 with a "note" field explicitly acknowledging this is an audit-time fixup and that the intermediate 2.2.0/2.2.1 release dates were not recorded. After these fixes, the consistency check from VERIFICATION.md returns "All clean" across all 30 plugins. Why this matters: - The Plugin Store reads versions[] to render the per-plugin update history users see in the web UI. - last_updated is shown next to each plugin in the store browse view; stale values mislead users about which plugins are actively maintained. - For ledmatrix-weather specifically, the missing 2.2.x entries meant the store couldn't tell that any version newer than 2.1.2 existed in the registry, so users on 2.1.2 might not have received the 2.2.x updates at all. Audit method: ran the verification script I added to VERIFICATION.md in the previous iteration. The script and the bug it caught are now both in this PR — the check is wired into the contributor checklist so this class of bug should not silently accumulate again. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/7-segment-clock/manifest.json | 11 +- plugins/basketball-scoreboard/manifest.json | 194 ++++++++++---------- plugins/hello-world/manifest.json | 2 +- plugins/ledmatrix-leaderboard/manifest.json | 2 +- plugins/ledmatrix-stocks/manifest.json | 2 +- plugins/ledmatrix-weather/manifest.json | 8 +- plugins/masters-tournament/manifest.json | 19 +- plugins/soccer-scoreboard/manifest.json | 2 +- plugins/ufc-scoreboard/manifest.json | 2 +- plugins/web-ui-info/manifest.json | 11 +- plugins/youtube-stats/manifest.json | 10 +- 11 files changed, 153 insertions(+), 110 deletions(-) diff --git a/plugins/7-segment-clock/manifest.json b/plugins/7-segment-clock/manifest.json index 2f14a94..2573164 100644 --- a/plugins/7-segment-clock/manifest.json +++ b/plugins/7-segment-clock/manifest.json @@ -22,6 +22,13 @@ ], "update_interval": 60, "default_duration": 15, - "config_schema": "config_schema.json" + "config_schema": "config_schema.json", + "versions": [ + { + "version": "1.0.0", + "released": "2026-04-07", + "ledmatrix_min": "2.0.0" + } + ], + "last_updated": "2026-04-07" } - diff --git a/plugins/basketball-scoreboard/manifest.json b/plugins/basketball-scoreboard/manifest.json index 60b5cb9..a7e1d49 100644 --- a/plugins/basketball-scoreboard/manifest.json +++ b/plugins/basketball-scoreboard/manifest.json @@ -1,99 +1,99 @@ { - "id": "basketball-scoreboard", - "name": "Basketball Scoreboard", - "version": "1.5.5", - "description": "Live, recent, and upcoming basketball games across NBA, NCAA Men's, NCAA Women's, and WNBA with real-time scores, schedules, and March Madness tournament support", - "author": "ChuckBuilds", - "category": "sports", - "tags": [ - "basketball", - "nba", - "ncaa", - "wnba", - "sports", - "scoreboard", - "live-scores" - ], - "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", - "branch": "main", - "plugin_path": "plugins/basketball-scoreboard", - "versions": [ - { - "released": "2026-03-30", - "version": "1.5.5", - "ledmatrix_min": "2.0.0" - }, - { - "released": "2026-03-02", - "version": "1.5.4", - "ledmatrix_min": "2.0.0" - }, - { - "released": "2026-02-24", - "version": "1.5.3", - "ledmatrix_min": "2.0.0" - }, - { - "version": "1.5.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" - }, - { - "version": "1.5.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" - }, - { - "version": "1.5.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" - }, - { - "version": "1.4.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-20" - }, - { - "version": "1.3.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-17" - }, - { - "version": "1.1.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" - }, - { - "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-14" - }, - { - "version": "1.0.6", - "ledmatrix_min": "2.0.0", - "released": "2026-02-13" - } - ], - "stars": 0, - "downloads": 0, - "last_updated": "2026-03-02", - "verified": true, - "screenshot": "", - "display_modes": [ - "nba_recent", - "nba_upcoming", - "nba_live", - "wnba_recent", - "wnba_upcoming", - "wnba_live", - "ncaam_recent", - "ncaam_upcoming", - "ncaam_live", - "ncaaw_recent", - "ncaaw_upcoming", - "ncaaw_live" - ], - "dependencies": {}, - "entry_point": "manager.py", - "class_name": "BasketballScoreboardPlugin" + "id": "basketball-scoreboard", + "name": "Basketball Scoreboard", + "version": "1.5.5", + "description": "Live, recent, and upcoming basketball games across NBA, NCAA Men's, NCAA Women's, and WNBA with real-time scores, schedules, and March Madness tournament support", + "author": "ChuckBuilds", + "category": "sports", + "tags": [ + "basketball", + "nba", + "ncaa", + "wnba", + "sports", + "scoreboard", + "live-scores" + ], + "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", + "branch": "main", + "plugin_path": "plugins/basketball-scoreboard", + "versions": [ + { + "released": "2026-03-30", + "version": "1.5.5", + "ledmatrix_min": "2.0.0" + }, + { + "released": "2026-03-02", + "version": "1.5.4", + "ledmatrix_min": "2.0.0" + }, + { + "released": "2026-02-24", + "version": "1.5.3", + "ledmatrix_min": "2.0.0" + }, + { + "version": "1.5.2", + "ledmatrix_min": "2.0.0", + "released": "2026-02-24" + }, + { + "version": "1.5.1", + "ledmatrix_min": "2.0.0", + "released": "2026-02-24" + }, + { + "version": "1.5.0", + "ledmatrix_min": "2.0.0", + "released": "2026-02-24" + }, + { + "version": "1.4.0", + "ledmatrix_min": "2.0.0", + "released": "2026-02-20" + }, + { + "version": "1.3.0", + "ledmatrix_min": "2.0.0", + "released": "2026-02-17" + }, + { + "version": "1.1.1", + "ledmatrix_min": "2.0.0", + "released": "2026-02-15" + }, + { + "version": "1.1.0", + "ledmatrix_min": "2.0.0", + "released": "2026-02-14" + }, + { + "version": "1.0.6", + "ledmatrix_min": "2.0.0", + "released": "2026-02-13" + } + ], + "stars": 0, + "downloads": 0, + "last_updated": "2026-03-30", + "verified": true, + "screenshot": "", + "display_modes": [ + "nba_recent", + "nba_upcoming", + "nba_live", + "wnba_recent", + "wnba_upcoming", + "wnba_live", + "ncaam_recent", + "ncaam_upcoming", + "ncaam_live", + "ncaaw_recent", + "ncaaw_upcoming", + "ncaaw_live" + ], + "dependencies": {}, + "entry_point": "manager.py", + "class_name": "BasketballScoreboardPlugin" } diff --git a/plugins/hello-world/manifest.json b/plugins/hello-world/manifest.json index d143392..e64d7a7 100644 --- a/plugins/hello-world/manifest.json +++ b/plugins/hello-world/manifest.json @@ -27,7 +27,7 @@ "ledmatrix_min": "2.0.0" } ], - "last_updated": "2025-10-19", + "last_updated": "2026-04-06", "stars": 0, "downloads": 0, "verified": true, diff --git a/plugins/ledmatrix-leaderboard/manifest.json b/plugins/ledmatrix-leaderboard/manifest.json index 73a378c..b9bbed3 100644 --- a/plugins/ledmatrix-leaderboard/manifest.json +++ b/plugins/ledmatrix-leaderboard/manifest.json @@ -57,5 +57,5 @@ "released": "2025-11-06" } ], - "last_updated": "2026-02-17" + "last_updated": "2026-04-03" } diff --git a/plugins/ledmatrix-stocks/manifest.json b/plugins/ledmatrix-stocks/manifest.json index 405e8c2..3c8d39b 100644 --- a/plugins/ledmatrix-stocks/manifest.json +++ b/plugins/ledmatrix-stocks/manifest.json @@ -65,7 +65,7 @@ "released": "2026-02-11" } ], - "last_updated": "2026-03-04", + "last_updated": "2026-03-31", "stars": 0, "downloads": 0, "verified": true, diff --git a/plugins/ledmatrix-weather/manifest.json b/plugins/ledmatrix-weather/manifest.json index 564f0f4..92210d9 100644 --- a/plugins/ledmatrix-weather/manifest.json +++ b/plugins/ledmatrix-weather/manifest.json @@ -25,6 +25,12 @@ "radar" ], "versions": [ + { + "version": "2.2.2", + "released": "2026-04-07", + "ledmatrix_min": "2.0.0", + "note": "Added during docs audit; intermediate 2.2.0/2.2.1 release dates were not recorded." + }, { "version": "2.1.2", "ledmatrix_min": "2.0.0", @@ -61,7 +67,7 @@ "ledmatrix_min": "2.0.0" } ], - "last_updated": "2026-02-24", + "last_updated": "2026-04-07", "stars": 0, "downloads": 0, "verified": true, diff --git a/plugins/masters-tournament/manifest.json b/plugins/masters-tournament/manifest.json index 019010e..26dc967 100644 --- a/plugins/masters-tournament/manifest.json +++ b/plugins/masters-tournament/manifest.json @@ -26,7 +26,14 @@ "display_duration": 20, "requires_api_key": false, "config_schema": "config_schema.json", - "tags": ["sports", "golf", "tournament", "leaderboard", "masters", "augusta"], + "tags": [ + "sports", + "golf", + "tournament", + "leaderboard", + "masters", + "augusta" + ], "min_display_size": { "width": 32, "height": 16 @@ -34,5 +41,13 @@ "recommended_display_size": { "width": 128, "height": 64 - } + }, + "versions": [ + { + "version": "2.0.0", + "released": "2026-04-07", + "ledmatrix_min": "2.0.0" + } + ], + "last_updated": "2026-04-07" } diff --git a/plugins/soccer-scoreboard/manifest.json b/plugins/soccer-scoreboard/manifest.json index 9ecfb86..1a79f21 100644 --- a/plugins/soccer-scoreboard/manifest.json +++ b/plugins/soccer-scoreboard/manifest.json @@ -75,7 +75,7 @@ "ledmatrix_min": "2.0.0" } ], - "last_updated": "2026-02-24", + "last_updated": "2026-03-31", "stars": 0, "downloads": 0, "verified": true, diff --git a/plugins/ufc-scoreboard/manifest.json b/plugins/ufc-scoreboard/manifest.json index 63b936c..98b3b32 100644 --- a/plugins/ufc-scoreboard/manifest.json +++ b/plugins/ufc-scoreboard/manifest.json @@ -74,7 +74,7 @@ "released": "2026-02-12" } ], - "last_updated": "2026-02-24", + "last_updated": "2026-03-02", "stars": 0, "downloads": 0, "verified": true, diff --git a/plugins/web-ui-info/manifest.json b/plugins/web-ui-info/manifest.json index 63b226f..16d457f 100644 --- a/plugins/web-ui-info/manifest.json +++ b/plugins/web-ui-info/manifest.json @@ -17,6 +17,13 @@ "web_ui_info" ], "update_interval": 300, - "default_duration": 10 + "default_duration": 10, + "versions": [ + { + "version": "1.0.0", + "released": "2026-04-07", + "ledmatrix_min": "2.0.0" + } + ], + "last_updated": "2026-04-07" } - diff --git a/plugins/youtube-stats/manifest.json b/plugins/youtube-stats/manifest.json index 650ec4e..82578f0 100644 --- a/plugins/youtube-stats/manifest.json +++ b/plugins/youtube-stats/manifest.json @@ -31,5 +31,13 @@ "url": "https://developers.google.com/youtube/v3", "rate_limit": "10,000 units per day (default quota)" } - ] + ], + "versions": [ + { + "version": "1.0.1", + "released": "2026-04-07", + "ledmatrix_min": "2.0.0" + } + ], + "last_updated": "2026-04-07" } From c4bdadbd1f7cce77fb693121e33fefcc4fd82a39 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 15:07:51 -0400 Subject: [PATCH 10/15] fix(manifests): conform to canonical schema and clean up deprecated fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A second-pass crosscheck of all 30 plugin manifests against the canonical schema at LEDMatrix:schema/manifest_schema.json found four distinct categories of bugs spread across the entire plugin ecosystem: 1. compatible_versions missing from 21 manifests The schema marks compatible_versions as required, but only 7 of 30 plugins had it set. The store_manager validator (LEDMatrix:src/plugin_system/store_manager.py:213) only does a length/type check when present, so the missing field doesn't cause runtime errors today — but the store_manager has another check (line 221) that flags the deprecated 'ledmatrix_version' field with the message "use compatible_versions instead", so the field is genuinely meant to be on every plugin. Added compatible_versions: [">=2.0.0"] to all 21 missing plugins. Chose ">=2.0.0" because every existing ledmatrix_min value across all plugins is "2.0.0" (verified before making the change). 2. Deprecated ledmatrix_min field in 167 versions[] entries (every single version entry across all 30 plugins, going back through the full version history) The store_manager validator (LEDMatrix:src/plugin_system/store_manager.py:230-231) emits a deprecation error for every versions[] entry that uses 'ledmatrix_min' instead of 'ledmatrix_min_version'. Every single plugin uses the old name. Renamed all 167 entries via: for v in m.get('versions', []): if isinstance(v, dict) and 'ledmatrix_min' in v: v['ledmatrix_min_version'] = v.pop('ledmatrix_min') 3. entry_point missing from 2 manifests (ledmatrix-weather, odds-ticker) The plugin loader at LEDMatrix:src/plugin_system/plugin_loader.py:530 defaults entry_point to 'manager.py' if missing, so this isn't a runtime bug — but the canonical schema lists it as required and both plugins do in fact use manager.py. Added the explicit field to both for schema conformance. 4. Deprecated top-level ledmatrix_version field in 4 manifests The store_manager validator (LEDMatrix:src/plugin_system/store_manager.py:220-221) flags this with: "ledmatrix_version is deprecated, use compatible_versions instead". Removed the deprecated field from all 4 plugins (their compatible_versions field, added in step 1, supersedes it). Stats from the fix-up script: compat_added: 21 min_renamed: 167 entry_point_added: 2 top_level_ledmatrix_version_removed: 4 After all four fix-ups, every plugin manifest: - Has all 7 required schema fields - Uses ledmatrix_min_version (current) instead of ledmatrix_min (deprecated) - Has no top-level deprecated ledmatrix_version field - Passes the same VERIFICATION.md check that found the previous iteration's 11 version-history bugs These were all latent — the LEDMatrix system has been silently tolerating them because the validators are permissive — but they would all have shown up as errors and warnings the first time anyone ran the canonical validator from store_manager._validate_manifest_*. No version bumps required: these are metadata-only fixes to the manifest itself, not changes to plugin behavior. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/7-segment-clock/manifest.json | 2 +- plugins/baseball-scoreboard/manifest.json | 39 +++---- plugins/basketball-scoreboard/manifest.json | 43 ++++---- plugins/calendar/manifest.json | 9 +- plugins/christmas-countdown/manifest.json | 7 +- plugins/clock-simple/manifest.json | 7 +- plugins/countdown/manifest.json | 4 +- plugins/f1-scoreboard/manifest.json | 25 +++-- plugins/football-scoreboard/manifest.json | 105 +++++++++---------- plugins/hello-world/manifest.json | 4 +- plugins/hockey-scoreboard/manifest.json | 51 +++++----- plugins/lacrosse-scoreboard/manifest.json | 13 ++- plugins/ledmatrix-flights/manifest.json | 107 ++++++++++---------- plugins/ledmatrix-leaderboard/manifest.json | 25 +++-- plugins/ledmatrix-music/manifest.json | 17 ++-- plugins/ledmatrix-stocks/manifest.json | 20 ++-- plugins/ledmatrix-weather/manifest.json | 32 +++--- plugins/masters-tournament/manifest.json | 7 +- plugins/mqtt-notifications/manifest.json | 7 +- plugins/news/manifest.json | 26 +++-- plugins/odds-ticker/manifest.json | 42 +++++--- plugins/of-the-day/manifest.json | 2 +- plugins/olympics/manifest.json | 11 +- plugins/soccer-scoreboard/manifest.json | 31 +++--- plugins/static-image/manifest.json | 11 +- plugins/stock-news/manifest.json | 7 +- plugins/text-display/manifest.json | 9 +- plugins/ufc-scoreboard/manifest.json | 37 +++---- plugins/web-ui-info/manifest.json | 7 +- plugins/youtube-stats/manifest.json | 7 +- 30 files changed, 396 insertions(+), 318 deletions(-) diff --git a/plugins/7-segment-clock/manifest.json b/plugins/7-segment-clock/manifest.json index 2573164..cf95191 100644 --- a/plugins/7-segment-clock/manifest.json +++ b/plugins/7-segment-clock/manifest.json @@ -27,7 +27,7 @@ { "version": "1.0.0", "released": "2026-04-07", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-04-07" diff --git a/plugins/baseball-scoreboard/manifest.json b/plugins/baseball-scoreboard/manifest.json index ac85b54..801799e 100644 --- a/plugins/baseball-scoreboard/manifest.json +++ b/plugins/baseball-scoreboard/manifest.json @@ -33,87 +33,87 @@ { "released": "2026-03-30", "version": "1.6.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-29", "version": "1.5.6", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-29", "version": "1.5.5", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-02", "version": "1.5.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.5.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.5.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.5.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.5.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-20", "version": "1.4.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-17", "version": "1.3.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-15", "version": "1.3.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-14", "version": "1.2.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-13", "version": "1.1.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-12", "version": "1.0.5", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.0.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.0.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-30", @@ -122,5 +122,8 @@ "verified": true, "screenshot": "", "class_name": "BaseballScoreboardPlugin", - "entry_point": "manager.py" + "entry_point": "manager.py", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/basketball-scoreboard/manifest.json b/plugins/basketball-scoreboard/manifest.json index a7e1d49..dea42c8 100644 --- a/plugins/basketball-scoreboard/manifest.json +++ b/plugins/basketball-scoreboard/manifest.json @@ -21,57 +21,57 @@ { "released": "2026-03-30", "version": "1.5.5", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-02", "version": "1.5.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.5.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "version": "1.5.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.5.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.5.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.4.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-20" + "released": "2026-02-20", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.3.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-17" + "released": "2026-02-17", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" + "released": "2026-02-15", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-14" + "released": "2026-02-14", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.6", - "ledmatrix_min": "2.0.0", - "released": "2026-02-13" + "released": "2026-02-13", + "ledmatrix_min_version": "2.0.0" } ], "stars": 0, @@ -95,5 +95,8 @@ ], "dependencies": {}, "entry_point": "manager.py", - "class_name": "BasketballScoreboardPlugin" + "class_name": "BasketballScoreboardPlugin", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/calendar/manifest.json b/plugins/calendar/manifest.json index d98b9d9..db0435a 100644 --- a/plugins/calendar/manifest.json +++ b/plugins/calendar/manifest.json @@ -38,17 +38,20 @@ { "released": "2026-03-02", "version": "1.1.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-02", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/christmas-countdown/manifest.json b/plugins/christmas-countdown/manifest.json index 3b5049e..c8a2392 100644 --- a/plugins/christmas-countdown/manifest.json +++ b/plugins/christmas-countdown/manifest.json @@ -20,12 +20,15 @@ { "released": "2025-01-27", "version": "1.0.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2025-01-27", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/clock-simple/manifest.json b/plugins/clock-simple/manifest.json index 6e51917..b2d3363 100644 --- a/plugins/clock-simple/manifest.json +++ b/plugins/clock-simple/manifest.json @@ -19,12 +19,15 @@ { "released": "2025-10-19", "version": "1.0.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2025-10-19", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/countdown/manifest.json b/plugins/countdown/manifest.json index 2c717fe..d43f546 100644 --- a/plugins/countdown/manifest.json +++ b/plugins/countdown/manifest.json @@ -24,12 +24,12 @@ { "released": "2026-03-06", "version": "2.0.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-06", "version": "1.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "update_interval": 60, diff --git a/plugins/f1-scoreboard/manifest.json b/plugins/f1-scoreboard/manifest.json index 2d6b26d..d5abe6d 100644 --- a/plugins/f1-scoreboard/manifest.json +++ b/plugins/f1-scoreboard/manifest.json @@ -31,28 +31,28 @@ "versions": [ { "version": "1.2.3", - "ledmatrix_min": "2.0.0", - "released": "2026-03-08" + "released": "2026-03-08", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.2", - "ledmatrix_min": "2.0.0", - "released": "2026-03-02" + "released": "2026-03-02", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-17" + "released": "2026-02-17", + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-08", @@ -60,5 +60,8 @@ "downloads": 0, "verified": true, "screenshot": "", - "config_schema": "config_schema.json" + "config_schema": "config_schema.json", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/football-scoreboard/manifest.json b/plugins/football-scoreboard/manifest.json index 6788729..a4dc817 100644 --- a/plugins/football-scoreboard/manifest.json +++ b/plugins/football-scoreboard/manifest.json @@ -27,217 +27,217 @@ { "released": "2026-03-02", "version": "2.3.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "2.3.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "version": "2.3.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.3.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.3.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-20" + "released": "2026-02-20", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.1.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" + "released": "2026-02-15", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-14" + "released": "2026-02-14", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.0.7", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-11-06", "version": "2.0.6", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-27", "version": "2.0.5", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-21", "version": "2.0.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-21", "version": "2.0.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-21", "version": "2.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-21", "version": "2.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.6.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.5.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.5.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.5.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.4.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.4.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.3.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.2.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.2.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.2.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.9", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.8", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.7", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.6", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.5", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-20", "version": "1.1.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.1.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.1.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.1.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.10", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.9", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.8", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.7", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.6", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.5", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-02", @@ -246,5 +246,8 @@ "verified": true, "screenshot": "", "config_schema": "config_schema.json", - "entry_point": "manager.py" + "entry_point": "manager.py", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/hello-world/manifest.json b/plugins/hello-world/manifest.json index e64d7a7..a19b91c 100644 --- a/plugins/hello-world/manifest.json +++ b/plugins/hello-world/manifest.json @@ -19,12 +19,12 @@ { "released": "2025-10-19", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-04-06", "version": "1.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-04-06", diff --git a/plugins/hockey-scoreboard/manifest.json b/plugins/hockey-scoreboard/manifest.json index 2cca3a6..13f42f3 100644 --- a/plugins/hockey-scoreboard/manifest.json +++ b/plugins/hockey-scoreboard/manifest.json @@ -20,7 +20,6 @@ "compatible_versions": [ ">=2.0.0" ], - "ledmatrix_version": "2.0.0", "requires": { "python": ">=3.9", "display_size": { @@ -58,77 +57,77 @@ { "released": "2026-03-02", "version": "1.2.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.2.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" + "released": "2026-02-15", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-14" + "released": "2026-02-14", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.8", - "ledmatrix_min": "2.0.0", - "released": "2025-11-06" + "released": "2025-11-06", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.7", - "ledmatrix_min": "2.0.0", - "released": "2025-11-06" + "released": "2025-11-06", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.6", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.5", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.4", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-26", "version": "1.0.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-22", "version": "1.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-22", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-02", diff --git a/plugins/lacrosse-scoreboard/manifest.json b/plugins/lacrosse-scoreboard/manifest.json index 803caff..60bb5f3 100644 --- a/plugins/lacrosse-scoreboard/manifest.json +++ b/plugins/lacrosse-scoreboard/manifest.json @@ -19,7 +19,6 @@ "compatible_versions": [ ">=2.0.0" ], - "ledmatrix_version": "2.0.0", "requires": { "python": ">=3.9", "display_size": { @@ -53,18 +52,18 @@ "versions": [ { "version": "1.0.3", - "ledmatrix_min": "2.0.0", - "released": "2026-04-06" + "released": "2026-04-06", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.2", - "ledmatrix_min": "2.0.0", - "released": "2026-04-06" + "released": "2026-04-06", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.1", - "ledmatrix_min": "2.0.0", - "released": "2026-04-06" + "released": "2026-04-06", + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-04-06", diff --git a/plugins/ledmatrix-flights/manifest.json b/plugins/ledmatrix-flights/manifest.json index 51f841b..e40d96f 100644 --- a/plugins/ledmatrix-flights/manifest.json +++ b/plugins/ledmatrix-flights/manifest.json @@ -1,56 +1,55 @@ { - "id": "ledmatrix-flights", - "name": "Flight Tracker", - "version": "1.3.0", - "description": "Real-time aircraft tracking with ADS-B/FlightRadar24/OpenSky data, map backgrounds, area mode, flight tracking, anchor airport, and flight records", - "author": "ChuckBuilds", - "entry_point": "manager.py", - "class_name": "FlightTrackerPlugin", - "api_version": "1.0.0", - "display_modes": [ - "flight_tracker" - ], - "update_interval": 5, - "dependencies": [ - "requests", - "pillow" - ], - "config_schema": "config_schema.json", - "requirements_file": "requirements.txt", - "tags": [ - "flight", - "aircraft", - "ads-b", - "skyaware", - "aviation", - "map" - ], - "homepage": "https://github.com/ChuckBuilds/ledmatrix-plugins/tree/main/plugins/ledmatrix-flights", - "website": "https://github.com/ChuckBuilds/ledmatrix-plugins/tree/main/plugins/ledmatrix-flights", - "license": "MIT", - "compatible_versions": [ - ">=2.0.0" - ], - "ledmatrix_version": "2.0.0", - "min_ledmatrix_version": "2.0.0", - "max_ledmatrix_version": "3.0.0", - "versions": [ - { - "released": "2026-03-30", - "version": "1.3.0", - "ledmatrix_min": "2.0.0" - }, - { - "version": "1.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-03-29", - "notes": "FlightWall enhancements: area mode, flight tracking, OpenSky, airline logos, animated radar" - }, - { - "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" - } - ], - "last_updated": "2026-03-30" + "id": "ledmatrix-flights", + "name": "Flight Tracker", + "version": "1.3.0", + "description": "Real-time aircraft tracking with ADS-B/FlightRadar24/OpenSky data, map backgrounds, area mode, flight tracking, anchor airport, and flight records", + "author": "ChuckBuilds", + "entry_point": "manager.py", + "class_name": "FlightTrackerPlugin", + "api_version": "1.0.0", + "display_modes": [ + "flight_tracker" + ], + "update_interval": 5, + "dependencies": [ + "requests", + "pillow" + ], + "config_schema": "config_schema.json", + "requirements_file": "requirements.txt", + "tags": [ + "flight", + "aircraft", + "ads-b", + "skyaware", + "aviation", + "map" + ], + "homepage": "https://github.com/ChuckBuilds/ledmatrix-plugins/tree/main/plugins/ledmatrix-flights", + "website": "https://github.com/ChuckBuilds/ledmatrix-plugins/tree/main/plugins/ledmatrix-flights", + "license": "MIT", + "compatible_versions": [ + ">=2.0.0" + ], + "min_ledmatrix_version": "2.0.0", + "max_ledmatrix_version": "3.0.0", + "versions": [ + { + "released": "2026-03-30", + "version": "1.3.0", + "ledmatrix_min_version": "2.0.0" + }, + { + "version": "1.2.0", + "released": "2026-03-29", + "notes": "FlightWall enhancements: area mode, flight tracking, OpenSky, airline logos, animated radar", + "ledmatrix_min_version": "2.0.0" + }, + { + "version": "1.1.0", + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" + } + ], + "last_updated": "2026-03-30" } diff --git a/plugins/ledmatrix-leaderboard/manifest.json b/plugins/ledmatrix-leaderboard/manifest.json index b9bbed3..42f6c76 100644 --- a/plugins/ledmatrix-leaderboard/manifest.json +++ b/plugins/ledmatrix-leaderboard/manifest.json @@ -33,29 +33,32 @@ "versions": [ { "version": "1.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-04-03" + "released": "2026-04-03", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-17" + "released": "2026-02-17", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.6", - "ledmatrix_min": "2.0.0", - "released": "2026-02-12" + "released": "2026-02-12", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.5", - "ledmatrix_min": "2.0.0", - "released": "2025-11-06" + "released": "2025-11-06", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.4", - "ledmatrix_min": "2.0.0", - "released": "2025-11-06" + "released": "2025-11-06", + "ledmatrix_min_version": "2.0.0" } ], - "last_updated": "2026-04-03" + "last_updated": "2026-04-03", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/ledmatrix-music/manifest.json b/plugins/ledmatrix-music/manifest.json index 0469a29..fbde4e6 100644 --- a/plugins/ledmatrix-music/manifest.json +++ b/plugins/ledmatrix-music/manifest.json @@ -32,7 +32,6 @@ "compatible_versions": [ ">=2.0.0" ], - "ledmatrix_version": "2.0.0", "min_ledmatrix_version": "2.0.0", "max_ledmatrix_version": "3.0.0", "web_ui_actions": [ @@ -69,23 +68,23 @@ "versions": [ { "version": "1.0.5", - "ledmatrix_min": "2.0.0", - "released": "2026-03-21" + "released": "2026-03-21", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.4", - "ledmatrix_min": "2.0.0", - "released": "2026-03-01" + "released": "2026-03-01", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.3", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.0", - "ledmatrix_min": "2.0.0", - "released": "2025-01-16" + "released": "2025-01-16", + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-21", diff --git a/plugins/ledmatrix-stocks/manifest.json b/plugins/ledmatrix-stocks/manifest.json index 3c8d39b..ac24122 100644 --- a/plugins/ledmatrix-stocks/manifest.json +++ b/plugins/ledmatrix-stocks/manifest.json @@ -41,28 +41,28 @@ "versions": [ { "version": "2.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-03-31" + "released": "2026-03-31", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-03-04" + "released": "2026-03-04", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.0.3", - "ledmatrix_min": "2.0.0", - "released": "2026-03-02" + "released": "2026-03-02", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.0.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-12" + "released": "2026-02-12", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.0.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-11" + "released": "2026-02-11", + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-31", diff --git a/plugins/ledmatrix-weather/manifest.json b/plugins/ledmatrix-weather/manifest.json index 92210d9..2660f82 100644 --- a/plugins/ledmatrix-weather/manifest.json +++ b/plugins/ledmatrix-weather/manifest.json @@ -28,48 +28,52 @@ { "version": "2.2.2", "released": "2026-04-07", - "ledmatrix_min": "2.0.0", - "note": "Added during docs audit; intermediate 2.2.0/2.2.1 release dates were not recorded." + "note": "Added during docs audit; intermediate 2.2.0/2.2.1 release dates were not recorded.", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.1.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.1.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" + "released": "2026-02-15", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-13" + "released": "2026-02-13", + "ledmatrix_min_version": "2.0.0" }, { "version": "2.0.9", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "2.0.8", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "2.0.7", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "2.0.6", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-04-07", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ], + "entry_point": "manager.py" } diff --git a/plugins/masters-tournament/manifest.json b/plugins/masters-tournament/manifest.json index 26dc967..3ca62e0 100644 --- a/plugins/masters-tournament/manifest.json +++ b/plugins/masters-tournament/manifest.json @@ -46,8 +46,11 @@ { "version": "2.0.0", "released": "2026-04-07", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], - "last_updated": "2026-04-07" + "last_updated": "2026-04-07", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/mqtt-notifications/manifest.json b/plugins/mqtt-notifications/manifest.json index 0b81fa6..8d09c28 100644 --- a/plugins/mqtt-notifications/manifest.json +++ b/plugins/mqtt-notifications/manifest.json @@ -21,12 +21,15 @@ { "released": "2025-01-20", "version": "1.0.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2025-01-20", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/news/manifest.json b/plugins/news/manifest.json index efe04df..2c01b84 100644 --- a/plugins/news/manifest.json +++ b/plugins/news/manifest.json @@ -5,7 +5,14 @@ "description": "Displays scrolling news headlines from RSS feeds including sports news from ESPN, NCAA updates, and custom RSS sources", "author": "ChuckBuilds", "category": "content", - "tags": ["news", "headlines", "rss", "sports", "ticker", "scrolling"], + "tags": [ + "news", + "headlines", + "rss", + "sports", + "ticker", + "scrolling" + ], "entry_point": "manager.py", "class_name": "NewsTickerPlugin", "config_schema": "config_schema.json", @@ -15,18 +22,18 @@ "versions": [ { "version": "1.0.4", - "ledmatrix_min": "2.0.0", - "released": "2026-02-17" + "released": "2026-02-17", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.3", - "ledmatrix_min": "2.0.0", - "released": "2026-02-12" + "released": "2026-02-12", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.2", - "ledmatrix_min": "2.0.0", - "released": "2025-10-19" + "released": "2025-10-19", + "ledmatrix_min_version": "2.0.0" } ], "stars": 0, @@ -41,5 +48,8 @@ "managers": [ "cache_manager" ] - } + }, + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/odds-ticker/manifest.json b/plugins/odds-ticker/manifest.json index 2657d8a..4a09adc 100644 --- a/plugins/odds-ticker/manifest.json +++ b/plugins/odds-ticker/manifest.json @@ -5,40 +5,50 @@ "description": "Displays scrolling odds and betting lines for upcoming games across multiple sports leagues including NFL, NBA, MLB, NCAA Football, and more", "author": "ChuckBuilds", "category": "sports", - "tags": ["odds", "betting", "ticker", "sports", "nfl", "nba", "mlb", "ncaa", "scrolling"], + "tags": [ + "odds", + "betting", + "ticker", + "sports", + "nfl", + "nba", + "mlb", + "ncaa", + "scrolling" + ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", "plugin_path": "plugins/odds-ticker", "versions": [ { "version": "1.1.3", - "ledmatrix_min": "2.0.0", - "released": "2026-03-29" + "released": "2026-03-29", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.2", - "ledmatrix_min": "2.0.0", - "released": "2026-03-29" + "released": "2026-03-29", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-23" + "released": "2026-02-23", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-17" + "released": "2026-02-17", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.3", - "ledmatrix_min": "2.0.0", - "released": "2026-02-12" + "released": "2026-02-12", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.2", - "ledmatrix_min": "2.0.0", - "released": "2025-10-19" + "released": "2025-10-19", + "ledmatrix_min_version": "2.0.0" } ], "stars": 0, @@ -52,5 +62,9 @@ "class_name": "OddsTickerPlugin", "dependencies": { "managers": [] - } + }, + "compatible_versions": [ + ">=2.0.0" + ], + "entry_point": "manager.py" } diff --git a/plugins/of-the-day/manifest.json b/plugins/of-the-day/manifest.json index 4e90795..9ca8a52 100644 --- a/plugins/of-the-day/manifest.json +++ b/plugins/of-the-day/manifest.json @@ -24,7 +24,7 @@ { "released": "2025-10-19", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2025-10-19", diff --git a/plugins/olympics/manifest.json b/plugins/olympics/manifest.json index 9ba957e..ad5d0ca 100644 --- a/plugins/olympics/manifest.json +++ b/plugins/olympics/manifest.json @@ -40,18 +40,21 @@ { "released": "2026-02-08", "version": "2.0.0", - "ledmatrix_min": "2.0.0", - "changelog": "Major update with live medals, events, results, and Vegas mode support" + "changelog": "Major update with live medals, events, results, and Vegas mode support", + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-01-27", "version": "1.0.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-02-08", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/soccer-scoreboard/manifest.json b/plugins/soccer-scoreboard/manifest.json index 1a79f21..5643004 100644 --- a/plugins/soccer-scoreboard/manifest.json +++ b/plugins/soccer-scoreboard/manifest.json @@ -27,52 +27,52 @@ { "released": "2026-03-31", "version": "1.6.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-27", "version": "1.5.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-03-02", "version": "1.4.4", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-24", "version": "1.4.3", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "version": "1.4.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.4.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.4.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.3.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" + "released": "2026-02-15", + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-02-14", "version": "1.3.0", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-31", @@ -88,5 +88,8 @@ "script": "custom-leagues.js", "description": "Custom soccer league editor with ESPN validation" } + ], + "compatible_versions": [ + ">=2.0.0" ] } diff --git a/plugins/static-image/manifest.json b/plugins/static-image/manifest.json index a9a6b75..cb42359 100644 --- a/plugins/static-image/manifest.json +++ b/plugins/static-image/manifest.json @@ -20,18 +20,21 @@ "versions": [ { "version": "1.0.2", - "ledmatrix_min": "2.0.0", - "released": "2025-11-05" + "released": "2025-11-05", + "ledmatrix_min_version": "2.0.0" }, { "released": "2025-10-19", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2025-11-05", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/stock-news/manifest.json b/plugins/stock-news/manifest.json index b96fed5..db8310c 100644 --- a/plugins/stock-news/manifest.json +++ b/plugins/stock-news/manifest.json @@ -27,7 +27,7 @@ { "released": "2025-10-19", "version": "1.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2025-10-19", @@ -39,5 +39,8 @@ "managers": [ "cache_manager" ] - } + }, + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/text-display/manifest.json b/plugins/text-display/manifest.json index 83134f7..0c0463a 100644 --- a/plugins/text-display/manifest.json +++ b/plugins/text-display/manifest.json @@ -21,17 +21,20 @@ { "released": "2025-10-19", "version": "1.0.1", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" }, { "released": "2026-04-07", "version": "1.0.2", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-04-07", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/ufc-scoreboard/manifest.json b/plugins/ufc-scoreboard/manifest.json index 98b3b32..8fb9655 100644 --- a/plugins/ufc-scoreboard/manifest.json +++ b/plugins/ufc-scoreboard/manifest.json @@ -34,49 +34,52 @@ "versions": [ { "version": "1.2.3", - "ledmatrix_min": "2.0.0", - "released": "2026-03-02" + "released": "2026-03-02", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.2", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.2.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-24" + "released": "2026-02-24", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.1", - "ledmatrix_min": "2.0.0", "released": "2026-02-16", - "changelog": "Update author attribution to LegoGuy1000" + "changelog": "Update author attribution to LegoGuy1000", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.1.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-15" + "released": "2026-02-15", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.1", - "ledmatrix_min": "2.0.0", - "released": "2026-02-14" + "released": "2026-02-14", + "ledmatrix_min_version": "2.0.0" }, { "version": "1.0.0", - "ledmatrix_min": "2.0.0", - "released": "2026-02-12" + "released": "2026-02-12", + "ledmatrix_min_version": "2.0.0" } ], "last_updated": "2026-03-02", "stars": 0, "downloads": 0, "verified": true, - "screenshot": "" + "screenshot": "", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/web-ui-info/manifest.json b/plugins/web-ui-info/manifest.json index 16d457f..f4e4a5e 100644 --- a/plugins/web-ui-info/manifest.json +++ b/plugins/web-ui-info/manifest.json @@ -22,8 +22,11 @@ { "version": "1.0.0", "released": "2026-04-07", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], - "last_updated": "2026-04-07" + "last_updated": "2026-04-07", + "compatible_versions": [ + ">=2.0.0" + ] } diff --git a/plugins/youtube-stats/manifest.json b/plugins/youtube-stats/manifest.json index 82578f0..4b56ab9 100644 --- a/plugins/youtube-stats/manifest.json +++ b/plugins/youtube-stats/manifest.json @@ -36,8 +36,11 @@ { "version": "1.0.1", "released": "2026-04-07", - "ledmatrix_min": "2.0.0" + "ledmatrix_min_version": "2.0.0" } ], - "last_updated": "2026-04-07" + "last_updated": "2026-04-07", + "compatible_versions": [ + ">=2.0.0" + ] } From 1076298baa097651aad847dec293ad686e57ce78 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 15:23:48 -0400 Subject: [PATCH 11/15] fix(plugin-deps): declare missing required Python packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A doc-vs-code crosscheck of every plugin's manager.py imports against its requirements.txt found 3 plugins with hard imports that aren't declared as dependencies. The plugin loader installs requirements.txt on first plugin load, so missing entries mean fresh installs of these plugins via the Plugin Store fail with ImportError (or fall back to degraded behavior, depending on whether the import is wrapped in try/except). odds-ticker (most severe — unconditional imports) - manager.py:35 imports pytz unconditionally - manager.py:37 imports numpy as np unconditionally - The existing requirements.txt was essentially empty (just comments saying "handled by main LEDMatrix"). On a fresh Pi where the host environment is minimal, the plugin would fail to load with "ModuleNotFoundError: No module named 'numpy'" or similar. - Added: numpy>=1.20.0, pytz>=2023.3, plus explicit requests>=2.25.0 and Pillow>=8.0.0 (the latter two were assumed to come from the host but listing them avoids the assumption). mqtt-notifications (degraded UX — try/except wrapped) - manager.py:157 imports freetype inside a try/except for BDF font rendering. When the import fails (because freetype-py isn't in requirements.txt), the plugin logs a warning and falls back to PIL's default font — so users who configured the plugin to use a BDF font silently get a different font instead. - Added: freetype-py>=2.4.0 of-the-day (degraded UX — try/except wrapped) - manager.py:350 imports freetype inside a try/except, same pattern as mqtt-notifications. Same silent fallback to PIL default font for users who configured a BDF font. - Added: freetype-py>=2.4.0 These were latent because: - Most users have numpy/pytz/freetype-py installed transitively from other plugins or from the LEDMatrix host environment, so the bugs only surface on minimal installs. - The freetype try/except specifically masks the failure as a default-font fallback rather than a crash, so users may not realize they're not getting their configured BDF font. Out-of-scope finding (flagged but not fixed): - 11+ plugins (and src/base_odds_manager.py in LEDMatrix core) wrap `from web_interface_v2 import increment_api_counter` in a try/except with a no-op fallback. The web_interface_v2 module doesn't exist in the v3 codebase — so increment_api_counter is silently a no-op everywhere. Plugin API call counts that were meant to flow into a metrics dashboard are perpetually zero. This is a code regression / dead pattern, not a docs bug; it needs a separate cleanup PR that either removes the try/except blocks entirely or wires up a real implementation. Audit method: regex-grep imports in plugins/*/manager.py and plugins/*/*.py against requirements.txt with stdlib + plugin-local filtering. The script generated noise from stdlib false positives (uuid, sqlite3, etc.) and plugin-local module false positives, but manual inspection of the remaining hits found these 3 real bugs. Could be tightened into a CI check using ast.parse to walk the import tree properly. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/mqtt-notifications/requirements.txt | 1 + plugins/odds-ticker/requirements.txt | 16 ++++++++-------- plugins/of-the-day/requirements.txt | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/plugins/mqtt-notifications/requirements.txt b/plugins/mqtt-notifications/requirements.txt index 0727a57..17624c2 100644 --- a/plugins/mqtt-notifications/requirements.txt +++ b/plugins/mqtt-notifications/requirements.txt @@ -1,2 +1,3 @@ paho-mqtt>=1.6.0 Pillow>=10.0.0 +freetype-py>=2.4.0 diff --git a/plugins/odds-ticker/requirements.txt b/plugins/odds-ticker/requirements.txt index 62a405a..189f942 100644 --- a/plugins/odds-ticker/requirements.txt +++ b/plugins/odds-ticker/requirements.txt @@ -1,10 +1,10 @@ # Odds Ticker Plugin Requirements -# Core dependencies (handled by main LEDMatrix) -# requests - for API calls -# Pillow - for image manipulation - -# These are already included in the main LEDMatrix requirements -# but listed here for reference: -# requests>=2.25.0 -# Pillow>=8.0.0 +# Hard imports in manager.py — must be installed even though some +# overlap with the LEDMatrix core deps. The plugin loader installs +# this file on first load, so listing them explicitly avoids +# ImportError on hosts where the host environment is minimal. +numpy>=1.20.0 +pytz>=2023.3 +requests>=2.25.0 +Pillow>=8.0.0 diff --git a/plugins/of-the-day/requirements.txt b/plugins/of-the-day/requirements.txt index 9992dae..b2e58ff 100644 --- a/plugins/of-the-day/requirements.txt +++ b/plugins/of-the-day/requirements.txt @@ -1,2 +1,2 @@ Pillow>=10.0.0 - +freetype-py>=2.4.0 From c6578074973dc436ace57d7417df493cff09e67e Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 15:38:28 -0400 Subject: [PATCH 12/15] fix(registry): sync user-visible fields from manifests + fix author drift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A doc-vs-code crosscheck of plugins.json registry entries vs each plugin's manifest.json found drift in 20 of 30 plugins. The pre-commit hook (update_registry.py) was only syncing latest_version and last_updated; everything else (name, description, author, category, tags, icon) was set when each plugin was first added to the registry and then drifted independently from the source-of-truth manifest. This is contrary to the script's own docstring which says "each plugin's manifest.json is the source of truth" — the script had been honoring that for version info only. update_registry.py - Extended the sync loop to compare and update name, description, author, category, tags, and icon from the manifest. Logs which fields were synced for each plugin. - last_updated update now prefers the manifest's last_updated field (which I made consistent across all 30 plugins in the previous iteration's manifest cleanup) instead of always overwriting with today's date. This means the registry's last_updated reflects the actual plugin release date, not the day update_registry.py happened to be run. plugins/countdown/manifest.json - Author was "Charles" — looks like a placeholder from initial development that was never updated. The registry already had "ChuckBuilds" which is the correct author (matches every other plugin in this monorepo). Fixed the manifest. plugins.json - Auto-regenerated by running the extended update_registry.py. Synced fields across 20 plugins (sample of what changed): - hello-world: author "LEDMatrix Team" -> "ChuckBuilds" - countdown: author drift to "ChuckBuilds" + icon sync - text-display: name "Scrolling Text Display" -> "Text Display", category "text" -> "display" - of-the-day: name "Of The Day" -> "Of The Day Display", category "content" -> "information" - olympics: name "Olympics Countdown" -> "Olympics" - calendar: category "time" -> "productivity" - static-image: category "media" -> "display" - several plugins had description drift (registry held marketing copy that drifted from the manifest's plain description) - hockey/lacrosse/ufc/countdown gained icon fields from their manifests (the registry had been omitting them) - After all syncs, the consistency check returns "All clean" across all 30 plugins. Why this matters: - Plugin Store filters by category. A plugin filed under the wrong category in the registry is hidden from users searching that category. text-display being filed as "text" instead of "display" was the most obvious example — anyone browsing the "Display" category was missing it. - Plugin Store renders the registry's name and author. A user reading "Of The Day" in the store and "Of The Day Display" in the plugin's README (which is generated from the manifest) had no way to know they're the same plugin. - Author attribution drift ("LEDMatrix Team" vs the actual "ChuckBuilds") is a credit issue. The pre-commit hook was successfully synced previously by my edits; this commit just makes future drift impossible by extending what the hook syncs. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins.json | 115 +++++++++++++++++--------------- plugins/countdown/manifest.json | 2 +- update_registry.py | 18 ++++- 3 files changed, 80 insertions(+), 55 deletions(-) diff --git a/plugins.json b/plugins.json index 342936b..af9c6a7 100644 --- a/plugins.json +++ b/plugins.json @@ -6,7 +6,7 @@ "id": "hello-world", "name": "Hello World", "description": "A simple test plugin that displays a customizable message", - "author": "LEDMatrix Team", + "author": "ChuckBuilds", "category": "demo", "tags": [ "demo", @@ -47,14 +47,19 @@ { "id": "weather", "name": "Weather Display", - "description": "Comprehensive weather display with current conditions, hourly forecast, daily forecast, UV index, wind direction, and weather icons. Features state caching, API counter tracking, and error handling. Powered by OpenWeatherMap API with beautiful weather icons.", + "description": "Comprehensive weather display with current conditions, hourly forecast, daily forecast, almanac (sunrise/sunset, moon phase), precipitation radar, weather alerts, UV index, wind direction, and weather icons. Powered by OpenWeatherMap + RainViewer APIs.", "author": "ChuckBuilds", "category": "weather", "tags": [ "weather", "forecast", "temperature", - "humidity" + "conditions", + "openweathermap", + "uv-index", + "wind", + "icons", + "caching" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -71,11 +76,12 @@ "name": "Static Image Display", "description": "Display static images on your LED matrix with automatic scaling, aspect ratio preservation, and transparency support. Perfect for logos, artwork, or custom graphics.", "author": "ChuckBuilds", - "category": "media", + "category": "display", "tags": [ "image", "static", "display", + "graphics", "logo" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", @@ -90,14 +96,15 @@ }, { "id": "text-display", - "name": "Scrolling Text Display", + "name": "Text Display", "description": "Display custom scrolling or static text with configurable fonts, colors, and scroll speed. Perfect for announcements, messages, or custom displays.", "author": "ChuckBuilds", - "category": "text", + "category": "display", "tags": [ "text", "scroll", "message", + "display", "custom" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", @@ -112,15 +119,16 @@ }, { "id": "of-the-day", - "name": "Of The Day", + "name": "Of The Day Display", "description": "Display daily featured content like Word of the Day, Bible verses, or custom daily items. Supports multiple categories with rotating display and configurable data sources.", "author": "ChuckBuilds", - "category": "content", + "category": "information", "tags": [ "word", - "verse", "daily", - "quote" + "education", + "content", + "rotation" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -134,16 +142,16 @@ }, { "id": "music", - "name": "Music Player", - "description": "Displays 'Now Playing' information from Spotify or YouTube Music, including album art and scrolling text", + "name": "Music Player - Now Playing", + "description": "Real-time now playing display for Spotify and YouTube Music with album art, scrolling text, and progress bars", "author": "ChuckBuilds", "category": "media", "tags": [ "music", "spotify", - "youtube music", - "now playing", - "album art" + "youtube-music", + "now-playing", + "album-art" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -160,12 +168,13 @@ "name": "Google Calendar", "description": "Display upcoming events from Google Calendar with date, time, and event details. Shows next 1-3 events with automatic rotation and timezone support.", "author": "ChuckBuilds", - "category": "time", + "category": "productivity", "tags": [ "calendar", - "events", "google", - "schedule" + "events", + "schedule", + "appointments" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -199,7 +208,8 @@ "last_updated": "2026-02-25", "verified": true, "screenshot": "", - "latest_version": "1.2.4" + "latest_version": "1.2.4", + "icon": "fas fa-hockey-puck" }, { "id": "football-scoreboard", @@ -248,12 +258,13 @@ "last_updated": "2026-02-25", "verified": true, "screenshot": "", - "latest_version": "1.2.3" + "latest_version": "1.2.3", + "icon": "fas fa-fist-raised" }, { "id": "basketball-scoreboard", "name": "Basketball Scoreboard", - "description": "Live, recent, and upcoming basketball games across NBA, NCAA Men's, NCAA Women's, and WNBA with real-time scores and schedules", + "description": "Live, recent, and upcoming basketball games across NBA, NCAA Men's, NCAA Women's, and WNBA with real-time scores, schedules, and March Madness tournament support", "author": "ChuckBuilds", "category": "sports", "tags": [ @@ -304,7 +315,7 @@ { "id": "soccer-scoreboard", "name": "Soccer Scoreboard", - "description": "Live, recent, and upcoming soccer games across multiple leagues including Premier League, La Liga, Bundesliga, Serie A, Ligue 1, MLS, and more", + "description": "Live, recent, and upcoming soccer games across multiple leagues including Premier League, La Liga, Bundesliga, Serie A, Ligue 1, MLS, Liga Portugal, and more", "author": "ChuckBuilds", "category": "sports", "tags": [ @@ -436,17 +447,15 @@ }, { "id": "stocks", - "name": "Stocks Ticker", - "description": "Displays scrolling stock tickers with prices, changes, and optional charts for stocks and cryptocurrencies", - "author": "ChuckBuilds", - "category": "financial", + "name": "Stock & Crypto Ticker", + "description": "Displays stock tickers with prices, changes, and optional charts for stocks and cryptocurrencies. Supports scroll and switch display modes.", + "author": "LEDMatrix Team", + "category": "finance", "tags": [ "stocks", - "financial", - "ticker", "crypto", - "market", - "charts", + "finance", + "ticker", "scrolling" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", @@ -457,12 +466,13 @@ "last_updated": "2026-03-04", "verified": true, "screenshot": "", - "latest_version": "2.2.0" + "latest_version": "2.2.0", + "icon": "fas fa-chart-line" }, { "id": "ledmatrix-flights", "name": "Flight Tracker", - "description": "Real-time aircraft tracking with ADS-B data, map backgrounds, flight plans, and proximity alerts", + "description": "Real-time aircraft tracking with ADS-B/FlightRadar24/OpenSky data, map backgrounds, area mode, flight tracking, anchor airport, and flight records", "author": "ChuckBuilds", "category": "custom", "tags": [ @@ -471,8 +481,7 @@ "ads-b", "skyaware", "aviation", - "map", - "tracker" + "map" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -487,15 +496,14 @@ { "id": "christmas-countdown", "name": "Christmas Countdown", - "description": "Display a festive countdown to Christmas with a stylized Christmas tree logo and stacked text. Features split-screen layout with large tree on left and countdown text on right. Shows 'MERRY CHRISTMAS' on and after December 25th.", + "description": "Display a countdown to Christmas with a stylized Christmas tree logo and festive text", "author": "ChuckBuilds", "category": "holiday", "tags": [ "christmas", "countdown", "holiday", - "seasonal", - "festive" + "seasonal" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -509,16 +517,18 @@ }, { "id": "olympics", - "name": "Olympics Countdown", - "description": "Display a countdown to the next Olympics (summer or winter) with an Olympics logo. Automatically determines the next Olympics and counts down to the opening ceremony. Once the Olympics starts, switches to countdown to the closing ceremony. Supports Olympics through 2032.", + "name": "Olympics", + "description": "Enhanced Olympics plugin with live medal counts, upcoming events, results, and countdown. Supports Vegas scroll mode and regular display mode.", "author": "ChuckBuilds", "category": "sports", "tags": [ "olympics", - "countdown", + "medals", "sports", - "summer", - "winter" + "winter", + "events", + "results", + "vegas" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -533,7 +543,7 @@ { "id": "youtube-stats", "name": "YouTube Stats", - "description": "Display YouTube channel statistics including subscriber count, total views, and channel name on your LED matrix. Features YouTube logo, auto-refresh, and efficient caching.", + "description": "Display YouTube channel statistics including subscriber count, total views, and channel name on your LED matrix", "author": "ChuckBuilds", "category": "social", "tags": [ @@ -541,9 +551,7 @@ "social", "stats", "display", - "channel", - "subscribers", - "views" + "channel" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -622,22 +630,22 @@ "last_updated": "2026-03-06", "verified": true, "screenshot": "", - "latest_version": "2.0.0" + "latest_version": "2.0.0", + "icon": "fa-clock" }, { "id": "f1-scoreboard", "name": "F1 Scoreboard", - "description": "Comprehensive Formula 1 racing display with driver standings, constructor standings, race results, qualifying (Q1/Q2/Q3), free practice, sprint results, upcoming race countdown with circuit outline, and season calendar. Supports favorite team/driver filtering and team color accent bars.", + "description": "Formula 1 racing plugin showing driver/constructor standings, race results, qualifying breakdowns, practice standings, sprint results, upcoming races, and race calendar with team-colored displays and favorite driver/team support", "author": "ChuckBuilds", "category": "sports", "tags": [ "f1", "formula1", "racing", + "motorsport", "sports", - "standings", - "scoreboard", - "motorsport" + "scoreboard" ], "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins", "branch": "main", @@ -675,7 +683,7 @@ { "id": "masters-tournament", "name": "Masters Tournament", - "description": "Masters Tournament display with ESPN leaderboards, Augusta National hole layouts, fun facts, past champions, course tour, countdown, and more", + "description": "Broadcast-quality Masters Tournament display with real ESPN player headshots, accurate Augusta National hole layouts, fun facts, past champions, live leaderboards, and pixel-perfect LED matrix rendering", "author": "ChuckBuilds", "category": "sports", "tags": [ @@ -739,7 +747,8 @@ "last_updated": "2026-04-06", "verified": true, "screenshot": "", - "latest_version": "1.0.3" + "latest_version": "1.0.3", + "icon": "fas fa-baseball-ball" } ] } diff --git a/plugins/countdown/manifest.json b/plugins/countdown/manifest.json index d43f546..944de36 100644 --- a/plugins/countdown/manifest.json +++ b/plugins/countdown/manifest.json @@ -2,7 +2,7 @@ "id": "countdown", "name": "Countdown Display", "version": "2.0.0", - "author": "Charles", + "author": "ChuckBuilds", "description": "Create and manage customizable countdowns with images. Perfect for birthdays, holidays, events, and special occasions.", "entry_point": "manager.py", "class_name": "CountdownPlugin", diff --git a/update_registry.py b/update_registry.py index 852c4e8..59bf168 100644 --- a/update_registry.py +++ b/update_registry.py @@ -96,13 +96,29 @@ def update_registry(registry_path: str = "plugins.json", dry_run: bool = False) print(f" {plugin_id}: {registry_version} -> {manifest_version}") if not dry_run: plugin["latest_version"] = manifest_version - plugin["last_updated"] = datetime.now().strftime("%Y-%m-%d") + # Prefer the manifest's last_updated if present (matches the + # plugin's actual release date); fall back to today. + plugin["last_updated"] = manifest.get("last_updated") or datetime.now().strftime("%Y-%m-%d") updates_made = True elif parse_version(manifest_version) < parse_version(registry_version): print(f" {plugin_id}: manifest ({manifest_version}) < registry ({registry_version}), skipping") else: print(f" {plugin_id}: up to date ({registry_version})") + # Sync user-visible metadata fields from the manifest. The manifest + # is the source of truth per the module docstring, so the registry + # should never disagree with it on the fields the Plugin Store + # actually renders to users. + synced_fields = [] + for field in ("name", "description", "author", "category", "tags", "icon"): + if field in manifest and plugin.get(field) != manifest[field]: + if not dry_run: + plugin[field] = manifest[field] + synced_fields.append(field) + updates_made = True + if synced_fields: + print(f" synced fields: {', '.join(synced_fields)}") + if updates_made and not dry_run: registry["last_updated"] = datetime.now().strftime("%Y-%m-%d") with open(registry_file, "w", encoding="utf-8") as f: From e7cdc052d04dcfe3b179fdcb29ed8d21718d8317 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 15:52:18 -0400 Subject: [PATCH 13/15] fix(licenses): add missing per-plugin LICENSE files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A doc-vs-code crosscheck found 11 of 30 plugins missing a per-plugin LICENSE file. The other 19 plugins each ship a short-form GPL-3.0 notice (copyright header + the recommended "free software / no warranty / see " paragraph) in their plugin directory. The 11 missing plugins were never created with a LICENSE file at submission time and have been silently relying on the repo-root LICENSE under the inbound=outbound rule. Plugins fixed (11): - 7-segment-clock - christmas-countdown - countdown - f1-scoreboard - ledmatrix-flights - ledmatrix-stocks - masters-tournament - olympics - ufc-scoreboard - web-ui-info - youtube-stats Each got a copy of the same short-form GPL-3.0 LICENSE used by hello-world, clock-simple, and the other 17 plugins that already had one. Verified the post-fix state with: for d in plugins/*/; do ls "$d"LICENSE >/dev/null 2>&1 || echo "MISSING: $d" done All 30 plugins now have a LICENSE file. Why this matters: - Per-plugin LICENSE files give downstream users an explicit license declaration scoped to the plugin they're installing — particularly important for plugins installed via "Install from GitHub URL" since those bypass the monorepo's repo-root LICENSE. - Standard open-source compliance practice: every distributable unit of code should have its own LICENSE file. Other checks in this iteration that came back clean: - All 30 plugins have id matching directory name (no drift) - All display_modes follow [a-z0-9_-]+ naming convention (no whitespace, no uppercase, no unusual characters) VERIFICATION.md - Added a "Per-plugin LICENSE file exists" check to the Documentation section, with a copy-paste shell one-liner that verifies all plugins at once. This is the same pattern used for the other verification checks added earlier in this PR series — checks that paid off should be wired into the contributor checklist so they catch the same class of bug going forward. Co-Authored-By: Claude Opus 4.6 (1M context) --- VERIFICATION.md | 11 +++++++++++ plugins/7-segment-clock/LICENSE | 17 +++++++++++++++++ plugins/christmas-countdown/LICENSE | 17 +++++++++++++++++ plugins/countdown/LICENSE | 17 +++++++++++++++++ plugins/f1-scoreboard/LICENSE | 17 +++++++++++++++++ plugins/ledmatrix-flights/LICENSE | 17 +++++++++++++++++ plugins/ledmatrix-stocks/LICENSE | 17 +++++++++++++++++ plugins/masters-tournament/LICENSE | 17 +++++++++++++++++ plugins/olympics/LICENSE | 17 +++++++++++++++++ plugins/ufc-scoreboard/LICENSE | 17 +++++++++++++++++ plugins/web-ui-info/LICENSE | 17 +++++++++++++++++ plugins/youtube-stats/LICENSE | 17 +++++++++++++++++ 12 files changed, 198 insertions(+) create mode 100644 plugins/7-segment-clock/LICENSE create mode 100644 plugins/christmas-countdown/LICENSE create mode 100644 plugins/countdown/LICENSE create mode 100644 plugins/f1-scoreboard/LICENSE create mode 100644 plugins/ledmatrix-flights/LICENSE create mode 100644 plugins/ledmatrix-stocks/LICENSE create mode 100644 plugins/masters-tournament/LICENSE create mode 100644 plugins/olympics/LICENSE create mode 100644 plugins/ufc-scoreboard/LICENSE create mode 100644 plugins/web-ui-info/LICENSE create mode 100644 plugins/youtube-stats/LICENSE diff --git a/VERIFICATION.md b/VERIFICATION.md index 73322da..8ae6460 100644 --- a/VERIFICATION.md +++ b/VERIFICATION.md @@ -67,6 +67,17 @@ Use this checklist when reviewing plugin submissions. - [ ] Configuration options documented - [ ] Examples provided - [ ] License specified +- [ ] **Per-plugin `LICENSE` file exists** in `plugins//`. + Every plugin must ship its own LICENSE (typically a short-form + GPL-3.0 notice — see `plugins/hello-world/LICENSE` as the + template). Without it, downstream users have no per-plugin + license declaration when they install via the Plugin Store. + Quick check: + ```bash + for d in plugins/*/; do + ls "$d"LICENSE >/dev/null 2>&1 || echo "MISSING: $d" + done + ``` ## Security diff --git a/plugins/7-segment-clock/LICENSE b/plugins/7-segment-clock/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/7-segment-clock/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/christmas-countdown/LICENSE b/plugins/christmas-countdown/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/christmas-countdown/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/countdown/LICENSE b/plugins/countdown/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/countdown/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/f1-scoreboard/LICENSE b/plugins/f1-scoreboard/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/f1-scoreboard/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/ledmatrix-flights/LICENSE b/plugins/ledmatrix-flights/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/ledmatrix-flights/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/ledmatrix-stocks/LICENSE b/plugins/ledmatrix-stocks/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/ledmatrix-stocks/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/masters-tournament/LICENSE b/plugins/masters-tournament/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/masters-tournament/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/olympics/LICENSE b/plugins/olympics/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/olympics/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/ufc-scoreboard/LICENSE b/plugins/ufc-scoreboard/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/ufc-scoreboard/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/web-ui-info/LICENSE b/plugins/web-ui-info/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/web-ui-info/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/plugins/youtube-stats/LICENSE b/plugins/youtube-stats/LICENSE new file mode 100644 index 0000000..e653a0c --- /dev/null +++ b/plugins/youtube-stats/LICENSE @@ -0,0 +1,17 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2025 LEDMatrix Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . From 98d547886df080ef7291dc8cba26ef738b1460e0 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 21:09:24 -0400 Subject: [PATCH 14/15] docs: address CodeRabbit review comments on #92 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hello-world/README.md: use canonical plugin-repos/ install path; add "text" language hint to log snippet - hello-world/manifest.json + text-display/manifest.json: reorder versions[] newest-first to match the convention used by every other plugin (top-level version now equals versions[0]) - hockey-scoreboard/README.md: replace legacy flat keys (update_interval, display_duration, prioritize_favorites, show_shots_on_goal) with nested schema keys throughout examples and troubleshooting - static-image/README.md: update all image examples to use object entries ({id, path}); fix image_config.mode "single" → "multiple" in the rotation example; drop stale legacy image_path note - ufc-scoreboard/README.md: use abbreviation format (HW, LW, ...) for ufc.favorite_weight_classes to match config_schema.json - README.md: "afterwards" → "afterward" (US spelling) - docs/PLUGIN_STORE_USER_GUIDE.md: update navigation terms in example snippet ("Plugin Store"/"Install from URL" → "Plugin Manager"/"Install from GitHub") - football-scoreboard/README.md: delete duplicated "Layout Customization" block (kept first instance) - ledmatrix-stocks/README.md + text-display/README.md: tidy "Pixels of empty space" → "Pixels of space" wording Not changed (verified against current code): - stock-news/manifest.json: CodeRabbit flagged as out of sync, but top-level version (1.0.2) already equals versions[0] (1.0.2). No action needed. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 2 +- docs/PLUGIN_STORE_USER_GUIDE.md | 6 +-- plugins/football-scoreboard/README.md | 67 --------------------------- plugins/hello-world/README.md | 7 +-- plugins/hello-world/manifest.json | 8 ++-- plugins/hockey-scoreboard/README.md | 48 ++++++++++++------- plugins/ledmatrix-stocks/README.md | 2 +- plugins/static-image/README.md | 44 +++++++----------- plugins/text-display/README.md | 2 +- plugins/text-display/manifest.json | 8 ++-- plugins/ufc-scoreboard/README.md | 2 +- 11 files changed, 68 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index 978d4e7..26c7df5 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,7 @@ cp -r ledmatrix-plugins/plugins/football-scoreboard /path/to/LEDMatrix/plugin-re ``` The directory name on the destination must match the plugin's `id` in -its `manifest.json`. Restart the LEDMatrix display service afterwards +its `manifest.json`. Restart the LEDMatrix display service afterward so the loader picks up the new plugin. > **Note:** See individual plugin README files for detailed setup diff --git a/docs/PLUGIN_STORE_USER_GUIDE.md b/docs/PLUGIN_STORE_USER_GUIDE.md index 8dc470c..d0a402f 100644 --- a/docs/PLUGIN_STORE_USER_GUIDE.md +++ b/docs/PLUGIN_STORE_USER_GUIDE.md @@ -412,10 +412,10 @@ https://github.com/yourusername/ledmatrix-awesome-plugin # Users install with: 1. Go to LEDMatrix web interface -2. Click "Plugin Store" tab -3. Scroll to "Install from URL" +2. Click "Plugin Manager" tab +3. Scroll to "Install from GitHub" 4. Paste: https://github.com/yourusername/ledmatrix-awesome-plugin -5. Click "Install from URL" +5. Click "Install from GitHub" ``` ## FAQ diff --git a/plugins/football-scoreboard/README.md b/plugins/football-scoreboard/README.md index ee0c52d..f026dc2 100644 --- a/plugins/football-scoreboard/README.md +++ b/plugins/football-scoreboard/README.md @@ -324,73 +324,6 @@ Layout customization is available in the web UI under the plugin configuration s Layout offsets work across different display sizes. The plugin calculates default positions based on your display dimensions, and offsets are applied relative to those defaults. This ensures compatibility with various LED matrix configurations. -### Layout Customization - -The plugin supports fine-tuning element positioning for custom display sizes. All offsets are relative to the default calculated positions, allowing you to adjust elements without breaking the layout. - -#### Accessing Layout Settings - -Layout customization is available in the web UI under the plugin configuration section: -1. Open the **Football Scoreboard** tab (second nav row) -2. Expand the **Customization** section -3. Find the **Layout Positioning** subsection - -#### Offset Values - -- **Positive values**: Move element right (x_offset) or down (y_offset) -- **Negative values**: Move element left (x_offset) or up (y_offset) -- **Default (0)**: No change from calculated position - -#### Available Elements - -- **home_logo**: Home team logo position (x_offset, y_offset) -- **away_logo**: Away team logo position (x_offset, y_offset) -- **score**: Game score position (x_offset, y_offset) -- **status_text**: Status/period text position (x_offset, y_offset) -- **date**: Game date position (x_offset, y_offset) -- **time**: Game time position (x_offset, y_offset) -- **records**: Team records/rankings position (away_x_offset, home_x_offset, y_offset) - -#### Example Adjustments - -**Move logos inward for smaller displays:** -```json -{ - "customization": { - "layout": { - "home_logo": { "x_offset": -5 }, - "away_logo": { "x_offset": 5 } - } - } -} -``` - -**Adjust score position:** -```json -{ - "customization": { - "layout": { - "score": { "x_offset": 0, "y_offset": -2 } - } - } -} -``` - -**Shift records upward:** -```json -{ - "customization": { - "layout": { - "records": { "y_offset": -3 } - } - } -} -``` - -#### Display Size Compatibility - -Layout offsets work across different display sizes. The plugin calculates default positions based on your display dimensions, and offsets are applied relative to those defaults. This ensures compatibility with various LED matrix configurations. - ### Color Coding - **Live Games**: Green text for active status - **Redzone**: Red highlighting when teams are in scoring position diff --git a/plugins/hello-world/README.md b/plugins/hello-world/README.md index adae164..9ba1e03 100644 --- a/plugins/hello-world/README.md +++ b/plugins/hello-world/README.md @@ -22,10 +22,11 @@ way to install it is from the LEDMatrix web UI: tab If you'd rather install it from source for local development, copy this -directory into your LEDMatrix installation's `plugins/` folder: +directory into your LEDMatrix installation's configured plugins +directory (default `plugin-repos/`): ```bash -cp -r plugins/hello-world ~/LEDMatrix/plugins/ +cp -r plugins/hello-world ~/LEDMatrix/plugin-repos/ sudo systemctl restart ledmatrix ``` @@ -96,7 +97,7 @@ sudo journalctl -u ledmatrix -f | grep hello-world You should see something like: -``` +```text Discovered plugin: hello-world v1.0.2 Loaded plugin: hello-world Hello World plugin initialized with message: 'Hello, World!' diff --git a/plugins/hello-world/manifest.json b/plugins/hello-world/manifest.json index a19b91c..458d07e 100644 --- a/plugins/hello-world/manifest.json +++ b/plugins/hello-world/manifest.json @@ -17,13 +17,13 @@ ], "versions": [ { - "released": "2025-10-19", - "version": "1.0.1", + "released": "2026-04-06", + "version": "1.0.2", "ledmatrix_min_version": "2.0.0" }, { - "released": "2026-04-06", - "version": "1.0.2", + "released": "2025-10-19", + "version": "1.0.1", "ledmatrix_min_version": "2.0.0" } ], diff --git a/plugins/hockey-scoreboard/README.md b/plugins/hockey-scoreboard/README.md index 61ad9b2..6c40258 100644 --- a/plugins/hockey-scoreboard/README.md +++ b/plugins/hockey-scoreboard/README.md @@ -79,7 +79,7 @@ The plugin registers granular display modes directly in `manifest.json`. The dis ### How Rotation Works -The display controller rotates through all registered modes in the order they appear in `manifest.json`. Each mode can have its own `display_duration` configured in the plugin config. +The display controller rotates through all registered modes in the order they appear in `manifest.json`. Each mode's duration is configured under `.display_durations.{base,live,recent,upcoming}` (or the cross-league fallback `defaults.display_duration`). **Default Rotation Order:** 1. `nhl_recent` @@ -319,12 +319,12 @@ Enable the leagues you want to track: ### 3. Add Favorite Teams -Add your favorite team abbreviations to the `favorite_teams` object for each league. Games involving these teams will be shown first if `prioritize_favorites` is enabled. +Add your favorite team abbreviations to the `favorite_teams` object for each league. Games involving these teams will be shown first when `.live_priority` is enabled. ### 4. Adjust Display Settings -- Set `display_duration` based on how many games you expect (shorter = more games shown) -- Adjust `update_interval` based on desired freshness (60s recommended for live games) +- Set `.display_durations.{base,live,recent,upcoming}` (or the fallback `defaults.display_duration`) based on how many games you expect (shorter = more games shown) +- Adjust `.update_intervals.{base,live,recent,upcoming,odds}` (or the fallback `defaults.update_interval_seconds`) based on desired freshness (30s live poll recommended) - Enable/disable display modes based on preference ### 5. Enable Plugin @@ -341,14 +341,14 @@ Make sure `enabled: true` in the configuration and the plugin is activated in th - Ensure internet connection is working **Games not updating:** -- Check `update_interval` setting +- Check `.update_intervals.*` (or `defaults.update_interval_seconds`) settings - Verify API is responding (check logs) - Try clearing cache: restart plugin or clear cache manually - Check background service is enabled **Favorite teams not showing:** - Verify team abbreviations are correct (case-sensitive) -- Ensure `prioritize_favorites` is true +- Ensure `.live_priority` is true - Check that favorite teams have games in current time window **Logos not displaying:** @@ -361,7 +361,7 @@ Make sure `enabled: true` in the configuration and the plugin is activated in th - Verify ESPN API includes situation data (may not be available for all leagues) **SOG not accurate:** -- Enable `show_shots_on_goal` in config +- Enable `defaults.show_shots_on_goal` (or the per-league override `.display_options.show_shots_on_goal`) in config - ESPN API may have delayed SOG updates - Some leagues may not provide SOG data @@ -500,16 +500,26 @@ This plugin uses the **ESPN public API** for all hockey data: "favorite_teams": { "nhl": ["TB", "TOR", "BOS"] }, + "defaults": { + "update_interval_seconds": 60, + "display_duration": 15 + }, "nhl": { "enabled": true, "display_modes": { "live": true, "recent": true, "upcoming": false + }, + "update_intervals": { + "base": 60, + "live": 30 + }, + "display_durations": { + "base": 15, + "live": 20 } - }, - "update_interval": 60, - "display_duration": 15 + } } ``` @@ -532,10 +542,12 @@ This plugin uses the **ESPN public API** for all hockey data: "live": true, "recent": true, "upcoming": true - } - }, - "upcoming_games_hours": 168, - "update_interval": 120 + }, + "update_intervals": { + "base": 120 + }, + "upcoming_games_hours": 168 + } } ``` @@ -554,11 +566,13 @@ This plugin uses the **ESPN public API** for all hockey data: "ncaa_mens": ["MICH"], "ncaa_womens": ["WISC"] }, - "prioritize_favorites": true, - "show_shots_on_goal": true, - "show_powerplay": true, + "defaults": { + "show_shots_on_goal": true, + "show_powerplay": true + }, "nhl": { "enabled": true, + "live_priority": true, "display_modes": { "live": true, "recent": true, diff --git a/plugins/ledmatrix-stocks/README.md b/plugins/ledmatrix-stocks/README.md index e63c32e..f2bb2e8 100644 --- a/plugins/ledmatrix-stocks/README.md +++ b/plugins/ledmatrix-stocks/README.md @@ -47,7 +47,7 @@ generated from it. The most-used keys, with their actual nesting: | `display.min_duration` | `30` | Floor for dynamic duration (seconds) | | `display.max_duration` | `300` | Ceiling for dynamic duration (seconds) | | `display.duration_buffer` | `0.1` | Padding factor on dynamic duration | -| `display.stock_gap` | `32` | Pixels of empty space between symbols | +| `display.stock_gap` | `32` | Pixels of space between symbols | ### `stocks.*` diff --git a/plugins/static-image/README.md b/plugins/static-image/README.md index 0c76629..6432d43 100644 --- a/plugins/static-image/README.md +++ b/plugins/static-image/README.md @@ -31,7 +31,9 @@ Display static images on your LED matrix with automatic scaling, aspect ratio pr ```json { "enabled": true, - "images": ["assets/static_images/my_logo.png"], + "images": [ + { "id": "logo", "path": "assets/static_images/my_logo.png" } + ], "fit_to_display": true, "preserve_aspect_ratio": true, "background_color": [0, 0, 0], @@ -45,12 +47,12 @@ Display static images on your LED matrix with automatic scaling, aspect ratio pr { "enabled": true, "images": [ - "assets/static_images/logo_a.png", - "assets/static_images/logo_b.png", - "assets/static_images/logo_c.png" + { "id": "logo_a", "path": "assets/static_images/logo_a.png" }, + { "id": "logo_b", "path": "assets/static_images/logo_b.png" }, + { "id": "logo_c", "path": "assets/static_images/logo_c.png" } ], "image_config": { - "mode": "single", + "mode": "multiple", "rotation_mode": "sequential" }, "rotation_settings": { @@ -86,9 +88,6 @@ from it. Key options: | `background_color` | `[0, 0, 0]` | RGB fill behind transparent pixels | | `display_duration` | `10` | Seconds the plugin holds the screen each rotation | -> **Legacy:** the plugin still accepts a single `image_path` string for -> backward compatibility, but new configs should use the `images` array. - ## Usage ### Basic Setup @@ -135,21 +134,8 @@ plugin.reload_image() ### Multiple Images Put all the images you want to cycle through into the `images` array (see -the multi-image example above). For older configs, you can still create -multiple plugin instances with different IDs: - -```json -{ - "static-image-1": { - "enabled": true, - "image_path": "assets/static_images/image1.png" - }, - "static-image-2": { - "enabled": true, - "image_path": "assets/static_images/image2.png" - } -} -``` +the multi-image example above) and set `image_config.mode` to +`"multiple"`. ## Troubleshooting @@ -178,7 +164,9 @@ multiple plugin instances with different IDs: ```json { "enabled": true, - "image_path": "assets/static_images/company_logo.png", + "images": [ + { "id": "company_logo", "path": "assets/static_images/company_logo.png" } + ], "fit_to_display": true, "preserve_aspect_ratio": true, "background_color": [0, 0, 0] @@ -189,7 +177,9 @@ multiple plugin instances with different IDs: ```json { "enabled": true, - "image_path": "assets/static_images/pixel_art.png", + "images": [ + { "id": "pixel_art", "path": "assets/static_images/pixel_art.png" } + ], "fit_to_display": false, "preserve_aspect_ratio": true, "background_color": [0, 0, 50] @@ -200,7 +190,9 @@ multiple plugin instances with different IDs: ```json { "enabled": true, - "image_path": "assets/static_images/photo.jpg", + "images": [ + { "id": "photo", "path": "assets/static_images/photo.jpg" } + ], "fit_to_display": true, "preserve_aspect_ratio": false, "background_color": [0, 0, 0] diff --git a/plugins/text-display/README.md b/plugins/text-display/README.md index ec1d78d..34b4c60 100644 --- a/plugins/text-display/README.md +++ b/plugins/text-display/README.md @@ -63,7 +63,7 @@ from it. Key options: | `scroll_speed` | `1` | Speed multiplier (≈ pixels per frame). Higher = faster. | | `scroll_delay` | `0.01` | Sleep between scroll steps in seconds. Lower = smoother but more CPU | | `scroll_loop` | `true` | Loop the text instead of stopping after one pass | -| `scroll_gap_width` | `32` | Pixels of empty space between scroll loops | +| `scroll_gap_width` | `32` | Pixels of space between scroll loops | | `target_fps` | `120` | Target frames per second cap for scroll rendering | | `text_color` | `[255, 255, 255]` | RGB text color | | `background_color` | `[0, 0, 0]` | RGB background color | diff --git a/plugins/text-display/manifest.json b/plugins/text-display/manifest.json index 0c0463a..bdabc33 100644 --- a/plugins/text-display/manifest.json +++ b/plugins/text-display/manifest.json @@ -19,13 +19,13 @@ "class_name": "TextDisplayPlugin", "versions": [ { - "released": "2025-10-19", - "version": "1.0.1", + "released": "2026-04-07", + "version": "1.0.2", "ledmatrix_min_version": "2.0.0" }, { - "released": "2026-04-07", - "version": "1.0.2", + "released": "2025-10-19", + "version": "1.0.1", "ledmatrix_min_version": "2.0.0" } ], diff --git a/plugins/ufc-scoreboard/README.md b/plugins/ufc-scoreboard/README.md index ba42dad..245871e 100644 --- a/plugins/ufc-scoreboard/README.md +++ b/plugins/ufc-scoreboard/README.md @@ -50,7 +50,7 @@ from it. The most-used keys: | `game_display_duration` | `15` | Seconds per individual fight in switch mode | | `ufc.enabled` | `true` | Toggle UFC content | | `ufc.favorite_fighters` | `[]` | Array of fighter names to prioritize (e.g. `["Jon Jones", "Islam Makhachev"]`) | -| `ufc.favorite_weight_classes` | `[]` | Weight classes to prioritize (e.g. `["Heavyweight", "Lightweight"]`) | +| `ufc.favorite_weight_classes` | `[]` | Weight class abbreviations to prioritize (e.g. `["HW", "LW"]`; see `config_schema.json` for the full list: `LW`, `HW`, `WW`, `MW`, `FW`, `BW`, `FLW`, `LHW`, `WSW`, `WFW`, `WBW`, `WFLW`) | | `ufc.display_modes.show_live` | `true` | Toggle live mode | | `ufc.display_modes.show_recent` | `true` | Toggle recent mode | | `ufc.display_modes.show_upcoming` | `true` | Toggle upcoming mode | From 52cd4b5f1e272f93f623c4a044a0689cfca6262b Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 21:10:24 -0400 Subject: [PATCH 15/15] docs: address CodeRabbit follow-up comments on #92 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CONTRIBUTING.md: add "text" language hint to repo-layout fenced block so markdownlint accepts it - SECURITY.md: vary sentence structure of the plugin-security-model bullets so they don't all start with "Plugins" Not changed (already fixed in 98d5478): - README.md line 212 "afterwards" → "afterward" (duplicate comment) Co-Authored-By: Claude Opus 4.6 (1M context) --- CONTRIBUTING.md | 2 +- SECURITY.md | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df0afe3..a443458 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ documentation fixes all help. ## Repository layout -``` +```text ledmatrix-plugins/ ├── plugins/ │ └── / diff --git a/SECURITY.md b/SECURITY.md index fb1830f..d833bdb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -64,11 +64,12 @@ service process with full file-system and network access. There is no sandboxing. The same warning the LEDMatrix `SECURITY.md` makes applies to every plugin here: -- **Plugins can read and write any file the LEDMatrix process can - reach**, including `config_secrets.json`. -- **Plugins can make arbitrary network requests.** -- **Plugins are loaded into the same Python process as the display - loop**, so a crash in a plugin can affect the whole display. +- **Any plugin can read and write any file the LEDMatrix process + can reach**, including `config_secrets.json`. +- **Arbitrary outbound network requests are possible from any + loaded plugin.** +- **Because plugins run in the same Python process as the display + loop**, a crash in one plugin can take down the whole display. The official plugins in this repo go through a manual review (see [VERIFICATION.md](VERIFICATION.md)) before being added to the