Adding External Information Models 

In this topic, we describe the features that allow the integration of external information models into the embedded OPC UA server of PLCnext:

  • First, the storage of the required NodeSet.xml files is described
  • Then the instance NodeSet.xml as a special form is explained.
  • We show how to reference existing nodes provided by the internal information models. This allows to reuse types and properties from other information models (e.g. DI properties or the file system).
  • It also gives you the opportunity to define an alternative address space with PLC variables that expose a different structure. For the implementation of a companion standard the PLC variables normally do not fit. In this case new variables need to be created that just get the value of the PLC variable.
  • Many companion standards make use of methods, so we show how to declare methods in the NodeSet and how to implement methods in IEC 61131, or in C++.
  • After all, there are some hints for debugging and solving issues in this context.

NodeSet.xml files on PLCnext

NodeSet.xml files are used to add external information models and a custom instance space ("instance NodeSets") to the PLCnext OPC UA Server. These files have to be stored in the folder /opt/plcnext/projects/Default/Services/OpcUA/NodeSets/ on PLCnext. All files in this folder are treated as NodeSet files and must follow the schema defined in OPC UA Part 6. Subfolders are allowed, e.g. to simplify deployment by automatic replacement of a whole subfolder. It is ok to have the same NodeSet file in different folders.

If a NodeSet file depends on other NodeSet files, the dependent files need to be available as well. Dependent models need to be declared in the <RequiredModel> section of the NodeSet.

With emerging standards, NodeSet files can be available in different versions. A common rule is to make these versions compatible so that newer versions can safely replace older versions. If several versions of a NodeSet file are available, only one can be loaded into the address space. Note: It is the responsibility of the user to ensure that only one version of the NodeSet file is provided in the folder structure.

Internal information models cannot be replaced via a NodeSet file. Their versions are fixed and depend on the version of PLCnext.

Normally a single namespace is defined in a single NodeSet file. However in some cases an OPC UA namespace is defined in several NodeSet files. In this case the contents of these NodeSet files are merged.

Instancing a NodeSet file for the Project

When integrating an external information model the instance space is provided as an instance NodeSet file.

There is no technical difference between the instance NodeSet file and the NodeSet file of a companion standard. Both use the same schema as defined by OPC UA Part 6. It is also possible to have several instance NodeSet files for different models.

Like any other NodeSet file the instance NodeSet file references all namespaces that it depends on at the top. Then the index in that list can be used as namespace index by the instance nodes within the NodeSet.

