Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 27 additions & 14 deletions .cursor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,39 +43,48 @@ cp ../../.cursor/plugin_templates/*.template .
2. **Using dev_plugin_setup.sh**:
```bash
# Link from GitHub
./dev_plugin_setup.sh link-github my-plugin
./scripts/dev/dev_plugin_setup.sh link-github my-plugin

# Link local repo
./dev_plugin_setup.sh link my-plugin /path/to/repo
./scripts/dev/dev_plugin_setup.sh link my-plugin /path/to/repo
```

### Running Plugins
### Running the Display

```bash
# Emulator (development)
python run.py --emulator
# Emulator mode (development, no hardware required)
python3 run.py --emulator
# (equivalent: EMULATOR=true python3 run.py)

# Hardware (production)
python run.py
# Hardware (production, requires the rpi-rgb-led-matrix submodule built)
python3 run.py

# As service
# As a systemd service
sudo systemctl start ledmatrix

# Dev preview server (renders plugins to a browser without running run.py)
python3 scripts/dev_server.py # then open http://localhost:5001
```

The `-e`/`--emulator` CLI flag is defined in `run.py:19-20` and
sets `os.environ["EMULATOR"] = "true"` before any display imports,
which `src/display_manager.py:2` then reads to switch between the
hardware and emulator backends.

### Managing Plugins

```bash
# List plugins
./dev_plugin_setup.sh list
./scripts/dev/dev_plugin_setup.sh list

# Check status
./dev_plugin_setup.sh status
./scripts/dev/dev_plugin_setup.sh status

# Update plugin(s)
./dev_plugin_setup.sh update [plugin-name]
./scripts/dev/dev_plugin_setup.sh update [plugin-name]

# Unlink plugin
./dev_plugin_setup.sh unlink <plugin-name>
./scripts/dev/dev_plugin_setup.sh unlink <plugin-name>
```

## Using These Files with Cursor
Expand Down Expand Up @@ -118,9 +127,13 @@ Refer to `plugins_guide.md` for:
- **Plugin System**: `src/plugin_system/`
- **Base Plugin**: `src/plugin_system/base_plugin.py`
- **Plugin Manager**: `src/plugin_system/plugin_manager.py`
- **Example Plugins**: `plugins/hockey-scoreboard/`, `plugins/football-scoreboard/`
- **Example Plugins**: see the
[`ledmatrix-plugins`](https://github.com/ChuckBuilds/ledmatrix-plugins)
repo for canonical sources (e.g. `plugins/hockey-scoreboard/`,
`plugins/football-scoreboard/`). Installed plugins land in
`plugin-repos/` (default) or `plugins/` (dev fallback).
- **Architecture Docs**: `docs/PLUGIN_ARCHITECTURE_SPEC.md`
- **Development Setup**: `dev_plugin_setup.sh`
- **Development Setup**: `scripts/dev/dev_plugin_setup.sh`

## Getting Help

Expand Down
22 changes: 18 additions & 4 deletions .cursor/plugin_templates/QUICK_START.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,20 +156,34 @@ def _fetch_data(self):

### Adding Image Rendering

There is no `draw_image()` helper on `DisplayManager`. To render an
image, paste it directly onto the underlying PIL `Image`
(`display_manager.image`) and then call `update_display()`:

```python
def _render_content(self):
# Load and render image
image = Image.open("assets/logo.png")
self.display_manager.draw_image(image, x=0, y=0)
# Load and paste image onto the display canvas
image = Image.open("assets/logo.png").convert("RGB")
self.display_manager.image.paste(image, (0, 0))

# Draw text overlay
self.display_manager.draw_text(
"Text",
x=10, y=20,
color=(255, 255, 255)
)

self.display_manager.update_display()
```

For transparency, paste with a mask:

```python
icon = Image.open("assets/icon.png").convert("RGBA")
self.display_manager.image.paste(icon, (5, 5), icon)
```


### Adding Live Priority

1. Enable in config:
Expand Down
77 changes: 43 additions & 34 deletions .cursor/plugins_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ This method is best for plugins stored in separate Git repositories.

```bash
# Link a plugin from GitHub (auto-detects URL)
./dev_plugin_setup.sh link-github <plugin-name>
./scripts/dev/dev_plugin_setup.sh link-github <plugin-name>

# Example: Link hockey-scoreboard plugin
./dev_plugin_setup.sh link-github hockey-scoreboard
./scripts/dev/dev_plugin_setup.sh link-github hockey-scoreboard

# With custom URL
./dev_plugin_setup.sh link-github <plugin-name> https://github.com/user/repo.git
./scripts/dev/dev_plugin_setup.sh link-github <plugin-name> https://github.com/user/repo.git
```

The script will:
Expand All @@ -71,10 +71,10 @@ The script will:

```bash
# Link a local plugin repository
./dev_plugin_setup.sh link <plugin-name> <path-to-repo>
./scripts/dev/dev_plugin_setup.sh link <plugin-name> <path-to-repo>

# Example: Link a local plugin
./dev_plugin_setup.sh link my-plugin ../ledmatrix-my-plugin
./scripts/dev/dev_plugin_setup.sh link my-plugin ../ledmatrix-my-plugin
```

### Method 2: Manual Plugin Creation
Expand Down Expand Up @@ -321,7 +321,8 @@ Each plugin has its own section in `config/config.json`:

### Secrets Management

Store sensitive data (API keys, tokens) in `config/config_secrets.json`:
Store sensitive data (API keys, tokens) in `config/config_secrets.json`
under the same plugin id you use in `config/config.json`:

```json
{
Expand All @@ -331,19 +332,21 @@ Store sensitive data (API keys, tokens) in `config/config_secrets.json`:
}
```

Reference secrets in main config:
At load time, the config manager deep-merges `config_secrets.json` into
the main config (verified at `src/config_manager.py:162-172`). So in
your plugin's code:

```json
{
"my-plugin": {
"enabled": true,
"config_secrets": {
"api_key": "my-plugin.api_key"
}
}
}
```python
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.api_key = config.get("api_key") # already merged from secrets
```

There is no separate `config_secrets` reference field — just put the
secret value under the same plugin namespace and read it from the
merged config.

### Plugin Discovery

Plugins are automatically discovered when:
Expand All @@ -355,7 +358,7 @@ Check discovered plugins:

```bash
# Using dev_plugin_setup.sh
./dev_plugin_setup.sh list
./scripts/dev/dev_plugin_setup.sh list

# Output shows:
# ✓ plugin-name (symlink)
Expand All @@ -368,7 +371,7 @@ Check discovered plugins:
Check plugin status and git information:

```bash
./dev_plugin_setup.sh status
./scripts/dev/dev_plugin_setup.sh status

# Output shows:
# ✓ plugin-name
Expand All @@ -391,13 +394,19 @@ cd ledmatrix-my-plugin

# Link to LEDMatrix project
cd /path/to/LEDMatrix
./dev_plugin_setup.sh link my-plugin ../ledmatrix-my-plugin
./scripts/dev/dev_plugin_setup.sh link my-plugin ../ledmatrix-my-plugin
```

### 2. Development Cycle

1. **Edit plugin code** in linked repository
2. **Test with emulator**: `python run.py --emulator`
2. **Test with the dev preview server**:
`python3 scripts/dev_server.py` (then open `http://localhost:5001`).
Or run the full display in emulator mode with
`python3 run.py --emulator` (or equivalently
`EMULATOR=true python3 run.py`). The `-e`/`--emulator` CLI flag is
defined in `run.py:19-20` and sets the same `EMULATOR` environment
variable internally.
3. **Check logs** for errors or warnings
4. **Update configuration** in `config/config.json` if needed
5. **Iterate** until plugin works correctly
Expand All @@ -406,30 +415,30 @@ cd /path/to/LEDMatrix

```bash
# Deploy to Raspberry Pi
rsync -avz plugins/my-plugin/ pi@raspberrypi:/path/to/LEDMatrix/plugins/my-plugin/
rsync -avz plugins/my-plugin/ ledpi@your-pi-ip:/path/to/LEDMatrix/plugins/my-plugin/

# Or if using git, pull on Pi
ssh pi@raspberrypi "cd /path/to/LEDMatrix/plugins/my-plugin && git pull"
ssh ledpi@your-pi-ip "cd /path/to/LEDMatrix/plugins/my-plugin && git pull"

# Restart service
ssh pi@raspberrypi "sudo systemctl restart ledmatrix"
ssh ledpi@your-pi-ip "sudo systemctl restart ledmatrix"
```

### 4. Updating Plugins

```bash
# Update single plugin from git
./dev_plugin_setup.sh update my-plugin
./scripts/dev/dev_plugin_setup.sh update my-plugin

# Update all linked plugins
./dev_plugin_setup.sh update
./scripts/dev/dev_plugin_setup.sh update
```

### 5. Unlinking Plugins

```bash
# Remove symlink (preserves repository)
./dev_plugin_setup.sh unlink my-plugin
./scripts/dev/dev_plugin_setup.sh unlink my-plugin
```

---
Expand Down Expand Up @@ -625,8 +634,8 @@ python run.py --emulator
**Solutions**:
1. Check symlink: `ls -la plugins/my-plugin`
2. Verify target exists: `readlink -f plugins/my-plugin`
3. Update plugin: `./dev_plugin_setup.sh update my-plugin`
4. Re-link plugin if needed: `./dev_plugin_setup.sh unlink my-plugin && ./dev_plugin_setup.sh link my-plugin <path>`
3. Update plugin: `./scripts/dev/dev_plugin_setup.sh update my-plugin`
4. Re-link plugin if needed: `./scripts/dev/dev_plugin_setup.sh unlink my-plugin && ./scripts/dev/dev_plugin_setup.sh link my-plugin <path>`
5. Check git status: `cd plugins/my-plugin && git status`

---
Expand Down Expand Up @@ -697,22 +706,22 @@ python run.py --emulator

```bash
# Link plugin from GitHub
./dev_plugin_setup.sh link-github <name>
./scripts/dev/dev_plugin_setup.sh link-github <name>

# Link local plugin
./dev_plugin_setup.sh link <name> <path>
./scripts/dev/dev_plugin_setup.sh link <name> <path>

# List all plugins
./dev_plugin_setup.sh list
./scripts/dev/dev_plugin_setup.sh list

# Check plugin status
./dev_plugin_setup.sh status
./scripts/dev/dev_plugin_setup.sh status

# Update plugin(s)
./dev_plugin_setup.sh update [name]
./scripts/dev/dev_plugin_setup.sh update [name]

# Unlink plugin
./dev_plugin_setup.sh unlink <name>
./scripts/dev/dev_plugin_setup.sh unlink <name>

# Run with emulator
python run.py --emulator
Expand Down
Loading