Magistrala
User-guide

Rules Engine

Automate IoT workflows with custom rules

Overview

The Rules Engine helps automate message processing using visual workflows composed of input sources, logic evaluations, and output destinations. Users can define rules by visually combining input, logic, and output nodes to determine how incoming messages are processed, evaluated, and responded to.

Features

1. Creation and Management

  • Create Rules: Define the name of a new rule and initiate creation.
  • Quick Actions: View, copy ID, enable/disable, or delete a rule directly from the list.

2. Node Configuration

  • Input Nodes: Attach an MQTT subscriber input by selecting the channel and topic.
  • Logic Nodes: Define conditions using comparison blocks, Lua scripts, or Go scripts.
  • Output Nodes: Output processed data to MQTT publishers, Email recipients, or PostgreSQL databases.

3. Scripting and Templating

  • Lua Script Editor: Use custom Lua scripts with a required logicFunction() for logic processing.
  • Go Script Editor: Write Go-based logic for more advanced use cases (requires Go syntax compliance).
  • Go Text Templating: Use dynamic value injection with:
    • {{.Result}}
    • {{.Result.<key>}}
    • {{.Message.<key>}}

4. Scheduling and Execution

  • Scheduling: Define execution windows with start time, specific time, recurring intervals, and periods.
  • Connection Layout: Visually connect all nodes to complete and activate a rule.

Use Cases

Here are some practical examples of how you can use the Rules Engine:

  • Temperature Alerts: Notify users by email when temperature exceeds safe limits.

  • Message Filtering: Only forward messages with specific fields or values.

  • Unit Conversion: Convert sensor data from Celsius to Fahrenheit before publishing.

Create a Rule

To create a new rule, navigate to the Rules section and click the + Create button.

Create a new Rule

You will be redirected to the rule configuration page. A valid rule must include at least three nodes:

  • Input Node – defines the data source.
  • Logic Node – applies conditions or transformations.
  • Output Node – specifies the resulting action.

The rule cannot be saved unless these required nodes are present.

Created Rule

Click Save Rule to open a popup dialog where you can enter the rule name and assign tags.

Create a Rule Dialog

Once created, the rule is added to the rules list with the following details:

  1. Rule Name
  2. Status – Enabled or Disabled
  3. Creation Date

Each rule entry also provides quick actions for:

  • Viewing rule details
  • Copying the rule ID
  • Enabling/Disabling the rule
  • Edit the rule name or tags
  • Deleting the rule

Quick Links

Rule Configuration

On the rule page, you can configure the following:

1. Input Node

  • Currently, only one input node is supported per rule.

select input

  • Select Channel Subscriber as the input type.

  • Choose the channel and topic to subscribe to.

    input variables

  • The input node will appear in the layout.

    input node

2. Logic Node

After setting the input, define your rule’s logic using one of three options:

  1. Comparison Block
  2. Lua Script Editor
  3. Go Script Editor

The logic nodes support different message payloads as inputs.
To utilize the message payload, you can use message.<key> in the input. For example if your message is a single SenML message, you can do message.payload.v to get the value.

Comparison Block

The Comparison Block lets you define conditions visually without writing a script. Each condition evaluates a field from the incoming message against a value you supply. When all conditions pass, the connected output nodes are triggered.

comparison node


Input

Every input must start with message. followed by the path to the field you want to inspect. Two access styles are supported:

StyleSyntaxExample
Dot notationmessage.<field>.<field>message.payload.temperature
Bracket (array index) notationmessage.<field>[<index>].<field>message.payload[1].v

You can mix both styles in the same path:

message.payload[1].v          ← SenML array, first record's numeric value
message.payload.sensor.temp   ← nested object
message.status                ← top-level field

SenML tip: SenML messages arrive as an array, so the value field is accessed with message.payload[1].v (numeric), message.payload[1].vs (string), or message.payload[1].vb (boolean).


Operators
OperatorSymbolDescription
Equal==Value matches exactly
Not equal~=Value does not match
Greater than>Value is strictly greater
Less than<Value is strictly less
Greater than or equal>=Value is greater or equal
Less than or equal<=Value is less or equal

Data Types

Set the Type dropdown to match the kind of value you are comparing against:

TypeWhen to useExample values
numAny number — integer or decimal20, 3.14, 100, 0.5
stringText values"alarm", "active", "room-1"
boolTrue/false flagstrue, false

Choosing the wrong type will cause the comparison to behave unexpectedly:

  • Use num for any threshold check (temperature, pressure, count, etc.).
  • Use string when comparing labels, status codes, or names.
  • Use bool when the field is a boolean flag (e.g., a pump on/off state).

Multiple Conditions

