Skip to main content

TCP Device Core - Advanced Model

The TCP Device Core has a new way to describe what a device can do. Instead of filling in a fixed table of commands, you build your own set of parameters in a web page — each one with a proper name, a type, its own inputs, and a rule for reading the device’s answers. Every parameter you define shows up in Reactor as a real parameter, ready to put on a button.

Nothing was taken away. The original TCP Command Table works exactly as it always has, side by side with this, and on the same devices — see TCP Device Core / UDP Device Core. Nothing needs migrating.

Reach for advanced parameters when you want a control that carries a value — a level, a preset number, a piece of text — or when you want the panel to show what the device is actually doing. Reach for the command table when a one-shot trigger is all you need.

Models and devices

Parameters live on a model, not on a device. A model describes one kind of equipment — a projector, a matrix, a power switch — and holds every command for it. A device is one physical unit: it has an address and a port, and it points at a model. Several devices can share one model, so you describe the protocol once and reuse it for every identical unit in the building.

Model page showing the model name, description and its list of parameters

The first time the core starts it creates an empty model called ‘Default Advanced Model’ for you to write into. Add more from the + next to Model in the sidebar. Until you assign a device to a model, that device uses the generic model and has no advanced parameters.

Opening the web UI

Open Reactor, go to the Packages menu, find the TCP core package and use its button to open the UI. The sidebar lists your devices, your models, and every parameter on the model you are looking at.

Setting up a device

The Setup page holds everything specific to one unit: where it is, and what the core sends around a connection. A badge in the corner tells you whether the core currently has the socket open.

Device Setup page with the Device Setup and Feedback Parsing cards

  • Device Name / Description
    How the unit is identified here and in Reactor.
  • Model
    Which model this device uses. Changing it needs a core reload.
  • Server IP Address / Port
    Where the device listens, e.g. ‘192.168.10.20’ port ‘4352’.
  • Init Command
    Sent once, as soon as the connection opens. Use it to wake or arm a device. Backslash escapes such as \r\n work here too.
  • Test Command
    Sent by the device’s Test trigger. Pick something whose effect is easy to spot.
  • Ping Command / Ping Period
    Sent over and over to keep an idle connection alive. Leave the command empty to switch it off.

Feedback Parsing

These two settings decide how the core chops up what the device sends, before any of your parameters look at it. Both start out doing what this core has always done, so an existing device is unaffected until you change them.

  • Feedback Delimiter — where one message ends and the next begins: \n, \r\n, \r, or None (whole packet). Choose None when the device sends one complete message per packet, which is the usual case for a binary protocol.
  • Match feedback as hex — show the core the incoming bytes as 50 57 52 instead of PWR, so you can write a matching rule for bytes that have no printable form.

If a device answers PWR:on followed by a carriage return and a newline, a delimiter of \n leaves the carriage return stuck on the end of the message — and a rule ending in $ will never match. Set the delimiter to \r\n for those devices.

Both settings apply to the TCP Command Table as well, since a device that needs them needs them for all of its feedback.

The parameter editor

Each parameter is one command plus the rules around it. The left column is what gets sent; the right column is how the parameter appears in Reactor and what the operator can feed into it. Everything saves as you type.

Parameter editor showing a Power toggle with its command, wire preview, feedback rule and parameter information

Command

The exact bytes written to the socket. It is put together in two passes, always in this order:

  1. Placeholders are filled in — every {tag} becomes its variable’s value, and {value} becomes the parameter’s own value.
  2. Backslash escapes are turned into raw bytes.
Escape What it sends
\r carriage return, 0x0D
\n newline, 0x0A
\xHH one raw byte written in hex, e.g. \x02
\{ \} a literal brace

Under the field, On the wire shows the result: the byte count, the printable text, and the hex. It is produced by the same code that does the sending, so it cannot be out of date. Control characters appear as small symbols — ‘PWR on␍␊’ — so a command that ends in CR LF still fits on one line.

Watch the byte count. A missing \r is the single most common reason a device quietly ignores a command.

Because escapes are decoded second, a value can never turn into a control byte by accident — text typed by an operator is protected on the way in. What you type into the Command field itself is interpreted, and that is what lets you send arbitrary binary.

Parameter Information

How the parameter appears and behaves in Reactor.

  • Parameter Label / Description — the display name and help text.
  • Parameter Type:
    • Trigger — a button. Sends the command once. It has no value of its own, so {value} is not available.
    • Toggle — an on/off switch.
    • String — a text field; the text is {value}.
    • Integer / Float — a number field with a Minimum and Maximum; the number is {value}.
  • Value Format — how {value} is written into the command. See Formats below.

Toggles

A toggle sends one command in both directions. {value} carries the word that tells on from off, and you set those two words in On Value and Off Value.

  • When the two commands share most of their text, put the difference in the values: PWR {value}\r\n with On Value ‘on’ and Off Value ‘off’ sends ‘PWR on’ and ‘PWR off’.
  • When they share nothing, put the whole word in the values: {value}\r\n with On Value ‘SHUT ON’ and Off Value ‘SHUT OFF’.

