# External Show Control

This guide explains how to connect Exaplay 3 to an external **show control system** (ETC Eos lighting console, Medialon, QLab, Crestron, Q-SYS, CueLab, Alcorn McBride, a custom PLC, or any other device that can send network commands). It covers every supported protocol, with tested command examples and a troubleshooting checklist for each direction.

```
External show control system           Exaplay 3
┌────────────────────────┐             ┌──────────────────────────┐
│  Lighting console      │──OSC/UDP──► │  Receives commands       │
│  QLab                  │──REST ────► │  Fires cues              │
│  Medialon              │──ArtNet ──► │  Syncs timecode          │
│  CueLab                │──TCP ─────► │  Navigate cuelist        │
│  Q-SYS                 │──REST ────► │  Set properties          │
│  Crestron              │◄─OSC ─────  │  Sends timecode out      │
│  Custom PLC            │◄─UDP ─────  │  Data Track values out   │
│  Touch panel / AMX     │◄─ArtNet ──  │  DMX output              │
└────────────────────────┘             └──────────────────────────┘
```

***

## Part 1 — Commands INTO Exaplay (Incoming)

### 1A — REST API (most flexible)

Any device that can send an HTTP POST request can control Exaplay.

**Fire a cue by name:**

```bash
curl -X POST http://192.168.1.5:8123/cue/trigger \
  -H "Content-Type: application/json" \
  -d '{"name": "Scene 1 - Opening"}'
```

**Fire a cue by number:**

```bash
curl -X POST http://192.168.1.5:8123/cue/trigger \
  -H "Content-Type: application/json" \
  -d '{"number": 3}'
```

**Set a property value (e.g. opacity of a layer):**

```bash
curl -X POST http://192.168.1.5:8123/data \
  -H "Content-Type: application/json" \
  -d '{"type":"exaObj","path":"comp.Main.layer.0.opacity","values":{"value":75}}'
```

**Play a composition:**

```bash
curl -X POST http://192.168.1.5:8123/composition/play \
  -H "Content-Type: application/json" \
  -d '{"name": "Main"}'
```

**Stop all playback:**

```bash
curl -X POST http://192.168.1.5:8123/stop
```

> **Tip:** To find the correct path for any property, open it in the Inspector, click the 🔗 link icon, and read the path from the **Panel** or **cURL** tab.

***

### 1B — OSC (Open Sound Control)

OSC is supported by virtually every professional show control system.

**Exaplay OSC listen port:** `8000` (default — configurable in Config → Network → OSC)

| OSC Address             | Arguments               | Action                   |
| ----------------------- | ----------------------- | ------------------------ |
| `/exaplay/cue/trigger`  | `s` (cue name)          | Fire a cue by name       |
| `/exaplay/cue/go`       | *(none)*                | Advance to next cue      |
| `/exaplay/cue/back`     | *(none)*                | Step back one cue        |
| `/exaplay/play`         | *(none)*                | Play current composition |
| `/exaplay/stop`         | *(none)*                | Stop all playback        |
| `/exaplay/fade`         | `f` (duration 0–10 s)   | Fade to black            |
| `/exaplay/data`         | `s` (path), `f` (value) | Set any numeric property |
| `/timecode/hh/mm/ss/ff` | *(path encodes TC)*     | Receive timecode sync    |

**Example — ETC Eos console firing a cue:**

In the Eos Macro editor, add a **Network** command:

```
/exaplay/cue/trigger "Scene 1 - Opening"
  UDP to 192.168.1.5:8000
```

**Example — Qlab sending OSC:**

1. In Qlab, add a **Network** cue.
2. Set Type to **OSC message**.
3. Set destination to `192.168.1.5:8000`.
4. Set message: `/exaplay/cue/trigger "Opening"`.

***

### 1C — ArtNet Timecode

For frame-accurate sync driven by a lighting console:

1. Open **Config → Network → ArtNet**.
2. Enable **Receive ArtNet Timecode**.
3. Set the universe to match your console's output (default: Universe 0).

On the lighting console side, enable **ArtNet Time Code** output on the same subnet.

