Skip to content
Open
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
344 changes: 344 additions & 0 deletions roadmap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
# LED Matrix Web Control - Implementation Options

## Current State

Two mature codebases exist:

- **led-matrix** (Python): Background service with system monitoring, plugin architecture, config management, systemd integration
- **dotmatrixtool** (Web): Browser-based drawing tool with Web Serial API, import/export JSON, direct hardware communication

## Hardware Configuration

**Framework 16 LED Matrix Panels:**

- Each panel: 9 columns (width) × 34 rows (height)
- Typical setup: 2 panels (left and right)
- Total logical display when both present: 18 wide × 34 tall
- Physical placement: Can flank keyboard OR sit side-by-side
- Backend always treats as 2 independent 9×34 panels
- Frontend can show "unified view" for drawing alignment (UX only)

**Quadrant Layout (when 2 panels present):**

- Top-Left: 9×17 (top half of left panel)
- Bottom-Left: 9×17 (bottom half of left panel)
- Top-Right: 9×17 (top half of right panel)
- Bottom-Right: 9×17 (bottom half of right panel)

**Single Panel Setup:**

- Only 2 sections available: top (9×17) and bottom (9×17)

## Option A: Hybrid Architecture (Python Backend + React Frontend)

### Architecture Overview

Python service runs continuously as systemd service. React web app provides control interface and communicates via API.

### Components to Build

#### Backend Development (Python)

1. **FastAPI Server Layer**

- REST API endpoints for control operations
- WebSocket endpoint for real-time state updates
- Serve React frontend as static files
- CORS configuration for development

1. **Mode Management System** (Critical - see problem statement)

- ModeController class with state machine (AUTO | MANUAL | MIXED)
- Hardware access locking (threading.Lock or asyncio.Lock)
- Transition handlers (pause auto mode, resume auto mode)
- Watchdog timer for manual mode timeout
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest an option to not set the timer, to enable a manual config to run indefinitely if desired.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I see manual mode having two variants:

Temporary Manual Mode (default):

  • Timeout-based (e.g., 5 min default, configurable)
  • Use case: Quick testing of icons/animations, showcase demos, drawing experiments
  • Returns to user's default configuration after timeout

Persistent Manual Mode:

  • No timeout - stays in manual until explicitly switched
  • Use case: When you want to override the default behavior entirely
  • Requires explicit switch back to configured default

The mode controller should support both via a toggle or API parameter.

Note on terminology: We should clarify "auto mode" vs "default mode":

  • Default Mode - the user's configured baseline (from config.yaml or custom settings, not necessarily the application-shipped default)
  • Manual Override - temporary deviation from default
  • Persistent Override - permanent change until explicitly reverted

This distinction matters because a user's "default" might itself be a customized configuration, not the original application defaults.

- Per-quadrant locking for MIXED mode (optional)

1. **API Endpoints**

- POST /mode/manual - Request manual control
- POST /mode/auto - Release manual control
- GET /mode/status - Current mode and locked quadrants
- POST /manual/draw/left - Send left panel pattern (9×34 array)
- POST /manual/draw/right - Send right panel pattern (9×34 array)
- POST /manual/quadrant - Control specific quadrant
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the current manual config persisted? Should we have a separate config file for manual mode? In memory?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This depends on the use case and will tie into the service/plugin implementation:

Mode types we should support:

  • DEFAULT - user's baseline configuration (from config.yaml or saved custom settings)
  • MANUAL_TEMP - temporary override (in-memory, optional timeout)
  • MANUAL_PERSIST - persistent override until explicitly changed
  • OFF - specific quadrant(s) disabled
  • Per-quadrant app selection (from installed plugins)

Persistence strategy:

  • In-memory for temporary manual/testing
  • Saved configurations (custom defaults, installed plugins) persist to disk
  • Users can save "preset configurations" that combine settings

The specifics will depend on how we implement the service layer and plugin management.

- GET /config - Read current config.yaml
- PUT /config - Update config.yaml
- GET /apps/list - Available apps and plugins
- GET /metrics - Current system metrics
- GET /panels - Detect connected panels (1 or 2)
- WebSocket /ws - Live LED matrix state

