rules

package
v0.39.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

README

Rules Service

The Rules service provides two complementary automation engines for processing incoming device messages: a rule engine for threshold-based condition matching, and a Lua scripting engine for arbitrary message processing logic.

Both engines are driven by the same event stream: every message published by a thing is evaluated against all rules and scripts assigned to that thing.

Resource Model

Group
└── Rule / Script
    └── assigned to → Things

Rules and scripts are created within a group and then assigned to individual things. When a thing publishes a message, the service evaluates all rules and scripts assigned to that thing against the message payload.

Rules

A rule evaluates a set of conditions against an incoming message payload. When all conditions are met (using AND or OR logic), the rule triggers one or more actions.

Field Description
id Unique rule identifier (UUID)
group_id ID of the group the rule belongs to
name Human-readable rule name
description Optional free-form description
conditions List of conditions to evaluate (see below)
operator Logical operator applied across all conditions: AND or OR. Required when more than one condition is defined.
actions List of actions to trigger when conditions are met (see below)
Conditions

Each condition compares a named field in the message payload against a numeric threshold.

Field Description
field The payload field name to evaluate. For SenML messages, this matches the name key. For JSON messages, dot-notation paths are supported (e.g. sensors.temperature).
comparator Comparison operator: ==, >=, <=, >, <
threshold Numeric value to compare against
Actions

Each action specifies what to do when a rule fires.

Field Description
type Action type: alarm, smtp, or smpp
id Required for smtp and smpp types — the ID of the configured notifier to trigger
  • alarm — publishes an alarm event consumed by the Alarms service
  • smtp — triggers an SMTP email notification via the registered notifier with the given id
  • smpp — triggers an SMPP SMS notification via the registered notifier with the given id

Lua Scripts

Lua scripts provide a programmable alternative to condition-based rules. A script is arbitrary Lua code that runs once per incoming message (or once per array element, for array payloads). Scripts can read the message payload, make decisions, and call platform API functions.

Script Fields
Field Description
id Unique script identifier (UUID)
group_id ID of the group the script belongs to
name Human-readable script name
description Optional free-form description
script Lua source code (max 65,535 bytes)
Lua Execution Environment

Each script execution receives an isolated Lua environment. The following global is available:

mfx table
Field Type Description
mfx.message.payload table Parsed message payload (JSON object or array item)
mfx.message.subtopic string Message subtopic
mfx.message.created number Message creation timestamp (Unix)
mfx.message.publisher_id string Thing ID that published the message
mfx API functions
Function Returns Description
mfx.smtp_notify(notifier_id) bool[, error_msg] Triggers an SMTP notification via the specified notifier. Max 2 calls per run.
mfx.create_alarm() bool[, error_msg] Creates an alarm event attributed to this script. Max 1 call per run.
mfx.log(message) bool[, error_msg] Appends a message to the run log (max 256 lines, 2048 chars each).

Available Lua standard libraries: base, math, string, table. The print function is disabled.

Execution Limits
Limit Value
Max instructions 1,000,000
Max log lines per run 256
Max log line length 2,048 chars
Example Script
local payload = mfx.message.payload

local temp = tonumber(payload["temperature"])
local hum  = tonumber(payload["humidity"])

if not temp or not hum or hum <= 0 then
  mfx.log("Invalid or missing fields")
  return
end

-- Magnus formula: dew point from temperature and relative humidity
local gamma = math.log(hum / 100.0) + (17.625 * temp) / (243.04 + temp)
local dew_point = 243.04 * gamma / (17.625 - gamma)
local spread = temp - dew_point  -- smaller spread → closer to condensation

mfx.log(string.format("temp=%.1f  hum=%.1f%%  dew_point=%.1f  spread=%.1f",
  temp, hum, dew_point, spread))

