Files
LEDMatrix/docs/PLUGIN_CONFIGURATION_GUIDE.md
Chuck 40fcd1ed9f docs: fix README_NBA_LOGOS and PLUGIN_CONFIGURATION_GUIDE
scripts/README_NBA_LOGOS.md
- "python download_nba_logos.py" — wrong on two counts. The script
  is at scripts/download_nba_logos.py (not the project root), and
  "python" is Python 2 on most systems. Replaced all 4 occurrences
  with "python3 scripts/download_nba_logos.py".
- The doc framed itself as the way to set up "the NBA leaderboard".
  The basketball/leaderboard functionality is now in the
  basketball-scoreboard and ledmatrix-leaderboard plugins (in the
  ledmatrix-plugins repo), which auto-download logos on first run.
  Reframed the script as a pre-population utility for offline / dev
  use cases.
- Bumped the documented Python minimum from 3.7 to 3.9 to match
  the rest of the project.

docs/PLUGIN_CONFIGURATION_GUIDE.md
- The "Plugin Manifest" example was missing 3 fields the plugin
  loader actually requires: id, entry_point, and class_name. A
  contributor copying this manifest verbatim would get
  PluginError("No class_name in manifest") at load time — the same
  loader bug already found in stock-news. Added all three.
- The same example showed config_schema as an inline object. The
  loader expects config_schema to be a file path string (e.g.
  "config_schema.json") with the actual schema in a separate JSON
  file — verified earlier in this audit. Fixed.
