Understanding Explore Output Types
This tutorial explains the different output types available in the Explore node and when to use each one. The output type determines what information is returned for leaf nodes (variables) in the explored structure.
Output Type Overview
The Explore node can return seven different types of information for each variable:
| Output Type | Returns | Use Case |
|---|---|---|
| Value | Actual data values | Display, analysis, processing |
| NodeId | Node identifiers | Monitoring, reading, writing |
| DataValue | Values with metadata | Quality checking, timestamping |
| StatusCode | Quality indicators | Data validation |
| BrowsePath | Full browse paths | Navigation, documentation |
| AliasedBrowsePath | Simplified paths | Human-readable references |
| NSUNodeId | NodeIds with URI | Cross-server references |
Value Output Type
Returns the actual current value of each variable.
Configuration
{
"nodeId": "/Server/ServerStatus",
"outputType": "Value"
}
Output Example
{
"StartTime": "2024-11-24T10:00:00.000Z",
"CurrentTime": "2024-11-24T10:30:45.123Z",
"State": 0,
"BuildInfo": {
"ProductName": "MyServer",
"SoftwareVersion": "1.0.0"
}
}
When to Use
✅ Best for:
- Displaying current data to users
- Data analysis and calculations
- Exporting data to other systems
- Dashboard creation
❌ Not ideal for:
- Setting up monitoring (use NodeId instead)
- Checking data quality (use DataValue instead)
Example: Display Data
// Function node: Format for display
const data = msg.payload;
msg.payload = {
title: "Server Status",
fields: [
{ label: "Product", value: data.BuildInfo.ProductName },
{ label: "Version", value: data.BuildInfo.SoftwareVersion },
{ label: "State", value: data.State === 0 ? "Running" : "Not Running" }
]
};
return msg;
NodeId Output Type
Returns the NodeId of each variable instead of its value.
Configuration
{
"nodeId": "/Server/ServerStatus",
"outputType": "NodeId"
}
Output Example
{
"StartTime": "ns=0;i=2257",
"CurrentTime": "ns=0;i=2258",
"State": "ns=0;i=2259",
"BuildInfo": {
"ProductName": "ns=0;i=2263",
"SoftwareVersion": "ns=0;i=2264"
}
}
When to Use
✅ Best for:
- Setting up monitoring configurations
- Creating read/write node configurations
- Building dynamic flows
- Storing references for later use
Example: Setup Monitoring
Connect Explore output directly to Monitor input:
[
{
"id": "explore1",
"type": "OpcUa-Explore",
"name": "Discover Variables",
"outputType": "NodeId"
},
{
"id": "monitor1",
"type": "OpcUa-Monitor",
"name": "Monitor All",
"startImmediately": false
}
]
The Monitor node receives a JSON structure with NodeIds and automatically monitors all variables!
Example: Batch Read
// Function node: Convert to read requests
const structure = msg.payload;
const nodeIds = [];
function extractNodeIds(obj) {
for (const value of Object.values(obj)) {
if (typeof value === 'string') {
nodeIds.push(value);
} else if (typeof value === 'object') {
extractNodeIds(value);
}
}
}
extractNodeIds(structure);
msg.payload = nodeIds;
return msg;
DataValue Output Type
Returns complete OPC UA DataValue structures with metadata.
Configuration
{
"nodeId": "ns=1;s=Temperature",
"outputType": "DataValue"
}
Output Example
{
"Temperature": {
"value": 23.5,
"statusCode": {
"value": 0,
"description": "Good",
"name": "Good"
},
"sourceTimestamp": "2024-11-24T10:30:45.123Z",
"sourcePicoseconds": 0,
"serverTimestamp": "2024-11-24T10:30:45.125Z",
"serverPicoseconds": 0
}
}
When to Use
✅ Best for:
- Quality checking (Good/Bad/Uncertain)
- Timestamp validation
- Historical data analysis
- Regulatory compliance (audit trails)
Example: Quality Check
// Function node: Filter good quality data
const structure = msg.payload;
const goodData = {};
function filterGoodQuality(obj, result = {}) {
for (const [key, value] of Object.entries(obj)) {
if (value.statusCode && value.statusCode.value === 0) {
result[key] = value.value;
} else if (typeof value === 'object' && !value.statusCode) {
result[key] = {};
filterGoodQuality(value, result[key]);
}
}
return result;
}
msg.payload = filterGoodQuality(structure);
return msg;
Example: Timestamp Validation
// Function node: Check data freshness
const maxAge = 60000; // 1 minute
const now = new Date();
function checkFreshness(obj, issues = []) {
for (const [key, value] of Object.entries(obj)) {
if (value.sourceTimestamp) {
const age = now - new Date(value.sourceTimestamp);
if (age > maxAge) {
issues.push({
variable: key,
age: age,
timestamp: value.sourceTimestamp
});
}
} else if (typeof value === 'object') {
checkFreshness(value, issues);
}
}
return issues;
}
const staleData = checkFreshness(msg.payload);
if (staleData.length > 0) {
msg.payload = {
warning: "Stale data detected",
staleVariables: staleData
};
return msg;
}
return null;
BrowsePath Output Type
Returns the full browse path for each variable with namespace indices.
Configuration
{
"nodeId": "/Server/ServerStatus/BuildInfo",
"outputType": "BrowsePath"
}
Output Example
{
"ProductUri": "/0:Server/0:ServerStatus/0:BuildInfo/0:ProductUri",
"ManufacturerName": "/0:Server/0:ServerStatus/0:BuildInfo/0:ManufacturerName",
"ProductName": "/0:Server/0:ServerStatus/0:BuildInfo/0:ProductName",
"SoftwareVersion": "/0:Server/0:ServerStatus/0:BuildInfo/0:SoftwareVersion"
}
When to Use
✅ Best for:
- Documentation generation
- Cross-reference with other systems
- Precise navigation paths
- Technical documentation
Example: Generate Documentation
// Function node: Create documentation
const paths = msg.payload;
const docs = [];
function generateDocs(obj, parentPath = '') {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'string') {
docs.push({
variable: key,
browsePath: value,
category: parentPath || 'Root'
});
} else if (typeof value === 'object') {
generateDocs(value, parentPath ? `${parentPath}.${key}` : key);
}
}
}
generateDocs(paths);
// Convert to markdown table
let markdown = "| Variable | Browse Path | Category |\n";
markdown += "|----------|-------------|----------|\n";
docs.forEach(doc => {
markdown += `| ${doc.variable} | ${doc.browsePath} | ${doc.category} |\n`;
});
msg.payload = markdown;
return msg;
AliasedBrowsePath Output Type
Returns simplified browse paths with aliased namespaces (dot notation).
Configuration
{
"nodeId": "/Server/ServerStatus/BuildInfo",
"outputType": "AliasedBrowsePath"
}
Output Example
{
"ProductUri": "/Server.ServerStatus.BuildInfo.ProductUri",
"ManufacturerName": "/Server.ServerStatus.BuildInfo.ManufacturerName",
"ProductName": "/Server.ServerStatus.BuildInfo.ProductName",
"SoftwareVersion": "/Server.ServerStatus.BuildInfo.SoftwareVersion"
}
When to Use
✅ Best for:
- Human-readable references
- Configuration files
- User documentation
- Simplified navigation
Example: Create Configuration File
// Function node: Generate config
const paths = msg.payload;
function flatten(obj, prefix = '', result = {}) {
for (const [key, value] of Object.entries(obj)) {
const path = prefix ? `${prefix}.${key}` : key;
if (typeof value === 'string') {
result[key] = value;
} else if (typeof value === 'object') {
flatten(value, path, result);
}
}
return result;
}
const config = {
timestamp: new Date().toISOString(),
server: "MyServer",
variables: flatten(paths)
};
msg.payload = JSON.stringify(config, null, 2);
return msg;
StatusCode Output Type
Returns only the quality status of each variable.
Configuration
{
"nodeId": "ns=2;s=Equipment.Reactor1",
"outputType": "StatusCode"
}
Output Example
{
"Temperature": {
"value": 0,
"description": "Good",
"name": "Good"
},
"Pressure": {
"value": 0,
"description": "Good",
"name": "Good"
},
"FailedSensor": {
"value": 2147483648,
"description": "Bad",
"name": "Bad"
}
}
When to Use
✅ Best for:
- Health monitoring
- Quality validation
- Finding bad sensors
- System diagnostics
Example: Health Check
// Function node: System health report
const statusCodes = msg.payload;
const health = {
good: 0,
bad: 0,
uncertain: 0,
issues: []
};
function analyzeHealth(obj, path = '') {
for (const [key, value] of Object.entries(obj)) {
const currentPath = path ? `${path}.${key}` : key;
if (value.value !== undefined) {
if (value.value === 0) {
health.good++;
} else if ((value.value & 0x80000000) !== 0) {
health.bad++;
health.issues.push({
variable: currentPath,
status: value.description
});
} else if ((value.value & 0x40000000) !== 0) {
health.uncertain++;
health.issues.push({
variable: currentPath,
status: value.description
});
}
} else if (typeof value === 'object') {
analyzeHealth(value, currentPath);
}
}
}
analyzeHealth(statusCodes);
const total = health.good + health.bad + health.uncertain;
health.healthPercentage = (health.good / total * 100).toFixed(1);
msg.payload = health;
return msg;
NSUNodeId Output Type
Returns NodeIds with namespace URIs instead of indices.
Configuration
{
"nodeId": "ns=2;s=Equipment.Reactor1",
"outputType": "NSUNodeId"
}
Output Example
{
"Temperature": "nsu=http://example.com/MyServer;s=Temperature",
"Pressure": "nsu=http://example.com/MyServer;s=Pressure"
}
When to Use
✅ Best for:
- Cross-server references
- Server migration
- Portable configurations
- Namespace-independent code
Example: Portable Configuration
// Function node: Create portable config
const nsuNodeIds = msg.payload;
// These NodeIds work even if namespace indices change
const config = {
monitoringTargets: nsuNodeIds,
portable: true,
note: "Can be used on different servers with same namespace URIs"
};
msg.payload = config;
return msg;
Combining Output Types
Use different output types for different purposes:
Workflow Example
// Step 1: Explore with NodeId to setup monitoring
msg.outputType = "NodeId";
// -> Send to Monitor node
// Step 2: Explore with Value for display
msg.outputType = "Value";
// -> Send to Dashboard
// Step 3: Explore with DataValue for quality check
msg.outputType = "DataValue";
// -> Check quality, log issues
// Step 4: Explore with AliasedBrowsePath for documentation
msg.outputType = "AliasedBrowsePath";
// -> Generate user documentation
Dynamic Output Type Selection
Choose output type based on context:
// Function node: Dynamic selection
const purpose = flow.get('explorePurpose');
let outputType;
switch(purpose) {
case 'monitor':
outputType = 'NodeId';
break;
case 'display':
outputType = 'Value';
break;
case 'document':
outputType = 'AliasedBrowsePath';
break;
case 'quality_check':
outputType = 'DataValue';
break;
default:
outputType = 'Value';
}
msg.outputType = outputType;
return msg;
Next Steps
- Exploring Basics - Getting started with Explore
- Exploring a Subtree - Detailed subtree exploration
- Monitor Subtree - Use NodeId output for monitoring