-- Condensation risk: surface is near or below dew point
if spread <= 2.0 then
  mfx.log("Condensation risk: spread=" .. string.format("%.1f", spread) .. "°C")
  mfx.create_alarm()
  mfx.smtp_notify("654e4567-e89b-12d3-a456-426614174999")
end
Script Runs

Every script execution is recorded as a script run. Run records capture the outcome, logs, and any runtime error.

Field Description
id Unique run identifier (UUID)
script_id ID of the script that was executed
thing_id ID of the thing that triggered the execution
logs Log lines written via mfx.log()
started_at Execution start timestamp (RFC 3339)
finished_at Execution end timestamp (RFC 3339)
status success or fail
error Runtime error message, if any

Run records are retrievable per thing and can be bulk-deleted via the API.

Configuration

The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.

Variable Description Default
MF_RULES_LOG_LEVEL Log level for the Rules service (debug, info, warn, error) error
MF_BROKER_URL Message broker instance URL nats://localhost:4222
MF_RULES_HTTP_PORT Rules service HTTP port 9027
MF_JAEGER_URL Jaeger server URL for distributed tracing. Leave empty to disable tracing.
MF_RULES_DB_HOST Database host address localhost
MF_RULES_DB_PORT Database host port 5432
MF_RULES_DB_USER Database user mainflux
MF_RULES_DB_PASS Database password mainflux
MF_RULES_DB Name of the database used by the service rules
MF_RULES_DB_SSL_MODE Database connection SSL mode (disable, require, verify-ca, verify-full) disable
MF_RULES_DB_SSL_CERT Path to the PEM encoded certificate file
MF_RULES_DB_SSL_KEY Path to the PEM encoded key file
MF_RULES_DB_SSL_ROOT_CERT Path to the PEM encoded root certificate file
MF_RULES_CLIENT_TLS Flag that indicates if TLS should be turned on false
MF_RULES_CA_CERTS Path to trusted CAs in PEM format
MF_RULES_SERVER_CERT Path to server certificate in PEM format
MF_RULES_SERVER_KEY Path to server key in PEM format
MF_THINGS_AUTH_GRPC_URL Things service Auth gRPC URL localhost:8183
MF_THINGS_AUTH_GRPC_TIMEOUT Things service Auth gRPC request timeout 1s
MF_RULES_ES_URL Event store URL redis://localhost:6379/0
MF_RULES_EVENT_CONSUMER Event store consumer name rules
MF_RULES_SCRIPTS_ENABLED Enable Lua scripting engine false

Deployment

The service itself is distributed as Docker container. Check the rules service section in docker-compose to see how service is deployed.

To start the service, execute the following shell script:

# Download the latest version of the service
git clone https://github.com/MainfluxLabs/mainflux

cd mainflux

# compile the rules service
make rules

# Copy binary to bin
make install

# Set the environment variables and run the service
MF_RULES_LOG_LEVEL=[Rules log level] \
MF_BROKER_URL=[Message broker instance URL] \
MF_RULES_HTTP_PORT=[Rules service HTTP port] \
MF_RULES_DB_HOST=[Database host address] \
MF_RULES_DB_PORT=[Database host port] \
MF_RULES_DB_USER=[Database user] \
MF_RULES_DB_PASS=[Database password] \
MF_RULES_DB=[Rules database name] \
MF_THINGS_AUTH_GRPC_URL=[Things service Auth gRPC URL] \
MF_THINGS_AUTH_GRPC_TIMEOUT=[Things service Auth gRPC request timeout] \
$GOBIN/mainfluxlabs-rules

Usage

For the full HTTP API reference, see the OpenAPI specification.

Documentation

Index

Constants

View Source
const (
	ScriptRunStatusSuccess = "success"
	ScriptRunStatusFail    = "fail"
)
View Source
const (
	ActionTypeSMTP  = "smtp"
	ActionTypeSMPP  = "smpp"
	ActionTypeAlarm = "alarm"

	OperatorAND = "AND"
	OperatorOR  = "OR"
)

Variables