Exaplay's Transport bar shows **TC: Locked** (green) when the sync is established.

**Supported frame rates:** 24, 25, 29.97 DF, 30 fps.

***

### 1D — LTC (Linear Timecode via Audio)

1. Connect the LTC output from your console to an audio input on the Exaplay ASIO interface.
2. Open **Config → Audio Settings → Timecode Input**.
3. Select the channel, set the frame rate to match the console.
4. The Transport bar shows **TC: Locked** when the signal is detected.

***

### 1E — TCP Text Protocol

Exaplay accepts persistent TCP connections that carry simple comma-delimited commands. This is ideal for Medialon, Alcorn McBride, Crestron/AMX, and any custom PLC that works natively with raw TCP sockets.

**Default port:** `8100` (configure in Config → Network → TCP Listen)

**Command format:** `COMMAND,COMPOSITION_ID[,ARGUMENT]` followed by `\r` or `\r\n`

Retrieve composition variable names first:

```
→ get:complist
← comp_main,Main Show
← comp_lobby,Lobby Loop
← END
```

Common transport commands:

```
→ play,comp_main
← OK

→ stop,comp_main
← OK

→ get:status,comp_main
← 1,42.1230,2527,2,0.0000
  (STATUS, TIME_SECONDS, FRAME, CUEINDEX, TOTAL)
```

CueList navigation:

```
→ next,comp_lobby
← OK

→ set:cue,comp_lobby,3
← OK
```

See [TCP Command API](/v3/developer-reference/tcp-api.md) for the complete command reference.

***

## Part 2 — Commands OUT of Exaplay (Outgoing)

### 2A — OSC Output

Exaplay can transmit its current playback position and custom events to any OSC listener.

**Configure OSC output:**

1. Open **Config → Network → OSC Output**.
2. Enter the destination IP and port (e.g. `192.168.1.20:9000`).
3. Choose the **Timecode OSC Address** pattern.

Exaplay sends `/timecode/hh/mm/ss/ff` to the configured destination on every frame during playback.

**Custom OSC via Data Tracks:**

Any Data Track can output to an OSC address. This lets you send a value (float) to any OSC address at any moment in the timeline:

```
Data Track "LightingMaster"
  Output Type: OSC
  OSC Address: /eos/fader/1/value
  Destination: 192.168.1.20:8000

  Keyframes: fade from 0 to 1.0 over 5 seconds
```

***

### 2B — ArtNet DMX Output

Exaplay can drive lighting fixtures, dimmers, and LED controllers directly over Art-Net, independent of any lighting console. This is useful for installations where Exaplay is the **only** show control system.

See [ArtNet & DMX Output](/v3/features/artnet-dmx.md) for the full guide.

***

### 2C — UDP Output

Any Data Track can output raw UDP datagrams to any device that accepts them:

```
Data Track "MotionRig"
  Output Type: UDP
  Destination: 192.168.1.30:9500
```

The current interpolated value is sent as a 4-byte big-endian float on every frame.

***

## Part 3 — Verifying Communication with the Monitor

The **Monitor** tab is the single most important tool for diagnosing show control integration issues.

### How to Use the Monitor Tab

1. Open the Control View (`/control`).
2. Click the **📡 Monitor** tab.
3. Trigger a command from the external system.
4. Check the **Event Log** for an entry.

### What Good Looks Like

| Protocol            | Event Log entry                                             |
| ------------------- | ----------------------------------------------------------- |
| REST API trigger    | `POST /cue/trigger — 200 OK from 192.168.1.20`              |
| OSC received        | `OSC /exaplay/cue/trigger "Opening" from 192.168.1.20:8000` |
| ArtNet TC locked    | `ArtNet TC 00:01:23:15 from 192.168.1.20 — TC LOCKED`       |
| ArtNet DMX sent     | `ArtNet OpDmx → Universe 0 → 192.168.1.50`                  |
| OSC sent (outgoing) | `OSC /eos/fader/1/value 0.75 → 192.168.1.20:8000`           |

If an expected entry is missing, the packet never reached Exaplay — see Part 4.

