Logic and routing nodes
Condition, Join, Inject, Catch, Expression, Cast, Debounce, Batch, JSON template and Throttle: how each is drawn, and what the runtime does with it on the device.
How the runtime executes them
Every node on the wire between a source and an output that is not folded into the tag (Scale, Unit conversion, Rename) or the route (Deadband, Rate limit) becomes a step on that route, in wire order. The runtime runs them in two halves around its publish decision.
Condition / Route
The node tests the value, the quality, the tag name, the device or the topic against rules evaluated top-down: ==, !=, >, >=, <, <=, between, contains, matches regex, is true, is false, is null / BAD and changed. Each rule is an output; a final Otherwise output catches the rest. First match wins unless Match all is on, in which case every matching output fires.
In the runtime each output is its own route, carrying the rules and which output it left through. A value that does not pass is counted as suppressed for that route and is not part of its grouped, joined or periodic messages. is null / BAD matches a reading whose quality is not usable, so a bad reading can be sent somewhere specific. changed remembers the last value it saw per tag.
Join
values holds every tag of both.| Strategy | The runtime |
|---|---|
| Merge tags | Coalesces the updates of a poll cycle and sends one message with the current value of every joined tag, keyed by tag name. Two devices with a tag of the same name: the newer reading wins. |
| Zip by ts | Sends only once every joined device has reported since the last message, so a message always carries a fresh value from each. |
| Latest wins | Sends the full snapshot on every update, so a consumer always has everything at the cost of more messages. |
{"devices":["Main meter","Pump"],"timestamp":"2026-09-29T07:25:03.629Z","values":{"Voltage_L1":230.5,"Speed":1480,"Running":true}}The topic's {device} becomes the joined device names (Main_meter_Pump); name the topic yourself when that is not what you want.
Inject / Trigger
- Through a Join with a device: the joined values are published on the Inject's interval, not on change. The runtime makes the route periodic at that interval.
- Straight into an output: a message on the interval. The Payload is sent as-is when it is JSON, as text otherwise; empty, the message is
{"event":"trigger","route":…,"timestamp":…}. A heartbeat for a broker, or a keep-alive for an API. - The interval is
500ms,5s,1mand so on; below 100 ms is refused at validation.
Catch / Status
The route becomes a status channel. A tag's first good reading is not news; its first bad one, and every change of quality after that, is sent with the reason: a timeout, a refused address, a device that stopped answering. Wired nodes only watches the device it is wired to; Whole flow watches every tag, and also reports a failed delivery to any other output (a broker that refused the connection, a database that is down).
{"event":"quality","device":"Main meter","tag":"Voltage_L1","quality":"TIMEOUT","previous":"GOOD","error":"no response","timestamp":"2026-09-29T07:25:03.629Z"}
{"event":"destination","destination":"Historian","error":"dial tcp 10.0.0.5:5432: connection refused","timestamp":"2026-09-29T07:25:04.101Z"}The default topic is modbuslogic/status/{device}/{tag}; set the node's output topic to put everything on one.
Expression, Cast, Debounce, Batch, JSON template, Throttle
| Node | Fields | The runtime |
|---|---|---|
| Expression | value * 1.8 + 32, value * Running, round(value, 1) | Computes over value and other tags by name, in the same closed grammar as a calculated tag: arithmetic, comparisons, abs, sqrt, floor, ceil, round, min, max, avg, sum, and, or. A tag that is missing or bad makes the result unavailable; the value is dropped and the log says why, once. A bad reading is passed through as bad, not computed on. |
| Cast | bool, int64, uint64, float64, string | Converts the value before it is published: int64 truncates, bool treats a non-zero number or true/1/on as true, string gives the text. |
| Debounce | Quiet period (ms) | Holds the message until the tag has been quiet for that long, then sends the last value. A flapping input gives one message with the value it settled on. |
| Batch / Aggregate | Max count, Max window (ms) | Collects messages into one JSON array and sends it when the count is reached or the window closes, addressed to the device. |
| JSON template | { "t": "{{ts}}", "v": {{value}} } | Fills the template and sends it as JSON when it parses, as text otherwise. Placeholders: {{value}} (JSON form: a string is quoted), {{text}} (plain), {{tag}}, {{device}}, {{unit}}, {{quality}}, {{ts}}, {{topic}}, {{project}}, {{route}} and {{payload}} (the whole standard envelope). |
| Throttle | Queue depth | Drops new messages while more than that many wait in memory for the destination, so a slow output cannot back up the gateway. Dropped messages are counted as suppressed on the route. |
Test it with the Modbus Simulator
You do not need the PLC to try this flow. The Modbus Simulator answers as a Modbus slave on your own PC, with registers that move, so the whole path from polling to the output can be watched before any hardware is involved.
- Start the Simulator and add a slave: Modbus TCP, bind host set to this PC's LAN address (the prefilled one), port
1502, unit ID 1. Add a few holding registers, say40001–40010as FLOAT32 or INT16 in random mode so the values change, and press Start. - In the editor, set the source node's host to that address, port
1502, unit ID 1, and the same addresses and data types. Poll interval1sis fine. - Deploy the design to a device on the same network, or to this very PC: the Edge Gateway Console installs on a laptop as readily as on an edge computer, and the gateway polls the Simulator over the LAN.
- The Simulator's request log shows the gateway's reads arriving: function code 03, the start address and quantity, once per poll interval. Neighbouring registers arrive as one read.
- Put a register in fixed mode and set it by hand across a Condition's threshold: the message appears on the one output and stops on the other. Random mode on a register behind a Debounce shows the difference between the poll rate and the messages that leave.
Registers in fixed mode make a deadband or a condition easy to exercise: change a value by hand and watch what is, and is not, published. A register set to a value the Simulator refuses (uncheck Fill unmapped and read an address that is not there) shows what a BAD quality looks like at the output. The Simulator's own page has the rest.
From design to device
- Validate. On the design page, Run validation. The editor's rules, the tag document and the runtime binary itself check the design; every issue names its node. Details: Validating a design.
- Install. From the Devices panel download the installer for the device's platform (Windows x64, Linux x64 or Linux ARM64). Windows: extract and run
Edge-Gateway-Console.exefrom an administrator terminal. Linux (Debian, Ubuntu, Raspberry Pi OS):sudo dpkg -ithe .deb, thensudo edge-gateway-console. It shows the device code. Details: Installing on the device. - Device code. Enter it in the Devices panel, choose a trial or one of your purchased licences, and press Download activation bundle: one small zip with the design and a licence bound to that machine, sealed so only that machine can open it. Details: Downloading.
- Bundle. Give the zip to the console (drag it onto the program, pass its path, or put it beside the program and run it again; a USB stick is fine for a device without internet). It opens the bundle with its own code, installs the runtime as a service and starts it. The device never contacts the site. Details: Activation and the licence.
The console then opens the gateway's web view in a browser (on a device without a desktop it prints the address instead) and stays attached with the live view: devices up or down, values as they change, what was published, and the log.
- The live view counts, per route, what was published and what a Condition, Debounce or Throttle held back (suppressed).
- A Catch route's messages arrive on its output when you stop the Simulator, and again when you start it.
Ctrl-C leaves the gateway running as a service. Run edge-gateway-console again at any time: it shows the service, the licence, every device and destination with what to check, the web view, and the live log. Running covers the data directory, secrets and the diagnostics.