OPC Studio User's Guide and Reference
IUADataTypeModelProvider Interface
Members 



OpcLabs.EasyOpcUA Assembly > OpcLabs.EasyOpc.UA.DataTypeModel Namespace : IUADataTypeModelProvider Interface
Provides methods to access data types in OPC UA model.
Syntax
'Declaration
 
<ComVisibleAttribute(False)>
Public Interface IUADataTypeModelProvider 
'Usage
 
Dim instance As IUADataTypeModelProvider
[ComVisible(false)]
public interface IUADataTypeModelProvider 
[ComVisible(false)]
public interface class IUADataTypeModelProvider 
Remarks

The following diagram shows the relationships between entities of IUADataTypeModelProvider, and the derivations (transitions) supported:
modelNodeDescriptor -} dataTypeId -} encodingNodeElement* (encodingNodeElement.NodeId = dataTypeEncodingId)
................................. {- dataTypeEncodingId
................................. -} dataTypeInfo
(in DataTypeDefinition model only)

The methods are designed to operate on multiple information elements at once, as this approach is more efficient. If you want to work with single elements, there are extension methods (OpcLabs.EasyOpc.UA.DataTypeModel.Extensions.IUADataTypeModelProviderExtension) for that as well.

The data type model provider typically caches the information obtained.

You can obtain the data type model provider interface (IUADataTypeModelProvider) from the OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData.DataTypeModelProvider property of the OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData service.

 

For accessing the metadata about data types in OPC UA and navigating in it, the OPC UA Complex Data extension gives you

The providers retrieve the information from the OPC server in various ways (by reading and browsing the metadata nodes). In addition, they cache the information obtained. This is very important for performance reasons, because the same metadata can be reused without having to retrieve them from the server again and again.

OPC UA data type model provider

Take following steps to get access to the OPC UA data type model provider:

  1. Get the IEasyUAClientComplexData Interface service from your EasyUAClient Class instance using the GetService Method.
  2. Using the DataTypeModelProvider Property, obtain the IUADataTypeModelProvider Interface.

When you have the IUADataTypeModelProvider Interface, you can call its methods to:

The basic methods on the IUADataTypeModelProvider Interface provide just one navigation "hop" at a time. Some of these "hops" are, however, commonly needed together, in a chain, possibly with some kind of additional simple processing. For this purpose, there are extension methods available (in the IUADataTypeModelProviderExtension Class) that make such tasks easier. With help of these methods, you can then, for example:

If you have more pieces of information to work on in the same way, it is much more efficient to process them together, in one operation. All methods on the IUADataTypeModelProvider Interface and the IUADataTypeModelProviderExtension Class therefore accept a read-only list on input, and return an array of processed element on the output. If performance is not a concern, or if you have just one piece of information to work on at a time, there are extension methods to make it easier as well. For example, instead of calling GetDataTypeIdsFromModelNodeDescriptors Method for just one node, you can use the GetDataTypeIdFromModelNodeDescriptor Method instead.

OPC UA data type dictionary provider

This chapter only applies to the data type dictionary model, i.e. the only complex type model available before OPC UA 1.04. It does not apply to the data type definition model.

Take following steps to get access to the OPC UA data type dictionary provider:

  1. Get the IEasyUAClientComplexData Interface service from your EasyUAClient Class instance using the GetService Method.
  2. Using the DataTypeDictionaryProvider Property, obtain the IUADataTypeDictionaryProvider Interface.

When you have the IUADataTypeDictionaryProvider Interface, you can call its methods to:

The basic methods on the IUADataTypeDictionaryProvider Interface provide just one navigation "hop" at a time. Some of these "hops" are, however, commonly needed together, in a chain, possibly with some kind of additional simple processing. For this purpose, there are extension methods available (in the IUADataTypeDictionaryProviderExtension Class) that make such tasks easier. With help of these methods, you can then, for example:

If you have more pieces of information to work on in the same way, it is much more efficient to process them together, in one operation. All methods on the IUADataTypeDictionaryProvider Interface and the IUADataTypeDictionaryProviderExtension Class therefore accept a read-only list on input, and return an array of processed element on the output. If performance is not a concern, or if you have just one piece of information to work on at a time, there are extension methods to make it easier as well.

OPC UA data type definition provider

This chapter only applies to the data type definition model, i.e. the complex type model available since OPC UA 1.04. It does not apply to the data type description model.

Take following steps to get access to the OPC UA data type dictionary provider:

  1. Get the IEasyUAClientComplexData Interface service from your EasyUAClient Class instance using the GetService Method.
  2. Using the DataTypeDefinitionProvider Property, obtain the IUADataTypeDefinitionProvider Interface.

When you have the IUADataTypeDefinitionProvider Interface, you can call its methods to:

If you have more pieces of information to work on in the same way, it is much more efficient to process them together, in one operation. All methods on the IUADataTypeDictionaryProvider Interface therefore accept a read-only list on input, and return an array of processed element on the output. If performance is not a concern, or if you have just one piece of information to work on at a time, there are extension methods in the IUADataTypeDefinitionProviderExtension Class to make it easier as well.

Resolving the data type

When you receive complex data in the GenericData Property of a UAGenericObject, it has its DataType Property filled in with information about the associated data type, so that you can process it as you need. But what you have not yet received the complex data from the server - maybe you are just preparing something to be written, and you want to inspect what is the data type structure for certain node or data type ID? In this case, you can use the methods on the IUADataTypeModelProvider Interface to obtain an instance of DataType Class.

The example below shows how to resolve a data type. The main work is done by the ResolveDataType Method.

.NET

// Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using Microsoft.Extensions.DependencyInjection;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.BaseLib.OperationModel.Generic;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.InformationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;

namespace UADocExamples.ComplexData._IEasyUAClientComplexData
{
    class ResolveDataType
    {
        public static void Main1()
        {
            // Define which server we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Obtain the data type ID.
            //
            // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            // attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface.
            // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract
            // data type, and the actual values are then sub-types of this base data type. This abstract data type does not
            // have any encodings associated with it and it is therefore not possible to extract its description from the
            // server. We therefore use a hard-coded data type ID for one of the sub-types in this example.
            //
            // The code to obtain the data type ID for given node would normally look like this:
            //    UANodeId dataTypeId = client.ReadDataType(
            //        endpointDescriptor,
            //        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            //
            UANodeId dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440";    // ScalarValueDataType

            // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            // operations.
            IEasyUAClientComplexData complexData = client.GetService<IEasyUAClientComplexData>();
            
            // Resolve the data type ID to the data type object, containing description of the data type.
            ValueResult<DataType> dataTypeResult = complexData.ResolveDataType(
                new UAModelNodeDescriptor(endpointDescriptor, dataTypeId), 
                UABrowseNames.DefaultBinary);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeResult.ErrorMessageBrief);
                return;
            }