View Source
var AllowedOrders = map[string]string{
	"id":      "id",
	"name":    "name",
	"rule_id": "rule_id",
}
View Source
var ErrScriptSize = errors.New("script size exceeds limit")

Functions

func NewLuaEnv added in v0.38.0

func NewLuaEnv(service *rulesService, script *LuaScript, message *protomfx.Message, payload map[string]any, functions ...luaAPIFunc) (*luaEnv, error)

Initializes and returns a new script environment associated with a specific Lua script and Mainflux message. The following is made available to the Lua environment as part of an "mfx" table in the global namespace:

  1. The associated Message payload, subtopic, creation timestamp, and publisher ID
  2. API functions

Types

type Action

type Action struct {
	ID   string `json:"id"`
	Type string `json:"type"`
}

type Condition

type Condition struct {
	Field      string   `json:"field"`
	Comparator string   `json:"comparator"`
	Threshold  *float64 `json:"threshold"`
}

type LuaScript added in v0.38.0

type LuaScript struct {
	ID      string
	GroupID string
	// Lua script content
	Script      string
	Name        string
	Description string
}

LuaScript represents a specific Lua script.

type LuaScriptsPage added in v0.38.0

type LuaScriptsPage struct {
	Total   uint64
	Scripts []LuaScript
}

type PageMetadata added in v0.39.0

type PageMetadata struct {
	Total  uint64 `json:"total,omitempty"`
	Offset uint64 `json:"offset,omitempty"`
	Limit  uint64 `json:"limit,omitempty"`
	Order  string `json:"order,omitempty"`
	Dir    string `json:"dir,omitempty"`
	Name   string `json:"name,omitempty"`
}

PageMetadata contains page metadata that helps navigation.

func (PageMetadata) Validate added in v0.39.0

func (pm PageMetadata) Validate(maxLimitSize, maxNameSize int) error

Validate validates the page metadata.

type Repository added in v0.38.0

type Repository interface {
	RepositoryRules
	RepositoryScripts
}

type RepositoryRules added in v0.38.0

type RepositoryRules interface {
	// Save persists multiple rules. Rules are saved using a transaction.
	// If one rule fails then none will be saved.
	// Successful operation is indicated by a non-nil error response.
	Save(ctx context.Context, rules ...Rule) ([]Rule, error)

	// RetrieveByID retrieves a rule having the provided ID.
	RetrieveByID(ctx context.Context, id string) (Rule, error)

	// RetrieveByThing retrieves rules assigned to a certain thing,
	// identified by a given thing ID.
	RetrieveByThing(ctx context.Context, thingID string, pm PageMetadata) (RulesPage, error)

	// RetrieveByGroup retrieves rules related to a certain group,
	// identified by a given group ID.
	RetrieveByGroup(ctx context.Context, groupID string, pm PageMetadata) (RulesPage, error)

	// RetrieveThingIDsByRule retrieves all thing IDs that have the given rule assigned.
	RetrieveThingIDsByRule(ctx context.Context, ruleID string) ([]string, error)

	// Update performs an update to the existing rule.
	// A non-nil error is returned to indicate operation failure.
	Update(ctx context.Context, r Rule) error

	// Remove removes rules having the provided IDs.
	Remove(ctx context.Context, ids ...string) error

	// RemoveByGroup removes rules related to a certain group,
	// identified by a given group ID.
	RemoveByGroup(ctx context.Context, groupID string) error

	// Assign assigns rules to the specified thing.
	Assign(ctx context.Context, thingID string, ruleIDs ...string) error

	// Unassign removes specific rule assignments from a given thing.
	Unassign(ctx context.Context, thingID string, ruleIDs ...string) error

	// UnassignByThing removes all rule assignments for a certain thing,
	// identified by a given thing ID.
	UnassignByThing(ctx context.Context, thingID string) error
}

type RepositoryScripts added in v0.38.0