Variables

A variable is a named blank in the command that the operator fills in. Type {slot} anywhere in the Command field and the editor offers to create the matching variable; or use the green + in the Variables card. Each one becomes an extra input on the parameter in Reactor, named after its Label.

Parameter editor showing a Recall Preset trigger with a slot variable of type Int, range 1 to 16

  • Tag — the name inside the braces. Letters and numbers only.
  • Label / Description — what the operator sees in Reactor.
  • Type — String, Int, Float or Binary.
  • Format — how the value is written into the command. See below.
  • Minimum / Maximum — the allowed range for a number.

Click a blue tag badge to drop that placeholder wherever you were last typing. {value} is listed alongside your variables, but it is built in and has no settings of its own beyond the parameter’s type and Value Format.

Formats — sending a number as bytes

By default a value goes into the command as plain text: the number 15 is sent as the two characters ‘15’. A Format changes that. It is set per variable, and separately for the parameter’s own value as Value Format.

Format The value 15 goes in as On the wire
Text (default) ‘15’ 31 35
Raw byte one byte 0F
Hex byte ‘0f’ 30 66
Decimal byte ‘15’, limited to 0–255 31 35
Scaled the number divided by Scale — 1500 with Scale 1000 goes in as ‘1.500’ ASCII digits

Parameter editor showing a Volume parameter whose value is sent as a raw byte inside an STX and ETX frame

The example above sends a speaker level as a single raw byte wrapped in the framing bytes 0x02 and 0x03: the command is \x02VOL{value}\x03 with a Value Format of Raw byte. Between the escapes and the formats, most binary protocols can be described without writing any code.

Feedback — reading a value back

A TCP device sends what it likes, when it likes. Nothing ties a reply to the command that caused it, so feedback here watches everything the device sends rather than waiting for an answer.

  • None — fire and forget. The parameter never reports a value.
  • Confirm on send — the value is echoed back as soon as the bytes leave the socket. Use it for a device that is silent but reliable.
  • Regex match value — a matching rule is checked against every message the device sends. When it matches, the last capture group — the innermost parentheses — becomes the parameter’s value.

A device that answers ‘PWR:on’ pairs with the rule ^PWR:(on|off)$. The ^ and $ pin the rule to a whole message, so unrelated chatter from the device cannot set your parameter by accident. For a toggle, set On Value and Off Value to the words the device itself uses and they will be compared against whatever the rule captured.

Editing the matching rule takes effect immediately — no reload. Changing the feedback type changes how the parameter is registered, so that one needs a reload. The editor flags a rule that is not valid, in red, before you ever send anything.

When the core needs a reload

Some changes only reach Reactor after the core restarts. When you make one, a red Reload Core button appears at the top of the sidebar. Make all your changes first, then press it once.

The red Reload Core button at the top of the sidebar

  • Needs a reload — adding, copying, importing or deleting a parameter or a model; a parameter’s label, description, type, minimum, maximum or feedback type; a variable’s label, description or type, and adding or removing one; a model’s name or description; assigning a device to a different model.
  • Takes effect straight away — the command text, the On/Off values, the matching rule, formats and scales, a variable’s tag and its minimum and maximum.

Testing a parameter

The green test-tube button at the top of the parameter page sends the command to a real device and shows you what happens — before you put it on a panel. Pick which device to run against, fill in the inputs, and press Send Command.

Test dialog showing the resolved bytes, the write to the device, an incoming reply and the value the regex would set

The log shows the fully resolved bytes as text and as hex, whether the write succeeded, and then every message the device sends during the listening window. When a message matches your rule, the log says so and names the value the parameter would be set to — which is the fastest way to get a matching rule right.

  • The bytes are resolved by the same code the live core uses, so the preview can never disagree with what is actually sent.
  • The preview appears even when the device is offline, so you can check your escaping without any hardware.
  • Listen for replies chooses how long to keep watching — 1, 3 or 10 seconds. The device is never asked to reply; this is only how long the window stays open.

Testing writes to the device’s live connection, for real. Do not test Power Off during a show.

Sharing parameters as files

Any parameter can be saved to a .json file and loaded again — on the same core or a different one. Use it to back up your work, copy a parameter between models, or build a library of ready-made devices.

New Parameter dialog with a name field and an Import from file button

  • Export — the export button on a parameter downloads it as ‘{Label}.json’.
  • Import as new — the import button on the model page, or Import from file… in the New Parameter dialog. You can pick several files at once.
  • Import over an existing parameter — the import button on a parameter replaces that parameter’s settings with the file.
  • Copy — duplicates a parameter on the same model as ‘{Label} (copy)’.

The file name becomes the parameter’s name. Importing ‘Recall Preset.json’ creates a parameter called Recall Preset. If that name is taken, the core adds ‘(1)’ rather than overwriting anything.