            // The actual data type is in the Value property.
            // Display basic information about what we have obtained.
            Console.WriteLine(dataTypeResult.Value);

            // If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
            // specifier. In the debugger, you can view the same by displaying the private DebugView property.
            Console.WriteLine();
            Console.WriteLine("{0:V}", dataTypeResult.Value);

            // For processing the internals of the data type, refer to examples for GenericData class.


            // Example output (truncated):
            //
            //ScalarValueDataType = structured
            //
            //ScalarValueDataType = structured
            //  [BooleanValue] Boolean = primitive(System.Boolean)
            //  [ByteStringValue] ByteString = primitive(System.Byte[])
            //  [ByteValue] Byte = primitive(System.Byte)
            //  [DateTimeValue] DateTime = primitive(System.DateTime)
            //  [DoubleValue] Double = primitive(System.Double)
            //  [EnumerationValue] Int32 = primitive(System.Int32)
            //  [ExpandedNodeIdValue] ExpandedNodeId = structured
            //    [ByteString] optional ByteStringNodeId = structured
            //      [Identifier] ByteString = primitive(System.Byte[])
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [FourByte] optional FourByteNodeId = structured
            //      [Identifier] UInt16 = primitive(System.UInt16)
            //      [NamespaceIndex] Byte = primitive(System.Byte)
            //    [Guid] optional GuidNodeId = structured
            //      [Identifier] Guid = primitive(System.Guid)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [NamespaceURI] optional CharArray = primitive(System.String)
            //    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
            //    [NodeIdType] switch NodeIdType = enumeration(6)
            //      TwoByte = 0
            //      FourByte = 1
            //      Numeric = 2
            //      String = 3
            //      Guid = 4
            //      ByteString = 5
            //    [Numeric] optional NumericNodeId = structured
            //      [Identifier] UInt32 = primitive(System.UInt32)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [ServerIndex] optional UInt32 = primitive(System.UInt32)
            //    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
            //    [String] optional StringNodeId = structured
            //      [Identifier] CharArray = primitive(System.String)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [TwoByte] optional TwoByteNodeId = structured
            //      [Identifier] Byte = primitive(System.Byte)
            //  [FloatValue] Float = primitive(System.Single)
            //  [GuidValue] Guid = primitive(System.Guid)
            //  [Int16Value] Int16 = primitive(System.Int16)
            //  [Int32Value] Int32 = primitive(System.Int32)
            //  [Int64Value] Int64 = primitive(System.Int64)
            //  [Integer] Variant = structured
            //    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
            //    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            //    [ArrayLength] length optional Int32 = primitive(System.Int32)
            //    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            //    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
            //    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
        }
    }
}
' Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports Microsoft.Extensions.DependencyInjection
Imports OpcLabs.BaseLib.DataTypeModel
Imports OpcLabs.BaseLib.OperationModel.Generic
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.InformationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData

Namespace ComplexData._IEasyUAClientComplexData

    Friend Class ResolveDataType

        Public Shared Sub Main1()

            ' Define which server we will work with.
            Dim endpointDescriptor As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
            ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            ' Instantiate the client object.
            Dim client = New EasyUAClient

            ' Obtain the data type ID.
            '
            ' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            ' attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            ' server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            ' and the actual values are then sub-types of this base data type. This abstract data type does not have any
            ' encodings associated with it and it is therefore not possible to extract its description from the server.
            ' We therefore use a hard-coded data type ID for one of the sub-types in this example.
            '
            ' The code to obtain the data type ID for given node would normally look like this:
            '    UANodeId dataTypeId = client.ReadDataType(
            '        endpointDescriptor,
            '        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            '
            Dim dataTypeId As UANodeId = "nsu=http://test.org/UA/Data/ ;i=9440"  ' ScalarValueDataType

            ' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            ' operations.
            Dim complexData As IEasyUAClientComplexData = client.GetService(Of IEasyUAClientComplexData)

            ' Resolve the data type ID to the data type object, containing description of the data type.
            Dim dataTypeResult As ValueResult(Of DataType) = complexData.ResolveDataType( _
                New UAModelNodeDescriptor(endpointDescriptor, dataTypeId), _
                UABrowseNames.DefaultBinary)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeResult.ErrorMessageBrief)
                Exit Sub
            End If

            ' The actual data type is in the Value property.
            ' Display basic information about what we have obtained.
            Console.WriteLine(dataTypeResult.Value)

            ' If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
            ' specifier. In the debugger, you can view the same by displaying the private DebugView property.
            Console.WriteLine()
            Console.WriteLine("{0:V}", dataTypeResult.Value)

            ' For processing the internals of the data type, refer to examples for GenericData class.


            ' Example output (truncated):
            '
            'ScalarValueDataType = structured
            '
            'ScalarValueDataType = structured
            '  [BooleanValue] Boolean = primitive(System.Boolean)
            '  [ByteStringValue] ByteString = primitive(System.Byte[])
            '  [ByteValue] Byte = primitive(System.Byte)
            '  [DateTimeValue] DateTime = primitive(System.DateTime)
            '  [DoubleValue] Double = primitive(System.Double)
            '  [EnumerationValue] Int32 = primitive(System.Int32)
            '  [ExpandedNodeIdValue] ExpandedNodeId = structured
            '    [ByteString] optional ByteStringNodeId = structured
            '      [Identifier] ByteString = primitive(System.Byte[])
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [FourByte] optional FourByteNodeId = structured
            '      [Identifier] UInt16 = primitive(System.UInt16)
            '      [NamespaceIndex] Byte = primitive(System.Byte)
            '    [Guid] optional GuidNodeId = structured
            '      [Identifier] Guid = primitive(System.Guid)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [NamespaceURI] optional CharArray = primitive(System.String)
            '    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
            '    [NodeIdType] switch NodeIdType = enumeration(6)
            '      TwoByte = 0
            '      FourByte = 1
            '      Numeric = 2
            '      String = 3
            '      Guid = 4
            '      ByteString = 5
            '    [Numeric] optional NumericNodeId = structured
            '      [Identifier] UInt32 = primitive(System.UInt32)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [ServerIndex] optional UInt32 = primitive(System.UInt32)
            '    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
            '    [String] optional StringNodeId = structured
            '      [Identifier] CharArray = primitive(System.String)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [TwoByte] optional TwoByteNodeId = structured
            '      [Identifier] Byte = primitive(System.Byte)
            '  [FloatValue] Float = primitive(System.Single)
            '  [GuidValue] Guid = primitive(System.Guid)
            '  [Int16Value] Int16 = primitive(System.Int16)
            '  [Int32Value] Int32 = primitive(System.Int32)
            '  [Int64Value] Int64 = primitive(System.Int64)
            '  [Integer] Variant = structured
            '    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
            '    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            '    [ArrayLength] length optional Int32 = primitive(System.Int32)
            '    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            '    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
            '    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
        End Sub
    End Class