type RepositoryScripts interface {
	// SaveScripts persists multiple Lua scripts.
	SaveScripts(ctx context.Context, scripts ...LuaScript) ([]LuaScript, error)

	// RetrieveScriptByID retrieves a single Lua script denoted by ID.
	RetrieveScriptByID(ctx context.Context, id string) (LuaScript, error)

	// RetrieveScriptsByThing retrieves a list of Lua scripts assigned to a specific Thing.
	RetrieveScriptsByThing(ctx context.Context, thingID string, pm PageMetadata) (LuaScriptsPage, error)

	// RetrieveScriptsByGroup retrieves a list of Lua scripts belonging to a specific Group.
	RetrieveScriptsByGroup(ctx context.Context, groupID string, pm PageMetadata) (LuaScriptsPage, error)

	// RetrieveThingIDsByScript retrieves a list of Thing IDs to which the specific Lua script is assigned.
	RetrieveThingIDsByScript(ctx context.Context, scriptID string) ([]string, error)

	// UpdateScript updates the script denoted by script.ID.
	UpdateScript(ctx context.Context, script LuaScript) error

	// RemoveScripts removes Lua scripts with the provided ids.
	RemoveScripts(ctx context.Context, ids ...string) error

	// RemoveScriptsByGroup removes all Lua scripts belonging to a specific Group.
	RemoveScriptsByGroup(ctx context.Context, groupID string) error

	// AssignScripts assigns one or more Lua scripts to a specific Thing.
	AssignScripts(ctx context.Context, thingID string, scriptIDs ...string) error

	// Unassign unassgins one or more Lua scripts from a specific Thing.
	UnassignScripts(ctx context.Context, thingID string, scriptIDs ...string) error

	// UnassignScriptsFromThing unassigns all scripts from a specific Thing.
	UnassignScriptsFromThing(ctx context.Context, thingID string) error

	// SaveScriptRuns preserves multiple ScriptRuns.
	SaveScriptRuns(ctx context.Context, runs ...ScriptRun) ([]ScriptRun, error)

	// RetrieveScriptRunByID retrieves a single ScriptRun based on its ID.
	RetrieveScriptRunByID(ctx context.Context, id string) (ScriptRun, error)

	// RetrieveScriptRunsByThing retrieves a list of Script runs by Thing ID.
	RetrieveScriptRunsByThing(ctx context.Context, thingID string, pm PageMetadata) (ScriptRunsPage, error)

	// RemoveScriptRuns removes one or more Script runs by IDs.
	RemoveScriptRuns(ctx context.Context, ids ...string) error
}

type Rule

type Rule struct {
	ID          string
	GroupID     string
	Name        string
	Description string
	Conditions  []Condition
	Operator    string
	Actions     []Action
}

type RulesPage

type RulesPage struct {
	Total uint64
	Rules []Rule
}

type ScriptRun added in v0.38.0

type ScriptRun struct {
	ID         string
	ScriptID   string
	ThingID    string
	Logs       []string
	StartedAt  time.Time
	FinishedAt time.Time
	Status     string
	// Human-readable string representing a runtime error during the execution of the lua script. May be an empty string in case of no error.
	Error string
	// contains filtered or unexported fields
}

ScriptRun represents a specific run of a certain Lua script

type ScriptRunsPage added in v0.38.0

type ScriptRunsPage struct {
	Total uint64
	Runs  []ScriptRun
}

type Service

type Service interface {
	ServiceScripts
	ServiceRules

	consumers.Consumer
}

Service specifies an API that must be fullfiled by the domain service implementation, and all of its decorators (e.g. logging & metrics). All methods that accept a token parameter use it to identify and authorize the user performing the operation.

func New

func New(rules Repository, things protomfx.ThingsServiceClient, pubsub messaging.PubSub, idp uuid.IDProvider, logger logger.Logger, scriptsEnabled bool) Service

New instantiates the rules service implementation.

type ServiceRules added in v0.38.0

