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) 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
Collecting data over MQTT IoT sensors publish through a broker; inSCADA subscribes and parses the message. IoT sensors MQTT Broker MQTT inSCADA subscribes and parses

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.

Publishing to the cloud over MQTT inSCADA publishes through a broker to cloud platforms. inSCADA MQTT publish Broker Cloud platform 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.