End Namespace

COM

// Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in Object Pascal (Delphi) on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-OP .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

class procedure ResolveDataType.Main;
var
  Client: _EasyUAClient;
  ComplexData: _EasyUAClientComplexData;
  DataType: _DataType;
  DataTypeId: string;
  DataTypeResult: _ValueResult;
  EncodingName: _UAQualifiedName;
  EndpointDescriptor: string;
  ModelNodeDescriptor: _UAModelNodeDescriptor;
begin
  // Define which server and node we will work with.
  EndpointDescriptor := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Obtain the data type ID.
  //
  // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
  // attribute.
  // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and
  // the actual values are then sub-types of this base data type. This abstract data type does not have any encodings
  // associated with it and it is therefore not possible to extract its description from the server. We therefore use
  // a hard-coded data type ID for one of the sub-types in this example.
  DataTypeId := 'nsu=http://test.org/UA/Data/ ;i=9440';    // ScalarValueDataType

  // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
  // operations.
  ComplexData := IInterface(Client.GetServiceByName('OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA')) as _EasyUAClientComplexData;

  // Resolve the data type ID to the data type object, containing description of the data type.
  ModelNodeDescriptor := CoUAModelNodeDescriptor.Create;
  ModelNodeDescriptor.EndpointDescriptor.UrlString := EndpointDescriptor;
  ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText := DataTypeId;
  EncodingName := CoUAQualifiedName.Create;
  EncodingName.StandardName := 'DefaultBinary';
  DataTypeResult := ComplexData.ResolveDataType(ModelNodeDescriptor, EncodingName);
  if not DataTypeResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeResult.ErrorMessageBrief]));
    Exit;
  end;

  // The actual data type is in the Value property.
  DataType := IUnknown(DataTypeResult.Value) as _DataType;

  // Display basic information about what we have obtained.
  WriteLn(DataType.ToString);

  // If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
  // specifier.
  Writeln;
  Writeln(DataType.ToString_2['V', nil]);

  // For processing the internals of the data type, refer to examples for GenericData class.


  // Example output (truncated):
  //
  //ScalarValueDataType = structured
  //
  //ScalarValueDataType = structured
  //  [BooleanValue] Boolean = primitive(System.Boolean)
  //  [ByteStringValue] ByteString = primitive(System.Byte[])
  //  [ByteValue] Byte = primitive(System.Byte)
  //  [DateTimeValue] DateTime = primitive(System.DateTime)
  //  [DoubleValue] Double = primitive(System.Double)
  //  [EnumerationValue] Int32 = primitive(System.Int32)
  //  [ExpandedNodeIdValue] ExpandedNodeId = structured
  //    [ByteString] optional ByteStringNodeId = structured
  //      [Identifier] ByteString = primitive(System.Byte[])
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [FourByte] optional FourByteNodeId = structured
  //      [Identifier] UInt16 = primitive(System.UInt16)
  //      [NamespaceIndex] Byte = primitive(System.Byte)
  //    [Guid] optional GuidNodeId = structured
  //      [Identifier] Guid = primitive(System.Guid)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [NamespaceURI] optional CharArray = primitive(System.String)
  //    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
  //    [NodeIdType] switch NodeIdType = enumeration(6)
  //      TwoByte = 0
  //      FourByte = 1
  //      Numeric = 2
  //      String = 3
  //      Guid = 4
  //      ByteString = 5
  //    [Numeric] optional NumericNodeId = structured
  //      [Identifier] UInt32 = primitive(System.UInt32)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [ServerIndex] optional UInt32 = primitive(System.UInt32)
  //    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
  //    [String] optional StringNodeId = structured
  //      [Identifier] CharArray = primitive(System.String)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [TwoByte] optional TwoByteNodeId = structured
  //      [Identifier] Byte = primitive(System.Byte)
  //  [FloatValue] Float = primitive(System.Single)
  //  [GuidValue] Guid = primitive(System.Guid)
  //  [Int16Value] Int16 = primitive(System.Int16)
  //  [Int32Value] Int32 = primitive(System.Int32)
  //  [Int64Value] Int64 = primitive(System.Int64)
  //  [Integer] Variant = structured
  //    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
  //    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
  //    [ArrayLength] length optional Int32 = primitive(System.Int32)
  //    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
  //    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
  //    [Byte] optional sequence[*] of Byte = primitive(System.Byte)

end;
Rem Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
Rem
Rem Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
Rem OPC client and subscriber examples in VBScript on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBScript .
Rem Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
Rem a commercial license in order to use Online Forums, and we reply to every post.

Option Explicit

' Define which server we will work with.
Dim endpointDescriptor: endpointDescriptor = _
    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
    '"http://opcua.demo-this.com:51211/UA/SampleServer"  
    '"https://opcua.demo-this.com:51212/UA/SampleServer/"

' Instantiate the client object.
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")

' Obtain the data type ID.
'
' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
' attribute. 
' The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and 
' the actual values are then sub-types of this base data type. This abstract data type does not have any encodings 
' associated with it and it is therefore not possible to extract its description from the server. We therefore use 
' a hard-coded data type ID for one of the sub-types in this example.
Dim dataTypeId: dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440"    ' ScalarValueDataType

' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
' operations.
Dim ComplexData: Set ComplexData = _
    Client.GetServiceByName("OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA")

' Resolve the data type ID to the data type object, containing description of the data type.
Dim ModelNodeDescriptor: Set ModelNodeDescriptor = CreateObject("OpcLabs.EasyOpc.UA.InformationModel.UAModelNodeDescriptor")
ModelNodeDescriptor.EndpointDescriptor.UrlString = endpointDescriptor
ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText = dataTypeId
Dim EncodingName: Set EncodingName = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UAQualifiedName")
EncodingName.StandardName = "DefaultBinary"
Dim DataTypeResult: Set DataTypeResult = ComplexData.ResolveDataType(ModelNodeDescriptor, EncodingName)
If Not DataTypeResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeResult.Exception.GetBaseException().Message
    WScript.Quit
