Skip to content

Rule node reference

This page details every node in the Rules editor.

In Comparison, Lua, Go, and output templates, the message is available as message:

Field Contents
channel The message’s channel.
subtopic The subtopic.
publisher The ID of the device (or rule/account) that sent it, from broker authentication.
protocol mqtt, ui (sent from the application), rule (from Channel Publisher), schedule.
created The receive time (epoch seconds).
payload The parsed content: an array of records for SenML, an object for SenFlat and JSON.
history true when the message is SenFlat v2 with gateway-history status (h = 1).
timeTrusted false when a SenFlat v2 source has an untrusted device clock.

Array indexes in paths and Lua start at 1: message.payload[1].v. For SenFlat v1, the metrics are at message.payload.m.<metric>.

Field Description
Channel The channel being watched.
Topic The subtopic. Wildcards + (one level) and # (many levels). Empty = all subtopics.

The Add Logic menu contains: Bypass (pass through), SenFlat v2 splitter → rows, Comparison, Lua code, Go code, and the list of available Custom Nodes.

The Add Logic menu with Bypass, SenFlat v2 splitter, Comparison, Lua code, Go code, and Custom Nodes.
The Add Logic menu.

Every logic node decides whether the message is forwarded. A result of nil, false, or an unmet condition = the message is not forwarded, so outputs below it do not run.

Forwards the payload as is. The cheapest way to store or forward every message because it runs no code. Used by the “Store in Internal DB” template.

One or more condition rows:

If message.payload[1].v >= number 24.5
  • Path with dot or bracket notation: message.payload.temp_inlet, message.payload.m.door_open.
  • Operators: ==, ~= (not equal), >, <, >=, <=.
  • Value types: number, text, bool.
  • Conditions are chained with AND or OR (AND is evaluated first). At most 20 conditions.
  • A path that does not exist, or has a different type from the one compared, makes the condition false.
  • When satisfied, the payload is forwarded as is.

It must have the form:

function logicFunction()
-- read message, return a result
end
return logicFunction()

The result: nil or false = not forwarded; true = the payload as is; a table = a new result (a sequential array becomes a JSON array, anything else an object). The syntax is checked on save and the error is shown in the editor.

The sandbox: a fresh interpreter per execution (no state leaks between messages), only the base, table, string, and math libraries. No os, io, package, debug, load*, dofile, require. An execution time of 500 ms, and a limit on the result size.

-- Forward only when the inlet temperature is above 23.5, and build an alarm
function logicFunction()
for _, rec in ipairs(message.payload) do
if rec.n and string.find(rec.n, "temp_inlet$") and rec.v and rec.v > 23.5 then
return { severity = 70, cause = "Inlet temperature above limit",
measurement = rec.n, value = rec.v, unit = "Cel" }
end
end
return false
end
return logicFunction()

Go code runs in a separate, isolated child process, with a package allowlist, a timeout, and a memory limit; on Linux, OS-level isolation is added. The shape is similar to Lua: import m "messaging" and a logicFunction() function. Availability depends on the server configuration (the administrator can disable it).

Uses logic you saved in Custom Nodes, at a specific version.

Splits one SenFlat v2 message (many sources and time points) into a list of wide rows, one row per (source, time), without Lua. The base columns: device_id, t_ms, time, time_trusted, history, q, plus every metric at that time. A message that is not SenFlat v2 is not forwarded. Full usage: Rule to PostgreSQL: many rows.

Every logic node has a Data scope:

Scope Meaning
All data Live data and all history (the default of older nodes).
Live data only Ignores gateway history (the default of a new Comparison).
Live data and fresh history History whose age does not exceed the window in minutes (5 by default).

Lua, Go, and Custom Node also have an Evaluation unit: Batch (the code runs once and sees the whole list of rows) or Per row. Comparison always evaluates each row by itself.

An output determines where a message goes, including whether it is stored. The Add Output menu contains: Internal DB (SenML), Internal DB (JSON), Channel Publisher, E-Mail, Telegram, PostgreSQL, Webhook HTTP, Alarm, and Device alarm.

The Add Output menu with Internal DB, Channel Publisher, E-Mail, Telegram, PostgreSQL, Webhook HTTP, Alarm, and Device alarm.
The Add Output menu.

Internal DB (SenML) and Internal DB (JSON)

Section titled “Internal DB (SenML) and Internal DB (JSON)”

Stores to Celestian’s internal time-series database. The SenML one accepts SenML and SenFlat (units are filled from the Metric Catalog) and validates strictly; the JSON one stores any result that can be turned into JSON (at most 1 MiB). They appear in different tabs in Messages. Internal DB does not accept the list of rows from the splitter.

Publishes the logic result to another channel (and subtopic), on behalf of the rule. The message is recorded with the rule protocol. A rule that writes to its own input channel on a topic it covers is refused on save, to prevent loops.

Creates an alarm from the logic result object. The fields come from the node template, or when empty from the key of the same name in the logic result:

Field Rule
severity Required, an integer from 0 to 100.
cause Required, text.
measurement Required, the name that distinguishes the alarm.
value, unit, threshold Optional.

An auto-clear option (none, after N minutes without recurrence, or after N consecutive normal messages) and a Gateway history data section (the history window and retroactive alarms). Details: Alarms.

For devices that compute alarms themselves (boolean metrics prefixed with alarm_): true opens an alarm, false closes it, with a warning severity of 40 and an alarm severity of 80 (changeable). A node behind a gateway is associated with a device through the Serial. A one-click template is available on the Rules page.

Recipients, Subject, and Content with a Go template: {{.Result}}, {{.Result.<key>}}, and {{.Message.<key>}}. Requires SMTP to be configured on the server.

A bot token (stored encrypted), a chat ID, and the message text as a template.

Writes to a table in an external PostgreSQL database. Fields: host, port, user, password (encrypted), database, table, and the column mapping (a Go template per column). Table and column names are validated and quoted, values are always parameters, and an empty result becomes NULL.

  • The One row per result item switch (foreach) inserts many rows in one atomic INSERT (at most 500 rows and 30 columns per message), with .Row, .Index, and the tsms function.
  • The Test connection button verifies without writing.

A URL, a method, headers (values encrypted), and the body as a template, with retries and backoff.

Templated fields (e-mail, Telegram, webhook, PostgreSQL, alarm fields) use Go text/template syntax. The available data: .Result (the logic result), .Message (the original message), and in multi-row mode .Row and .Index. Helper functions: json, tsms, and printf.

Temperature {{printf "%.1f" (index .Result 0).v}} °C at {{.Message.subtopic}}