This standard defines three data encodings: OPC UA Binary, OPC UA XML and OPC UA JSON. It describes how to construct Messages using each of these encodings.

All OPC UA DataEncodings are based on rules that are defined for a standard set of built-in types. These built-in types are then used to construct structures, arrays and Messages. The built-in types are described in Table 1.

Table 1 – Built-in Data Types

ID

Name

Description

1

Boolean

A two-state logical value (true or false).

2

SByte

An integer value between −128 and 127 inclusive.

3

Byte

An integer value between 0 and 255 inclusive.

4

Int16

An integer value between −32 768 and 32 767 inclusive.

5

UInt16

An integer value between 0 and 65 535 inclusive.

6

Int32

An integer value between −2 147 483 648 and 2 147 483 647 inclusive.

7

UInt32

An integer value between 0 and 4 294 967 295 inclusive.

8

Int64

An integer value between −9 223 372 036 854 775 808 and 9 223 372 036 854 775 807 inclusive.

9

UInt64

An integer value between 0 and 18 446 744 073 709 551 615 inclusive.

10

Float

An IEEE single precision (32 bit) floating point value.

11

Double

An IEEE double precision (64 bit) floating point value.

12

String

A sequence of Unicode characters.

13

DateTime

An instance in time.

14

Guid

A 16-byte value that can be used as a globally unique identifier.

15

ByteString

A sequence of octets.

16

XmlElement

An XML element.

17

NodeId

An identifier for a node in the address space of an OPC UA Server.

18

ExpandedNodeId

A NodeId that allows the namespace URI to be specified instead of an index.

19

StatusCode

A numeric identifier for an error or condition that is associated with a value or an operation.

20

QualifiedName

A name qualified by a namespace.

21

LocalizedText

Human readable text with an optional locale identifier.

22

ExtensionObject

A structure that contains an application specific data type that may not be recognized by the receiver.

23

DataValue

A data value with an associated status code and timestamps.

24

Variant

A union of all of the types specified above.

25

DiagnosticInfo

A structure that contains detailed error and diagnostic information associated with a StatusCode.

Most of these data types are the same as the abstract types defined in OPC 10000-3 and OPC 10000-4. However, the ExtensionObject and Variant types are defined in this standard. In addition, this standard defines a representation for the Guid type defined in OPC 10000-3.

A Guid is a 16-byte globally unique identifier with the layout shown in Table 2.

Table 2 – Guid structure

Component

Data Type

Data1

UInt32

Data2

UInt16

Data3

UInt16

Data4

Byte [8]

Guid values may be represented as a string in this form:

<Data1>-<Data2>-<Data3>-<Data4[0:1]>-<Data4[2:7]>

Where Data1 is 8 characters wide, Data2 and Data3 are 4 characters wide and each Byte in Data4 is 2 characters wide. Each value is formatted as a hexadecimal number with padded zeros. A typical Guid value would look like this when formatted as a string:

C496578A-0DFE-4B8F-870A-745238C6AEAE

A ByteString is structurally the same as a one-dimensional array of Byte. It is represented as a distinct built-in data type because it allows encoders to optimize the transmission of the value. However, some DevelopmentPlatforms will not be able to preserve the distinction between a ByteString and a one-dimensional array of Byte.

If a decoder for DevelopmentPlatform cannot preserve the distinction it shall convert all one-dimensional arrays of Byte to ByteStrings.

Each element in a one-dimensional array of ByteString can have a different length which means is structurally different from a two-dimensional array of Byte where the length of each dimension is the same. This means decoders shall preserve the distinction between two or more dimension arrays of Byte and one or more dimension arrays of ByteString.

If a DevelopmentPlatform does not support unsigned integers, then it will have to represent ByteStrings as arrays of SByte. In this case, the requirements for Byte would then apply to SByte.