End If

' The actual data type is in the Value property.
Dim DataType: Set DataType = DataTypeResult.Value

' Display basic information about what we have obtained.
WScript.Echo DataType

' If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
' specifier. 
WScript.Echo
WScript.Echo DataType.ToString_2("V", Nothing)

' For processing the internals of the data type, refer to examples for GenericData class.


' Example output (truncated):
'
'ScalarValueDataType = structured
'
'ScalarValueDataType = structured
'  [BooleanValue] Boolean = primitive(System.Boolean)
'  [ByteStringValue] ByteString = primitive(System.Byte[])
'  [ByteValue] Byte = primitive(System.Byte)
'  [DateTimeValue] DateTime = primitive(System.DateTime)
'  [DoubleValue] Double = primitive(System.Double)
'  [EnumerationValue] Int32 = primitive(System.Int32)
'  [ExpandedNodeIdValue] ExpandedNodeId = structured
'    [ByteString] optional ByteStringNodeId = structured
'      [Identifier] ByteString = primitive(System.Byte[])
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [FourByte] optional FourByteNodeId = structured
'      [Identifier] UInt16 = primitive(System.UInt16)
'      [NamespaceIndex] Byte = primitive(System.Byte)
'    [Guid] optional GuidNodeId = structured
'      [Identifier] Guid = primitive(System.Guid)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [NamespaceURI] optional CharArray = primitive(System.String)
'    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
'    [NodeIdType] switch NodeIdType = enumeration(6)
'      TwoByte = 0
'      FourByte = 1
'      Numeric = 2
'      String = 3
'      Guid = 4
'      ByteString = 5
'    [Numeric] optional NumericNodeId = structured
'      [Identifier] UInt32 = primitive(System.UInt32)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [ServerIndex] optional UInt32 = primitive(System.UInt32)
'    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
'    [String] optional StringNodeId = structured
'      [Identifier] CharArray = primitive(System.String)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [TwoByte] optional TwoByteNodeId = structured
'      [Identifier] Byte = primitive(System.Byte)
'  [FloatValue] Float = primitive(System.Single)
'  [GuidValue] Guid = primitive(System.Guid)
'  [Int16Value] Int16 = primitive(System.Int16)
'  [Int32Value] Int32 = primitive(System.Int32)
'  [Int64Value] Int64 = primitive(System.Int64)
'  [Integer] Variant = structured
'    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
'    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
'    [ArrayLength] length optional Int32 = primitive(System.Int32)
'    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
'    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
'    [Byte] optional sequence[*] of Byte = primitive(System.Byte)

Python

# Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
# a commercial license in order to use Online Forums, and we reply to every post.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from Microsoft.Extensions.DependencyInjection import *
from System import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.AddressSpace import *
from OpcLabs.EasyOpc.UA.AddressSpace.Standard import *
#from OpcLabs.EasyOpc.UA.Extensions import *
from OpcLabs.EasyOpc.UA.InformationModel import *
from OpcLabs.EasyOpc.UA.Plugins.ComplexData import *


endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'

# Instantiate the client object.
client = EasyUAClient()

# Obtain the data type ID.
#
# In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
# attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface.
# The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract
# data type, and the actual values are then sub-types of this base data type. This abstract data type does not
# have any encodings associated with it and it is therefore not possible to extract its description from the
# server. We therefore use a hard-coded data type ID for one of the sub-types in this example.
#
# The code to obtain the data type ID for given node would normally look like this:
#    dataTypeId = IEasyUAClientExtension2.ReadDataType(client,
#        endpointDescriptor,
#        UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10239'))    # [ObjectsFolder]/Data.Static.Scalar.StructureValue
dataTypeId = UANodeId('nsu=http://test.org/UA/Data/ ;i=9440')   # ScalarValueDataType

# Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
# operations.
complexData = ServiceProviderServiceExtensions.GetService[IEasyUAClientComplexData](client)
if complexData is None:
    print('The client complex data service is not available.')
    exit()

# Resolve the data type ID to the data type object, containing description of the data type.
dataTypeResult = IEasyUAClientComplexDataExtension.ResolveDataType(complexData,
    UAModelNodeDescriptor(endpointDescriptor, UANodeDescriptor(dataTypeId)),
    UABrowseNames.DefaultBinary)
# Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
if not dataTypeResult.Succeeded:
    print('*** Failure: ', dataTypeResult.ErrorMessageBrief)
    exit()

# The actual data type is in the Value property.
# Display basic information about what we have obtained.
print(dataTypeResult.Value)

# If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
# specifier. In the debugger, you can view the same by displaying the private DebugView property.
print()
print(String.Format('{0:V}', dataTypeResult.Value))

# For processing the internals of the data type, refer to examples for GenericData class.

print()
print('Finished.')

 

Obtaining content of the data type dictionary

You may sometimes need to view the actual content of the data type dictionary that resides in the OPC server. In itself, this is easy: The data type dictionary is in a node, so you just read the node. But, how do you find out which node to read? Here is where the IUADataTypeModelProvider Interface or the IUADataTypeDictionaryProvider Interface can help. They have methods to navigate from the node you want to access (read, write, or subscribe to) to the data type dictionary. Or, they have similar methods if you know the data type ID of the data type you are interested in. The example below shows the steps necessary.

.NET

// Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
// content of the data type dictionary.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using OpcLabs.BaseLib.OperationModel.Generic;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.DataTypeModel;
using OpcLabs.EasyOpc.UA.DataTypeModel.Extensions;
using OpcLabs.EasyOpc.UA.InformationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;

namespace UADocExamples.ComplexData._IUADataTypeDictionaryProvider
{
    class ResolveDataTypeDescriptorFromDataTypeEncodingId
    {
        public static void Main1()
        {
            // Define which server we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Obtain the data type ID.
            //
            // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            // attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            // server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            // and the actual values are then sub-types of this base data type. This abstract data type does not have any
            // encodings associated with it and it is therefore not possible to extract its description from the server.
            // We therefore use a hard-coded data type ID for one of the sub-types in this example.
            //
            // The code to obtain the data type ID for given node would normally look like this:
            //    UANodeId dataTypeId = client.ReadDataType(
            //        endpointUriString,
            //        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            //
            UANodeId dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440";    // ScalarValueDataType

            // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            // operations.
            IEasyUAClientComplexData complexData = client.GetService<IEasyUAClientComplexData>();

            // Get the data type model provider. Provides methods to access data types in OPC UA model.
            IUADataTypeModelProvider dataTypeModelProvider = complexData.DataTypeModelProvider;

            // Resolve the data type ID from our data type ID, for encoding name "Default Binary".
            ValueResult<UAModelNodeDescriptor> encodingIdResult = dataTypeModelProvider.ResolveEncodingIdFromDataTypeId(
                new UAModelNodeDescriptor(endpointDescriptor, dataTypeId),
                UABrowseNames.DefaultBinary);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!encodingIdResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", encodingIdResult.ErrorMessageBrief);
                return;
            }
            UAModelNodeDescriptor encodingId = encodingIdResult.Value;

            // Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
            IUADataTypeDictionaryProvider dataTypeDictionaryProvider = complexData.DataTypeDictionaryProvider;

            // Resolve the data type descriptor from the encoding ID.
            ValueResult<UADataTypeDescriptor> dataTypeDescriptorResult =
                dataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(encodingId);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeDescriptorResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeDescriptorResult.ErrorMessageBrief);
                return;
            }
            UADataTypeDescriptor dataTypeDescriptor = dataTypeDescriptorResult.Value;

            // The data type descriptor contains two pieces of information:
            // The data type dictionary ID: This determines the dictionary where the data type is defined.
            Console.WriteLine(dataTypeDescriptor.DataTypeDictionaryId);
            // And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific 
            // type definition inside the data type dictionary. The format of it depends on the data type system;
            // in our case, it is a string that is the name of one of the type elements in the XML document of the data type
            // dictionary.
            Console.WriteLine(dataTypeDescriptor.DataTypeDescription);

            // Obtain the actual content of the data type dictionary.
            ValueResult<byte[]> dataTypeDictionaryResult =
                dataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(dataTypeDescriptor.DataTypeDictionaryId);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeDictionaryResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeDictionaryResult.ErrorMessageBrief);
                return;
            }
            byte[] dataTypeDictionary = dataTypeDictionaryResult.Value;

            // The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type 
            // system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
            string text = Encoding.UTF8.GetString(dataTypeDictionary);
            Console.WriteLine();
            Console.WriteLine(text);


            // Example output (truncated):
            //
            //http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http://test.org/UA/Data/ ;ns=2;i=11422"
            //ScalarValueDataType
            //
            //<opc:TypeDictionary
            //  xmlns:opc="http://opcfoundation.org/BinarySchema/"
            //  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            //  xmlns:ua="http://opcfoundation.org/UA/"
            //  xmlns:tns="http://test.org/UA/Data/"
            //  DefaultByteOrder="LittleEndian"
            //  TargetNamespace="http://test.org/UA/Data/"
            //>
            //  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
            //  <opc:Import Namespace="http://opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
            //
            //  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
            //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
            //    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
            //    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
            //    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
            //    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
            //    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
            //    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
            //    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
            //    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
            //    <opc:Field Name="FloatValue" TypeName="opc:Float" />
            //    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
            //    <opc:Field Name="StringValue" TypeName="opc:String" />
            //    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
            //    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
            //    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
            //    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
            //    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
            //    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
            //    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
            //    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
            //    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
            //    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
            //    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
            //    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
            //    <opc:Field Name="Number" TypeName="ua:Variant" />
            //    <opc:Field Name="Integer" TypeName="ua:Variant" />
            //    <opc:Field Name="UInteger" TypeName="ua:Variant" />
            //  </opc:StructuredType>
            //
            //  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
            //    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
            //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
            //    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />
        }
    }
}
' Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
' content of the data type dictionary.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports System.Text
Imports Microsoft.Extensions.DependencyInjection
Imports OpcLabs.BaseLib.OperationModel.Generic
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.DataTypeModel
Imports OpcLabs.EasyOpc.UA.DataTypeModel.Extensions
Imports OpcLabs.EasyOpc.UA.InformationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData

Namespace ComplexData._IUADataTypeDictionaryProvider

    Friend Class ResolveDataTypeDescriptorFromDataTypeEncodingId

        Public Shared Sub Main1()

            ' Define which server we will work with.
            Dim endpointDescriptor As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
            ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            ' Instantiate the client object.
            Dim client = New EasyUAClient

            ' Obtain the data type ID.
            '
            ' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            ' attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            ' server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            ' and the actual values are then sub-types of this base data type. This abstract data type does not have any
            ' encodings associated with it and it is therefore not possible to extract its description from the server.
            ' We therefore use a hard-coded data type ID for one of the sub-types in this example.
            '
            ' The code to obtain the data type ID for given node would normally look like this:
            '    UANodeId dataTypeId = client.ReadDataType(
            '        endpointUriString,
            '        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            '
            Dim dataTypeId As UANodeId = "nsu=http://test.org/UA/Data/ ;i=9440"  ' ScalarValueDataType

            ' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            ' operations.
            Dim complexData As IEasyUAClientComplexData = client.GetService(Of IEasyUAClientComplexData)

            ' Get the data type model provider. Provides methods to access data types in OPC UA model.
            Dim dataTypeModelProvider As IUADataTypeModelProvider = complexData.DataTypeModelProvider

            ' Resolve the data type ID from our data type ID, for encoding name "Default Binary".
            Dim encodingIdResult As ValueResult(Of UAModelNodeDescriptor) = dataTypeModelProvider.ResolveEncodingIdFromDataTypeId(
                New UAModelNodeDescriptor(endpointDescriptor, dataTypeId),
                UABrowseNames.DefaultBinary)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not encodingIdResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", encodingIdResult.ErrorMessageBrief)
                Exit Sub
            End If
            Dim encodingId As UAModelNodeDescriptor = encodingIdResult.Value

            ' Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
            Dim dataTypeDictionaryProvider As IUADataTypeDictionaryProvider = complexData.DataTypeDictionaryProvider

            ' Resolve the data type descriptor from the encoding ID.
            Dim dataTypeDescriptorResult As ValueResult(Of UADataTypeDescriptor) =
                    dataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(encodingId)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeDescriptorResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeDescriptorResult.ErrorMessageBrief)
                Exit Sub
            End If
            Dim dataTypeDescriptor As UADataTypeDescriptor = dataTypeDescriptorResult.Value

            ' The data type descriptor contains two pieces of information:
            ' The data type dictionary ID: This determines the dictionary where the data type is defined.
            Console.WriteLine(dataTypeDescriptor.DataTypeDictionaryId)
            ' And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific 
            ' type definition inside the data type dictionary. The format of it depends on the data type system;
            ' in our case, it is a string that is the name of one of the type elements in the XML document of the data type
            ' dictionary.
            Console.WriteLine(dataTypeDescriptor.DataTypeDescription)

            ' Obtain the actual content of the data type dictionary.
            Dim dataTypeDictionaryResult As ValueResult(Of Byte()) =
                    dataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(dataTypeDescriptor.DataTypeDictionaryId)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeDictionaryResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeDictionaryResult.ErrorMessageBrief)
                Exit Sub
            End If
            Dim dataTypeDictionary() As Byte = dataTypeDictionaryResult.Value

            ' The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type 
            ' system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
            Dim text As String = Encoding.UTF8.GetString(dataTypeDictionary)
            Console.WriteLine()
            Console.WriteLine(text)


            ' Example output (truncated):
            '
            'http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http://test.org/UA/Data/ ;ns=2;i=11422"
            'ScalarValueDataType
            '
            '<opc:TypeDictionary
            '  xmlns:opc="http://opcfoundation.org/BinarySchema/"
            '  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            '  xmlns:ua="http://opcfoundation.org/UA/"
            '  xmlns:tns="http://test.org/UA/Data/"
            '  DefaultByteOrder="LittleEndian"
            '  TargetNamespace="http://test.org/UA/Data/"
            '>
            '  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
            '  <opc:Import Namespace="http://opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
            '
            '  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
            '    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
            '    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
            '    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
            '    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
            '    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
            '    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
            '    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
            '    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
            '    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
            '    <opc:Field Name="FloatValue" TypeName="opc:Float" />
            '    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
            '    <opc:Field Name="StringValue" TypeName="opc:String" />
            '    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
            '    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
            '    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
            '    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
            '    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
            '    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
            '    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
            '    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
            '    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
            '    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
            '    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
            '    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
            '    <opc:Field Name="Number" TypeName="ua:Variant" />
            '    <opc:Field Name="Integer" TypeName="ua:Variant" />
            '    <opc:Field Name="UInteger" TypeName="ua:Variant" />
            '  </opc:StructuredType>
            '
            '  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
            '    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
            '    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
            '    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />
        End Sub
    End Class