1. **Modified Auto Mode Loop**

- Check mode_controller.current_mode before drawing
- Pause app cycling when mode == MANUAL
- Resume from correct position when returning to AUTO

1. **Hardware Access Serialization**

- Modify DrawingThread to use mode_controller.hardware_lock
- Single point of hardware access
- Queue management during mode transitions

#### Frontend Development (React)

1. **Project Setup**

- Vite + React + TypeScript
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vite is probably fine, but it's worth asking the question whether we anticipate sufficient complexity to drive us toward Next.js

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vite should be sufficient for the MVP.

Next.js would only make sense if we go the full plugin installation/configuration/management route, which brings significant complexity. For now, let's start with Vite and keep it simple. We can reassess if requirements change.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any preference for rendering library? I switched from Bootstrap to Tailwind CSS a couple years ago and find it very good.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on Tailwind. Let's keep it lightweight and simple - the matrix itself is limited in presentation capabilities, so we don't need heavy UI frameworks. Tailwind + minimal component library (if needed) should be sufficient.

- API client library (axios or fetch)
- WebSocket client
- State management (Zustand or React Context)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with Zustand, but I see it's lightweight and Flux-based, so that sounds good. Will defer to you on preference vis-à-vis React Context. I think we both agree there's not sufficient complexity to justify Redux.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I defer to Mark's experience here. Zustand or React Context both sound reasonable for this scope. Mark, what's your preference?


1. **Mode Control Interface**

- Toggle between Auto/Manual modes
- Visual indicator of current mode
- Timeout countdown when in manual mode
- Warning dialog before switching modes

1. **Auto Mode Configuration Panel**

- Quadrant selector (4 quadrants: top-left, top-right, bottom-left, bottom-right)
- App dropdown per quadrant (populated from /apps/list)
- Duration slider per app
- Animation toggle per app
- Add/remove apps for time-multiplexing
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Configure arguments and settings per app

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, essential feature. This ties into the broader configuration/plugin system:

  • Apps/plugins should have configurable arguments
  • API should expose available settings per app
  • Frontend provides interface to configure these args
  • Configurations can be saved as presets/templates
  • Support both temporary testing and persistent custom configs

The exact implementation depends on how we structure the plugin/service architecture.

Important: Configuration files should remain human-readable (YAML, TOML, etc.) so they can be edited via CLI editors for users without GUI access. The web interface is just another way to edit the same underlying config files.

- Save/load config.yaml

1. **Manual Control Interface**

- Quadrant selector for targeted control
- App selector with live application
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you articulate a little more your vision of how the manual control will look? What exactly do the presets consist of? Will we reuse the app config widget used to configure apps for automatic control?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I see it, there are two main aspects:

1. Configuration Management:

  • If you have a configuration different from application defaults (customizations, added plugins), you'd want it to persist after reboots/restarts
  • Two approaches:
    • Simple: Basic preset interface with combinable settings templates
    • Advanced: Full plugin management system (more complexity)

2. Quick Access:

  • Ability to quickly showcase/test icons, animations, or drawings
  • Load preset configurations or templates
  • Reusable templates for common patterns

The app config widget from default mode should be reusable, with added preset/template support.

- Quick preset buttons

1. **Free Draw Canvas** (from dotmatrixtool)

- Refactor dotmatrixtool app.js to React component
- Two 9×34 LED grid components (left and right panels)
- Optional "unified view" toggle - displays both as single 18×34 canvas for alignment (UX only)
- Mouse/touch drawing (left click draw, ctrl+click erase)
- Brightness slider
- Color/grayscale picker
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there color LED devices available? I saw someone who made one for himself last year, but I don't know that any are available for purchase. Would love to have one if they are.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not aware of commercial availability yet - just the community POC.

For implementation: let's future-proof for RGB but don't over-engineer it. If we can support limited grayscale now with minimal extra work to accommodate RGB later, great. If it becomes complex, we can drop RGB support easily. It's mainly acknowledging that at least one color implementation exists in the wild.

- Export to snapshot_files/
- Send directly to backend API (not Web Serial)
- Always exports/sends as two separate panel arrays (left 9×34, right 9×34)

