OPC UA Servers shall provide type definitions for Objects and Variables. The HasTypeDefinition Reference shall be used to link an instance with its type definition represented by a TypeDefinitionNode. Type definitions are required; however, OPC 10000-5 defines a BaseObjectType, a PropertyType, and a BaseDataVariableType so a Server can use such a base type if no more specialised type information is available. Objects and Variables inherit the Attributes specified by their TypeDefinitionNode (see 6.4 for details).
In some cases, the NodeId used by the HasTypeDefinition Reference will be well-known to Clients and Servers. Organizations may define TypeDefinitionNodes that are well-known in the industry. Well-known NodeIds of TypeDefinitionNodes provide for commonality across OPC UA Servers and allow Clients to interpret the TypeDefinitionNode without having to read it from the Server. Therefore, Servers may use well-known NodeIds without representing the corresponding TypeDefinitionNodes in their AddressSpace. However, the TypeDefinitionNodes shall be provided for generic Clients. These TypeDefinitionNodes may exist in another Server.
The following example, illustrated in Figure 5, describes the use of the HasTypeDefinition Reference. In this example, a setpoint parameter “SP” is represented as a DataVariable in the AddressSpace. This DataVariable is part of an Object not shown in the figure.
To provide for a common setpoint definition that can be used by other Objects, a specialised VariableType is used. Each setpoint DataVariable that uses this common definition will have a HasTypeDefinition Reference that identifies the common “SetPoint” VariableType.
Figure 5 – Example of a Variable defined by a VariableType
TypeDefinitionNodes can be complex. A complex TypeDefinitionNode also defines References to other Nodes as part of the type definition. The ModellingRules defined in 6.4.4 specify how those Nodes are handled when creating an instance of the type definition.
A TypeDefinitionNode references instances instead of other TypeDefinitionNodes to allow unique names for several instances of the same type, to define default values and to add References for those instances that are specific to this complex TypeDefinitionNode and not to the TypeDefinitionNode of the instance. For example, in Figure 6 the ObjectType “AI_BLK_TYPE”, representing a function block, has a HasComponent Reference to a Variable “SP” of the VariableType “SetPoint”. “AI_BLK_TYPE” could have an additional setpoint Variable of the same type using a different name. It could add a Property to the Variable that was not defined by its TypeDefinitionNode “SetPoint”. And it could define a default value for “SP”, that is, each instance of “AI_BLK_TYPE” would have a Variable “SP” initially set to this value.
Figure 6 – Example of a Complex TypeDefinition
This approach is commonly used in object-oriented programming languages in which the variables of a class are defined as instances of other classes. When the class is instantiated, each variable is also instantiated, but with the default values (constructor values) defined for the containing class. That is, typically, the constructor for the component class runs first, followed by the constructor for the containing class. The constructor for the containing class may override component values set by the component class.
To distinguish instances used for the type definitions from instances that represent real data, those instances are called InstanceDeclarations. However, this term is used to simplify this specification, if an instance is an InstanceDeclaration or not is only visible in the AddressSpace by following its References. Some instances may be shared and therefore referenced by TypeDefinitionNodes, InstanceDeclarations and instances. This is similar to class variables in object-oriented programming languages.
This standard allows subtyping of type definitions. The subtyping rules are defined in Clause 6. Subtyping of ObjectTypes and VariableTypes allows:
- Clients that only know the supertype to handle an instance of the subtype as if it were an instance of the supertype;
- instances of the supertype to be replaced by instances of the subtype;
- specialised types that inherit common characteristics of the base type.
In other words, subtypes reflect the structure defined by their supertype but may add additional characteristics. For example, a vendor may wish to extend a general “TemperatureSensor” VariableType by adding a Property providing the next maintenance interval. The vendor would do this by creating a new VariableType which is a TargetNode for a HasSubtype reference from the original VariableType and adding the new Property to it.
The instantiation of complex TypeDefinitionNodes depends on the ModellingRules defined in 6.4.4. However, the intention is that instances of a type definition will reflect the structure defined by the TypeDefinitionNode. Figure 7 shows an instance of the TypeDefinitionNode “AI_BLK_TYPE”, where the ModellingRule Mandatory, defined in 6.4.4.4.1, was applied for its containing Variable. Thus, an instance of “AI_BLK_TYPE”, called AI_BLK_1”, has a HasTypeDefinition Reference to “AI_BLK_TYPE”. It also contains a Variable “SP” having the same BrowseName as the Variable “SP” used by the TypeDefinitionNode and thereby reflects the structure defined by the TypeDefinitionNode.
Figure 7 – Object and its Components defined by an ObjectType
A client knowing the ObjectType “AI_BLK_TYPE” can use this knowledge to directly browse to the containing Nodes for each instance of this type. This allows programming against the TypeDefinitionNode. For example, a graphical element may be programmed in the client that handles all instances of “AI_BLK_TYPE” in the same way by showing the value of “SP”.
There are several constraints related to programming against the TypeDefinitionNode. A TypeDefinitionNode or an InstanceDeclaration shall never reference two Nodes having the same BrowseName using forward hierarchical References. Instances based on InstanceDeclarations shall always keep the same BrowseName as the InstanceDeclaration they are derived from. A special Service defined in OPC 10000-4 called TranslateBrowsePathsToNodeIds may be used to identify the instances based on the InstanceDeclarations. Using the simple Browse Service might not be sufficient since the uniqueness of the BrowseName is only required for TypeDefinitionNodes and InstanceDeclarations, not for other instances. Thus, “AI_BLK_1” may have another Variable with the BrowseName “SP”, although this one would not be derived from an InstanceDeclaration of the TypeDefinitionNode.
Instances derived from an InstanceDeclaration shall be of the same TypeDefinitionNode or a subtype of this TypeDefinitionNode.
A TypeDefinitionNode and its InstanceDeclarations shall always reside in the same Server. However, instances may point with their HasTypeDefinition Reference to a TypeDefinitionNode in a different Server.