- Added a paragraph explaining the loader's required fields and
  the case-sensitivity rule on class_name (the bug that broke
  hello-world's manifest before this PR fixed it).
- "Plugin Manager Class" example had the wrong constructor
  signature: (config, display_manager, cache_manager, font_manager).
  The real BasePlugin.__init__ at base_plugin.py:53-60 takes
  (plugin_id, config, display_manager, cache_manager, plugin_manager).
  A copy-pasted example would TypeError on instantiation. Fixed,
  including a comment noting which attributes BasePlugin sets up.
- Renamed the example class from MyPluginManager to MyPlugin to
  match the project convention (XxxPlugin / XxxScoreboardPlugin
  in actual plugins).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:07:39 -04:00

11 KiB

Plugin Configuration Guide

Overview

The LEDMatrix system uses a plugin-based architecture where each plugin manages its own configuration. This guide explains the configuration structure, how to configure plugins via the web interface, and advanced configuration options.

Quick Start

  1. Install a plugin from the Plugin Store in the web interface
  2. Navigate to the plugin's configuration tab (automatically created when installed)
  3. Configure settings using the auto-generated form
  4. Save configuration and restart the display service

For detailed information, see the sections below.

Configuration Structure

Core System Configuration

The main configuration file (config/config.json) now contains only essential system settings:

{
    "web_display_autostart": true,
    "schedule": {
        "enabled": true,
        "start_time": "07:00",
        "end_time": "23:00"
    },
    "timezone": "America/Chicago",
    "location": {
        "city": "Dallas",
        "state": "Texas",
        "country": "US"
    },
    "display": {
        "hardware": {
            "rows": 32,
            "cols": 64,
            "chain_length": 2,
            "parallel": 1,
            "brightness": 90,
            "hardware_mapping": "adafruit-hat",
            "scan_mode": 0,
            "pwm_bits": 9,
            "pwm_dither_bits": 1,
            "pwm_lsb_nanoseconds": 130,
            "disable_hardware_pulsing": false,
            "inverse_colors": false,
            "show_refresh_rate": false,
            "limit_refresh_rate_hz": 100
        },
        "runtime": {
            "gpio_slowdown": 3
        },
        "display_durations": {
            "calendar": 30
        },
        "use_short_date_format": true
    },
    "calendar": {
        "enabled": false,
        "update_interval": 3600,
        "max_events": 5,
        "show_all_day": true,
        "date_format": "%m/%d",
        "time_format": "%I:%M %p"
    },
    "plugin_system": {
        "plugins_directory": "plugin-repos",
        "auto_discover": true,
        "auto_load_enabled": true
    }
}

Configuration Sections

1. System Settings

  • web_display_autostart: Enable web interface auto-start
  • schedule: Display schedule settings
  • timezone: System timezone
  • location: Default location for location-based plugins

2. Display Hardware

  • hardware: LED matrix hardware configuration
  • runtime: Runtime display settings
  • display_durations: How long each display mode shows (in seconds)
  • use_short_date_format: Use short date format

3. Core Components

  • calendar: Calendar manager settings (core system component)

4. Plugin System

  • plugin_system: Plugin system configuration
    • plugins_directory: Directory where plugins are stored
    • auto_discover: Automatically discover plugins
    • auto_load_enabled: Automatically load enabled plugins

Plugin Configuration

Plugin Discovery

Plugins are automatically discovered from the plugin-repos directory. Each plugin should have:

  • manifest.json: Plugin metadata and configuration schema
  • manager.py: Plugin implementation
  • requirements.txt: Plugin dependencies

Plugin Configuration in config.json

Plugins are configured by adding their plugin ID as a top-level key in the config:

{
    "weather": {
        "enabled": true,
        "api_key": "your_api_key",
        "update_interval": 1800,
        "units": "imperial"
    },
    "stocks": {
        "enabled": true,
        "symbols": ["AAPL", "GOOGL", "MSFT"],
        "update_interval": 600
    }
}

Plugin Display Durations

Add plugin display modes to the display_durations section:

{
    "display": {
        "display_durations": {
            "calendar": 30,
            "weather": 30,
            "weather_forecast": 30,
            "stocks": 30,
            "stock_news": 20
        }
    }
}

Migration from Old Configuration

Removed Sections

The following configuration sections have been removed as they are now handled by plugins:

  • All sports manager configurations (NHL, NBA, NFL, etc.)
  • Weather manager configuration
  • Stock manager configuration
  • News manager configuration
  • Music manager configuration
  • All other content manager configurations

What Remains

Only core system components remain in the main configuration:

  • Display hardware settings
  • Schedule settings
  • Calendar manager (core component)
  • Plugin system settings

Plugin Development

Plugin Structure

Each plugin should follow this structure:

plugin-repos/
└── my-plugin/
    ├── manifest.json
    ├── manager.py
    ├── requirements.txt
    └── README.md

Plugin Manifest

{
    "id": "my-plugin",
    "name": "My Plugin",
    "version": "1.0.0",
    "description": "Plugin description",
    "author": "Your Name",
    "entry_point": "manager.py",
    "class_name": "MyPlugin",
    "display_modes": ["my_plugin"],
    "config_schema": "config_schema.json"
}

The required fields the plugin loader will check for are id, name, version, class_name, and display_modes. entry_point defaults to manager.py if omitted. config_schema must be a file path (relative to the plugin directory) — the schema itself lives in a separate JSON file, not inline in the manifest. The class_name value must match the actual class defined in the entry point file exactly (case-sensitive, no spaces); otherwise the loader fails with AttributeError at load time.

Plugin Manager Class

from src.plugin_system.base_plugin import BasePlugin

class MyPlugin(BasePlugin):
    def __init__(self, plugin_id, config, display_manager, cache_manager, plugin_manager):
        super().__init__(plugin_id, config, display_manager, cache_manager, plugin_manager)
        # self.config, self.display_manager, self.cache_manager,
        # self.plugin_manager, self.logger, and self.enabled are
        # all set up by BasePlugin.__init__.

    def update(self):
        """Fetch/update data. Called based on update_interval."""
        pass

    def display(self, force_clear=False):
        """Render plugin content to the LED matrix."""
        pass
    
    def get_duration(self):
        """Get display duration for this plugin"""
        return self.config.get('duration', 30)

Dynamic Duration Configuration

Plugins that render multi-step content (scrolling leaderboards, tickers, etc.) can opt-in to dynamic durations so the display controller waits for a full cycle.

{
    "football-scoreboard": {
        "enabled": true,
        "dynamic_duration": {
            "enabled": true,
            "max_duration_seconds": 240
        }
    },
    "display": {
        "dynamic_duration": {
            "max_duration_seconds": 180
        }
    }
}
  • Set dynamic_duration.enabled per plugin to toggle the behaviour.
  • Optional dynamic_duration.max_duration_seconds on the plugin overrides the global cap (defined under display.dynamic_duration.max_duration_seconds, default 180s).
  • Plugins should override supports_dynamic_duration(), is_cycle_complete(), and reset_cycle_state() (see BasePlugin) to control when a cycle completes.

Configuration Tabs

Each installed plugin automatically gets its own dedicated configuration tab in the web interface. This provides a clean, organized way to configure plugins.

Accessing Plugin Configuration

  1. Navigate to the Plugins tab to see all installed plugins
  2. Click the Configure button on any plugin card, or
  3. Click directly on the plugin's tab button in the navigation bar

Auto-Generated Forms

Configuration forms are automatically generated from each plugin's config_schema.json:

  • Boolean → Toggle switch
  • Number/Integer → Number input with min/max validation
  • String → Text input with length constraints
  • Array → Comma-separated input
  • Enum → Dropdown menu

Configuration Features

  • Type-safe inputs: Form inputs match JSON Schema types
  • Default values: Fields show current values or schema defaults
  • Real-time validation: Input constraints enforced (min, max, maxLength, etc.)
  • Reset to defaults: One-click reset to restore original settings
  • Help text: Each field shows description from schema

For more details, see Plugin Configuration Tabs.

For information about how core properties (enabled, display_duration, live_priority) are handled, see Core Plugin Properties.

Schema Validation

The configuration system uses JSON Schema Draft-07 for validation:

  • Pre-save validation: Invalid configurations are rejected before saving
  • Automatic defaults: Default values extracted from schemas
  • Error messages: Clear error messages show exactly what's wrong
  • Reliable loading: Schema loading with caching and fallback paths
  • Core properties handling: System-managed properties (enabled, display_duration, live_priority) are automatically handled - they don't need to be in plugin schemas and aren't validated as required fields

Schema Structure

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "enabled": {
      "type": "boolean",
      "default": true,
      "description": "Enable or disable this plugin"
    },
    "update_interval": {
      "type": "integer",
      "default": 3600,
      "minimum": 60,
      "maximum": 86400,
      "description": "Update interval in seconds"
    }
  }
}

Best Practices

  1. Keep main config minimal: Only include core system settings
  2. Use plugin-specific configs: Each plugin manages its own configuration
  3. Document plugin requirements: Include clear documentation for each plugin
  4. Version control: Keep plugin configurations in version control
  5. Testing: Test plugins in emulator mode before hardware deployment
  6. Use schemas: Always provide config_schema.json for your plugins
  7. Sensible defaults: Ensure defaults work without additional configuration
  8. Add descriptions: Help users understand each setting

Troubleshooting

Common Issues

  1. Plugin not loading: Check plugin manifest and directory structure
  2. Configuration errors: Validate plugin configuration against schema
  3. Display issues: Check display durations and plugin display methods
  4. Performance: Monitor plugin update intervals and resource usage
  5. Tab not showing: Verify config_schema.json exists and is referenced in manifest
  6. Settings not saving: Check validation errors and ensure all required fields are filled

Debug Mode

Enable debug logging to troubleshoot plugin issues:

{
    "plugin_system": {
        "debug": true,
        "log_level": "debug"
    }
}

See Also