End Namespace

COM

// Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
// content of the data type dictionary.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in Object Pascal (Delphi) on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-OP .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

class procedure ResolveDataTypeDescriptorFromDataTypeEncodingId.Main;
var
  Client: _EasyUAClient;
  ComplexData: _EasyUAClientComplexData;
  DataTypeDictionary: OleVariant;
  DataTypeDictionaryResult: _ValueResult;
  DataTypeDescriptor: _UADataTypeDescriptor;
  DataTypeDescriptorResult: _ValueResult;
  DataTypeId: string;
  DataTypeModelProvider: _UADataTypeModelProvider;
  DataTypeDictionaryProvider: _UADataTypeDictionaryProvider;
  EncodingId: _UAModelNodeDescriptor;
  EncodingIdResult: _ValueResult;
  EncodingName: _UAQualifiedName;
  EndpointDescriptor: string;
  I: Cardinal;
  ModelNodeDescriptor: _UAModelNodeDescriptor;
  Text: string;
begin
  // Define which server and node we will work with.
  EndpointDescriptor :=
    'http://opcua.demo-this.com:51211/UA/SampleServer';
    //or 'https://opcua.demo-this.com:51212/UA/SampleServer/';
    //or 'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Obtain the data type ID.
  //
  // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
  // attribute.
  // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and
  // the actual values are then sub-types of this base data type. This abstract data type does not have any encodings
  // associated with it and it is therefore not possible to extract its description from the server. We therefore use
  // a hard-coded data type ID for one of the sub-types in this example.
  DataTypeId := 'nsu=http://test.org/UA/Data/ ;i=9440';    // ScalarValueDataType

  // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
  // operations.
  ComplexData := IInterface(Client.GetServiceByName('OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA')) as _EasyUAClientComplexData;

  // Get the data type model provider. Provides methods to access data types in OPC UA model.
  DataTypeModelProvider := ComplexData.DataTypeModelProvider;

  // Resolve the data type ID from our data type ID, for encoding name "Default Binary".
  ModelNodeDescriptor := CoUAModelNodeDescriptor.Create;
  ModelNodeDescriptor.EndpointDescriptor.UrlString := EndpointDescriptor;
  ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText := DataTypeId;
  EncodingName := CoUAQualifiedName.Create;
  EncodingName.StandardName := 'DefaultBinary';
  EncodingIdResult := DataTypeModelProvider.ResolveEncodingIdFromDataTypeId(ModelNodeDescriptor, EncodingName);
  // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
  if not EncodingIdResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [EncodingIdResult.ErrorMessageBrief]));
    Exit;
  end;
  EncodingId := IUnknown(EncodingIdResult.Value) as _UAModelNodeDescriptor;

  // Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
  DataTypeDictionaryProvider := ComplexData.DataTypeDictionaryProvider;

  // Resolve the data type descriptor from the encoding ID.
  DataTypeDescriptorResult := DataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(EncodingId);
  // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
  if not DataTypeDescriptorResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeDescriptorResult.ErrorMessageBrief]));
    Exit;
  end;
  DataTypeDescriptor := IUnknown(DataTypeDescriptorResult.Value) as _UADataTypeDescriptor;

  // The data type descriptor contains two pieces of information:
  // The data type dictionary ID: This determines the dictionary where the data type is defined.
  WriteLn(DataTypeDescriptor.DataTypeDictionaryId.ToString);
  // And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific
  // type definition inside the data type dictionary. The format of it depends on the data type system;
  // in our case, it is a string that is the name of one of the type elements in the XML document of the data type
  // dictionary.
  WriteLn(DataTypeDescriptor.DataTypeDescription);

  // Obtain the actual content of the data type dictionary.
  DataTypeDictionaryResult :=
    DataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(DataTypeDescriptor.DataTypeDictionaryId);
  // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
  if not DataTypeDictionaryResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeDictionaryResult.ErrorMessageBrief]));
    Exit;
  end;
  DataTypeDictionary := DataTypeDictionaryResult.Value;

  // The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type
  // system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
  for I := VarArrayLowBound(DataTypeDictionary, 1) to VarArrayHighBound(DataTypeDictionary, 1) do
  begin
      Text := Text + Chr(Byte(DataTypeDictionary[I]));
  end;

  WriteLn;
  WriteLn(Text);

  // Example output (truncated):
  //
  //http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http://test.org/UA/Data/ ;ns=2;i=11422"
  //ScalarValueDataType
  //
  //<opc:TypeDictionary
  //  xmlns:opc="http://opcfoundation.org/BinarySchema/"
  //  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  //  xmlns:ua="http://opcfoundation.org/UA/"
  //  xmlns:tns="http://test.org/UA/Data/"
  //  DefaultByteOrder="LittleEndian"
  //  TargetNamespace="http://test.org/UA/Data/"
  //>
  //  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
  //  <opc:Import Namespace="http://opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
  //
  //  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
  //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
  //    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
  //    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
  //    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
  //    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
  //    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
  //    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
  //    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
  //    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
  //    <opc:Field Name="FloatValue" TypeName="opc:Float" />
  //    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
  //    <opc:Field Name="StringValue" TypeName="opc:String" />
  //    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
  //    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
  //    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
  //    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
  //    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
  //    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
  //    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
  //    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
  //    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
  //    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
  //    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
  //    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
  //    <opc:Field Name="Number" TypeName="ua:Variant" />
  //    <opc:Field Name="Integer" TypeName="ua:Variant" />
  //    <opc:Field Name="UInteger" TypeName="ua:Variant" />
  //  </opc:StructuredType>
  //
  //  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
  //    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
  //    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
  //    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />

end;
Rem Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the actual
Rem content of the data type dictionary.
Rem
Rem Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
Rem OPC client and subscriber examples in VBScript on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBScript .
Rem Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
Rem a commercial license in order to use Online Forums, and we reply to every post.

Option Explicit

' Define which server we will work with.
Dim endpointDescriptor: endpointDescriptor = _
    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
    '"http://opcua.demo-this.com:51211/UA/SampleServer"  
    '"https://opcua.demo-this.com:51212/UA/SampleServer/"

' Instantiate the client object.
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")

' Obtain the data type ID.
'
' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
' attribute. 
' The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and 
' the actual values are then sub-types of this base data type. This abstract data type does not have any encodings 
' associated with it and it is therefore not possible to extract its description from the server. We therefore use 
' a hard-coded data type ID for one of the sub-types in this example.
Dim dataTypeId: dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440"    ' ScalarValueDataType

' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
' operations.
Dim ComplexData: Set ComplexData = _
    Client.GetServiceByName("OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA")

' Get the data type model provider. Provides methods to access data types in OPC UA model.
Dim DataTypeModelProvider: Set DataTypeModelProvider = ComplexData.DataTypeModelProvider

' Resolve the data type ID from our data type ID, for encoding name "Default Binary".
Dim ModelNodeDescriptor: Set ModelNodeDescriptor = CreateObject("OpcLabs.EasyOpc.UA.InformationModel.UAModelNodeDescriptor")
ModelNodeDescriptor.EndpointDescriptor.UrlString = endpointDescriptor
ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText = dataTypeId
Dim EncodingName: Set EncodingName = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UAQualifiedName")
EncodingName.StandardName = "DefaultBinary"
Dim EncodingIdResult: Set EncodingIdResult = _
    DataTypeModelProvider.ResolveEncodingIdFromDataTypeId(ModelNodeDescriptor, EncodingName)
' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
If Not EncodingIdResult.Succeeded Then
    WScript.Echo "*** Failure: "  & EncodingIdResult.Exception.GetBaseException().Message
    WScript.Quit
End If
Dim EncodingId: Set EncodingId = EncodingIdResult.Value

' Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
Dim DataTypeDictionaryProvider: Set DataTypeDictionaryProvider = ComplexData.DataTypeDictionaryProvider

' Resolve the data type descriptor from the encoding ID.
Dim DataTypeDescriptorResult: Set DataTypeDescriptorResult = _
    DataTypeDictionaryProvider.ResolveDataTypeDescriptorFromDataTypeEncodingId(EncodingId)
' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
If Not DataTypeDescriptorResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeDescriptorResult.Exception.GetBaseException().Message
    WScript.Quit
End If
Dim DataTypeDescriptor: Set DataTypeDescriptor = DataTypeDescriptorResult.Value

' The data type descriptor contains two pieces of information:
' The data type dictionary ID: This determines the dictionary where the data type is defined.
WScript.Echo DataTypeDescriptor.DataTypeDictionaryId
' And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific 
' type definition inside the data type dictionary. The format of it depends on the data type system;
' in our case, it is a string that is the name of one of the type elements in the XML document of the data type
' dictionary.
WScript.Echo DataTypeDescriptor.DataTypeDescription

' Obtain the actual content of the data type dictionary.
Dim DataTypeDictionaryResult: Set DataTypeDictionaryResult = _
    DataTypeDictionaryProvider.GetDataTypeDictionaryFromDataTypeDictionaryId(DataTypeDescriptor.DataTypeDictionaryId)
' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
If Not DataTypeDictionaryResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeDictionaryResult.Exception.GetBaseException().Message
    WScript.Quit
End If
Dim DataTypeDictionary: DataTypeDictionary = DataTypeDictionaryResult.Value

' The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type 
' system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
Dim text
Dim i: For i = LBound(DataTypeDictionary) To UBound(DataTypeDictionary)
    text = text & Chr(DataTypeDictionary(i))
Next
WScript.Echo
WScript.Echo text


