Rewrite README for production app
This commit is contained in:
253
README.md
253
README.md
@@ -1,12 +1,37 @@
|
|||||||
# Custom Streamdeck Button Prototype
|
# Custom Streamdeck
|
||||||
|
|
||||||
This project is now a local Stream Deck-style control app for the 10-button Pico prototype.
|
Custom Streamdeck is a local control surface platform for a 10-button Raspberry Pi Pico device. It pairs physical button input with a desktop web app, persistent configuration, and a backend action engine so the deck can launch apps, send shortcuts, switch folders, and run backend plugins.
|
||||||
|
|
||||||
The Pico firmware still prints the same USB serial JSON events. The new backend consumes those events, stores configuration in SQLite, executes actions, loads backend plugins, and serves the built React UI.
|
This repository is organized more like an application than a hardware experiment: the Pico emits button events, the backend manages state and automation, and the frontend provides a live configuration surface for day-to-day use.
|
||||||
|
|
||||||
## Button Wiring
|
## What The App Does
|
||||||
|
|
||||||
Button order is the order you gave:
|
- Reads button press and release events from a Raspberry Pi Pico over USB serial
|
||||||
|
- Stores profiles, folders, button mappings, and action configuration in SQLite
|
||||||
|
- Serves a local web UI for deck configuration and live monitoring
|
||||||
|
- Executes built-in actions such as key presses, action chains, app launch, and folder navigation
|
||||||
|
- Loads backend plugins for feature-specific actions such as HTTP requests, media control, and clipboard tools
|
||||||
|
- Broadcasts live state updates over WebSocket so the UI stays in sync with the device
|
||||||
|
|
||||||
|
## Production View
|
||||||
|
|
||||||
|
The app is intended to run as a local always-on controller on a Windows workstation:
|
||||||
|
|
||||||
|
- The backend is the source of truth for device state and button configuration.
|
||||||
|
- The frontend is a built artifact served by FastAPI in production-style usage.
|
||||||
|
- The Pico is treated as an attached input device rather than a development-only serial toy.
|
||||||
|
- Button layouts are protected by a canonical hardware mapping so profile changes do not drift physical position assignments.
|
||||||
|
- Plugins extend backend behavior without requiring frontend-specific code for every new action.
|
||||||
|
|
||||||
|
This is still a local app, not a hosted SaaS service, but the codebase now behaves like an operational desktop product.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Hardware Layer
|
||||||
|
|
||||||
|
The Pico firmware in `pico/main.py` scans the 10 physical buttons and prints JSON events over USB serial.
|
||||||
|
|
||||||
|
Button wiring order:
|
||||||
|
|
||||||
1. GP28
|
1. GP28
|
||||||
2. GP27
|
2. GP27
|
||||||
@@ -19,66 +44,71 @@ Button order is the order you gave:
|
|||||||
9. GP17
|
9. GP17
|
||||||
10. GP16
|
10. GP16
|
||||||
|
|
||||||
The other leg of every button goes to GND. The Pico script uses internal pull-ups, so a pressed button reads as LOW.
|
Each button’s other leg goes to GND. The firmware uses internal pull-ups, so a pressed button reads as LOW.
|
||||||
|
|
||||||
## Files
|
### Backend Layer
|
||||||
|
|
||||||
- `pico/main.py`: MicroPython code that runs on the Pico and prints button events over USB serial.
|
The FastAPI backend:
|
||||||
- `pc/listen_buttons.py`: PC listener that reads serial events and appends them to `button_log.txt`.
|
|
||||||
- `backend/`: FastAPI backend, WebSocket events, SQLite state, action engine, app discovery, plugin loading.
|
|
||||||
- `frontend/`: React + Vite + Tailwind UI.
|
|
||||||
- `plugins/`: Backend Python plugins. Each plugin exposes a top-level `PLUGIN` object.
|
|
||||||
|
|
||||||
## Run The App
|
- auto-detects the Pico serial port, or uses a configured port override
|
||||||
|
- reads and validates button events
|
||||||
|
- persists state in SQLite under `data/`
|
||||||
|
- executes actions through a central action engine
|
||||||
|
- loads plugin modules from `plugins/`
|
||||||
|
- serves the built frontend and WebSocket updates
|
||||||
|
|
||||||
Install Python dependencies:
|
Key backend areas:
|
||||||
|
|
||||||
```powershell
|
- `backend/main.py`: app lifecycle, API routes, WebSocket endpoint
|
||||||
python -m pip install -r requirements.txt
|
- `backend/database.py`: SQLite schema, settings, profiles, folders, buttons, event history
|
||||||
```
|
- `backend/services/serial_service.py`: Pico connection and event loop
|
||||||
|
- `backend/services/actions.py`: action execution engine
|
||||||
|
- `backend/services/plugins.py`: runtime plugin loading and dispatch
|
||||||
|
- `backend/services/apps.py`: Windows app discovery and launch support
|
||||||
|
|
||||||
Install and build the UI:
|
### Frontend Layer
|
||||||
|
|
||||||
```powershell
|
The frontend is a React + Vite application that:
|
||||||
cd frontend
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
cd ..
|
|
||||||
```
|
|
||||||
|
|
||||||
Start the backend and open `http://127.0.0.1:8000/`:
|
- shows connection and sync status
|
||||||
|
- manages profiles and folders
|
||||||
|
- edits button labels, colors, icons, trigger modes, and actions
|
||||||
|
- renders plugin action fields dynamically from backend metadata
|
||||||
|
- stays synchronized through backend WebSocket broadcasts
|
||||||
|
|
||||||
```powershell
|
Primary frontend source lives in `frontend/src/`.
|
||||||
python -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
|
|
||||||
```
|
|
||||||
|
|
||||||
For frontend dev mode, run the backend above and then:
|
## Current Action Model
|
||||||
|
|
||||||
```powershell
|
Built-in actions currently include:
|
||||||
cd frontend
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Legacy Listener
|
- No-op / display-only buttons
|
||||||
|
- Keyboard shortcut execution
|
||||||
|
- Chained multi-step actions
|
||||||
|
- Windows app launch
|
||||||
|
- Folder open
|
||||||
|
- Folder rotation
|
||||||
|
- Plugin-backed actions
|
||||||
|
|
||||||
```powershell
|
Plugin actions currently include examples such as:
|
||||||
python .\pc\listen_buttons.py
|
|
||||||
```
|
|
||||||
|
|
||||||
If auto-detect fails:
|
- HTTP requests
|
||||||
|
- Media controls
|
||||||
|
- Clipboard tools
|
||||||
|
|
||||||
```powershell
|
## Plugin System
|
||||||
python .\pc\listen_buttons.py --port COM5
|
|
||||||
```
|
|
||||||
|
|
||||||
## Plugin Shape
|
Backend plugins live in `plugins/` and expose a top-level `PLUGIN` object. The backend imports each plugin, reads its declared actions, and exposes those actions to the frontend automatically.
|
||||||
|
|
||||||
Backend plugins live in `plugins/` and expose `PLUGIN`.
|
That means new capabilities can usually be added by shipping a Python plugin file without hand-building a matching frontend form.
|
||||||
|
|
||||||
|
Example shape:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class MyPlugin:
|
class MyPlugin:
|
||||||
name = "My Plugin"
|
name = "My Plugin"
|
||||||
desc = "Does a thing"
|
desc = "Does a thing"
|
||||||
|
version = "0.1.0"
|
||||||
actions = [
|
actions = [
|
||||||
{
|
{
|
||||||
"id": "do_thing",
|
"id": "do_thing",
|
||||||
@@ -98,3 +128,140 @@ class MyPlugin:
|
|||||||
|
|
||||||
PLUGIN = MyPlugin()
|
PLUGIN = MyPlugin()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Repository Layout
|
||||||
|
|
||||||
|
- `backend/`: FastAPI app, database, action engine, serial service, plugin runtime
|
||||||
|
- `frontend/`: React configuration UI
|
||||||
|
- `plugins/`: backend plugin modules
|
||||||
|
- `pico/`: MicroPython firmware for the device
|
||||||
|
- `pc/`: utility scripts used during hardware bring-up and diagnostics
|
||||||
|
- `tests/`: backend tests
|
||||||
|
- `data/`: local runtime state, including SQLite data
|
||||||
|
|
||||||
|
## Local Setup
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Windows machine
|
||||||
|
- Python 3.13 or compatible recent Python 3
|
||||||
|
- Node.js and npm
|
||||||
|
- Raspberry Pi Pico flashed with the firmware in `pico/main.py`
|
||||||
|
|
||||||
|
### Install Backend Dependencies
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Frontend Dependencies
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
cd ..
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running The App
|
||||||
|
|
||||||
|
### Production-Style Local Run
|
||||||
|
|
||||||
|
Build the frontend first:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the backend:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open:
|
||||||
|
|
||||||
|
`http://127.0.0.1:8000/`
|
||||||
|
|
||||||
|
In this mode, FastAPI serves the built frontend from `frontend/dist`.
|
||||||
|
|
||||||
|
### Frontend Development Mode
|
||||||
|
|
||||||
|
Run the backend in one shell:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
Run Vite in another:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd frontend
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open the Vite URL, usually:
|
||||||
|
|
||||||
|
`http://127.0.0.1:5173/`
|
||||||
|
|
||||||
|
## Operational Notes
|
||||||
|
|
||||||
|
### Device Detection
|
||||||
|
|
||||||
|
By default the backend attempts to auto-detect the Pico using USB metadata. If that fails, the serial port can be set in the application settings.
|
||||||
|
|
||||||
|
### Persistence
|
||||||
|
|
||||||
|
Profiles, folders, button assignments, manual app entries, and event history are stored in SQLite under `data/streamdeck.sqlite`.
|
||||||
|
|
||||||
|
### Live Updates
|
||||||
|
|
||||||
|
The UI receives `state.updated` and action/device events over WebSocket. This keeps the browser view aligned with the live backend without manual refreshes.
|
||||||
|
|
||||||
|
### Windows Integration
|
||||||
|
|
||||||
|
App launch discovery currently focuses on Windows environments:
|
||||||
|
|
||||||
|
- Start Menu shortcuts
|
||||||
|
- installed applications from uninstall registry keys
|
||||||
|
- manually registered app paths
|
||||||
|
|
||||||
|
### Logging And Diagnostics
|
||||||
|
|
||||||
|
The backend records event history in SQLite. During hardware bring-up, `pc/listen_buttons.py` can still be used as a simple serial diagnostic tool.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Run the backend test suite from the repo root:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:PYTHONPATH = (Get-Location).Path
|
||||||
|
pytest -q
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Considerations
|
||||||
|
|
||||||
|
For a reliable day-to-day setup on a dedicated machine:
|
||||||
|
|
||||||
|
- build the frontend and serve the compiled assets from FastAPI
|
||||||
|
- pin Python dependencies from `requirements.txt`
|
||||||
|
- run the backend under a process manager, scheduled task, or startup shortcut
|
||||||
|
- keep the Pico on a stable USB port when possible
|
||||||
|
- treat `data/` as local runtime state and back it up if profiles matter
|
||||||
|
|
||||||
|
This app is best thought of as a local control appliance: hardware input on one side, desktop automation and operator UI on the other.
|
||||||
|
|
||||||
|
## Legacy Utility
|
||||||
|
|
||||||
|
For raw serial logging without the full app:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python .\pc\listen_buttons.py
|
||||||
|
```
|
||||||
|
|
||||||
|
If auto-detect fails:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python .\pc\listen_buttons.py --port COM5
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user