***

## Part 4 — Troubleshooting

### No incoming commands received

| Check           | What to do                                                                                        |
| --------------- | ------------------------------------------------------------------------------------------------- |
| **IP address**  | Open Monitor tab → Host Information card → confirm the correct IP address                         |
| **Port**        | Confirm the sending device is targeting the correct port (REST: `8123`, OSC: `8000`, TCP: `8100`) |
| **Firewall**    | Allow inbound UDP 8000 and TCP 8123, 8100 in Windows Defender Firewall                            |
| **Subnet**      | Both devices must be on the same subnet (e.g. `192.168.1.x / 255.255.255.0`)                      |
| **OSC address** | OSC addresses are case-sensitive — `/exaplay/cue/trigger` ≠ `/Exaplay/cue/trigger`                |

**Windows Firewall — allow Exaplay ports:**

```batch
netsh advfirewall firewall add rule name="Exaplay HTTP" dir=in action=allow protocol=TCP localport=8123
netsh advfirewall firewall add rule name="Exaplay TCP Control" dir=in action=allow protocol=TCP localport=8100
netsh advfirewall firewall add rule name="Exaplay OSC" dir=in action=allow protocol=UDP localport=8000
netsh advfirewall firewall add rule name="Exaplay ArtNet" dir=in action=allow protocol=UDP localport=6454
```

***

### ArtNet timecode not locking

| Check                 | What to do                                                                               |
| --------------------- | ---------------------------------------------------------------------------------------- |
| **Universe**          | Confirm the ArtNet TC universe in Exaplay matches the console's output universe          |
| **Network**           | Exaplay and console must be on the same subnet for ArtNet broadcast                      |
| **Frame rate**        | Project frame rate (Config → Video Settings) must match the console's TC frame rate      |
| **Monitor Event Log** | ArtNet TC packets should appear in the log — if not, the network is blocking the packets |

***

### OSC going out but console not receiving

| Check                               | What to do                                                                     |
| ----------------------------------- | ------------------------------------------------------------------------------ |
| **Destination IP**                  | Confirm the console's IP in Config → Network → OSC Output                      |
| **Destination port**                | Confirm the console's OSC receive port matches the configured destination port |
| **Console OSC enabled**             | Many consoles require OSC receive to be explicitly enabled                     |
| **Firewall on the console machine** | Ensure the console's firewall allows incoming UDP on the OSC port              |
| **Monitor Event Log**               | Outgoing OSC messages should appear in the log — confirm they are being sent   |

***

### REST API returns 404 or connection refused

| Check              | What to do                                                                                        |
| ------------------ | ------------------------------------------------------------------------------------------------- |
| **Engine running** | The engine (not just the UI) must be running — check the tray icon                                |
| **Port**           | REST API is on port `8123` — ensure no other app is using this port                               |
| **Endpoint path**  | Check the exact endpoint path (case-sensitive); use the cURL tab in Inspector for confirmed paths |
| **JSON format**    | Request body must be valid JSON; `Content-Type: application/json` header is required              |

***

## Part 5 — Quick Reference

### Incoming commands summary

| Protocol            | Port             | Enable in                       |
| ------------------- | ---------------- | ------------------------------- |
| REST HTTP           | `8123` (TCP)     | Always on                       |
| OSC                 | `8000` (UDP)     | Config → Network → OSC          |
| ArtNet TC (receive) | `6454` (UDP)     | Config → Network → ArtNet       |
| LTC                 | ASIO audio input | Config → Audio → Timecode Input |
| TCP Text Protocol   | `8100` (TCP)     | Config → Network → TCP Listen   |
| WebSocket events    | `8123` (WS)      | Always on (same port as HTTP)   |

### Outgoing commands summary

| Protocol            | Port             | Enable in                        |
| ------------------- | ---------------- | -------------------------------- |
| OSC output          | Configurable UDP | Config → Network → OSC Output    |
| ArtNet DMX          | `6454` (UDP)     | Data Track → Output Type: ArtNet |
| UDP raw             | Configurable     | Data Track → Output Type: UDP    |
| WebSocket (effects) | `3001` (WS)      | Effects Server (auto-started)    |

