Files
LEDMatrix/docs/PLUGIN_QUICK_REFERENCE.md
T
ChuckandClaude Opus 5.5 a231d4dbc7 chore: delete unreferenced scripts and archived docs; fix stale doc claims (#607)
* chore(scripts): delete unreferenced helper scripts

None of these is referenced by an installer, systemd unit, CI workflow,
test, the web UI or src/:

- utils/cleanup_venv.sh removes venv_web_v2, which nothing creates
- utils/clear_python_cache.sh hardcodes ~/LEDMatrix and a .webassets-cache
  nothing uses
- install/migrate_config.sh only copies the template, which the installer
  and ConfigManager already do
- install/debug_install.sh, debug/debug_web_manual.py
- diagnose_web_ui.sh and verify_web_ui.sh overlap diagnose_web_interface.sh,
  which the docs point to
- fix_internet_connectivity.sh is iptables-only (stale on nftables)
- diagnose_plugin_permissions.sh, dev/validate_python.py
- download_nba_logos.py + README_NBA_LOGOS.md: logo_downloader fetches
  logos on demand
- setup_plugin_repos.py linked into the production plugin-repos/ dir; the
  dev workflow is scripts/dev/dev_plugin_setup.sh, and
  MULTI_ROOT_WORKSPACE_SETUP.md now uses it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(config): drop unused plugin_system flags and a dead unit comment

- config.template.json: remove plugin_system.auto_discover,
  auto_load_enabled and development_mode. Nothing reads them; the web UI
  only stores them when a client sends them. ConfigManager's migration
  only adds template keys, so existing configs keep theirs unchanged.
- config.template.json: re-indent vegas_scroll's live_* keys.
- systemd/ledmatrix.service: remove the comment documenting
  LEDMATRIX_ON_DEMAND_PLUGIN / on_demand_env.conf; nothing reads either.
- CONFIG_REFERENCE.md: say the legacy keys are no longer in the template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: delete docs/archive and PLUGIN_IMPLEMENTATION_SUMMARY.md

- docs/archive/: superseded guides; the repository history keeps them
  and no live doc links into the directory. The one open document in it,
  WEB_UI_AUDIT_2026-09.md, moves to docs/audits/ and is linked from the
  docs index.
- PLUGIN_IMPLEMENTATION_SUMMARY.md invented usage statistics, called
  v2.0.0 current, listed shipped auto-updates as future work and
  documented a BasePlugin.get_config() that does not exist.
- docs/README.md: drop both, and stop telling contributors to archive
  obsolete pages instead of deleting them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(plugin-api): fix extra_small_font size, cache metric key and scroll pacing example

- PLUGIN_API_REFERENCE: extra_small_font loads at 7, not 6 (crisp_size
  snaps it, src/display_manager.py); get_cache_metrics() returns
  cache_hit_rate, not hit_rate (src/cache/cache_metrics.py).
- ADVANCED_PLUGIN_DEVELOPMENT: the basic scrolling example slept in a loop
  and never passed frame_hold; use ScrollHelper + scroll_config.configure()
  and set_scrolling_state(True, frame_hold=...) as PLUGIN_API_REFERENCE does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(plugin-config): match the config tab, icon and web-action docs to the code

- PLUGIN_CONFIG_QUICK_START / PLUGIN_CONFIGURATION_TABS /
  PLUGIN_CONFIGURATION_GUIDE: there is no "Reset to Defaults" button (the
  tab has Refresh, Update, Uninstall, Save Configuration); plugin config
  hot-reloads (ConfigService + on_config_change), so no restart; the
  schema is found by the fixed name config_schema.json, not a manifest
  config_schema field; the tab row is "Plugin Manager", not "Plugins";
  forms are server-rendered from /v3/partials/plugin-config/<id>; the
  duration hook is get_display_duration()/display_duration; a class_name
  mismatch raises PluginError; the store requires id, name, class_name and
  display_modes (not version); plugin_system.debug/log_level do not exist
  (use run.py -d / LEDMATRIX_DEBUG). Drop "future" features that shipped.
- PLUGIN_CONFIG_CORE_PROPERTIES: list all of CORE_PLUGIN_PROPERTIES,
  including skin, skin_options and the vegas_* tuning keys.
- PLUGIN_CUSTOM_ICONS: icon is only a Font Awesome class (fallback
  fa-puzzle-piece); emoji/URL icons and getPluginIcon() never existed in
  v3. Note that /api/v3/plugins/installed currently omits icon.
- PLUGIN_WEB_UI_ACTIONS (+ example JSON): success_message, error_message
  and step1_message are never read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(store): describe the monorepo registry and the store UI as they are

- PLUGIN_STORE_GUIDE: the Plugin Store is a section of the Plugin
  Manager tab; URL installs are "Install from GitHub" -> "Install Single
  Plugin"; bulk update exists (Check & Update All) plus opt-in weekly
  auto-update; PluginStoreManager() defaults to plugins/, so the Python
  examples pass plugin-repos; registry plugins are downloaded (GitHub API,
  ZIP fallback), not cloned; updates compare version with latest_version.
- PLUGIN_REGISTRY_SETUP_GUIDE: replace the per-plugin-repo + tag
  walkthrough with a short page on the monorepo registry (plugin_path,
  latest_version, update_registry.py) that points at the monorepo's own
  SUBMISSION.md. Drops the reference to the deleted
  PLUGIN_IMPLEMENTATION_SUMMARY.md and setup_plugin_repos.py.
- plugin_registry_template.json: use the real entry shape.
- PLUGIN_QUICK_REFERENCE: automatic background updates exist (opt-in);
  registry example and publishing steps use the monorepo, not tags.
- PLUGIN_DEVELOPMENT_GUIDE: tags/releases are not read by the store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(readme): fix the Triple Bonnet mapping, install prerequisites and backup names

- README: the Adafruit Triple Bonnet uses `regular` (3 outputs), not
  `regular-pi1` (1 output) -- src/matrix_support.py MAPPING_OUTPUTS, and
  the README's own hardware_mapping section; the template default mapping
  is adafruit-hat, the PWM mod switches it to adafruit-hat-pwm; manual
  install only needs git up front (first_time_install.sh installs
  python-dev-is-python3, cmake, ninja-build etc.; cython3/scons are not
  used); the Pi Zero 2 W is a supported low-memory board, consistent with
  PRODUCT.md, LOW_MEMORY_BOARDS.md and the installer's low-memory build;
  fix the "First_time_install.sh" spelling, an orphan "2." list item and
  the hello-world starter link (it lives in the plugins monorepo).
- CONFIG_DEBUGGING: automatic backups are
  config/backups/config.json.backup.<YYYYMMDD_HHMMSS_ffffff> (five kept),
  not config_YYYYMMDD_HHMMSS.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(dev): correct the test-running and rgbmatrix build instructions

- HOW_TO_RUN_TESTS: coverage is not collected by a plain pytest run and
  pytest.ini has no threshold; the only one is --cov-fail-under=52 in the
  core unit-test job of .github/workflows/test.yml, which runs the whole
  test/ tree (not an allowlist). Almost no tests carry markers, so
  -m integration / -m slow select nothing; drop them and -m unit as the
  quick check. Replace the hardcoded /home/chuck path.
- DEVELOPMENT: the rgbmatrix package is built with pip install . from
  the submodule root (scikit-build-core + CMake + Ninja), as
  first_time_install.sh does; there is no make build-python /
  bindings/python step, and the build deps are python-dev-is-python3,
  cmake and ninja-build, not cython3/scons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(wifi): the setup AP is open; auto-enable can be turned off without code changes

- WIFI_NETWORK_SETUP / SSH_UNAVAILABLE_AFTER_INSTALL: both AP paths in
  src/wifi_manager.py create an open network and nothing reads
  ap_password, so drop the "ledmatrix123" password and the ap_password
  key/advice.
- SSH_UNAVAILABLE_AFTER_INSTALL: disabling automatic AP mode does not
  need code changes -- auto_enable_ap_mode is a WiFi-tab toggle and
  POST /api/v3/wifi/ap/auto-enable; note the monitor daemon reads
  wifi_config.json at start, so restart it after changing the setting.
  Use the ledpi username and a relative install path like the other docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(reference): add auto_update, drop drifted line numbers, fix UI and service details

- CONFIG_REFERENCE: document the top-level auto_update.enabled key (read
  by web_interface/auto_update.py and src/auto_update_setup.py); replace
  drifted file:line references with function names; the template's
  dim_schedule mode is "global".
- ADVANCED_FEATURES: core does not read a per-plugin background_service
  block (the sports plugins read their own), and priority is "higher
  number = higher priority" on FetchRequest but not used for ordering.
- WEB_INTERFACE_GUIDE: the General tab toggle is "Web Display Autostart"
  (web interface service), brightness is 1-100, and config paths are
  relative to the LEDMatrix folder, not /config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: drop references to code removed in #608

get_installed_plugin_info, WiFiManager's saved_networks and the six
always-skipping plugin test files are deleted there. NetworkManager already
remembers joined networks; LEDMatrix no longer stores WiFi passwords.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: don't link SKIN_SYSTEM.md from the core-properties page

#615 deletes SKIN_SYSTEM.md; with this link, whichever of the two merged
second would break test_doc_links. The skin/skin_options entries go when
#615 removes the keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:36:38 -04:00

6.8 KiB

LEDMatrix Plugin Architecture - Quick Reference

Overview

LEDMatrix is a modular, plugin-based system where users create, share, and install custom displays via a GitHub-based store (similar in spirit to HACS for Home Assistant). This page is a quick reference; for the full design see PLUGIN_ARCHITECTURE_SPEC.md and PLUGIN_DEVELOPMENT_GUIDE.md.

Key Decisions

✅ Plugin-First: All display features (calendar excepted) are now plugins ✅ GitHub Store: Discovery from ledmatrix-plugins registry plus any GitHub URL ✅ Plugin Location: configured by plugin_system.plugins_directory in config.json (default plugin-repos/). Plugin discovery scans only this directory — there is no loader fallback to plugins/ (only Plugin Store operations and schema lookup additionally probe plugins/)

File Structure

LEDMatrix/
├── src/
│   └── plugin_system/
│       ├── base_plugin.py          # Plugin interface
│       ├── plugin_manager.py       # Load/unload plugins
│       ├── plugin_loader.py        # Discovery + dynamic import
│       └── store_manager.py        # Install from GitHub
├── plugin-repos/                   # Default plugin install location
│   ├── clock-simple/
│   │   ├── manifest.json           # Metadata
│   │   ├── manager.py              # Main plugin class
│   │   ├── requirements.txt        # Dependencies
│   │   ├── config_schema.json      # Validation
│   │   └── README.md
│   └── hockey-scoreboard/
│       └── ... (same structure)
└── config/config.json               # Plugin configs

Creating a Plugin

1. Minimal Plugin Structure

manifest.json:

{
  "id": "my-plugin",
  "name": "My Display",
  "version": "1.0.0",
  "author": "YourName",
  "entry_point": "manager.py",
  "class_name": "MyPlugin",
  "category": "custom"
}

manager.py:

from src.plugin_system.base_plugin import BasePlugin

class MyPlugin(BasePlugin):
    def update(self):
        # Fetch data
        pass
    
    def display(self, force_clear=False):
        # Render to display
        self.display_manager.draw_text("Hello!", x=5, y=15)
        self.display_manager.update_display()

2. Configuration

config_schema.json:

{
  "type": "object",
  "properties": {
    "enabled": {"type": "boolean", "default": true},
    "message": {"type": "string", "default": "Hello"}
  }
}

User's config.json:

{
  "my-plugin": {
    "enabled": true,
    "message": "Custom text",
    "display_duration": 15
  }
}

3. Publishing

Official plugins live in the ledmatrix-plugins monorepo: add plugins/<your-plugin-id>/, bump version in its manifest.json on every change, run python update_registry.py there and open a pull request. A third-party plugin can stay in its own repository and be installed by URL. Git tags and releases are not read by the store; see PLUGIN_REGISTRY_SETUP_GUIDE.md.

Using Plugins

Web UI

  1. Browse Store: Plugin Manager tab → Plugin Store section → Search/filter
  2. Install: Click Install in the plugin's row
  3. Configure: open the plugin's tab in the second nav row
  4. Enable/Disable: toggle switch in the Installed Plugins list
  5. Reorder: use the drag-and-drop Rotation Order list in the Rotation tab (saved to display.plugin_rotation_order)

REST API

The API is mounted at /api/v3 (the api_v3 blueprint in web_interface/blueprints/api_v3/, registered in web_interface/app.py).

# Install plugin from the registry
curl -X POST http://your-pi-ip:5000/api/v3/plugins/install \
  -H "Content-Type: application/json" \
  -d '{"plugin_id": "hockey-scoreboard"}'

# Install from custom 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/User/plugin"}'

# List installed
curl http://your-pi-ip:5000/api/v3/plugins/installed

# Toggle
curl -X POST http://your-pi-ip:5000/api/v3/plugins/toggle \
  -H "Content-Type: application/json" \
  -d '{"plugin_id": "hockey-scoreboard", "enabled": true}'

See REST_API_REFERENCE.md for the full list.

Plugin Registry Structure

The official registry lives at ChuckBuilds/ledmatrix-plugins. The Plugin Store reads plugins.json at the root of that repo, which follows this shape:

{
  "plugins": [
    {
      "id": "clock-simple",
      "name": "Simple Clock",
      "author": "ChuckBuilds",
      "category": "time",
      "repo": "https://github.com/ChuckBuilds/ledmatrix-plugins",
      "branch": "main",
      "plugin_path": "plugins/clock-simple",
      "latest_version": "1.0.0",
      "verified": true
    }
  ]
}

plugin_path is empty for a third-party plugin in its own repository. The store offers an update when the installed manifest's version is older than latest_version.

Benefits

For Users

  • ✅ Install only what you need
  • ✅ Easy discovery of new displays
  • ✅ Simple updates
  • ✅ Community-created content

For Developers

  • ✅ Lower barrier to contribute
  • ✅ No need to fork core repo
  • ✅ Faster iteration
  • ✅ Clear plugin API

For Maintainers

  • ✅ Smaller core codebase
  • ✅ Less merge conflicts
  • ✅ Community handles custom displays
  • ✅ Easier to review changes

Known Limitations

The plugin system is shipped and stable, but some things are still intentionally simple:

  1. Sandboxing: plugins run in the same process as the display loop; there is no isolation. Review code before installing third-party plugins.
  2. Resource limits: there's a resource monitor that warns about slow plugins, but no hard CPU/memory caps.
  3. Plugin ratings: not yet — the Plugin Store shows version, author, and category but no community rating system.
  4. Auto-updates: off by default. Update from the Plugin Manager tab (per plugin, or Check & Update All), or turn on weekly automatic updates in the General tab (auto_update.enabled, web_interface/auto_update.py), which update LEDMatrix and then the installed plugins.
  5. Dependency conflicts: each plugin's requirements.txt is installed via pip; conflicting versions across plugins are not resolved automatically.
  6. Plugin testing framework: see HOW_TO_RUN_TESTS.md and DEV_PREVIEW.md — there are tools, but no mandatory test gate.

See PLUGIN_ARCHITECTURE_SPEC.md for the full architectural specification.