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