Skip to main content

write complex values

This tutorial covers how to write complex OPC UA data types including arrays, structures, extension objects, and custom data types using the OPC UA Write Node. Complex data types allow you to work with sophisticated industrial data structures that go beyond simple numeric and string values.

Understanding how to handle complex types is essential for advanced OPC UA applications that deal with structured data, configuration objects, and specialized industrial protocols.

Prerequisites

OPC UA Complex Variant Overview

Array Types

OPC UA supports several array formats:

  • Scalar: Single value (not an array)
  • Array: One-dimensional array [1, 2, 3]
  • Matrix: Multi-dimensional array with dimensions

Structure Types

  • Built-in Structures: Predefined OPC UA structures
  • Custom Structures: User-defined structured data types
  • Extension Objects: Complex objects with custom encoding

Data Type Categories

  1. Primitive Arrays: Arrays of basic types
  2. Structured Data: Complex objects with multiple fields
  3. Union Types: Data that can be one of several types
  4. Enumeration Arrays: Arrays of enumerated values

Writing Array Data Types

Simple Arrays

Numeric Arrays

// Integer array
msg = {
payload: {
dataType: "Int32",
value: [10, 20, 30, 40, 50],
arrayType: "Array"
},
nodeId: "ns=2;s=IntegerArray"
};

// Double array
msg = {
payload: {
dataType: "Double",
value: [1.1, 2.2, 3.3, 4.4],
arrayType: "Array"
},
nodeId: "ns=2;s=DoubleArray"
};

// Boolean array
msg = {
payload: {
dataType: "Boolean",
value: [true, false, true, false],
arrayType: "Array"
},
nodeId: "ns=2;s=BooleanArray"
};

String Arrays

msg = {
payload: {
dataType: "String",
value: ["Recipe1", "Recipe2", "Recipe3"],
arrayType: "Array"
},
nodeId: "ns=2;s=RecipeList"
};

Multi-Dimensional Arrays

// 2D Matrix (3x3)
msg = {
payload: {
dataType: "Double",
value: [
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0
],
arrayType: "Matrix",
dimensions: [3, 3] // 3 rows, 3 columns
},
nodeId: "ns=2;s=Matrix3x3"
};

// 3D Array (2x2x2)
msg = {
payload: {
dataType: "Int32",
value: [1, 2, 3, 4, 5, 6, 7, 8],
arrayType: "Matrix",
dimensions: [2, 2, 2]
},
nodeId: "ns=2;s=Cube2x2x2"
};

Dynamic Arrays with Function Node

// Generate array data dynamically
const size = flow.get("arraySize") || 10;
const dataArray = [];

for (let i = 0; i < size; i++) {
dataArray.push(Math.random() * 100);
}

msg = {
payload: {
dataType: "Double",
value: dataArray,
arrayType: "Array"
},
nodeId: "ns=2;s=DynamicArray"
};

return msg;

Writing Structured Data

Simple Structures

Writing an extension object can be performaed by providing the OPC UA Json Encoding of the structure.

Both JSON encoding from OPCUA version 1.05 and 1.04 (legacy) are supported.

For 1.05: the UaTypeId and UaBody properties are used. , UtaTypeId is a string with the NodeId of the structure type.