***

## Part 6 — Integration Examples by System

### ETC Eos / Ion

1. Enable **OSC Rx** on Exaplay (port 8000).
2. In Eos, create a Macro with a **Network cue**: OSC `/exaplay/cue/trigger "My Cue"` → target `192.168.1.5:8000`.
3. For bidirectional: configure Eos OSC Tx to send timecode, and Exaplay OSC Rx to receive it.

### Qlab (Mac)

1. Add a **Network cue** in Qlab.
2. Select OSC or HTTP based on preference.
3. For OSC: target `192.168.1.5:8000`, address `/exaplay/cue/trigger`, argument `"My Cue"`.
4. For HTTP: target `http://192.168.1.5:8123/cue/trigger`, method POST, body `{"name":"My Cue"}`.

### Medialon / Alcorn McBride

Both systems support **TCP socket** connections natively — this is the recommended integration path.

1. Configure a **TCP Device** in Medialon/Alcorn targeting `192.168.1.5:8100`.
2. Send commands as ASCII strings with `\r` or `\r\n` terminators (e.g. `play,comp_main\r`).
3. Alternatively, use the REST API — both systems also support HTTP GET/POST natively — targeting port `8123`.

See [TCP Command API](/v3/developer-reference/tcp-api.md) for the full command reference.

### Crestron / AMX Touch Panels

Crestron and AMX processors can control Exaplay over the **TCP Command Protocol** (recommended for cue navigation) or via the **REST API** (recommended for property control and status queries).