This can include namespaces of internal information models which are not available as a separate NodeSet file, e.g.:

  • the file system (http://phoenixcontact.com/OpcUA/Files/)
  • the GDS (http://phoenixcontact.com/OpcUA/PLCnext/GlobalDataSpace/)
  • devices (http://phoenixcontact.com/OpcUA/PLCnext/Devices/)

Referencing existing nodes

There are several scenarios where an information model exposes existing nodes in a new structure. In this case the new namespace could just reference the nodes from the existing PLCnext address space. As a result these nodes show up in two places. Now both nodes share the sameNodeId,BrowseName and TypeDefinition. To accomplish this the NodeSet needs to declare the dependent namespace in the namespace table at the beginning of the document. Then references can target nodes in this namespace as well.

Referencing DI Properties

Several companion standards are based on the Device information model (Part 100), the DI. This often defines new device instances that have properties like e.g. Manufacturer and SerialNumber. The main device in PLCnext is also a DI device and already exposes these properties. With additional references to the existing properties the complete node and specific value can be reused.

In this case the instance NodeSet depends on thehttp://phoenixcontact.com/OpcUA/PLCnext/Devices/ namespace and reference the used nodes:
<Reference ReferenceType="HasProperty">ns=5;s=ThisDevice.SerialNumber</Reference>.

Note that the namespace index (5 in this example) is the index in the namespace list of the NodeSet file.

Referencing the File System

Some companion standards define access to files or folders. This can be accomplished with the FileType and FileDirectoryType of the OPC UA standard.

PLCnext also can expose nodes of these types with the OPC UA file access feature. These file and folder nodes can be referenced from the instance NodeSet file. See OPC UA file access for a description of the used NodeIds.

Note: If a filter is configured to show only specific files of a folder, the methods to add and remove subfolders are not supported.

Restructuring PLC Variables

Another use case is exposing the PLC variables in a custom structure other than the default component–program–function block structure, e.g. in a logical or physical topology.

Note that this just changes the structure of the address space. The variables still belong to the GDS namespace and not to one defined by another companion standard.

To accomplish this, the instance NodeSet file defines a new hierarchy of objects that refer to PLC variables from the GDS namespace. Therefore the namespace of the GDS variableshttp://phoenixcontact.com/OpcUA/PLCnext/GlobalDataSpace/ needs to be referenced by the instance NodeSet, so that objects of the instance NodeSet can reference variables nodes from the GDS namespace.

Getting values from PLC variables

If a companion standard needs to be implemented, the reuse of PLC variables from the GDS namespace is normally not an option. Main reason is that a variable of a companion standard requires aBrowseName (which includes the namespace) of that companion standard, and not one from the GDS namespace of PLCnext.

In this case the instance NodeSet defines a new variable with the appropriate type and just takes the value (and some other attributes) from the original GDS variable provided by the PLC project.

To connect a variable node with a GDS variable, an Extension element needs to be added to the UAVariable element in the NodeSet. The extension is added in the following form:

<UAVariable ...>
    <DisplayName>...</DisplayName>
    <References>
        ...
    </References>
    <Extensions>
        <Extension>
            <AttributeSource xmlns="http://phoenixcontact.com/OpcUA/2019/NodeSetExtensions.xsd" GdsValueAttribute="INSTANCEPATH"/>
        </Extension>
    </Extensions>
</UAVariable>

Here the INSTANCEPATH needs to be filled with the GDS instance path of the variable. It has the same format as used in the NodeId of the GDS address space (see GDS namespace).
The path generally has the form Arp.Plc.Eclr/PGInst1.FBInt1.ArrOfStruct1[0].Var1.

Here, PGInst1 is the name of a program instance, FBInst1 of an FB instance, ArrOfStruct1 of an array of structures where the structure has a field Var1. If not clear a client like UaExpert can be used to check the identifier of the NodeId.

If a variable node is connected like this, the Value attribute is mapped to the GDS variable. Consequently the attributes WriteMask, UserWriteMask, ValueRank, ArrayDimensions, MinimumSamplingInterval, AccessLevel, UserAccessLevel and Historizing are mapped to the GDS variable as well.

In case the INSTANCEPATH is invalid, reading the attributes above will return BadNodeIdUnknown to OPC UA clients.

Other attribute like the Comment can get a static value in the NodeSet file.

The DataType attribute is taken from the instance NodeSet which enables a maping to binary compatible data types in the PLC. This could be used to map an OPC UA enumeration to an UDINT (UInt32) in the PLC or a primitive OptionSet to the appropriate integer variable in the PLC.

Note: Complete structures cannot be mapped to GDS variables yet.

Implementing methods as PLC function blocks

An OPC UA method can be implemented with a PLC function block. Therefore theUAMethod element of the NodeSet file needs an Extension element that connects it to the backing function block instance of the PLC program like this:

<UAMethod ...>
    <DisplayName>...</DisplayName>
    <References>
        ...
    </References>
    <Extensions>
        <Extension>
            <MethodTarget xmlns="http://phoenixcontact.com/OpcUA/2019/NodeSetExtensions.xsd" FunctionBlock="INSTANCEPATH"/>
        </Extension>
    </Extensions>
</UAMethod>

Here the INSTANCEPATH need to be filled with the GDS instance path of the function block instance. The path generally has the form Arp.Plc.Eclr/PGInst1.FBInt1.

Here PGInst1 is the name of a program instance, FBInst1 of an FB instance. If more function blocks are nested the instance names are separated by a ".". If the variable cannot be found an issue is added to the notification log.

The associated function block needs to have the proper signature in order to be usable as a UA method. The most important part is a local state variable with the fixed name UA_MethodState of type INT. This variable maintains the state of the method call over the cycles of the PLC task.

The variable is written by the function block and by the UA server according to some special rule:

  • Initially the variable has the value of 0. In this case the function block must not write to the variable.
  • It is set to 1 by the UA server when the method is called by a client. Then the function block can change the variable to any value, e.g. to maintain its internal state.
  • If method processing is complete the function block shall set the variable back to 0 which is an indication for the UA server that the method is complete.
  • The UA server only writes to the variable if it is 0 and the only value that it writes is a 1.

If a method is called several times e.g. by different clients, the calls are processed one by one. This means if the function block sets the state to 0 it should be prepared to get a 1 in the next cycle for the next call to the same method.

Note: According to OPC UA a method should not execute for a long time. Otherwise the OPC client might signal a timeout.

If the method should return status codes other than OK it can implement an additional variable UA_StatusCode of type UA_StatusCodeEnum.

UA_StatusCodeEnum is part of the PLCnext Controller library so it should be automatically available. This variable could be set to one of the values provided in the enumeration when the method completes. The UA server will read the value and return it to the UA client.

For methods with IN or OUT parameters additional variables with the same name and a binary compatible type need to be added to the function block.

  • The inputs are written by the OPC server before the method is started, so they are available when the state changes to 1.
  • The outputs are read from the function block after the method signals completion by setting the state to 0.

Parameters can also be of enumeration type or an option set of primitive type. Complex types like structures or NodeIds are not supported.

Implementing methods in C++

The implementation using C++ is similar to that with the PLC function block:

There need to be an instance of a class similar to the function block. The variables and interaction with the UA server are the same. The State variable shall have the type Int16 and the status code variable is of type UInt32. The StatusCodes.csv file from the OPC Foundation website provides the latest list of allowed status codes.

Example for the creation of an OPC UA Method

The example PLCnext Technology - OpcUaMethods on GitHub is about the basic steps for creating an OPC UA method.

In this example, the OPC UA method will be used to call a PLCnext Engineer function block instance from an OPC UA client. 

The procedure uses a custom OPC UA "Information Model", which in this case is generated using the UaModeler tool from Unified Automation. This technique can also be applied when using standard OPC UA information models for various industries and applications.

Reloading the NodeSet files

When loading PLCnext, or during "download changes" from the PLCnext Engineer, the folder with NodeSet files is scanned. If there are new, changed, or removed files all connections to the server are closed and clients have to reconnect. Note that this might result in changed namespace indices.

Error handling

Error logs

Errors that can be solved in the PLCnext Engineer (e.g., if a mapped method cannot be found in the PLC) will be listed in the notification log in PLCnext Engineer. Other issues (e.g. invalid XML files) are logged into the general log file (see /opt/plcnext/logs/Output.log).

Parsing errors

After restart of PLCnext, or after downloading of a changed PLC project, the NodeSet.xml files are parsed and the address space is built up. Several aspects of the XML files are checked during parsing:

  • If severe issues occur, the parsing is aborted.
  • For minor issues (like a missing target of a reference) the parsing continues and the issues are only tracked in the log file (see /opt/plcnext/logs/Output.log).

 


• Published/reviewed: 2024-10-30   ☀  Revision 074 •