-
Notifications
You must be signed in to change notification settings - Fork 0
Control Server
The custom control server runs on the Pi at port 5000 and provides a richer interface on top of QLC+'s native web UI.
Access it at http://lights.local:5000
The control server provides:
- AI Chat — Natural language commands ("make it warmer", "party mode", "fade to black over 5 seconds")
-
Virtual Console — Per-fixture channel sliders with correct labels from
.qxfdefinitions - Scene Management — Activate existing scenes, save AI-generated ones permanently
- Fixture Groups — Organize fixtures into named zones, target commands to specific groups
- Health Dashboard — Live status of QLC+, WebSocket connection, AI provider, and workspace
./lightsctl.sh control-installThis creates a Python venv on the Pi, installs dependencies, and sets up lighting-control.service.
The server maintains a single persistent WebSocket to QLC+ on a dedicated background thread. All HTTP requests dispatch channel commands through this one connection. This avoids the CLOSE_WAIT socket leak that occurs when each request opens its own short-lived connection (QLC+ 4.14.x has a hard limit of ~50 concurrent WebSocket clients).
See CONTROL_SERVER_ARCHITECTURE.md for the full technical deep-dive.
| Method | Path | Purpose |
|---|---|---|
| POST | /api/command |
AI natural-language command |
| POST | /api/action |
Structured action dispatch (used by MCP-Server, bypasses AI interpreter) |
| POST | /api/batch |
Execute an ordered list of actions in one request |
| POST | /api/blackout |
Instant kill-all — zeroes every channel on targeted fixtures |
| GET | /api/status |
Multi-service health JSON |
| GET | /api/scenes |
List workspace scenes |
| GET | /api/scenes/<id> |
Describe a saved scene (per-fixture channel breakdown) |
| POST | /api/scenes/<id>/activate |
Apply a scene live |
| POST | /api/scenes/save |
Save scene XML to workspace permanently |
| POST | /api/scenes/snapshot |
Capture current state as a new scene |
| POST | /api/scenes/<id>/duplicate |
Clone a saved scene under a new name |
| PATCH | /api/scenes/<id> |
Rename a scene (and/or move its Path folder) |
| DELETE | /api/scenes/<id> |
Delete a saved scene |
| GET | /api/fixtures |
List fixtures with channel_info |
| GET | /api/fixture_channels/<id> |
Per-fixture channel breakdown |
| POST | /api/fixtures/<id>/identify |
Flash a fixture so you can locate it physically |
| GET | /api/groups |
List fixture groups |
| POST | /api/groups |
Create a new group |
| PATCH | /api/groups/<name> |
Rename / re-describe / replace fixture list |
| DELETE | /api/groups/<name> |
Delete a group |
| POST | /api/groups/<name>/fixtures |
Append fixtures to a group |
| DELETE | /api/groups/<name>/fixtures |
Remove fixtures from a group |
| POST | /api/channel |
Set a single channel value |
| GET | /api/channel_values |
Live DMX values from QLC+ |
| POST | /api/diagnostics/test_dmx |
R → G → B → restore sweep across fixtures |
| GET | /api/diagnostics/logs/<service> |
Tail systemd journal for an allowlisted service |
| GET | /api/diagnostics/system |
Pi-level health JSON |
| GET | /api/chases |
List chases in the workspace |
| GET | /api/chases/<id> |
Describe a chase (steps, scene names, timing) |
| POST | /api/chases |
Create a new chase |
| DELETE | /api/chases/<id> |
Remove a chase |
| POST | /api/chases/<id>/start |
Start chase playback |
| POST | /api/chases/<id>/stop |
Stop chase playback |
| GET | /api/cue_lists |
List saved cue lists (with runtime status) |
| GET | /api/cue_lists/active |
Currently-playing cue lists, with elapsed time |
| GET | /api/cue_lists/<id> |
Describe a cue list |
| POST | /api/cue_lists |
Create a new cue list |
| PATCH | /api/cue_lists/<id> |
Rename / re-describe / replace cues array |
| DELETE | /api/cue_lists/<id> |
Remove (stops playback first if running) |
| POST | /api/cue_lists/<id>/go |
GO — start playback |
| POST | /api/cue_lists/<id>/stop |
Halt running cue list |
The save feature lets you persist any AI-generated scene (or the current live state) into the QLC+ workspace permanently:
# Via API
curl -X POST http://lights.local:5000/api/scenes/save \
-H "Content-Type: application/json" \
-d '{"name": "My Scene", "snapshot": true}'
# Or with scene XML from a previous generate
curl -X POST http://lights.local:5000/api/scenes/save \
-H "Content-Type: application/json" \
-d '{"name": "Warm Sunset", "scene_xml": "<Function Type=\"Scene\" ...>...</Function>"}'Saved scenes appear in the Scenes tab immediately and persist through reboots.
The server reads QLC+ .qxf fixture definition files to resolve each channel's semantic role. This means:
- Channel sliders show correct labels (e.g. "Warm White" not "Ch 2")
- The AI knows which channels are color vs strobe vs configuration
- Color commands drive the right channels per fixture type
The parser checks /usr/share/qlcplus/fixtures/ (system) and ~/.qlcplus/fixtures/ (user overrides).
To expose the same control surface to MCP-capable LLM agents (Claude Desktop, ChatGPT, Cursor, custom clients), install the sibling MCP server — see MCP-Server. It runs at port 5001 and calls back into this server's /api/action endpoint.
./lightsctl.sh control-status # Service status
./lightsctl.sh control-logs # Recent logs
./lightsctl.sh control-restart # Restart the server
./lightsctl.sh control-uninstall # Remove the server
./lightsctl.sh env-sync # Push .env to Pi and restart