' Example output (truncated):
'
'http://opcua.demo-this.com:51211/UA/SampleServer; NodeId="nsu=http:'test.org/UA/Data/;ns=2;i=11422"
'ScalarValueDataType
'
'<opc:TypeDictionary
'  xmlns:opc="http:'opcfoundation.org/BinarySchema/"
'  xmlns:xsi="http:'www.w3.org/2001/XMLSchema-instance"
'  xmlns:ua="http:'opcfoundation.org/UA/"
'  xmlns:tns="http:'test.org/UA/Data/"
'  DefaultByteOrder="LittleEndian"
'  TargetNamespace="http:'test.org/UA/Data/"
'>
'  <!-- This File was generated on 2013-01-22 and supports the specifications supported by version 1.1.334.0 of the OPC UA deliverables. -->
'  <opc:Import Namespace="http:'opcfoundation.org/UA/" Location="Opc.Ua.BinarySchema.bsd"/>
'
'  <opc:StructuredType Name="ScalarValueDataType" BaseType="ua:ExtensionObject">
'    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" />
'    <opc:Field Name="SByteValue" TypeName="opc:SByte" />
'    <opc:Field Name="ByteValue" TypeName="opc:Byte" />
'    <opc:Field Name="Int16Value" TypeName="opc:Int16" />
'    <opc:Field Name="UInt16Value" TypeName="opc:UInt16" />
'    <opc:Field Name="Int32Value" TypeName="opc:Int32" />
'    <opc:Field Name="UInt32Value" TypeName="opc:UInt32" />
'    <opc:Field Name="Int64Value" TypeName="opc:Int64" />
'    <opc:Field Name="UInt64Value" TypeName="opc:UInt64" />
'    <opc:Field Name="FloatValue" TypeName="opc:Float" />
'    <opc:Field Name="DoubleValue" TypeName="opc:Double" />
'    <opc:Field Name="StringValue" TypeName="opc:String" />
'    <opc:Field Name="DateTimeValue" TypeName="opc:DateTime" />
'    <opc:Field Name="GuidValue" TypeName="opc:Guid" />
'    <opc:Field Name="ByteStringValue" TypeName="opc:ByteString" />
'    <opc:Field Name="XmlElementValue" TypeName="ua:XmlElement" />
'    <opc:Field Name="NodeIdValue" TypeName="ua:NodeId" />
'    <opc:Field Name="ExpandedNodeIdValue" TypeName="ua:ExpandedNodeId" />
'    <opc:Field Name="QualifiedNameValue" TypeName="ua:QualifiedName" />
'    <opc:Field Name="LocalizedTextValue" TypeName="ua:LocalizedText" />
'    <opc:Field Name="StatusCodeValue" TypeName="ua:StatusCode" />
'    <opc:Field Name="VariantValue" TypeName="ua:Variant" />
'    <opc:Field Name="EnumerationValue" TypeName="ua:Int32" />
'    <opc:Field Name="StructureValue" TypeName="ua:ExtensionObject" />
'    <opc:Field Name="Number" TypeName="ua:Variant" />
'    <opc:Field Name="Integer" TypeName="ua:Variant" />
'    <opc:Field Name="UInteger" TypeName="ua:Variant" />
'  </opc:StructuredType>
'
'  <opc:StructuredType Name="ArrayValueDataType" BaseType="ua:ExtensionObject">
'    <opc:Field Name="NoOfBooleanValue" TypeName="opc:Int32" />
'    <opc:Field Name="BooleanValue" TypeName="opc:Boolean" LengthField="NoOfBooleanValue" />
'    <opc:Field Name="NoOfSByteValue" TypeName="opc:Int32" />

Python

# Shows how to obtain data type description object for complex data node with OPC UA Complex Data plug-in, and the
# actual content of the data type dictionary.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
# a commercial license in order to use Online Forums, and we reply to every post.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from Microsoft.Extensions.DependencyInjection import *
from System import *
from System.Text import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.AddressSpace import *
from OpcLabs.EasyOpc.UA.AddressSpace.Standard import *
from OpcLabs.EasyOpc.UA.DataTypeModel.Extensions import *
#from OpcLabs.EasyOpc.UA.Extensions import *
from OpcLabs.EasyOpc.UA.InformationModel import *
from OpcLabs.EasyOpc.UA.Plugins.ComplexData import *


endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'

# Instantiate the client object.
client = EasyUAClient()

# Obtain the data type ID.
#
# In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
# attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface.
# The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract
# data type, and the actual values are then sub-types of this base data type. This abstract data type does not
# have any encodings associated with it and it is therefore not possible to extract its description from the
# server. We therefore use a hard-coded data type ID for one of the sub-types in this example.
#
# The code to obtain the data type ID for given node would normally look like this:
#    dataTypeId = IEasyUAClientExtension2.ReadDataType(client,
#        endpointDescriptor,
#        UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10239'))    # [ObjectsFolder]/Data.Static.Scalar.StructureValue
dataTypeId = UANodeId('nsu=http://test.org/UA/Data/ ;i=9440')   # ScalarValueDataType

# Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
# operations.
complexData = ServiceProviderServiceExtensions.GetService[IEasyUAClientComplexData](client)
if complexData is None:
    print('The client complex data service is not available.')
    exit()

# Get the data type model provider. Provides methods to access data types in OPC UA model.
dataTypeModelProvider = complexData.DataTypeModelProvider

# Resolve the data type ID from our data type ID, for encoding name "Default Binary".
encodingIdResult = IUADataTypeModelProviderExtension.ResolveEncodingIdFromDataTypeId(dataTypeModelProvider,
    UAModelNodeDescriptor(endpointDescriptor, UANodeDescriptor(dataTypeId)),
    UABrowseNames.DefaultBinary)
# Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
if not encodingIdResult.Succeeded:
    print('*** Failure: ', encodingIdResult.ErrorMessageBrief)
    exit()
encodingId = encodingIdResult.Value

# Get the data type dictionary provider. Provides methods to access data type dictionaries in OPC UA model.
dataTypeDictionaryProvider = complexData.DataTypeDictionaryProvider

# Resolve the data type descriptor from the encoding ID.
dataTypeDescriptorResult = IUADataTypeDictionaryProviderExtension.ResolveDataTypeDescriptorFromDataTypeEncodingId(
    dataTypeDictionaryProvider, encodingId)
# Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
if not dataTypeDescriptorResult.Succeeded:
    print('*** Failure: ', dataTypeDescriptorResult.ErrorMessageBrief)
    exit()
dataTypeDescriptor = dataTypeDescriptorResult.Value

# The data type descriptor contains two pieces of information:
# The data type dictionary ID: This determines the dictionary where the data type is defined.
print(dataTypeDescriptor.DataTypeDictionaryId)
# And the data type description: It is a "pointer" into the data type dictionary itself, selecting a specific
# type definition inside the data type dictionary. The format of it depends on the data type system;
# in our case, it is a string that is the name of one of the type elements in the XML document of the data type
# dictionary.
print(dataTypeDescriptor.DataTypeDescription)

# Obtain the actual content of the data type dictionary.
dataTypeDictionaryResult = IUADataTypeDictionaryProviderExtension.GetDataTypeDictionaryFromDataTypeDictionaryId(
    dataTypeDictionaryProvider, dataTypeDescriptor.DataTypeDictionaryId)
# Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
if not dataTypeDictionaryResult.Succeeded:
    print('*** Failure: ', dataTypeDictionaryResult.ErrorMessageBrief)
    exit()
dataTypeDictionary = dataTypeDictionaryResult.Value

# The data type dictionary returned is an array of bytes; its syntax and semantics depends on the data type
# system. In our case, we know that the data type dictionary is actually a string encoded in UTF-8.
text = Encoding.UTF8.GetString(dataTypeDictionary)
print()
print(text)

print()
print('Finished.')

 

 

 

Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2016, Windows Server 2022; .NET: Linux, macOS, Microsoft Windows

See Also