Skip to main content

Monitoring Multiple Variables (Array)

This tutorial shows you how to monitor multiple OPC UA variables simultaneously using an array of NodeIds.

All monitored variables share the same monitoring parameters and output their values together.

This approach is ideal when:

  • You need to monitor several related variables
  • All variables should use the same sampling interval
  • You want consolidated output for all values

Prerequisites

  • An active connection to an OPC UA server (see Create a connection)
  • A subscription configured in the connection endpoint
  • NodeIds of the variables you want to monitor

Configuration

Monitor Node Setup

  1. Start Immediately: Uncheck this option
  2. NodeId Field: Leave empty
  3. Configure Monitoring Parameters:
    • Sample Interval: 1000 ms
    • Queue Size: 1000
    • Discard Oldest: true
note

When monitoring multiple variables, you must inject the array - you cannot configure it statically in the node.

Basic Array Injection

Inject an array of NodeIds to monitor multiple variables:

{
"payload": [
"ns=1;s=Temperature",
"ns=1;s=Pressure",
"ns=1;s=FlowRate"
]
}

Example Flow:

[
{
"id": "inject1",
"type": "inject",
"name": "Monitor 3 Variables",
"payload": [
"ns=1;s=Temperature",
"ns=1;s=Pressure",
"ns=1;s=FlowRate"
],
"payloadType": "json"
},
{
"id": "monitor1",
"type": "OpcUa-Monitor",
"name": "Array Monitor",
"endpoint": "opcua_endpoint1",
"subscription": "subscription1",
"startImmediately": false,
"nodeId": "",
"samplingInterval": 1000
},
{
"id": "debug1",
"type": "debug",
"name": "Show All Values"
}
]

Output Format

When monitoring an array, the output contains all current values:

Value Format (Default):

{
"payload": [
23.5,
101.3,
45.2
]
}

The values are in the same order as the input array.

DataValue Format:

To get full metadata for each variable, set msg.outputType = "DataValue":

{
"payload": [
{
"value": 23.5,
"statusCode": {"value": 0, "description": "Good"},
"sourceTimestamp": "2024-11-24T10:30:45.123Z",
"serverTimestamp": "2024-11-24T10:30:45.125Z"
},
{
"value": 101.3,
"statusCode": {"value": 0, "description": "Good"},
"sourceTimestamp": "2024-11-24T10:30:45.124Z",
"serverTimestamp": "2024-11-24T10:30:45.126Z"
},
{
"value": 45.2,
"statusCode": {"value": 0, "description": "Good"},
"sourceTimestamp": "2024-11-24T10:30:45.125Z",
"serverTimestamp": "2024-11-24T10:30:45.127Z"
}
]
}

Example: Process Monitoring Dashboard

Monitor key process variables for a reactor:

[
{
"id": "inject1",
"type": "inject",
"name": "Monitor Reactor",
"payload": [
"ns=2;s=Reactor1.Temperature",
"ns=2;s=Reactor1.Pressure",
"ns=2;s=Reactor1.Level",
"ns=2;s=Reactor1.pH",
"ns=2;s=Reactor1.FlowRate"
],
"payloadType": "json",
"once": true
},
{
"id": "monitor1",
"type": "OpcUa-Monitor",
"name": "Reactor Monitor",
"endpoint": "opcua_endpoint1",
"subscription": "subscription1",
"startImmediately": false,
"samplingInterval": 500
},
{
"id": "function1",
"type": "function",
"name": "Format for Dashboard",
"func": `
// Extract values with labels
const [temp, pressure, level, ph, flowRate] = msg.payload;

msg.payload = {
temperature: temp,
pressure: pressure,
level: level,
pH: ph,
flowRate: flowRate
};

return msg;
`
},
{
"id": "dashboard1",
"type": "ui_template",
"name": "Reactor Dashboard"
}
]

Function Node - Process Array:

// Extract values from the array
const [temp, pressure, level, ph, flowRate] = msg.payload;

// Create a named object for easier use
msg.payload = {
temperature: temp,
pressure: pressure,
level: level,
pH: ph,
flowRate: flowRate
};

return msg;

Example: Multiple Pumps Monitoring

Monitor status of multiple pumps:

// Function node: Build pump NodeId array
const pumpCount = 10;
const nodeIds = [];

for (let i = 1; i <= pumpCount; i++) {
nodeIds.push(`ns=1;s=Pump${i}.Status`);
nodeIds.push(`ns=1;s=Pump${i}.Speed`);
nodeIds.push(`ns=1;s=Pump${i}.Power`);
}

msg.payload = nodeIds;
return msg;

Output Processing:

// Function node: Parse pump data
const pumps = [];
const values = msg.payload;

// Group values by pump (3 values per pump)
for (let i = 0; i < values.length; i += 3) {
const pumpNumber = Math.floor(i / 3) + 1;
pumps.push({
id: pumpNumber,
status: values[i], // Status
speed: values[i + 1], // Speed
power: values[i + 2] // Power
});
}

