Skip to content

MQTT

MQTT (Message Queuing Telemetry Transport) is a lightweight, publish/subscribe-based messaging protocol. It is widely used in IoT and IIoT applications for data transmission between sensors, gateways, and cloud platforms. It runs over TCP/IP and uses port 1883 by default (or 8883 with TLS).

inSCADA supports the MQTT protocol in Client role — both Subscribe (receiving data) and Publish (sending data) are possible.

What Makes MQTT Different: Script-Based Message Processing

Section titled “What Makes MQTT Different: Script-Based Message Processing”

The MQTT implementation in inSCADA uses a different approach from other protocols. In protocols like MODBUS or IEC 104, the data structure is fixed (registers, IOA addresses, etc.). In MQTT, the message payload is completely free-form — it can be JSON, XML, plain text, or binary.

For this reason, inSCADA parses MQTT messages using JavaScript scripts defined at the Frame level. Each Frame has two script fields:

  • Subscribe Expression: A script that parses incoming messages and converts them to variable values
  • Publish Expression: A script that converts variable values into MQTT messages

With this approach, you can map MQTT messages in any format to inSCADA variables.

Connection (Broker IP, port, credentials)
└── Device (Base topic)
└── Frame (Data Block — Topic + Subscribe/Publish scripts)
└── Variable (Key in script output)
ParameterExampleDescription
ProtocolMQTTProtocol selection
IP Address192.168.1.200MQTT Broker IP address
Port1883Broker port (1883: TCP, 8883: TLS)
Identifierinscada-client-1Client identifier (must be unique)
Username(optional)Broker authentication
Password(optional)Broker password
Use SSLfalseTLS/SSL encryption
Clean SessiontrueClean session (no persistent subscriptions)
Keep Alive60000 msKeep-alive check period
Initial Delay1000 msInitial connection wait time
Max Delay60000 msMaximum reconnection wait time
Pool Size1Connection pool
ParameterExampleDescription
Base Topicfactory/line1Base topic path (prefix for Frame topics)
ParameterExampleDescription
Topicsensors/temperatureMQTT topic (subscribe or publish)
QoS1Quality of Service (0, 1, or 2)
Subscribe Expression(JavaScript code)Script that parses incoming messages
Publish Expression(JavaScript code)Script that creates outgoing messages
QoSDescription
0At most once — the message is delivered at most once, loss possible
1At least once — the message is delivered at least once, duplicates possible
2Exactly once — the message is delivered exactly once, guaranteed
ParameterExampleDescription
NametemperatureVariable name (must match the key in script output)
TypeFloatData type
Data TypeDescription
BooleanSingle bit value
Byte8-bit integer
Short16-bit integer
Integer32-bit integer
Long64-bit integer
Float32-bit floating point
Double64-bit floating point
StringCharacter string

When an MQTT message arrives, inSCADA executes the Subscribe Expression script in the Frame. The following objects are provided to the script as bindings:

BindingTypeDescription
messageObjectIncoming MQTT message
message.topicStringTopic the message arrived from
message.payloadStringMessage content (as string)
message.qosIntegerQoS level
message.retainedBooleanWhether it is a retained message
frameObjectFrame summary information

The script must return a JavaScript Map (Object). The Map’s keys must match Variable names. inSCADA writes each key-value pair from the returned map to the corresponding Variable.

Incoming message: {"temperature": 25.4, "humidity": 62.1, "status": true}

// Subscribe Expression
var data = JSON.parse(message.payload);
// Return an object matching Variable names
var result = {};
result.temperature = data.temperature;
result.humidity = data.humidity;
result.status = data.status;
return result;

When this script runs:

  • 25.4 is written to the temperature variable
  • 62.1 is written to the humidity variable
  • true is written to the status variable

Incoming message: {"device": {"id": "sensor-01", "readings": {"temp": 72.5, "press": 3.2}}}

var data = JSON.parse(message.payload);
var result = {};
result.device_id = data.device.id;
result.temp = data.device.readings.temp;
result.press = data.device.readings.press;
return result;

Incoming message: 25.4;62.1;1;1024

var parts = message.payload.split(';');
var result = {};
result.temperature = parseFloat(parts[0]);
result.humidity = parseFloat(parts[1]);
result.status = parseInt(parts[2]) === 1;
result.pressure = parseFloat(parts[3]);
return result;
var data = JSON.parse(message.payload);
var result = {};
if (message.topic.indexOf('temperature') > -1) {
result.temperature = data.value;
} else if (message.topic.indexOf('pressure') > -1) {
result.pressure = data.value;
}
return result;

Example 5: Using ins.* API (Cross-Variable Access)

Section titled “Example 5: Using ins.* API (Cross-Variable Access)”

You can access other variables within the subscribe script using the ins API:

var data = JSON.parse(message.payload);
var result = {};
result.temperature = data.temp;
// Read the current value of another variable
var currentSetpoint = ins.getVariableValue('setpoint_temp');
if (currentSetpoint != null) {
// Calculate the difference and write to another variable
var diff = data.temp - currentSetpoint.value;
result.temp_deviation = diff;
}
return result;

When a value is written (set value) to a Variable, inSCADA executes the Publish Expression script in the Frame. The following objects are provided to the script as bindings:

BindingTypeDescription
frameObjectFrame summary information
setValueRequestsArrayList of variables and values to be written
setValueRequests[n].variableObjectVariable information (name, type)
setValueRequests[n].valueObjectValue to write

The script must return a String payload to be published to the MQTT broker.

var payload = {};
for (var i = 0; i < setValueRequests.length; i++) {
var req = setValueRequests[i];
payload[req.variable.name] = req.value;
}
return JSON.stringify(payload);

This script produces a JSON string like {"temperature": 25.0, "setpoint": 30.0} and publishes it to the broker.

var req = setValueRequests[0];
var command = {
action: 'set',
variable: req.variable.name,
value: req.value,
timestamp: new Date().toISOString()
};
return JSON.stringify(command);

Key ins API functions available within MQTT scripts:

FunctionDescription
ins.getVariableValue(name)Read the live value of a Variable (same project)
ins.getVariableValue(project, name)Read a variable from a different project
ins.getVariableValues(names[])Read multiple variables in bulk
ins.setVariableValue(name, {value: X})Write a value to a Variable
ins.setVariableValues({name: {value: X}, ...})Write values to multiple variables in bulk
ins.mapVariableValue(src, dest)Copy a variable’s value to another
ins.toggleVariableValue(name)Toggle a Boolean variable
ins.sparkplugDecode(payload)Decode a Sparkplug B Protobuf payload
ins.sparkplugEncode(metrics)Create a Sparkplug B Protobuf payload

Sparkplug B is a payload specification standardized by the Eclipse Foundation for carrying industrial SCADA data over MQTT. It adds the following on top of standard MQTT:

  • Standard topic structure: A fixed hierarchy in the format spBv1.0/{group}/{message_type}/{edge_node}/{device}
  • Birth/Death certificates: NBIRTH message when a device connects, NDEATH when it disconnects — the SCADA side instantly knows whether the device is online/offline
  • Auto-discovery: The device sends its variable list and data types with the BIRTH message — no manual tag definition needed
  • Report by exception: Only changed values are sent — bandwidth is optimized
  • Industrial data types: Integer, Float, Boolean, DateTime, String, Dataset, Template

Sparkplug B messages are encoded in Protobuf (Protocol Buffers) format — a binary format, not plain text like JSON. inSCADA can directly decode/encode Sparkplug B Protobuf messages within scripts using the ins.sparkplugDecode() and ins.sparkplugEncode() API functions.

// Decode Sparkplug B message
var decoded = ins.sparkplugDecode(message.payload);
var result = {};
// metrics: [{name, value, dataType, timestamp}, ...]
var metrics = decoded.metrics;
for (var i = 0; i < metrics.length; i++) {
result[metrics[i].name] = metrics[i].value;
}
return result;

This script parses all metrics from a Sparkplug B DDATA or DBIRTH message and writes them to the corresponding variables.

// Create Sparkplug B payload from variable values
var metrics = [];
for (var i = 0; i < setValueRequests.length; i++) {
var req = setValueRequests[i];
metrics.push({
name: req.variable.name,
value: req.value
});
}
return ins.sparkplugEncode(metrics);
TopicMessage TypeDescription
spBv1.0/group/NBIRTH/edge_nodeNode BirthEdge node came online
spBv1.0/group/NDEATH/edge_nodeNode DeathEdge node went offline
spBv1.0/group/DBIRTH/edge_node/deviceDevice BirthDevice online + metric list
spBv1.0/group/DDATA/edge_node/deviceDevice DataLive data (changed metrics)
spBv1.0/group/DCMD/edge_node/deviceDevice CommandSending commands to device

An MQTT Frame configuration using Sparkplug B:

ParameterValue
TopicspBv1.0/factory/DDATA/gateway-01/plc-01
QoS0
Subscribe ExpressionThe decode script above
IoT Sensors ──(MQTT)──► Broker ──(MQTT)──► inSCADA
(Subscribe + Parse)

inSCADA subscribes to MQTT messages from IoT gateways or sensors, parses them with scripts, and writes to variables. This way, MQTT-based IoT devices are directly integrated into the SCADA system.

inSCADA ──(MQTT Publish)──► Broker ──► Azure IoT Hub / AWS IoT / Google Cloud IoT

inSCADA converts the collected field data to JSON format with a publish expression and forwards it to cloud platforms via the MQTT broker.

Thanks to MQTT’s script-based architecture, you can also process non-standard or custom format messages. You can decode binary payloads with JavaScript, combine multiple topics in a single frame, or apply conditional logic.