An ExtensionObject is a container for any Structured DataTypes which cannot be encoded as one of the other built-in data types. The ExtensionObject contains a complex value serialized as a sequence of bytes or as an XML element. It also contains an identifier which indicates what data it contains and how it is encoded.

Structured DataTypes are represented in a Server address space as sub-types of the Structure DataType. The DataEncodings available for any given Structured DataTypes are represented as a DataTypeEncoding Object in the Server AddressSpace. The NodeId for the DataTypeEncoding Object is the identifier stored in the ExtensionObject. OPC 10000-3 describes how DataTypeEncoding Nodes are related to other Nodes of the AddressSpace.

Server implementers should use namespace qualified numeric NodeIds for any DataTypeEncoding Objects they define. This will minimize the overhead introduced by packing Structured DataType values into an ExtensionObject.

ExtensionObjects and Variants allow unlimited nesting which could result in stack overflow errors even if the message size is less than the maximum allowed. Decoders shall support at least 100 nesting levels. Decoders shall report an error if the number of nesting levels exceeds what it supports.

A Variant is a union of all built-in data types including an ExtensionObject. Variants can also contain arrays of any of these built-in types. Variants are used to store any value or parameter with a data type of BaseDataType or one of its subtypes.

Variants can be empty. An empty Variant is described as having a null value and should be treated like a null column in a SQL database. A null value in a Variant may not be the same as a null value for data types that support nulls such as Strings. Some DevelopmentPlatforms may not be able to preserve the distinction between a null for a DataType and a null for a Variant, therefore, applications shall not rely on this distinction. This requirement also means that if an Attribute supports the writing of a null value it shall also support writing of an empty Variant and vice versa.

Variants can contain arrays of Variants but they cannot directly contain another Variant.

DiagnosticInfo types only have meaning when returned in a response message with an associated StatusCode and table of strings. As a result, Variants cannot contain instances of DiagnosticInfo.

Values of Attributes are always returned in instances of DataValues. Therefore, the DataType of an Attribute cannot be a DataValue. Variants can contain DataValue when used in other contexts such as Method Arguments or PubSub Messages. The Variant in a DataValue cannot, directly or indirectly, contain another DataValue.

Variables with a DataType of BaseDataType are mapped to a Variant, however, the ValueRank and ArrayDimensions Attributes place restrictions on what is allowed in the Variant. For example, if the ValueRank is Scalar then the Variant may only contain scalar values.

ExtensionObjects and Variants allow unlimited nesting which could result in stack overflow errors even if the message size is less than the maximum allowed. Decoders shall support at least 100 nesting levels. Decoders shall report an error if the number of nesting levels exceeds what it supports.

A Decimal is a high-precision signed decimal number. It consists of an arbitrary precision integer unscaled value and an integer scale. The scale is the power of ten that is applied to the unscaled value.

A Decimal has the fields described in Table 3.

Table 3 – Layout of Decimal

Field

Type

Description

TypeId

NodeId

The identifier for the Decimal DataType.

Encoding

Byte

This value is always 1.

Length

Int32

The length of the Decimal.If the length is less than or equal to 0 then the Decimal value is 0.

Scale

Int16

A signed integer representing the power of ten used to scale the value.

i.e. the decimal number of the value * 10-scale

The integer is encoded starting with the least significant bit.

Value

Byte [*]

A 2-complement signed integer representing the unscaled value.

The number of bits is inferred from the length of the length field.

If the number of bits is 0 then the value is 0.

The integer is encoded with the least significant byte first.

When a Decimal is encoded in a Variant the built-in type is set to ExtensionObject. Decoders that do not understand the Decimal type shall treat it like any other unknown Structure and pass it on to the application. Decoders that do understand the Decimal can parse the value and use any construct that is suitable for the DevelopmentPlatform.

If a Decimal is embedded in another Structure then the DataTypeDefinition for the field shall specify the NodeId of the Decimal Node as the DataType. If a Server publishes an OPC Binary type description for the Structure then the type description shall set the DataType for the field to ExtensionObject.