Skip to main content

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 TypeReturnsUse Case
ValueActual data valuesDisplay, analysis, processing
NodeIdNode identifiersMonitoring, reading, writing
DataValueValues with metadataQuality checking, timestamping
StatusCodeQuality indicatorsData validation
BrowsePathFull browse pathsNavigation, documentation
AliasedBrowsePathSimplified pathsHuman-readable references
NSUNodeIdNodeIds with URICross-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

See Also