Exploring the OPC UA Address Space
This tutorial shows you how to use the Explore node to discover and navigate the structure of an OPC UA server's address space. The Explore node helps you understand what data is available on a server and how it's organized.
Prerequisites
- An active connection to an OPC UA server (see Create a connection)
- Basic understanding of OPC UA address space concepts
What is Address Space Exploration?
The OPC UA address space is a hierarchical structure of nodes representing:
- Objects: Equipment, systems, folders
- Variables: Data points, measurements, parameters
- Methods: Callable functions
- Types: Data type definitions
The Explore node traverses this structure and returns it as a JSON object, making it easy to understand what's available on the server.
Basic Configuration
Explore Node Setup
- Name: Descriptive name for the node
- Endpoint: Select your OPC UA server connection
- NodeId: Starting point for exploration (optional - can be injected)
- Output Type: What to return for leaf nodes (Value, NodeId, etc.)
- Follow Organizes: Whether to follow folder references
Example: Explore Server Status
Explore the standard Server Status structure:
[
{
"id": "inject1",
"type": "inject",
"name": "Explore Server Status",
"topic": "/Server/ServerStatus",
"payload": ""
},
{
"id": "explore1",
"type": "OpcUa-Explore",
"name": "Explore",
"endpoint": "opcua_endpoint1",
"outputType": "Value"
},
{
"id": "debug1",
"type": "debug",
"name": "Show Structure"
}
]
Output:
{
"payload": {
"StartTime": "2024-11-24T10:00:00.000Z",
"CurrentTime": "2024-11-24T10:30:45.123Z",
"State": 0,
"BuildInfo": {
"ProductUri": "urn:MyServer",
"ManufacturerName": "ACME Corp",
"ProductName": "MyServer",
"SoftwareVersion": "1.0.0",
"BuildNumber": "12345",
"BuildDate": "2024-01-01T00:00:00.000Z"
},
"SecondsTillShutdown": 0,
"ShutdownReason": {}
}
}
NodeId Specification Methods
Method 1: Static Configuration
Configure the NodeId directly in the Explore node:
// In node configuration
nodeId: "ns=1;s=Equipment.Reactor1"
Method 2: Inject via Topic
Send the NodeId in msg.topic:
{
"topic": "ns=1;s=Equipment.Reactor1"
}
Method 3: Inject via NodeId Property
Send the NodeId in msg.nodeId:
{
"nodeId": "ns=1;s=Equipment.Reactor1"
}
Method 4: Browse Path
Use a browse path starting from /Objects:
{
"topic": "/Server/ServerStatus/BuildInfo"
}
Priority Order:
msg.nodeId(highest)msg.topic- Configured NodeId (lowest)
Output Types
Control what the Explore node returns for leaf nodes (variables) using msg.outputType or the node configuration:
Value (Default)
Returns the actual value of variables:
{
"topic": "/Server/ServerStatus",
"outputType": "Value"
}
Output:
{
"StartTime": "2024-11-24T10:00:00.000Z",
"CurrentTime": "2024-11-24T10:30:45.123Z",
"State": 0
}
NodeId
Returns NodeIds instead of values - useful for monitoring or reading later:
{
"topic": "/Server/ServerStatus",
"outputType": "NodeId"
}
Output:
{
"StartTime": "ns=0;i=2257",
"CurrentTime": "ns=0;i=2258",
"State": "ns=0;i=2259",
"BuildInfo": "ns=0;i=2260"
}
Use NodeId output type with the Monitor node to automatically monitor entire subtrees!
DataValue
Returns complete DataValue with metadata:
{
"topic": "ns=1;s=Temperature",
"outputType": "DataValue"
}
Output:
{
"Temperature": {
"value": 23.5,
"statusCode": {"value": 0, "description": "Good"},
"sourceTimestamp": "2024-11-24T10:30:45.123Z",
"serverTimestamp": "2024-11-24T10:30:45.125Z"
}
}
BrowsePath
Returns browse paths for each variable:
{
"topic": "/Server/ServerStatus/BuildInfo",
"outputType": "BrowsePath"
}
Output:
{
"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"
}
AliasedBrowsePath
Returns browse paths with aliased namespaces:
{
"topic": "/Server/ServerStatus/BuildInfo",
"outputType": "AliasedBrowsePath"
}
Output:
{
"ProductUri": "/Server.ServerStatus.BuildInfo.ProductUri",
"ManufacturerName": "/Server.ServerStatus.BuildInfo.ManufacturerName",
"ProductName": "/Server.ServerStatus.BuildInfo.ProductName"
}
Output Type Comparison
| Output Type | Use Case | Example |
|---|---|---|
| Value | Get actual data | 23.5 |
| NodeId | For monitoring/reading | "ns=1;i=1001" |
| DataValue | Need timestamps/quality | {value: 23.5, timestamp: "..."} |
| BrowsePath | Human-readable paths | "/Server/ServerStatus/State" |
| AliasedBrowsePath | Simplified paths | "/Server.ServerStatus.State" |
| StatusCode | Check data quality | {value: 0, description: "Good"} |
Example: Explore Equipment
Explore a piece of equipment to understand its structure:
[
{
"id": "inject1",
"type": "inject",
"name": "Explore Reactor",
"topic": "ns=2;s=Equipment.Reactor1"
},
{
"id": "explore1",
"type": "OpcUa-Explore",
"name": "Explore",
"endpoint": "opcua_endpoint1",
"outputType": "Value",
"followOrganizes": true
},
{
"id": "function1",
"type": "function",
"name": "Process Structure",
"func": `
// Count how many variables were found
function countVariables(obj) {
let count = 0;
for (const value of Object.values(obj)) {
if (typeof value === 'object' && value !== null) {
count += countVariables(value);
} else {
count++;
}
}
return count;
}
const varCount = countVariables(msg.payload);
node.log(\`Found \${varCount} variables\`);
return msg;
`
},
{
"id": "debug1",
"type": "debug"
}
]
Output Structure:
{
"payload": {
"Process": {
"Temperature": 85.3,
"Pressure": 2.5,
"pH": 7.2
},
"Cooling": {
"InletTemp": 15.0,
"OutletTemp": 22.5,
"FlowRate": 120.0
},
"Status": {
"Running": true,
"Mode": "Auto"
}
}
}
Follow Organizes Reference
The followOrganizes flag controls which references to follow:
When True (Default)
Follows all organizational references:
- Organizes: Folder structures
- HasComponent: Equipment components
- HasProperty: Properties
Use for: Complete exploration of equipment and folders
When False
Only follows:
- HasComponent: Direct components
- HasProperty: Direct properties
Use for: Exploring only the direct children of a node
Example:
// Explore complete folder structure
msg.followOrganizes = true;
// Explore only direct properties
msg.followOrganizes = false;
Exclude Empty Nodes
Remove empty folders from the output:
{
"nodeId": "ns=2;s=Equipment",
"excludeEmpty": true
}
Before (excludeEmpty: false):
{
"Reactor1": {
"Temperature": 85.3
},
"Reactor2": {},
"Reactor3": {}
}
After (excludeEmpty: true):
{
"Reactor1": {
"Temperature": 85.3
}
}
Example: Discover Available Data
Explore the Objects folder to see all available equipment:
// Function node: Discover structure
msg.nodeId = "i=85"; // Objects folder
msg.outputType = "NodeId";
msg.followOrganizes = true;
return msg;
Process the result:
// Function node: List all equipment
function listNodes(obj, path = '', result = []) {
for (const [key, value] of Object.entries(obj)) {
const currentPath = path ? `${path}.${key}` : key;
if (typeof value === 'string') {
result.push({
path: currentPath,
nodeId: value
});
} else if (typeof value === 'object') {
listNodes(value, currentPath, result);
}
}
return result;
}
const nodeList = listNodes(msg.payload);
msg.payload = {
total: nodeList.length,
nodes: nodeList
};
return msg;
Limiting Exploration Depth
Control how deep to explore:
{
"nodeId": "ns=2;s=Equipment"
}
Exploration:
- Explores the full hierarchy under the specified node
- Use more specific NodeIds to limit scope
- 3-5: Typical equipment structures
- 10: Default maximum
- > 10: Very deep structures (use with caution)
Tips & Best Practices
For comprehensive best practices and optimization techniques, see:
Key topics covered:
- Starting with appropriate scope
- Choosing the right output type
- Caching exploration results
- Validation before use
- Common use cases and patterns
Troubleshooting
For detailed troubleshooting guidance and solutions to common problems, see:
Common issues covered:
- No results returned
- Too much data
- Missing variables
- Incorrect output format
- Performance issues
- Error messages
Next Steps
- Tips & Best Practices - Optimization techniques
- Troubleshooting - Common problems and solutions
- Exploring a Subtree - Detailed subtree exploration
- Output Types - All output type options
- Monitor Subtree - Use exploration results for monitoring