msg.payload = pumps;
return msg;

Notification Behavior

When a Value Changes:

The Monitor node sends a message containing all current values, not just the one that changed.

Example:

  • Initial values: [23.5, 101.3, 45.2]
  • Temperature changes to 24.1
  • Output: [24.1, 101.3, 45.2] (complete array)

Efficiency Note:

All monitored items in the array share the same subscription, making this approach efficient for monitoring related variables.

Advanced: Dynamic Array Updates

You can change which variables are monitored by injecting a new array:

// Function node: Switch monitoring targets
if (msg.topic === "production") {
msg.payload = [
"ns=1;s=ProductionLine1.Speed",
"ns=1;s=ProductionLine1.Count",
"ns=1;s=ProductionLine1.Quality"
];
} else if (msg.topic === "maintenance") {
msg.payload = [
"ns=1;s=ProductionLine1.Vibration",
"ns=1;s=ProductionLine1.Temperature",
"ns=1;s=ProductionLine1.Hours"
];
}

return msg;

Combining with Other Nodes

Example: Data Logging

Log all monitored values to a database:

// Function node: Prepare for database
const timestamp = new Date();
const [temp, pressure, flowRate] = msg.payload;

msg.payload = {
timestamp: timestamp,
measurements: {
temperature: temp,
pressure: pressure,
flowRate: flowRate
}
};

// Insert into database
msg.topic = "INSERT INTO process_data VALUES (?, ?, ?, ?)";
msg.params = [timestamp, temp, pressure, flowRate];

return msg;

Example: Alarm Detection

Check multiple values for alarm conditions:

// Function node: Detect alarms
const [temp, pressure, level] = msg.payload;
const alarms = [];

if (temp > 80) {
alarms.push({
type: "HighTemperature",
value: temp,
limit: 80
});
}

if (pressure > 150) {
alarms.push({
type: "HighPressure",
value: pressure,
limit: 150
});
}

if (level < 20) {
alarms.push({
type: "LowLevel",
value: level,
limit: 20
});
}

if (alarms.length > 0) {
msg.payload = alarms;
return msg;
}

return null; // No alarms

Performance Considerations

Array Size Limits

  • Small arrays (< 10 items): No concerns
  • Medium arrays (10-100 items): Efficient and recommended
  • Large arrays (100-1000 items): Consider subscription parameters
  • Very large arrays (> 1000 items): May need multiple Monitor nodes

Subscription Efficiency

All items in an array share:

  • The same subscription
  • The same sampling interval
  • The same queue settings

This is more efficient than using multiple Monitor nodes.

Network Bandwidth

Each notification sends all values, so consider:

  • Number of monitored variables
  • Sampling interval
  • Value change frequency
  • Network capacity

Tips & Best Practices

Group logically related variables in the same array:

Good:

// All reactor variables together
["Reactor1.Temp", "Reactor1.Pressure", "Reactor1.Level"]

Avoid:

// Unrelated variables
["Reactor1.Temp", "Pump5.Speed", "Tank3.Level"]

Document Array Order

Always document the order of values in your array:

// Array order: [Temperature, Pressure, FlowRate, Level, pH]
const nodeIds = [
"ns=1;s=Temperature", // Index 0
"ns=1;s=Pressure", // Index 1
"ns=1;s=FlowRate", // Index 2
"ns=1;s=Level", // Index 3
"ns=1;s=pH" // Index 4
];

or use json structures instead (see Monitoring JSON Structure).

Use Destructuring

ES6 destructuring makes array processing cleaner:

// Extract values with descriptive names
const [temp, pressure, flowRate, level, pH] = msg.payload;

// Use directly
if (temp > 80 || pressure > 150) {
node.warn("Critical condition detected");
}

Handle Partial Failures

Some variables may have bad status codes:

// Check status when using DataValue format
msg.outputType = "DataValue";

const values = msg.payload;
const goodValues = values.filter(v => v.statusCode.value === 0);

if (goodValues.length < values.length) {
node.warn(`${values.length - goodValues.length} values have bad quality`);
}

Troubleshooting

Missing Values in Output

Symptom: Output array has fewer values than expected

Cause: Some NodeIds are invalid or inaccessible

Solution:

  1. Verify each NodeId using the Read node
  2. Check server logs for access denied errors
  3. Ensure all NodeIds exist on the server

Values in Wrong Order

Symptom: Values don't match expected order

Cause: NodeId array order changed

Solution:

  1. Document the expected order
  2. Use the same array generation logic
  3. Add validation to check array length

Memory Issues with Large Arrays

Symptom: Node-RED becomes slow or crashes

Cause: Too many monitored items

Solution:

  1. Split into multiple Monitor nodes
  2. Increase queue size gradually
  3. Consider using JSON structure instead

Next Steps

See Also