1. **System Metrics Dashboard**

- Real-time display via WebSocket
- CPU utilization graph
- Memory usage
- Disk I/O rates
- Network traffic
- Temperature sensors
- Fan speeds

1. **System Alerts Configuration** (from notification API design)

- Define alert triggers
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since alerts are transient, should they preempt the current display? Should we configure one or more quadrants to be the place where alerts go when they occur? Should we have a configurable time persistence?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of templates/presets for alert behavior:

Alert Templates:

  • Preemptive (interrupt current display temporarily)
  • Dedicated quadrant (always show in specific location)
  • System tray only
  • Custom (user-defined behavior)

Customization per template:

  • Which quadrant(s) to use
  • Timeout/persistence duration
  • Priority levels
  • Whether alerts can interrupt or only queue

This gives flexibility while keeping it manageable. All alert features are open for discussion - we should prioritize what makes sense for MVP.

- Route alerts to system tray OR LED matrix
- Priority levels
- Icon/pattern selection per alert type

1. **Live Preview**

- Visual representation of LED matrix
- Shows left panel (9×34) and right panel (9×34) if present
- Optional unified view (18×34 when both panels present)
- Updates via WebSocket from Python backend
- Shows actual hardware state

### Deployment

- Python service runs as systemd unit
- React app built to static files
- FastAPI serves static files at /
- Access via <http://localhost:8000>
- Optional: nginx reverse proxy for production

### Advantages

- Leverages existing Python codebase (system monitoring, plugins, hardware control)
- Python's psutil provides accurate system metrics
- Service runs independently of browser
- Systemd integration for auto-start
- NixOS flake already exists
- Can reuse dotmatrixtool canvas component

### Disadvantages

- Need to build FastAPI layer
- Need to refactor dotmatrixtool jQuery to React
- More complexity (two languages)

## Option B: Enhanced Python Service + Embedded dotmatrixtool

### Architecture Overview

Python service runs continuously. Serve dotmatrixtool (mostly as-is) with minimal modifications to communicate with Python backend.

### Components to Build

#### Backend Development (Python)

1. **FastAPI Server Layer**

- Same as Option A
- Serve dotmatrixtool HTML/JS/CSS as static files

1. **Mode Management System**

- Same as Option A
- Critical for preventing conflicts

1. **API Endpoints**

- POST /mode/manual - Request manual control
- POST /mode/auto - Release manual control
- POST /manual/draw - Receive pattern from dotmatrixtool
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- POST /manual/draw - Receive pattern from dotmatrixtool
- POST /manual/draw/left - Send left panel pattern (9×34 array) dotmatrixtool
- POST /manual/draw/right - Send right panel pattern (9×34 array) dotmatrixtool

For consistency with Option A description

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - consistency is important for maintainability and potential future migration.

- POST /config/quadrant - Configure quadrant app
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- POST /config/quadrant - Configure quadrant app
- POST /manual/quadrant - Configure specific quadrant

For consistency with Option A description

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - consistency is important for maintainability and potential future migration.

- GET /config - Current configuration
- GET /metrics - System metrics
- WebSocket /ws - Live state updates

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are other endpoints from Option A not included here? Less GUI implementation, I assume?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - we should probably include all endpoints regardless of which option we choose, for consistency and to avoid limiting future functionality.

1. **Modified Auto Mode Loop**

- Same as Option A

1. **Hardware Access Serialization**

- Same as Option A

#### Frontend Development (Minimal Modifications)

1. **Modify dotmatrixtool app.js**

- Add mode selector UI (auto/manual)
- Replace Web Serial API calls with fetch to Python API
- Add quadrant configuration form (4 quadrants across both panels)
- Add app selector dropdowns per quadrant
- Keep existing drawing canvas (left 9×34 and right 9×34)
- Add optional "unified view" toggle for drawing alignment (displays as 18×34)
- Always send data as two separate panel arrays to backend

1. **Add Control Interface (vanilla JS or minimal framework)**

- Mode toggle button (Auto/Manual)
- Quadrant configuration panel (4 quadrants: TL, BL, TR, BR)
- App selector per quadrant with duration and animation settings
- Panel detection display (shows 1 or 2 panels connected)
- Save config button