payload:{
UaTypeId: "nsu=http://opcfoundation.org/UA/AutoID/;i=3007",
UaBody: {
CodeType: "Ean13",
Timestamp: "2025-10-01T12:00:00.000Z",
ScanData: {
Epc: {
PC: 12,
UId: "XBASE64d=",
XPC_W1: 10,
XPC_W2: 12,
},
},
Location: {
Local: {
X: 100,
Y: 200,
Z: 300,
DilutionOfPrecision: 0.01,
UsefulPrecision: 2,
},
},
}
``` 

for 1.04 (legacy) : the TypeId and Body properties are used. TypeId is an object with IdType, Namespace and Id properties.

```javascript
payload: {
TypeId: {
IdType: 0, // Numeric
Namespace: 3,
Id: 3007,
},
Body: {
CodeType: "Ean13",
Timestamp: "2025-10-01T12:00:00.000Z"
ScanData: {
Epc: {
PC: 12,
UId: Buffer.from("Hello"),
XPC_W1: 10,
XPC_W2: 12,
},
},
Location: {
Local: {
X: 100,
Y: 200,
Z: 300,
DilutionOfPrecision: 0.01,
UsefulPrecision: 2,
},
},
}

All together:

// Equipment status structure (version 1.05)
msg = {
payload: {
UaTypeId: "nsu=http://opcfoundation.org/UA/AutoID/;i=3007",
UaBody: {
CodeType: "Ean13",
Timestamp: "2025-10-01T12:00:00.000Z",
ScanData: {
}
nodeId: "ns=2;s=ScanResult",
};

Configuration Structures

// Process configuration object
msg = {
payload: {
dataType: "ExtensionObject",
value: {
UaTypeId: "ns=2;i=2001",
UaBody: {
ProcessName: "Heating Process",
Parameters: {
TargetTemperature: 150.0,
HeatingRate: 5.0,
HoldTime: 3600,
CoolingRate: 2.0
},
Alarms: {
HighTempAlarm: 180.0,
LowTempAlarm: 140.0,
PressureAlarm: 10.0
},
Safety: {
EmergencyShutdown: true,
AutoRestart: false,
MaxCycles: 100
}
}
}
},
nodeId: "ns=2;s=ProcessConfig"
};

Recipe Data Structures

// Manufacturing recipe
msg = {
payload: {
dataType: "ExtensionObject",
value: {
UaTypeId: "ns=2;i=3001",
UaBody: {
RecipeId: "RCP_001",
RecipeName: "Standard Mix",
Version: "1.2",
Ingredients: [
{
Name: "Component A",
Quantity: 50.0,
Unit: "kg",
Tolerance: 2.0
},
{
Name: "Component B",
Quantity: 25.0,
Unit: "kg",
Tolerance: 1.0
}
],
Steps: [
{
StepNumber: 1,
Action: "Heat",
Parameter: 80.0,
Duration: 1800,
Description: "Heat to 80°C for 30 minutes"
},
{
StepNumber: 2,
Action: "Mix",
Parameter: 500.0,
Duration: 600,
Description: "Mix at 500 RPM for 10 minutes"
}
]
}
}
},
nodeId: "ns=2;s=ActiveRecipe"
};

Working with Custom Data Types

Enumeration Types

// Status enumeration
const StatusEnum = {
STOPPED: 0,
STARTING: 1,
RUNNING: 2,
STOPPING: 3,
ERROR: 4
};

msg = {
payload: {
value: StatusEnum.RUNNING
},
nodeId: "ns=2;s=MachineStatus"
};

// Or with string representation
msg = {
payload: {
value: "Running"
},
nodeId: "ns=2;s=MachineStatusText"
};

Advanced Complex Type Scenarios

1. Array of Structures

implicitly defined

You can simply provide an array of structured objects without explicitly defining the array type:

msg = {
payload: [
{
UaTypeId: "ns=2;i=6001",
UaBody: {
AlarmId: "ALM_001",
Severity: "High",
Message: "Temperature too high",
Timestamp: new Date("2024-01-15T10:30:00Z"),
Acknowledged: false
}
},
{
UaTypeId: "ns=2;i=6001",
UaBody: {
AlarmId: "ALM_002",
Severity: "Medium",
Message: "Pressure low",
Timestamp: new Date("2024-01-15T10:32:00Z"),
Acknowledged: true
}
}
],
nodeId: "ns=2;s=ActiveAlarms"
};

The Node-RED OPC UA Write node will automatically detect that the variable expect an array of extension object by querying it's DataType and ValueRank.

It will then convert the array of object into an array of extension object of the appropriate type in a ExtensionObject Array Variant.

The node will issue an error if the node does not expect an array of extension object of the provided type.

explicitly defined

You can also explicitly define the array type in the payload, and data type of the array elements:

// Array containing multiple structured objectsœ
msg = {
payload: {
dataType: "ExtensionObject",
value: [
{
UaTypeId: "ns=2;i=6001",
UaBody: {
AlarmId: "ALM_001",
Severity: "High",
Message: "Temperature too high",
Timestamp: new Date("2024-01-15T10:30:00Z"),
Acknowledged: false
}
},
{
UaTypeId: "ns=2;i=6001",
UaBody: {
AlarmId: "ALM_002",
Severity: "Medium",
Message: "Pressure low",
Timestamp: new Date("2024-01-15T10:32:00Z"),
Acknowledged: true
}
}
],
arrayType: "Array"
},
nodeId: "ns=2;s=ActiveAlarms"
};