Click Add Condition to chain more than one comparison. Each additional condition requires a logical join:

JoinBehaviour
andAll conditions must be true
orAt least one condition must be true

Add multiple conditions

Example — trigger when flow is low AND pump is running:

InputOperatorTypeValueJoin
message.payload[1].v<num50
message.pump_running==booltrueand

Example — alert on high H₂S OR high LEL reading:

InputOperatorTypeValueJoin
message.h2s>num10
message.lel>num20or

Script Editors

The script editor allows you to toggle between Lua and Go modes using the selector at the top of the editor:

toggle script node

Toggle between:

  • Lua script mode (default)
  • Go script mode
Lua Script Editor

Craft your own logic in Lua by implementing a logicFunction() that returns either a primitive value or a table.

lua editor node

Example:

Return an object (e.g., converted temperature)
function logicFunction()
  local converted_temp = (message.payload.v * 1.8 + 32)
  return {n = "Temp_fahrenheit", v = converted_temp, u = "°F", }
end
return logicFunction()
Returns a primitive
function logicFunction()
  return (message.payload.v * 1.8 + 32)
end
return logicFunction()
Go Script Editor

Write Go-based logic for advanced use cases. Return a value or struct:

go editor node

Example:

  package main

  import (
      m "messaging"
  )
  func logicFunction() any {
      return m.message.Payload
  }

Note:
Output nodes only trigger if the script returns a truthy value.
If the logic node returns false, the connected output nodes will not be executed.
This allows for conditional flows, ensuring actions such as MQTT publishing, email alerts, or database inserts only occur when the specified logic conditions are satisfied.

3. Output Node

You can add one or more output nodes. The following nodes are supported:

  1. Channel publisher
  2. Email
  3. PostgreSQL
  4. Alarm
  5. Magistrala DB
  6. Slack

select output

Channel Publisher

Enables you to specify the output channel and topic. The result of the logic node is published to this topic.

Select the Channel Publisher as the output node and enter the channel and topic.

publisher variables

publisher node

Email

Send results via email with templated fields:

email variables

Subject
Current Volume
  • Use dynamic template fields:
    • {{.Result}} — the entire result from logic block
    • {{.Result.<key>}} — a specific field from the result
    • {{.Message.<key>}} — a field from the original message
Content
 Current volume is {{(index .Result 0).v}} {{(index .Result 0).u}}.

email node

PostgreSQL

Store message processing results to your PostgreSQL database. Select the PostgreSQL output node option and enter the following information:

PostgreSQL variables

  • Host
  • Port
  • Username
  • Password
  • Database name
  • Table name
  • Map data to table columns using templates
Go template mapping
{
  "channel": "{{.Message.Channel}}",
  "value":   "{{(index .Result 0).v}}",
  "unit":    "{{(index .Result 0).u}}"
}

PostgreSQL node

Internal DB

To be able to store messages in the internal Magistrala DB, you need to create a rule that processes the results. More information about this is in the Store Messages section.

Magistrala DB rule example

Alarms

An alarm output will enable you to be able to generate alarms in the case where a threshold has been exceeded. More information about this node is provided in the Alarms section.

Alarm rule example

Slack

Slack output enables you to send notifications to a Slack channel when a rule is triggered.

To configure a Slack output node, provide the following fields:

Slack variables

  • Token: Your Slack App token (used for authentication).

  • Channel ID: The ID of the Slack channel where notifications will be sent.

  • Message: A valid Slack message payload in JSON format.

    • You can use dynamic template fields in the message object.
    • The payload must follow Slack's structure (e.g., text, blocks, attachment).

    Example:

Slack Message Payload
{
  "text": "Temperature alert for {{.Message.sensor}}",
  "attachments": [
    {
      "pretext": "Threshold exceeded",
      "text": "Current temperature is {{.Result.v}} {{.Result.u}}"
    }
  ],
  "icon_url": "http://lorempixel.com/48/48"
}

Slack node

Dynamic Variables and Templates

You can inject dynamic values from your message or logic result using templating variables.

Available template variables:

VariableDescriptionExample
{{.Result}}Entire output from the logic node.{{.Result}}
{{.Result.<key>}}Field from the logic result.{{.Result.v}}
{{.Message.<key>}}Field from the input message{{.Message.Channel}}
{{(index .Result 0)}}Access slices/arrays{{(index .Result 0).v}}

These variables work in outputs like:

  • Email (body)

  • PostgreSQL (column mapping)

Example usage in Email message
Current temperature is {{.Result.CelValue}}°C  or ({{.Result.FarValue}}°F).
Example usage in PostgreSQL column mapping
{
  "channel": "{{.Message.Channel}}",
  "value":   "{{(index .Result 0).v}}",
  "unit":    "{{(index .Result 0).u}}"
}