Writing parameter files with AI

Parameter files are plain JSON with a small, fixed shape, so an AI assistant can write them for you from a device’s protocol documentation. Attached to this page is CLAUDE.md, a guide that describes the format, the rules and several worked examples.

  1. Paste CLAUDE.md into an assistant such as Claude.
  2. Paste your device’s protocol documentation — the manufacturer’s command list or serial-protocol PDF.
  3. Ask for one importable .json file per action, named after the action.
  4. Import the files on the model page, then check each one with the Test button.

Always test what comes back. An assistant reading a protocol manual will get most of it right and can still get a terminator or a range wrong — and those are exactly the mistakes the Test dialog makes obvious.

Example walkthrough — a projector, from scratch

This builds a small but complete model for an imaginary projector whose protocol is line-based and ends every command with CR LF. The five finished parameters are attached to this page as .json files — import them, or follow along and build them by hand.

1. Create the device. On the Setup page, give it a name, set the IP address and port, and pick a model. Set the Feedback Delimiter to \r\n, since that is how this projector terminates its replies.

2. Power — a toggle that knows its own state. The projector accepts ‘PWR on’ and ‘PWR off’, and announces ‘PWR:on’ whenever it changes.

  • Command: PWR {value}\r\n
  • Type: Toggle, On Value ‘on’, Off Value ‘off’
  • Feedback: Regex match value, rule ^PWR:(on|off)$
    Power.json

3. Recall Preset — a button with an input. One button that can recall any of sixteen presets.

  • Command: PRE {slot}\r\n — typing {slot} creates the variable
  • Type: Trigger; Feedback: None
  • Variable slot: Label ‘Preset Slot’, Type Int, range 1–16
    Recall Preset.json

4. Lamp Hours — a number read off the device. Ask, and let the reply set the value.

  • Command: LAMP?\r\n
  • Type: Integer, Maximum 9999
  • Feedback: Regex match value, rule ^LAMP:([0-9]+)$
    Lamp Hours.json

5. Shutter — a toggle whose two commands share nothing. The projector wants ‘SHUT ON’ and ‘SHUT OFF’, so the whole word goes in the values.

  • Command: {value}\r\n
  • Type: Toggle, On Value ‘SHUT ON’, Off Value ‘SHUT OFF’
  • Feedback: Regex match value, rule ^SHUT:(ON|OFF)$
    Shutter.json

6. Volume — a binary command. The level is one raw byte, wrapped in framing bytes.

  • Command: \x02VOL{value}\x03
  • Type: Integer, range 0–255, Value Format Raw byte
  • Feedback: Confirm on send
    Volume.json

7. Test, then reload. Check each parameter with the Test button — watch the byte count and the hex line — then press Reload Core once. The five parameters now appear in Reactor under the model’s name.

Using the parameters from a panel

After a reload, every parameter you defined shows up in Reactor under the model’s name, called Adv_ followed by its label with spaces turned into underscores — a parameter labelled Recall Preset is Adv_Recall_Preset. Its type decides the control: a Trigger is a button, a Toggle a switch, an Integer or Float a fader or encoder, a String a text field. Any variables you defined appear as extra inputs on the parameter, named after their labels.

The parameters from the TCP Command Table — Commands/label, toggle, triggerOn, triggerOff, status and the Wild West escape hatch — are still there too, on the same device.

Troubleshooting

  • The device ignores the command — check the byte count in the wire preview. A missing \r or \n is the usual cause.
  • The parameter never gets a value — open the Test dialog and watch the incoming lines. If the message looks right but does not match, the delimiter is probably leaving a stray carriage return on the end; set Feedback Delimiter to \r\n.
  • The matching rule is flagged red — it is not a valid expression and will never match, so the parameter will never receive a value.
  • A change does not show up in Reactor — look for the red Reload Core button in the sidebar.
  • Nothing sends at all — check the connection badge on the Setup page. Advanced parameters write to the same socket the device loop keeps open.
  • A binary reply matches nothing — turn on Match feedback as hex and write the rule against 50 57 52 rather than PWR.

Reference

Parameter types: Trigger, Toggle, String, Integer, Float.

Variable types: String, Int, Float, Binary.

Formats: Text, Raw byte, Hex byte, Decimal byte, Scaled.

Feedback types: None, Confirm on send, Regex match value.

Escapes: \r, \n, \xHH, and \{ / \} for a literal brace.

Placeholders: {value} is the parameter’s own value, available on every type except Trigger; {tag} is one of your variables.

Feedback Delimiter: \n, \r\n, \r, None (whole packet).

The UDP Device Core, core-protocol-udp, works the same way and has the same web UI. Everything on this page applies to it, with UDP packets in place of a TCP connection.

Built-in Help

The web UI carries its own Help page, reachable from the bottom of the sidebar. It covers the same ground as this article in shorter form, so you can check a format or a feedback type without leaving the editor.

The built-in Help page in the TCP core web UI