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
- read writing a Single Value page.
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
- Primitive Arrays: Arrays of basic types
- Structured Data: Complex objects with multiple fields
- Union Types: Data that can be one of several types
- 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"
};