1. **System Metrics Display** (optional)

- Basic dashboard using Chart.js or similar
- WebSocket connection to Python backend

### Deployment

- Python service runs as systemd unit
- Serves dotmatrixtool files at /
- Access via <http://localhost:8000>

### Advantages

- Less frontend development (reuse dotmatrixtool mostly as-is)
- No need to refactor jQuery to React
- Simpler tech stack
- Faster to implement
- Still leverages Python backend strengths

### Disadvantages

- Limited UI/UX capabilities (jQuery vs React)
- Harder to build complex configuration interface
- Less maintainable frontend code
- System alerts configuration would be basic

## Comparison Matrix

### Development Effort

- **Option A**: Higher (full React app, refactor dotmatrixtool)
- **Option B**: Lower (minimal modifications to dotmatrixtool)

### User Experience

- **Option A**: Modern, polished UI with advanced features
- **Option B**: Functional but basic UI

### Maintainability

- **Option A**: Better (React component architecture)
- **Option B**: Mixed (Python good, frontend dated)

### Extensibility

- **Option A**: Excellent (easy to add features in React)
- **Option B**: Limited (jQuery codebase harder to extend)

### System Alerts Integration

- **Option A**: Full implementation of notification API design
- **Option B**: Basic implementation

### Time to MVP

- **Option A**: 3-4 weeks
- **Option B**: 1-2 weeks

## Recommendation

**Start with Option B, migrate to Option A later:**

1. Implement Mode Management System (critical for both)
2. Build FastAPI layer with minimal endpoints
3. Modify dotmatrixtool to call Python API instead of Web Serial
4. Add basic quadrant configuration UI
5. Test and validate architecture
6. Later: Migrate frontend to React incrementally

This approach:

- Validates the architecture quickly
- Solves the mode management problem first
- Provides working system faster
- Allows React migration when UI needs justify effort
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUggest consideration of Option C: Implement the client with React.JS but leave alerts capability for the next iteration.

Rationale: Implementing mode and app control in vanilla JS is non-trivial. Would the ease we gain from doing it in React to begin with be worth the effort to port existing dotmatrix code to React? The GUI elements would easily port (we could even just wrap them in an iframe for the first iteration) and jquery -> React translation should be straightforward. Alert capability is a big chunk, involving significant UI and backend work, and may be a better candidate for deferral than React implementation.

Just bringing this up for consideration. I'm not necessarily preferring it. Would like to hear your take on it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this approach. Let's deliver the MVP with the core of what we have now, and build from there.


## Common Requirements (Both Options)

### Critical Components

1. **Mode Management System** - Prevents auto/manual conflicts
2. **Hardware Access Locking** - Serializes LED matrix access
3. **API Layer** - Communication between frontend and Python service
4. **Auto Mode Pause/Resume** - Clean state transitions
5. **Manual Mode Timeout** - Safety mechanism

### Configuration Management

- Read/write config.yaml via API
- Validate configuration before applying
- Backup previous config on changes
- Reload service configuration without restart

### Integration with Existing Code

- led-matrix/monitors.py - Already provides system metrics
- led-matrix/plugins/ - Plugin architecture works as-is
- led-matrix/drawing.py - Needs locking modification for mode management
- led-matrix/config.yaml - Becomes API-editable, already has 4-quadrant structure
- led-matrix/led_system_monitor.py - Already detects 1 or 2 panels via discover_led_devices()
- dotmatrixtool/app.js - Canvas reused in both options (left/right already separate)

### Panel Configuration Notes

- Backend always treats panels independently (2× 9×34)
- No "unified mode" in backend code - always 4 quadrants (to be decided)
- "Unified view" is purely a frontend UX feature for drawing alignment
- When drawing spans both panels, frontend sends left data + right data separately (to be decided)
- Existing config.yaml structure already supports this (top-left, bottom-left, top-right, bottom-right)

### Future development
- dotmatrixtool/app.js / led-matrix/plugins/ Plugin and icon / animation management and installation through API and dotmatixtool. UX friendly