**Option A — TCP (SIMPL+ / SIMPL# Pro)**

Use the built-in TCP/IP client symbol (`TCPClient` in SIMPL+) to open a persistent connection to Exaplay on port `8100`.

```
// SIMPL+ pseudocode
TCP_CLIENT ExaplayClient;
STRING txBuf[100], rxBuf[100];

FUNCTION PlayComp(STRING compId)
    txBuf = compId + "\x0D\x0A";    // "play,comp_main\r\n"
    ExaplayClient.SendData(txBuf);
END_FUNCTION
```

In **SIMPL#**:

```csharp
var client = new TCPClient("192.168.1.5", 8100, 4096);
client.ConnectToServer();
client.SendData(Encoding.ASCII.GetBytes("play,comp_main\r\n"), 16);
```

Common commands for a touch-panel button map:

| Button     | Command sent               |
| ---------- | -------------------------- |
| Play       | `play,comp_main\r\n`       |
| Stop       | `stop,comp_main\r\n`       |
| Cue 1      | `set:cue,comp_main,1\r\n`  |
| Next       | `next,comp_main\r\n`       |
| Volume 80% | `set:vol,comp_main,80\r\n` |

**Option B — REST (HTTP Client)**

Use Crestron's `HttpClient` (SIMPL# Pro) or a third-party REST module:

```csharp
var http = new HttpClient();
http.Post(
    "http://192.168.1.5:8123/cue/trigger",
    "application/json",
    "{\"name\":\"Scene 1 - Opening\"}"
);
```

> **Tip:** Use the REST API for feedback (e.g. polling `GET /status`) and the TCP protocol for low-latency button presses.

***

### Q-SYS (QSC)

Q-SYS cores run a **Lua 5.3** scripting environment with built-in `TcpSocket` and `HttpClient` objects. Both work well with Exaplay.

**TCP integration (recommended — persistent connection, low latency)**

Add a **Scriptable Controls** component in Q-SYS Designer and use the following Lua snippet:

```lua
-- Q-SYS Lua: Exaplay TCP control
local EXAPLAY_IP   = "192.168.1.5"
local EXAPLAY_PORT = 8100
local sock         = TcpSocket.New()
local connected    = false

local function connect()
  sock:Connect(EXAPLAY_IP, EXAPLAY_PORT)
end

sock.EventHandler = function(s, evt, err)
  if evt == TcpSocket.Events.Connected then
    connected = true
    print("Exaplay: connected")
  elseif evt == TcpSocket.Events.Disconnected then
    connected = false
    Timer.CallAfter(connect, 5)   -- auto-reconnect after 5 s
  elseif evt == TcpSocket.Events.Data then
    local resp = s:Read(s:Lines())
    print("Exaplay response: " .. resp)
  end
end

local function send(cmd)
  if connected then
    sock:Write(cmd .. "\r\n")
  end
end

-- Wire up Named Controls
Controls["Play"].EventHandler = function()
  send("play,comp_main")
end

Controls["Stop"].EventHandler = function()
  send("stop,comp_main")
end

Controls["Next"].EventHandler = function()
  send("next,comp_main")
end

Controls["SetCue"].EventHandler = function()
  -- value of a Named Control slider = cue number
  send(string.format("set:cue,comp_main,%d", math.floor(Controls["SetCue"].Value)))
end

connect()
```

**HTTP integration (for one-shot triggers or status polling)**

```lua
-- Q-SYS Lua: fire a cue via REST
HttpClient.Download({
  Url     = "http://192.168.1.5:8123/cue/trigger",
  Method  = "POST",
  Headers = { ["Content-Type"] = "application/json" },
  Data    = '{"name":"Scene 1 - Opening"}',
  EventHandler = function(tbl, code, data, err)
    if code == 200 then
      print("Cue fired OK")
    else
      print("Error: " .. tostring(err))
    end
  end
})
```

> **Note:** Q-SYS `TcpSocket` keeps the TCP session open across multiple triggers, which is more efficient than a new HTTP request per cue. Use TCP for real-time control and HTTP for infrequent or complex requests.

***

### CueLab

CueLab (by Avolites/Cogenta) supports **OSC** and **REST HTTP** output — both work natively with Exaplay.

**OSC setup (simplest)**

1. In CueLab, open **Settings → Network**.
2. Under **OSC Output**, add a destination: IP `192.168.1.5`, Port `8000`.
3. For each CueLab cue that should trigger Exaplay, add an **OSC Action**:
   * Address: `/exaplay/cue/trigger`
   * Argument (string): name of the Exaplay cue (e.g. `"Scene 1 - Opening"`)

| CueLab OSC Action                | What Exaplay does            |
| -------------------------------- | ---------------------------- |
| `/exaplay/play`                  | Start composition            |
| `/exaplay/stop`                  | Stop composition             |
| `/exaplay/cue/trigger "Opening"` | Fire cue by name             |
| `/exaplay/cue/go`                | Advance to next cue          |
| `/exaplay/cue/back`              | Step back one cue            |
| `/exaplay/fade 2.0`              | Fade to black over 2 seconds |

**REST setup (more control)**

1. In CueLab, create a cue with a **Web Request** action.
2. Set **Method** to `POST` and **URL** to `http://192.168.1.5:8123/cue/trigger`.
3. Set **Body** to `{"name":"Scene 1 - Opening"}` and **Content-Type** to `application/json`.

**Bidirectional — receive Exaplay timecode in CueLab**

1. In Exaplay, open **Config → Network → OSC Output**.
2. Set destination to `<CueLab machine IP>:<CueLab OSC Rx port>` (check CueLab Settings → Network → OSC Input).
3. Exaplay will send `/timecode/hh/mm/ss/ff` on every frame — CueLab can use this to auto-follow Exaplay's timeline.

***

## Summary Checklist

* [ ] Engine IP address confirmed (Monitor tab → Host Information)
* [ ] Firewall rules added for ports 8123 (TCP), 8100 (TCP) and 8000 (UDP)
* [ ] OSC Rx enabled on the correct port
* [ ] OSC Tx configured with the correct destination IP/port
* [ ] ArtNet TC universe matches the console's output universe (if using ArtNet sync)
* [ ] LTC audio channel and frame rate configured (if using LTC)
* [ ] REST API tested with a cURL command
* [ ] Monitor → Event Log shows incoming commands from the external system
* [ ] Monitor → Event Log shows outgoing commands to the external system
* [ ] Full show run-through with all external triggers verified


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.exaplay.one/v3/workflows/show-control.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
