Skip to Content

Condition

Connect some inputs and some outputs to this node, then write rules in the schema box that describe what to watch for and what to send when a rule is met.

Every time a new value arrives on any input, the node checks all the rules. If a rule’s conditions are all satisfied, it immediately sends the values specified to the chosen outputs — then resets, ready to fire again the next time.

Note: It only fires once per “completion” — after firing, it forgets what it saw and waits for fresh values to arrive again before it can fire a second time.


Writing rules (the schema)

The schema is a JSON array — a list of rules, each with a condition and a list of actions to take when that condition is true.

// A list of rules. You can have as many as you like. [ { "condition": { }, "actions": [ ] } ]

Three ways to write a condition

TypeWhat it means
andAll of the sub-conditions must be true at the same time
orAt least one sub-condition needs to be true
evalCheck one input value — against a fixed value, another input’s value, or by its length

Setting up a check (eval)

Every eval starts with the input to read and how to compare it:

SettingWhat to put here
receiverThe name of the input to read. If the input carries a map, use a dot to reach inside it: sensor.temperature
operatorHow to compare: == != < <= > >=

Then choose what to compare against — one of the two options below.

Option A — a fixed value (the usual way):

SettingWhat to put here
datatypeWhat kind of value you’re comparing against: BOOL, INT, FLOAT, STRING, BYTES
valueThe value to compare against. For numeric datatypes, numbers are decimal. if you need hexadecimal, provide the value as a string with a 0x prefix (e.g., "0xFF"); for INT, this is automatically converted, so "0x64" and 100 are treated the same. For BYTES, provide a comma- or space-separated list (e.g., "0x00, 0x04, 0xFF")

Option B — another input’s value:

SettingWhat to put here
value_receiverThe name of another input whose most recent value to compare against. Use a dot to reach inside a map, e.g. sensorB.temperature. No datatype is needed — the two values are compared directly

Use either value (with datatype) or value_receiver — not both.

Comparing lengths instead of values

Add length: true to any eval to compare the length of the input value rather than the value itself:

SettingWhat to put here
lengthWhen true, compares the number of bytes in the input value — for a STRING this is its UTF-8 byte length, for BYTES it’s the byte count. Compared against value (a whole number, e.g. 8), or against another input’s length when combined with value_receiver

Two ways to send output (actions)

Send a fixed value — always sends the same thing, no matter what came in:

"payload": { "type": "static", "datatype": "STRING", "value": "Alert!" }

Forward a value from an input — passes along whatever arrived on a given input. Use a dot to reach into a map:

"payload": { "type": "dynamic", "receiver": "sensor.temp" }

Example 1 — temperature alert

Fire when a sensor reads 100 or above AND the system status says "ACTIVE". Send a warning message to one output and the raw temperature number to another.

Condition Prefab Example 1

Inputs: sensor (a map containing temperature), status (a string)
Outputs: alert_channel, metrics_channel

[ { "condition": { "type": "and", "operands": [ { "type": "eval", "receiver": "sensor.temperature", "operator": ">=", "datatype": "INT", "value": 100 }, { "type": "eval", "receiver": "status", "operator": "==", "datatype": "STRING", "value": "ACTIVE" } ] }, "actions": [ { "sender": "alert_channel", "payload": { "type": "static", "datatype": "STRING", "value": "Overheating!" } }, { "sender": "metrics_channel", "payload": { "type": "dynamic", "receiver": "sensor.temperature" } } ] } ]

Example 2 — matching byte sequences

Route two different incoming messages to different places based on a byte ID. Both rules watch the same input; whichever ID matches fires its action.

Condition Prefab Example 2

Inputs: data (a map containing frame_id as bytes)
Outputs: alert_channel

[ { "condition": { "type": "eval", "receiver": "data.frame_id", "operator": "==", "datatype": "BYTES", "value": "0x00, 0x04, 0x04, 0x10" }, "actions": [{ "sender": "alert_channel", "payload": { "type": "static", "datatype": "STRING", "value": "Hello" } }] }, { "condition": { "type": "eval", "receiver": "data.frame_id", "operator": "==", "datatype": "BYTES", "value": "0x00, 0x04, 0x04, 0x08" }, "actions": [{ "sender": "alert_channel", "payload": { "type": "static", "datatype": "STRING", "value": "World" } }] } ]

Example 3 — two independent rules sharing inputs

Rule 1 needs sensor1 and sensor2 to both say "HIGH". Rule 2 needs sensor1 and sensor3. Each rule keeps its own memory — when Rule 1 fires and resets, Rule 2 still remembers the value it already received from sensor1.

Condition Prefab Example 3

Inputs: sensor1, sensor2, sensor3
Outputs: alert1, alert2

[ { "condition": { "type": "and", "operands": [ { "type": "eval", "receiver": "sensor1", "operator": "==", "datatype": "STRING", "value": "HIGH" }, { "type": "eval", "receiver": "sensor2", "operator": "==", "datatype": "STRING", "value": "HIGH" } ] }, "actions": [{ "sender": "alert1", "payload": { "type": "static", "datatype": "STRING", "value": "SCHEMA_1_FIRED" } }] }, { "condition": { "type": "and", "operands": [ { "type": "eval", "receiver": "sensor1", "operator": "==", "datatype": "STRING", "value": "HIGH" }, { "type": "eval", "receiver": "sensor3", "operator": "==", "datatype": "STRING", "value": "HIGH" } ] }, "actions": [{ "sender": "alert2", "payload": { "type": "static", "datatype": "STRING", "value": "SCHEMA_2_FIRED" } }] } ]

Example 4 — comparing two inputs

Fire when one sensor reads higher than another, instead of comparing against a fixed number. Note there’s no datatype or value — the rule compares the two inputs’ latest values directly.

Inputs: sensorA (a map containing temp), sensorB (a map containing temp)
Outputs: alert_channel

[ { "condition": { "type": "eval", "receiver": "sensorA.temp", "operator": ">", "value_receiver": "sensorB.temp" }, "actions": [{ "sender": "alert_channel", "payload": { "type": "static", "datatype": "STRING", "value": "A is hotter than B" } }] } ]

Example 5 — checking length

Fire when an incoming message is at least 8 bytes long, regardless of its contents. The value is the length to compare against.

Inputs: data (bytes)
Outputs: alert_channel

[ { "condition": { "type": "eval", "receiver": "data", "operator": ">=", "length": true, "value": 8 }, "actions": [{ "sender": "alert_channel", "payload": { "type": "static", "datatype": "STRING", "value": "Long enough" } }] } ]

Things to keep in mind

Reaching inside a mapUse a dot to access a field inside a map value — e.g. sensor.temperature. Multiple levels can be chained: data.packet.id
An input named with a dotIf an input is itself named sensor.temperature, that input wins — the name is read as the input, not as a path into sensor. This holds even before that input has received anything, so the meaning of a receiver never changes with the data that has arrived
Output names must matchThe sender name in each action must exactly match an output added to the node
Input names must matchThe receiver name in each condition — and the value_receiver name, when comparing against another input — must exactly match an input added to the node
Waiting for dataIf a required input hasn’t arrived yet, the rule simply waits — nothing breaks
Multiple actionsAll actions in a rule fire together the moment its condition is met
Sharing inputs across rulesMultiple rules can watch the same input. Each rule remembers values independently, so one firing doesn’t affect the others
Last updated on