Remote Control: Node Endpoints
How to push values into a node graph and read values back out — the escape hatch that makes anything in your show logic remotely controllable, not just the built-in entities.
The other elements in this section are entities Backstage already knows about. The node domain is different: you decide what it exposes, by labelling nodes in the graph.
Giving a node an address
A node becomes a control endpoint when it carries a label. The label is the address — there are no ids. Three kinds of node qualify:
|
Kind |
Where |
Use it for |
|---|---|---|
|
Remote Control In / Remote Control Out |
Network category |
Dedicated bridge nodes. In receives values and emits them into the graph as String, as a parsed Float, and as a Bang; Out publishes a value to subscribers |
|
Labelled datatype nodes |
Bang, String, Float, Int, Color |
The quick route: give an existing graph variable a label and it becomes controllable. Clearing the label hides it again |
|
CompanionIO |
UI category |
Typed endpoints that also publish metadata — ranges, choices, grouping — so a controller can render a proper widget instead of a text box |
An unlabelled datatype node is not an endpoint. If node.list comes back missing something you expected, the label is almost always why.
JSON protocol — domain node
|
Action |
Args |
Effect |
|---|---|---|
|
|
— |
Every endpoint, with its direction and any metadata. The discovery call — start here |
|
|
— |
The current value of a readable endpoint |
|
|
|
Drive a settable endpoint, as if the value had arrived on its input |
{"domain":"node","action":"list"}
{"domain":"node","action":"send","target":"houselights","args":{"value":"0.5"}}
{"domain":"node","action":"status","target":"showState"}
Direction matters
Every endpoint reports a dir, and sending to a readable-only endpoint will not work:
-
in— settable only. Remote Control In behaves this way. -
out— readable only. Remote Control Out behaves this way. -
inout— both. Datatype nodes are settable and publish their current value, which is what makes them convenient.
Values are always sent as strings
The value is a string whatever the endpoint's type, and each type parses it its own way:
|
Endpoint |
What to send |
|---|---|
|
Float, Int, String |
The value as text — parsed on arrival |
|
Color |
|
|
Bang |
Anything — the payload is ignored and the bang just fires |
|
CompanionIO Bool |
|
|
CompanionIO Enum |
The 0-based index of the choice, not its label |
Metadata, when there is any
CompanionIO endpoints publish extra fields that let a controller build a real widget: type (bang, float, int, bool, enum, string or color), min/max/step for numeric ranges, choices for enum labels, and group for display grouping by graph name.
Plain datatype and Remote Control endpoints carry none of this — a controller sees a name and a direction and must decide the rest itself. That is the reason to use CompanionIO when a hardware surface is involved.
Live values
{"domain":"sys","action":"subscribe","args":{"domains":["node"]}}
Readable endpoints are pushed as node events on change, so a graph can report state outward — a computed show state, a countdown, a health flag — without the controller polling for it.
Web Console — bound Ui Elements
Node endpoints are how Web Console pages go beyond the fixed show-control blocks. Any bindable Ui Element on a page takes these dropdowns, each listing labelled nodes:
-
Value Node — the element's value follows a String, Float, Int, Color or Bang node
-
Click Node — a click fires a Bang or sets a String node
-
Text Colour Node and Background Node — appearance follows a Color node
So the same label that a control system drives over JSON can colour a badge or wire a button on an operator page — one endpoint, both routes.
Bitfocus Companion
The Companion module is a plain client of this protocol over one TCP connection, so enabling the protocol is all it needs. CompanionIO nodes are optional extras that make its buttons better typed rather than a requirement.
Common Mistakes
-
An endpoint is missing from
node.list— the node has no label. Labelling is what publishes it. -
sendis rejected or ignored — checkdir. Anoutendpoint cannot be written to. -
An enum jumps to the wrong choice — send the 0-based index, not the label text.
-
A Color does nothing — it expects four comma-separated floats in
0–1, not hex and not 0–255. -
Two things answer to one name — labels are the address space and nothing enforces uniqueness for you. Keep them distinct across the whole project, not just per graph.
-
Renaming a label breaks control silently — the old name simply stops existing. Nothing warns the controller.
Related
Remote Control — the three routes, and every other controllable element
Enable and Configure the Show-Control Protocol — the protocol in full: transports, auth, allowlist, the reference client
Control Backstage with the Bitfocus Companion Module — Bitfocus Companion, the main consumer of typed node endpoints
Build and Serve Web Pages with the Web Console — binding page elements to these endpoints
Your First Graph — getting started in the Node editor
