Skip to main content

Reading History from Multiple Variables

Learn how to efficiently read historical data from multiple OPC UA variables.

Method 1: Sequential Reading

Use a loop to read variables one at a time:

[ Inject ] → [ Split Variables ] → [ History Read ] → [ Join ] → [ Debug ]

Split Variables (Function):

const variables = [
"ns=2;s=Temperature",
"ns=2;s=Pressure",
"ns=2;s=FlowRate"
];

const messages = variables.map(nodeId => ({
nodeId: nodeId,
startTime: "1 hour ago",
endTime: "now"
}));

return [messages];

Join Node: Set to "automatic" mode to combine results

Method 2: Using a Loop

[ Inject ] → [ Function ] → [ History Read ] → [ Collect ] → [ Debug ]
↑_______________|

Function Node:

// Initialize on first run
if (!context.variables) {
context.variables = [
"ns=2;s=Temperature",
"ns=2;s=Pressure",
"ns=2;s=FlowRate"
];
context.index = 0;
context.results = [];
}

// Get current variable
const current = context.variables[context.index];

if (current) {
msg.nodeId = current;
msg.startTime = "1 hour ago";
msg.endTime = "now";
context.index++;
return [msg, null];
} else {
// All done - send results
msg.payload = context.results;
context.variables = null;
return [null, msg];
}

Method 3: Parallel Processing

[ Inject ] → [ Var1 History ] → [ Format1 ] ┐
→ [ Var2 History ] → [ Format2 ] ├→ [ Join ] → [ Debug ]
→ [ Var3 History ] → [ Format3 ] ┘

Set up separate History Read nodes for each variable, then join the results.

Combining Results

Merge by Timestamp

// Function node after collecting all results
const combined = {};

// msg.payload is array of results from different variables
msg.payload.forEach(varData => {
varData.data.forEach(point => {
const time = point.sourceTimestamp;
if (!combined[time]) {
combined[time] = { timestamp: time };
}
combined[time][varData.nodeId] = point.value;
});
});

// Convert to array sorted by time
msg.payload = Object.values(combined).sort((a, b) =>
new Date(a.timestamp) - new Date(b.timestamp)
);

return msg;

Output:

[
{
timestamp: "2024-11-24T10:00:00Z",
"ns=2;s=Temperature": 23.5,
"ns=2;s=Pressure": 1.2,
"ns=2;s=FlowRate": 45.3
},
{
timestamp: "2024-11-24T10:05:00Z",
"ns=2;s=Temperature": 23.7,
"ns=2;s=Pressure": 1.21,
"ns=2;s=FlowRate": 46.1
}
]

Complete Example: Multi-Variable Dashboard

[ Timer (15m) ] → [ Get Variables ] → [ History Read ] → [ Process ] → [ Dashboard ]
↑__________________|

Get Variables (Function):

// Get list of variables from flow context
const vars = flow.get('monitoredVars') || [
"ns=2;s=Temp1",
"ns=2;s=Temp2",
"ns=2;s=Temp3"
];

// Initialize or continue loop
const index = context.get('index') || 0;

if (index < vars.length) {
msg.nodeId = vars[index];
msg.startTime = "15 minutes ago";
msg.endTime = "now";
msg.varIndex = index;
context.set('index', index + 1);
return msg;
} else {
// Reset for next cycle
context.set('index', 0);
return null;
}

Tips

  • Sequential reading is simpler but slower
  • Parallel reading is faster but uses more resources
  • Always store results in context or global for combining
  • Consider server load when reading many variables
  • Use aggregated data for multiple variables over long periods