type ServiceRules interface {
	// CreateRules creates rules.
	CreateRules(ctx context.Context, token, groupID string, rules ...Rule) ([]Rule, error)

	// ListRulesByThing retrieves a paginated list of rules by thing.
	ListRulesByThing(ctx context.Context, token, thingID string, pm PageMetadata) (RulesPage, error)

	// ListRulesByGroup retrieves a paginated list of rules by group.
	ListRulesByGroup(ctx context.Context, token, groupID string, pm PageMetadata) (RulesPage, error)

	// ListThingIDsByRule retrieves a list of thing IDs attached to the given rule ID.
	ListThingIDsByRule(ctx context.Context, token, ruleID string) ([]string, error)

	// ViewRule retrieves a specific rule by its ID.
	ViewRule(ctx context.Context, token, id string) (Rule, error)

	// UpdateRule updates the rule identified by the provided ID.
	UpdateRule(ctx context.Context, token string, rule Rule) error

	// RemoveRules removes the rules identified with the provided IDs.
	RemoveRules(ctx context.Context, token string, ids ...string) error

	// RemoveRulesByGroup removes the rules identified with the provided IDs.
	RemoveRulesByGroup(ctx context.Context, groupID string) error

	// AssignRules assigns rules to a specific thing.
	AssignRules(ctx context.Context, token, thingID string, ruleIDs ...string) error

	// UnassignRules removes rule assignments from a specific thing.
	UnassignRules(ctx context.Context, token, thingID string, ruleIDs ...string) error

	// UnassignRulesByThing removes all rule assignments from a specific thing.
	UnassignRulesByThing(ctx context.Context, thingID string) error
}

type ServiceScripts added in v0.38.0

type ServiceScripts interface {
	// CreateScripts persists multiple Lua scripts.
	CreateScripts(ctx context.Context, token, groupID string, scripts ...LuaScript) ([]LuaScript, error)

	// ListScriptsByThing retrieves a list of Scripts associated with a specific Thing.
	ListScriptsByThing(ctx context.Context, token, thingID string, pm PageMetadata) (LuaScriptsPage, error)

	// ListScriptsByGroup retrieves a list of scripts belonging to a specific Group.
	ListScriptsByGroup(ctx context.Context, token, groupID string, pm PageMetadata) (LuaScriptsPage, error)

	// ListThingIDsByScript retrieves a list of IDs of Things associated with a specific Script.
	ListThingIDsByScript(ctx context.Context, token, scriptID string) ([]string, error)

	// ViewScript retrieves a specific Script by its ID.
	ViewScript(ctx context.Context, token, id string) (LuaScript, error)

	// UpdateScript updates the Script identified by the provided ID.
	UpdateScript(ctx context.Context, token string, script LuaScript) error

	// RemoveScripts removes the Scripts identified by the provided IDs.
	RemoveScripts(ctx context.Context, token string, ids ...string) error

	// RemoveScriptsByGroup removes all Scripts belonging to a specific Group.
	RemoveScriptsByGroup(ctx context.Context, groupID string) error

	// AssignScripts assigns one or more Scripts to a specific Thing.
	AssignScripts(ctx context.Context, token, thingID string, scriptIDs ...string) error

	// UnassignScripts unassigns one or more scripts from a specific Thing.
	UnassignScripts(ctx context.Context, token, thingID string, scriptIDs ...string) error

	// UnassignScriptsFromThing unassigns all scripts from a specific Thing.
	UnassignScriptsFromThing(ctx context.Context, thingID string) error

	// ListScriptRunsByThing retrieves a list of Script Runs associated with a specific Thing.
	ListScriptRunsByThing(ctx context.Context, token, thingID string, pm PageMetadata) (ScriptRunsPage, error)

	// RemoveScriptRuns removes the Runs identified by the provided IDs.
	RemoveScriptRuns(ctx context.Context, token string, ids ...string) error
}

Directories

Path Synopsis
api

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL