The Q-SYS Core is the pub’s audio and AV hub. The Raspberry Pi reads and controls the other AV gear through the Core over QRC (Q-SYS Remote Control, JSON-RPC on TCP 1710) instead of opening a separate session to each device. The Pi forwards what it reads into its heartbeat, so the admin System Status panel shows live device state.

Why through the Core: the AVPro matrix and the projector each expose a single control session. When the Q-SYS plugins and the Pi both opened those sessions directly, they fought for the one slot and the plugins flapped. Routing the Pi’s reads through QRC ended that contention.

Topology

flowchart LR
  subgraph Core["Q-SYS Core 110f"]
    QRC["QRC named controls"]
    MODE["Sound-stage ModeSelect"]
  end
  AVPRO["AVPro AC-MX-42<br/>HDMI matrix"] --- Core
  PROJ["Panasonic PT-FRZ55<br/>projector"] --- Core
  TSC["TSC-70-G3<br/>touchscreen"] --- Core
  PI["Raspberry Pi"] -->|"QRC read: matrix routing,<br/>projector, touchscreen, mode"| QRC
  PI -->|"QRC set: apply desired mode"| MODE
  PI -->|"heartbeat: device status"| WK["Worker / admin<br/>System Status"]
  WK -->|"desired mode (D1 poll)"| PI
  TSC -->|"lighting plugin: HTTP to dmx-api :5001"| DMXAPI["Pi dmx-api<br/>par-can rig"]

What the Pi reads over QRC

DeviceReadPi env
AVPro AC-MX-42 matrixActive HDMI route + signal-detect per inputAVPRO_SOURCE=qsys
Panasonic PT-FRZ55Power, input, signalPROJECTOR_SOURCE=qsys
TSC-70-G3 touchscreenCurrent page, temp, brightness, networkTSC_ENABLED (default on)

content_mode is signal-gated: an input that’s routed but has no live signal (InputDetect=0) reports music, not video, so a dead HDMI source can’t force a movie layout.

The admin System Status panel renders what the Pi reports over QRC — the Song-ID Pi, AVPro matrix, projector, and touchscreen — next to the external API health:

Admin System Status showing device + API health Admin system health view · June 2026

Sound-stage modes (Party / Default / Movie)

A single-row D1 table (pub_qsys_state) holds a desired mode (set by the admin or the TSC) and the current mode (read from the Core). The Pi polls GET /api/qsys/desired ~every 5s and applies the change via QRC; the Core’s ModeSelect is the source of truth. Gated by QSYS_ENABLED until the Designer-side ModeSelect control and snapshots exist.

FieldMeaning
desired_*Pending request from admin / TSC
current_*Live mode the Pi read from the Core

DMX lighting from the TSC-70

Lighting is the second surface driven from Q-SYS, and it ships. The IHNYC Pub Lighting plugin (qsys/ihnyc-pub-lighting.qplug, v1.11+) gives the TSC-70 touchscreen live, Hexcon-parity control of the DMX par-can rig. Unlike the sound-stage modes, the plugin does not go through the Core’s QRC — it talks HTTP straight to the Pi’s dmx-api on :5001 (the Pi is the DMX master). Each button press fires an async, timed HTTP call; a /status poll drives the Online dot, the live per-can swatches, and the mirrored fader positions, so a Pi outage just makes the panel go dark instead of hanging.

What the panel exposes:

  • Looks — every dmx-api program (rainbow / chase / fade / pulse / wave / comet / aurora / strobe / police / sparkle / theme / music) as a radio toggle.
  • Music modes — music-reactive autopilot incl. an RGB reactive mode.
  • Color — 8 preset macro washes + manual R/G/B mix faders (POST /color, whole-rig solid color), plus a Fade-time fader.
  • My Looks — 6 save-a-look presets (/preset/save|recall).
  • Moments — one-shot cue bursts (/cue flash / last-call / birthday / closing) that take over then restore the prior look.
  • Blackout — a latching hold (/config force_black), not a momentary flash.

Install = double-click the .qplug (it appears under the IHNYC category in Schematic Elements — not via Asset Manager). The plugin is re-paginated for the TSC-70-G3’s 7” touch floor into three pages (Operator / Looks / Mix). The full behavior of the rig itself lives in dmx-lighting.

TSC theme-sync — what does and doesn’t follow the theme

The bar TVs and the par-cans follow the active V2 theme accent live; the TSC-70 touchscreen does not fully. Whole-venue TSC reskinning was investigated and closed as won’t-do (PR #725): the touchscreen’s base accent is hardcoded CSS, not script-recolorable, so the static navy / light-blue look stays put by design. A separate tsc-theme-sync.lua Control Script does sync what can be synced — it polls the live theme_accent (exposed on the lighting Pi’s /status) and tints the handful of named UCI controls that accept a runtime .Color. It is an accent shift, not a reskin.

One-tap “Vibe” (audio + lights together)

A Vibe sets the whole room mood in a single press — it recalls a sound-stage audio snapshot and drives the lights at once. This is the qsys/soundstage-vibe.lua Control Script (not the lighting plugin), because the plugin can only speak HTTP to the Pi and can’t recall a Core-side audio snapshot; the script bridges both halves. It reaches the Snapshot Controller by name (no schematic wiring) and POSTs the lighting straight to the Pi.

VibeAudio snapshotLights
PartyParty voicing (load_2)full intensity + music autopilot
ChillDefault voicing (load_1)half intensity + warm scene
MovieMovie voicing (load_3, optional)dim + warm scene
ClosingDefault voicing (load_1)amber wash