TQL Engine supports OPC-UA protocol Handler, that can be used to subscribe/update various nodes present on OPC-UA server.
OPCUA Protocol Handler Flow:
OPCUA Protocol Handler Installation: Download the protocol handlers zip file from the link below
http://sandbox.atomiton.com:8080/fid-downloads/res/downloads/protocolhandlers.zip
once downloaded unzip it. After you unzip it go to protocolhandlers/Opcua directory and copy the sff.bundle.ext.opc.jar from this location to the sff.auto.launch folder which is present in your TQL engine folder.
OPCUA Protocol Parameters:
The table below lists all the parameters of opcua protocol handler and their description
Parameter Name | Parameter Description |
ConnectionConfig | A def containing all the information about connection and security parameters of OPCUA server, it has the following fields ServerUri, SecurityConfig and SecurityMode (0-6). Security Mode Description 0 None 1 128-bit RSA Sign 2 128-bit RSA Sign and encrypt 3 256-bit Basic Sign 4 256-bit Basic Sign and encrypt 5 256-bit SHA Sign 6 256-bit SHA Sign and encrypt |
SecurityConfig | A def containing information about security parameters of the server, it has the following fields UserName, Password, ApplicationIdentity and CertificationParameters. |
ApplicationIdentity | A def Containing information about the client’s Idenitiy, it has following fields AppName, AppUri and ProductUri. |
CertificationParameters | A def containing information about the connection’s certificate parameters, it has following parameters OrgName, Path, PrivateKeyPwd, ValidityInDay, AutoCertificateRenewal and KeySize. |
Operation | This field specifies the operation to be performed, the operation are subscription and write. |
NodeID | This parameter is used in case of write Operation, the Node ID on which the write operation is to be performed. |
AttributeID | This parameter is used in case of write Operation, the Attribute ID of the respective Node ID on which the write operation is to be performed. |
OpcData | This parameter is used in case of write Operation, and this specifies the write value. |
OPCUaSubscribe | A def specific to subscribe operation, It has fields like NodeID: the Node Id to which we need to subscribe. AttributeID: attribute ID is optional for subscription. SubscribeChild: Whether you want to subscribe to child nodes also. |
Usage of opcua protocol handler:
Opcua Write:
<ThingFacet Name="OPCWriteFacet"> <String Name="OpcData" KnownBy="OPCSubscriberAction"/> <String Name="NodeID"/> <Integer Name="AttributeID"/> <String Name="Operation"/> <ConnectionConfig Name="OPCWriteConnectionConfig"/> <Action Name="OPCSubscriberAction"> <Workflow Limit="1" Live="1" Timeout="-1"> <Task name="Main" > <Event as="ActionArgument" name="Argument"/> <Invoke get="opcua://" waitFor="Argument" name="InvokeOPCWrite" Operation="[%:Event.Argument.Operation.Value:%]" ServerUri="[%:Event.Argument.OPCWriteConnectionConfig.ServerUri.Value:%]" SecurityMode="[%:Event.Argument.OPCWriteConnectionConfig.SecurityMode.Value:%]" UserName="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.UserName.Value:%]" Password="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.Password.Value:%]" Path="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.CertificationParameters.Path.Value:%]" ValidityInDay="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.CertificationParameters.ValidityInDay.Value:%]" AutoCertificateRenewal="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.CertificationParameters.AutoCertificateRenewal.Value:%]" PrivateKeyPwd="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.CertificationParameters.PrivateKeyPwd.Value:%]" OrgName="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.CertificationParameters.OrgName.Value:%]" KeySize="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.CertificationParameters.KeySize.Value:%]" AppUri="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.ApplicationIdentity.AppUri.Value:%]" AppName="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.ApplicationIdentity.AppName.Value:%]" ProductUri="[%:Event.Argument.OPCWriteConnectionConfig.SecurityOptions.ApplicationIdentity.ProductUri.Value:%]" NodeID="[%:Event.Argument.NodeID.Value:%]" AttributeID="[%:Event.Argument.AttributeID.Value:%]"> <Message> <Value> "[%:Event.Argument.opcData.Value:%]" </Value> </Message> </Invoke> <Output As="ActionResult" Name="Result"> <Value> <OpcData>[%:Invoke.InvokeOPCWrite.Message.Value:%]</OpcData> </Value> </Output> </Task> </Workflow> </Action> </ThingFacet> |
<Query> <DeleteAll> <OPCWriteModel> <writeId ne=""/> </OPCWriteModel> </DeleteAll> <Create> <OPCWriteModel> <Operation> Write </Operation> <OPCWriteConnectionConfig> <ServerUri> opc.tcp://MSEDGEWIN10:49320 </ServerUri> <SecurityMode> 2 </SecurityMode> <SecurityOptions> <UserName/> <Password/> <ApplicationIdentity> <AppName> atomitonClient@localhost </AppName> <AppUri> urn:localhost:OPCUATQL </AppUri> <ProductUri> urn:atomiton.com:OPCUA </ProductUri> </ApplicationIdentity> <CertificationParameters> <OrgName> atomiton </OrgName> <Path> /atomiton/certs </Path> <PrivateKeyPwd> tql123# </PrivateKeyPwd> <ValidityInDay> 3650 </ValidityInDay> <AutoCertificateRenewal> true </AutoCertificateRenewal> <KeySize> 2048 </KeySize> </CertificationParameters> </SecurityOptions> </OPCWriteConnectionConfig> <NodeID> ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_FCU_Temperature </NodeID> <AttributeID> 13 </AttributeID> <OpcData> 1024 </OpcData> </OPCWriteModel> </Create> </Query> |
<Query> <Find format="version,known"> <OPCWriteModel> <writeId ne=""/> </OPCWriteModel> </Find> <if condition="$Response.Message.Value/Find/Status eq 'Success'"> <then> <SetResponseData> <key> Message.Value.Find.Result.OPCWriteModel.OpcData.Value </key> <value> 200 </value> </SetResponseData> <Update> <from> Result </from> <Include> $Response.Message.Value.Find </Include> </Update> </then> </if> </Query> |
Opcua Subscription:
<Def Name="CertificationParams"> <String Name="OrgName"/> <String Name="Path"/> <String Name="PrivateKeyPwd"/> <String Name="ValidityInDay"/> <String Name="AutoCertificateRenewal"/> <Integer Name="KeySize"/> </Def> <Def Name="AppIdentity"> <String Name="AppName"/> <String Name="AppUri"/> <String Name="ProductUri"/> </Def> <Def Name="SecurityConfig"> <String Name="UserName"/> <String Name="Password"/> <AppIdentity Name="ApplicationIdentity"/> <CertificationParams Name="CertificationParameters"/> </Def> <Def Name="ConnectionConfig"> <String Name="ServerUri"/> <Integer Name="SecurityMode"/> <SecurityConfig Name="SecurityOptions"/> </Def> <Def Name="OPCUaSubscribe"> <String Name="NodeID" Cardinality="0..m"/> <String Name="AttributeID"/> <String Name="SubscribeChild"/> </Def> <ThingFacet Name="OPCSubscriberFacet"> <String Format="$ObjectFormat(xml)" Name="SubscriptionPayload" KnownBy="OPCSubscriberAction" update="auto"/> <String Name="Operation"/> <ConnectionConfig Name="OPCSubscribeConnectionConfig"/> <OPCUaSubscribe Name="OPCSubscriptionConfig"/> <Action Name="OPCSubscriberAction"> <Workflow Limit="1" Live="1" Timeout="-1"> <Task name="Main" while="true"> <Event as="ActionArgument" name="Argument"/> <Invoke AppName="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.ApplicationIdentity.AppName.Value:%]" AppUri="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.ApplicationIdentity.AppUri.Value:%]" AutoCertificateRenewal="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.CertificationParameters.AutoCertificateRenewal.Value:%]" KeySize="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.CertificationParameters.KeySize.Value:%]" OPCSubscriptionConfig="[%:Event.Argument.OPCSubscriptionConfig:%]" Operation="[%:Event.Argument.Operation.Value:%]" OrgName="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.CertificationParameters.OrgName.Value:%]" Password="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.Password.Value:%]" Path="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.CertificationParameters.Path.Value:%]" PrivateKeyPwd="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.CertificationParameters.PrivateKeyPwd.Value:%]" ProductUri="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.ApplicationIdentity.ProductUri.Value:%]" SecurityMode="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityMode.Value:%]" ServerUri="[%:Event.Argument.OPCSubscribeConnectionConfig.ServerUri.Value:%]" UserName="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.UserName.Value:%]" ValidityInDay="[%:Event.Argument.OPCSubscribeConnectionConfig.SecurityOptions.CertificationParameters.ValidityInDay.Value:%]" get="opcua://Subscribe" name="InvokeOPCSubscription" scope="process" waitFor="Argument"/> <Output As="ActionResult" Name="Result"> <Value> <SubscriptionPayload> <Include>Invoke.InvokeOPCSubscription.Message.Value</Include> </SubscriptionPayload> </Value> </Output> </Task> </Workflow> </Action> </ThingFacet> |
Note: The output is stored in the variable SubscriptionPayload although the Known By is on the variable SubscriptionData, this has been done to preserve the Xml structure and avoid TP processing.
<Query> <DeleteAll> <OPCSubscriberModel> <subscribeId ne=""/> </OPCSubscriberModel> </DeleteAll> <Create> <OPCSubscriberModel> <Operation> subscription </Operation> <OPCSubscribeConnectionConfig> <ServerUri> opc.tcp://MSEDGEWIN10:49320 </ServerUri> <SecurityMode> 2 </SecurityMode> <SecurityOptions> <UserName/> <Password/> <ApplicationIdentity> <AppName> atomitonClient@localhost </AppName> <AppUri> urn:localhost:OPCUATQL </AppUri> <ProductUri> urn:atomiton.com:OPCUA </ProductUri> </ApplicationIdentity> <CertificationParameters> <OrgName> atomiton </OrgName> <Path>/atomiton/certs</Path> <PrivateKeyPwd> tql123# </PrivateKeyPwd> <ValidityInDay> 3650 </ValidityInDay> <AutoCertificateRenewal> true </AutoCertificateRenewal> <KeySize> 2048 </KeySize> </CertificationParameters> </SecurityOptions> </OPCSubscribeConnectionConfig> <OPCSubscriptionConfig> <NodeID> ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1 </NodeID> <AttributeID/> <SubscribeChild> true </SubscribeChild> </OPCSubscriptionConfig> <SubscriptionPayload>$Null()</SubscriptionPayload> </OPCSubscriberModel> </Create> </Query> |
<Query> <DeleteAll> <OPCSubscriberModel> <subscribeId ne=""/> </OPCSubscriberModel> </DeleteAll> </Query> |
Note: It is possible to subscribe to multiple root nodes using a single facet, separate the NodeID's with ;; delimiter in subscription initialization query as shown below
<NodeID> ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1;;ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank2 </NodeID> |
<SubscriptionPayload Version="2"> <Value> <OpcUaNodes> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_Agitator_Motor_Running_Bit</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_FCU_Temperature</NodeID> <NodeValue>201.0</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Float</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_Gallon_Value</NodeID> <NodeValue>1.34646997E15</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Double</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_Loading_PP_Motor_Running_Bit</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_RAW_Level_Inches</NodeID> <NodeValue>568.0</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Double</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_steaming_in_auto_selected_HMI</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_unld_PP_Motor_Running_Bit</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> </OpcUaNodes> </Value> <Known> <OpcUaNodes> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_Agitator_Motor_Running_Bit</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_FCU_Temperature</NodeID> <NodeValue>201.0</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Float</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_Gallon_Value</NodeID> <NodeValue>1.34646997E15</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Double</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_Loading_PP_Motor_Running_Bit</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_RAW_Level_Inches</NodeID> <NodeValue>568.0</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Double</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_steaming_in_auto_selected_HMI</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> <OpcUaNode> <ServerTimeStamp/> <NodeID>ns=2;s=Vopak.Device1.TankData.USSAV1S01HST.Tank1.Tank_1_unld_PP_Motor_Running_Bit</NodeID> <NodeValue>false</NodeValue> <StatusCode>GOOD</StatusCode> <SourceTimeStamp>08/10/16 00:38:27.0823950 GMT</SourceTimeStamp> <DataType>Boolean</DataType> </OpcUaNode> </OpcUaNodes> </Known> </SubscriptionPayload> |