System Topology · Iziko Constantia AV

Constantia AV — System Topology

How the installation fits together: six players, one Q-SYS Core, five projectors and the software that drives them — sliced by network, by runtime, by control path, and by build pipeline.

Video / HDMI Audio Control / UDP LAN / HTTP 100 V speaker Cloud / WAN

1. Network

One isolated static LAN — no gateway, no router, no internet, by design. All traffic is on-subnet. The only device that reaches outside is the on-site PC, and it does so outbound only.

Gallery — live signal path

Q-SYS Core192.168.1.10 16 audio players → bus → amp
listens UDP :7000 · QRC :1710
Master BrightSign192.168.1.11 · LS445 roSync Leader · emits S0/L0
video only, no audio out
5 × Followers192.168.1.30 – .34 · LS425 Office 1/2 · Window 1/2 · Drawing Room
5 × Epson projectors192.168.1.40+ power + AV-mute from Q-SYS
15 s periodic re-assert
AUDAC amplifiers100 V line zones per-room volume + mute
Master → Core · UDP :7000 · S0/L0 markers Core → 6 players · UDP :5000 · Start/Stop/Pause/Resume Master ↔ Followers · roSync / PTP domain 6 Wall → players · DWS HTTP :8008 · Digest Wall → Core · QRC JSON-RPC :1710

On-site PC — monitoring only

“Wall” PC192.168.1.48 · Windows Wall app + embedded bridge 127.0.0.1:5000
polls the cloud mailbox, outbound
CloudflareWorker · Pages · R2 · KV installer feed, dashboard,
command + schedule relay
The Wall is not in the live path. It can sleep, crash or be unplugged and the show still runs. That was the point of the 2 June architecture change — everything the show needs is on the Core.

2. Where the code runs

The same system sliced by runtime rather than by folder.

Runs onSoftwareLinesJob
Q-SYS Corebridge_controller_master.lua v2.23.2Scheduler, UDP send, projector watchers, clock sync
Q-SYS Coresync_receiver.lua v1.11.10Owns UDP :7000, marker-anchored playhead
Q-SYS Core15 further Lua controllersShow latch, timers, zones, AUDAC, projector gate
BrightSign ×6Stock BA autorun.brs + .bpfxTwo-state machine: park image ⇄ show video
Wall PCbs-provisioner renderer5,914Operator UI, grid, sync clock, Q-SYS tabs
Wall PCbs-provisioner main2,636Electron main, IPC, the only reboot path
Wall PCbridge-server.js877Embedded Express bridge on :5000
Wall PCdws-client.js524DWS HTTP + Digest, file push/pull, recovery
Wall PCnet-doctor.js839Network diagnostics, ARP sweep
CloudflareWorker index.js722Feed, OTP, telemetry ingest, command relay
CloudflareDashboard index.html1,428This site (+ switch 181, manual 275)
BenchProvisioner · bridge CLI · WAV→MP3 · 40 toolsSD cloning, diagnostics, authoring, deploy

3. One show start, end to end

What happens between the scheduled start time and frame zero. Each step crosses a boundary between two of the layers above.

  1. The Core's clock reaches StartTime

    No cron and no cloud trigger. The Core has no NTP, so it syncs from the Wall's /api/time and reads it back in UTC form — correcting drift and a mis-set timezone at once.

    startup_timer.lua v1.3.0 — one-shot
  2. The countdown fires the show latch

    Every start source — timer, wall button, web switch — converges on one latch. Two absolute buttons rather than a toggle, because a momentary toggle double-pulses on press and release.

    show_button.lua v1.1.0 — Play = force ON
  3. Projectors warm, then the master broadcasts

    A warm-up delay lets the projectors come up before video starts. The AND gate re-asserts power every 15 s, so a dropped command self-heals instead of leaving one room dark.

    start_launcher.lua → proj_on_gate.lua v1.3.0
  4. Core sends the UDP keyword to all six players

    Start on port 5000, direct to each player. The BrightAuthor state machine moves from park image to show video at frame 0.

    bridge_controller_master.lua — runPlay() sends it
  5. Leader locks the followers, then reports back

    roSync on PTP domain 6 frame-locks the fleet, which needs firmware parity, equal fps and equal frame count. The Leader emits S0/L0 markers back to the Core.

    sync_receiver.lua owns :7000
  6. Gallery audio anchors to the video playhead

    The Core drives its 16 audio players from the marker feed, so sound re-anchors to picture rather than free-running.

    set locate.Value, then play:Trigger()
  7. The Wall watches, and only watches

    Screenshots over DWS and telemetry to the cloud — gated on whether anyone is actually looking at the dashboard, to stay inside the free-tier write budget.

    outbound only

4. How code reaches a machine

SourceTriggerLands at
Wall apptag wall-v*R2 → the in-app updater
This sitesame jobCloudflare Pages
WorkermanualCloudflare Worker
Autostart bundletag tools-autostart-v*GitHub Release
Changelog + version tablepush to mainRepo docs, auto-generated from tags
Q-SYS LuanoneHand-pasted — needs pins, Start Automatically, then F5
BrightSign presentationsnoneBrightAuthor:Connected, published Standalone → SD card
Two things that will bite you. The Lua controllers are the show logic and have no pipeline — nothing verifies that what is running on the Core matches what is in the repository. And each Pages deploy is a full snapshot, so deploying this site by hand without carrying version.json across removes it, and every Wall in the field starts failing its update check.