Checking light from the house without running back to the laptop, why SSE was enough instead of websockets, and what happens if you skip the PIN on an open venue Wi-Fi.
The scenarios people actually set this up for
Checking from the house. You walk the rows, running cues as you go, and
watch how it looks from the seats. Without this, setting angles and levels
becomes a relay race: five steps there, five back, forty times over.
Focusing from the stage. You stand under the fixture, select it on the
phone, push the intensity — and see the beam where you are standing rather
than through a camera feed.
A second person at the run. An assistant runs GO from the script while
you fix levels. Or the other way round.
Get-in. Blackout from the phone when the stage must go dark right now
and you are up a ladder.
The console stays with the operator. The phone is not a replacement, it's a
second hand.
Inside: why SSE and not websockets
An engineering decision worth explaining, because it is counterintuitive.
Data flows both ways here: down to the phone goes state (active cue, engaged
presets, master position), up go commands. Reflex says: bidirectional
exchange, take a WebSocket.
We took Server-Sent Events downward and plain POST upward, and here is
why.
Upward go finger presses — a handful per second at their most energetic. For
that traffic a POST is no worse than a websocket frame, and it can be
debugged with curl.
Downward flows state, and it flows downward only. SSE is literally an
HTTP response that never ends: the server holds the connection and appends
lines to it. No framing, no handshake, no ping-pong to work out whether the
client is still alive.
The price difference: a WebSocket in Node means either an external
dependency or your own implementation of RFC 6455 with framing and masking.
SSE is res.write() in a loop. For the feature "show the phone which cue is
active", the second one is more honest.
A side benefit: SSE reconnects by itself. The phone slept, the Wi-Fi
blinked — the browser restores the stream without a single line of our
code. With a websocket we would have written that by hand, and written it
with bugs.
State is sent with 120 ms throttling and de-duplication: while the operator
drags a fader, snapshots don't fly out on every frame.
Commands take the same road as MIDI and OSC
This is a matter of principle. The phone does not get its own path into the
application's stores: its command goes through the same dispatcher as a pad
press on a MIDI controller or an OSC message from a tablet.
The motive is pragmatic: three parallel routes to one action means three
sets of bugs and three places where somebody forgot to update the logic. One
route, one set.
The HTTP server itself lives in the application's main process, next to DMX
and OSC. The interface window opens no ports at all.
On security: the PIN is not decorative
The server listens on every network interface — otherwise the phone
couldn't reach it. Which means the whole venue network can see it.
Picture what that means at a concert: a guest Wi-Fi with three hundred
people on it, and an open page with a blackout button on it. No malice is
required — curiosity and an accidentally guessed address like
192.168.1.42:7331 will do.
Therefore:
- Set a PIN. An empty PIN means "let everyone on this network in", and
the settings say so outright. With a PIN the phone gets a session cookie
(HttpOnly, 12 hours), so you don't retype it constantly.
- Brute force is cut off: more than ten attempts from one address per
minute and it stops answering. A four-digit PIN takes ten thousand
attempts, i.e. seventeen hours at that rate rather than a minute.
- Changing the PIN logs everyone out. The assistant left with their own
phone — change the PIN and their session dies with the rest.
The ideal option is of course a separate show network that outsiders can't
physically reach. But since we know that in reality there will be one switch
for everything, the PIN is on by default for a reason.
Connecting, and the small thing that ruins it
The settings show the address and a QR code — you point the phone's
camera instead of typing an IP with your fingers in a half-dark hall. Saves
about thirty seconds and one typo.
If the page won't open, it is almost always client isolation: guest Wi-Fi is
frequently configured so devices can't see each other. Checked instantly —
the phone and the laptop should ping each other.
And the most annoying thing, worth doing in advance: turn off the screen
lock. The phone goes dark exactly when GO needs pressing, and you unlock
it one-handed while standing on a ladder.