Enable or Disable Rules

To enable or disable a rule:

  • Use the toggle at the top right of the rule page.

    Disable rule in rule page

  • You can also enable/disable directly from the rule list using the quick actions menu

    Disable rule in quick links

Add a Scheduler

You can configure a scheduler to define when a rule executes.

Scheduler

Fields:

  • Start Time: Date when the schedule becomes active
  • Time: Time of day the rule should run
  • Recurring Interval: Unit of recurrence (e.g., daily, hourly)
  • Recurring Period: Frequency of execution (e.g., every 2 intervals = every other day/hour)

This helps automate rule execution based on custom schedules.

Store Messages

To store messages in Magistrala's internal database, you must create a Rule for this.

  • Magistrala only stores messages in SenML format.

  • You can submit data in any format(e.g, JSON), but must convert it to SenML using a Lua script. SenML format fields:

    NameLabelCBOR LabelJSON TypeXML Type
    Base Namebn-2Stringstring
    Base Timebt-3Numberdouble
    Base Unitbu-4Stringstring
    Base Valuebv-5Numberdouble
    Base Sumbs-6Numberdouble
    Base Versionbver-1Numberint
    Namen0Stringstring
    Unitu1Stringstring
    Valuev2Numberdouble
    String Valuevs3Stringstring
    Boolean Valuevb4Booleanboolean
    Data Valuevd8String (*)string (*)
    Sums5Numberdouble
    Timet6Numberdouble
    Update Timeut7Numberdouble

Example: Convert JSON to SenML

Assume your incoming payload is:

{
  "temperature": 28.5,
  "unit": "C",
  "sensor": "room-1"
}

Use the following scripts to convert it:

Lua script
function logicFunction()
  return {
    n = message.payload.sensor,
    v = message.payload.temperature,
    u = message.payload.unit
  }
end
return logicFunction()
Go script
package main
import (
  m "messaging"
)

func logicFunction() any {
  payload := m.message.Payload.(map[string]any)
  return map[string]any{
    "n": payload["sensor"],
    "v": payload["temperature"],
    "u": payload["unit"],
  }
}

This returns a valid SenML message the internal DB will accept.


Then set your output node to store this result using the Magistrala Internal DB option.

Storage with json input

Example: Input is SenML

If your message payload is already SenML format, you can just return the message payload directly in your script functions:

Lua script
function logicFunction()
  return message.payload
end
return logicFunction()
Go script
  package main

  import (
      m "messaging"
  )
  func logicFunction() any {
      return m.message.Payload
  }

Storage with senml input

:::info

With the Rules Engine, users can easily automate data processing pipelines in a powerful and visual way by combining inputs, logical conditions, and flexible outputs.

:::

Rule Roles

Roles define a set of actions that can be allocated to users for a specific rule.

To create a role, navigate to the Roles tab on the rule sidebar. Click on the + Create button and provide a role name. The actions and members are optional fields.

Create rule role

Role Information

Rule role information

The Role name is compulsory. You can optionally provide the role actions by selecting from the available actions. You can also optionally provide the members by searching for a user with their username.

The following is the list of available actions for a rule:

  • rule_read
  • rule_update
  • rule_delete
  • rule_manage_role
  • rule_add_role_users
  • rule_view_role_users
  • rule_remove_role_users

Update Rule Roles

Click a role in the Roles table to open its page. The page has two tables for the Role Actions and the assigned Role Members.

To update a role name, click on the pencil icon on the far right end of the field, update the value then click on the check icon to save or the cross icon to cancel.

Update role name

To update the Role Actions, click on the pencil icon. A dialog box will appear allowing you to select the actions you want to add.

Update role actions

To update the Role Members, click the Add Members button. A popup dialog will appear with the list of Domain Members from which a user can select.

Update role members

Delete Rule Roles

You can delete actions by clicking on the trash icon. It opens a dialog that allows you to select which actions to remove. There is also an option to delete all actions at once.

Delete role actions

For Role Members, you can clear the entire table with the Delete All Members button:

Delete all role members

To delete specific members from the Role Members table, click on the trash icon next to their entry.

Delete role members

Rule Members

While members can be added through the Roles tab when creating a role, you can also assign members directly through the Members tab.

Clicking the Assign Member button opens a dialog where you can select from the Domain Members and choose the role to assign them to.

Assign Members

Delete a rule

To delete a rule, click the Delete quick action. A confirmation dialog appears asking you to type the rule's name before deletion is finalized. Use the copy button to copy the name, paste it into the input field, then click Delete to permanently remove the rule.

Delete rule

On this page