QSC Q-SYS Core
GEM controls QSC Q-SYS Core processors via the QRC (Q-SYS Remote Control) JSON-RPC 2.0 protocol on TCP port 1710. One GEM device row represents one Core; each named control exposed by the deployed Q-SYS design becomes a GEM zone.
Prerequisites
- A Q-SYS Core (Core 8 Flex / 110f / 510i / NV-32-H / etc.) running a design in Run mode (not Emulate). The QRC port only listens while a design is running.
- External Control Access enabled in the design. In Q-SYS Designer:
File → Design Properties → External Control Access. Choose the lowest access level that meets the project's security requirement —External Control Access: All Controlsis simplest. - Each control you want to drive must have a Code Name. Right-click a control in Designer → Properties → set Code Name. The Code Name is what GEM puts on the zone as
zone.address. - TCP port 1710 reachable from the GEM controller (no firewall block between the controller and the Core).
Setup
- In Q-SYS Designer, decide which controls GEM should drive (volume, mic mute, source select, scene-recall buttons, page triggers, etc.) and give each a stable Code Name. Push the design to the Core (Run mode).
- In GEM admin → Devices → Add Device, pick driver
qsys_core. Enter the Core IP. Leave the TCP port at the default 1710. - If the design's External Control Access uses PIN-only auth, enter the PIN in the
passwordfield and leaveusernameblank. For user/password auth, fill both. For "All Controls" / no-auth, leave both blank. - Save and enable the device. The driver will:
- Open the JSON-RPC socket on port 1710.
- Send
Logonif credentials are present. - Issue
StatusGetand surfacedesign_name,platform, andcore_stateas device attributes. - Start a 30 s
NoOpkeepalive so the Core does not idle-close the socket.
- Run the
get_controlscommand with a comma-separated list of Code Names to verify each one resolves. Then create one zone per Code Name;zone.addressis the Code Name verbatim (e.g.lobby_volume,conf_mic_mute). For component controls useComponentName.ControlName.
Attribute reference
Device
| Attribute | Required | Description |
|---|---|---|
ip | yes | LAN IP or hostname of the Core. |
port | no | QRC port. Defaults to 1710 — only change for a TCP proxy in front of the Core. |
username | no | Q-SYS user. Only used when External Control Access is User/Password. |
password | no | Password (User/Password mode) or PIN (PIN-only mode). Encrypted at rest. |
status_interval | no | Status poll cadence, ms. Default 30 000; values below 5 000 are raised to 5 000. After 3 consecutive failed polls the driver skips 1, 2, 4, 8 then 16 ticks between attempts, and returns to every tick on the first good reply. |
keepalive_interval | no | NoOp keepalive cadence, ms. Default 30 000 (under the Core's 60 s idle timeout); values below 5 000 are raised to 5 000. |
request_timeout | no | Per-request JSON-RPC timeout, ms. Default 5 000. |
Zone
| Attribute | Required | Description |
|---|---|---|
address | yes | The Q-SYS Code Name. Case sensitive. For component controls use ComponentName.ControlName. |
level_scale | no | Which Control.Set field set_level writes to. position (default) maps GEM's 0..100 onto Q-SYS Position 0..1, which works for any control type. value writes the raw value directly — use when the underlying control's units are known. With value, the polled level is also read back as the raw numeric Value (e.g. -12.5 dB) rather than scaled from Position; a control whose Value isn't a number still reads back from Position. |
Zone address format
A Q-SYS Code Name as it appears in Q-SYS Designer. Two shapes:
- Top-level named controls:
lobby_volume,conf_mic_mute,scene_outdoor. - Component controls:
Gain1.gain,Mixer.mute_1,Page.station_1.
Case matters. Designer's "copy code name" gives you the exact string.
Command reference
| Command | Args | Effect |
|---|---|---|
on | address | Control.Set with Position: 1.0. Boolean on / max gain. |
off | address | Control.Set with Position: 0.0. Boolean off / mute / min gain. |
set_level | address, level | Writes Position: level/100 for a 0..100 level (default), or Value: level when the zone's level_scale is value — then the level is the control's own units and may be negative. |
set_value | address, value | Writes a raw numeric Value — bypasses Position scaling. Use for exact dB / integer writes. A blank value is refused (value required); 0 is sent. |
set_string | address, value | Writes a string Value — for combo-box / string controls. |
mute_on / mute_off | address | Writes boolean Value: true / false. |
mute_toggle | address | Resolved client-side from the cached control state. The cached Value decides — a numeric 1 (how Control.Get reports a mute) reads as muted, 0 as unmuted; Position is used only when there is no Value. |
trigger | address | Pulse: writes Position: 1.0, then Position: 0.0 200 ms later — for momentary buttons / page triggers. If the Core refuses the press, the release is not sent and the press error is returned. |
get_controls | controls (csv) | Control.Get of multiple Code Names in one request. |
get_status | – | StatusGet: DesignName, Platform, State, IsRedundant, DesignCode. |
raw_command | method, params (JSON) | Send any QRC method (e.g. ChangeGroup.AddControl, Mixer.SetCrossPointGain). |
What's not yet supported
- ChangeGroup-based push status. The driver currently polls every zone via
Control.Getonstatus_interval. For designs with hundreds of controls this is wasteful; a future revision should let zones opt into aChangeGroup.AddControl+ChangeGroup.AutoPollflow. As a stop-gap, useraw_commandto set up your own change group and process notifications via the device log. - Phone / dialer control surfaces (
PA.SoftphoneDialand friends). The protocol supports them; the driver does not yet expose convenience verbs. - Mixer / matrix component setters (
Mixer.SetCrossPointGain,Mixer.SetInputMute, etc.). Reachable viaraw_commandbut not wrapped. - Snapshot recall via
Snapshot.Load. Reachable viaraw_command. - Logon for SSH/HTTPS encrypted control (Q-SYS Reflect tier). The driver speaks the plain TCP QRC port; if a design restricts QRC to the encrypted variant only, the connection will not open.
Troubleshooting
- "control not found" from
get_controlsor no status updates. The Code Name on the zone must match Designer exactly, including case. In Designer, click the control → Properties → copy the Code Name string. logon failedor socket closes shortly after connect. External Control Access level is higher than the supplied credentials cover. Open Design Properties → External Control Access in Designer and either lower the access level or supply matchingusername/password.- Status polling lags or commands time out. A run of failed polls logs
qsys core status polling backing offonce and slows the poll until the Core answers again. Failed attribute writes are logged asqsys core: attribute write failed. Q-SYS Cores throttle per-connection QRC traffic. Raisestatus_interval, reduce the number of polled zones, or migrate frequently-changing controls to aChangeGroupviaraw_command. socket not readyon every command. The Core is not in Run mode, or the design's External Control Access is set toNone. Open the Core's diagnostic page — under Network the QRC port should reportListening.qsys core keepalive failedin the device log. The 30 sNoOpwent out but the Core did not answer it withinrequest_timeout. GEM's socket is still open, so this is a Core that has stopped servicing QRC rather than a dropped connection — a design stopped or being redeployed, a Core rebooting, or a half-open socket left behind by a network break. Commands will time out for as long as it persists, and the message repeats once per keepalive until the Core answers or the socket closes and the driver reconnects.- Commands change the GEM-side level but nothing happens at the Core. Some controls are read-only in the design. In Designer, confirm the control's
Properties → Permissionsincludes Set.