v2.4.0 — Diagnostics surface (test_dmx, get_logs, get_system_info)
Highlights
Three new diagnostic primitives so an agent (or operator) can debug a misbehaving rig without SSHing in. Verify the DMX signal reaches your fixtures, tail any of the systemd journals, and pull Pi-level health — all from any MCP client. MCP tool catalog goes from 28 → 31.
Closes #9.
What's new
test_dmx(duration?, groups?)
POST /api/diagnostics/test_dmx
Runs a known-good R → G → B → restore sweep across every targeted fixture's color-relevant channels. The pattern is .qxf-role-aware:
- RGB fixtures — drives r/g/b channels in sequence
- WWA / tungsten fixtures — drives warm → amber → cool to approximate a hot → warm → cool sweep
- White-only or dimmer-only fixtures — pulses at full
Snapshots channel state before the test and restores it after, so the rig returns to whatever it looked like before the call. Bounded 2–30s duration. Async via the persistent QLC+ WebSocket loop.
get_logs(service, n?)
GET /api/diagnostics/logs/<service>?n=50
Tail systemd journals from any MCP client. Allowlisted services: qlcplus-web, lighting-control, lighting-mcp, nginx. Unknown service names return a 400 with the valid list — no shell injection surface. Lines bounded 1–500. Returns a structured 503 when invoked from a workstation rather than the Pi.
get_system_info()
GET /api/diagnostics/system
Pi-level health snapshot:
- CPU temperature (
/sys/class/thermal/thermal_zone0/temp) - Load averages (
os.getloadavg()) - Memory breakdown (
/proc/meminfo) with used / available / pct - Disk usage for
/and/home(shutil.disk_usage) - Uptime in seconds + human-readable summary (
Xd Yh Zm) - USB devices filtered to ENTTEC / FTDI / DMX matches
systemctl is-activefor each lighting service
Every field is best-effort. Anything unavailable on the current platform (e.g. CPU temp on a non-Linux dev machine) is reported as null rather than failing the whole call.
Use case
Tell your MCP agent "the lights aren't responding, what's wrong?" — it can now call all three diagnostics tools in sequence: check QLC+ logs for errors, verify the Pi isn't overheating or out of memory, then run test_dmx to confirm the signal is actually reaching the fixtures. Three round trips, full triage.
Security
get_logsuses static allowlist lookup, never interpolates the URL path into the shell command./api/diagnostics/logs/etc-passwdreturns 400.get_system_info'ssystemctlandlsusbcalls also use only static command strings.test_dmxwrites DMX but is bounded (≤30s) and always restores pre-test state.
Upgrade
git pull
./lightsctl.sh control-restart # picks up the new endpoints
./lightsctl.sh mcp-restart # picks up the new MCP toolsNo package dependency changes.
Compatibility
- No breaking changes. Every existing endpoint and MCP tool continues to behave identically.
- All new routes sit under
/api/diagnostics/— a previously-unused path. get_logson a workstation returns 503 with a clear error rather than misbehaving — intentional.
Documentation
docs/MCP_SERVER.md— new "Diagnostics" section in the tool catalogdocs/CONTROL_SERVER_ARCHITECTURE.md— API surface table extendedmcp-server/README.md+ rootREADME.md— tool lists refreshed- Wiki:
MCP-Server.md+Control-Server.mdupdated and pushed - Marketing site (
lights.griffen.codes): tool catalog auto-renders 31; new FAQ entry on agent-assisted debugging
Follow-up
Tier 2 and remaining Tier 3 items still tracked: