Using OpcCmd Utility as OPC UA PubSub Subscriber
Introduction
The OpcCmd utility is a program that allows performing various OPC operations from the command line. It can act as a generic OPC UA PubSub subscriber, and be used for evaluation, experiments, and testing.
OpcCmd is a console application, running on .NET. It is available for .NET Framework (Windows only), or .NET Core (Windows or Linux). It is available free of charge, but without an appropriate QuickOPC commercial or evaluation license made available to it, it provides valid data only for 30 minutes (it needs to be started over then).
Note: This page describes a preliminary version (5.55.0.3) of the program; the behavior is subject to change in future versions. This version only supports the OPC UA UDP transport protocol mapping (UADP over UDP). Security is not supported. We plan to add more features and mappings in the future. Once released, the documentation to the OpcCmd (intended to be a superset of this page) will be found in the QuickOPC User's Guide and Reference.
Note: OpcCmd may be enhanced in the future to support other OPC-related functionality, for Client-Server or PubSub. This page, however, is only for the PubSub subscriber aspect of the OpcCmd tool.
Usage
In order to run the OpcCmd utility, open a command prompt, and switch to the directory that contains the program. You start the program and give it a command and additional parameters (options). If you are using the .NET Framework version, type OpcCmd, followed by the commands and options, and press Enter. If you are using the .NET Core version, type dotnet OpcCmd.dll, followed by the commands and options, and press Enter. In the text that follows, when discussing the command line options, we will be listing the commands simply with the OpcCmd at the beginning; remember to use dotnet OpcCmd.dll in .NET Core instead.
After the program starts, it displays all dataset messages received (according to the criteria given by the command-line options) and their content (data fields). In case of an error, it displays an appropriate error message.
By default, OpcCmd stays subscribed for one minute, or until you interrupt it using the Ctrl+Break key combination. The time period can be configured using the --SleepTimeMilliseconds (-stm) or --SleepTimeSpan (-sts) command-line option.
Command-line Options
OpcCmd has a concept of (possibly nested) commands and options. For the usage as OPC UA PubSub subscriber, you will need one command (uaSubscriber) and one sub-command (subscribeDataSet), so they will practically always be present on the command line, and you will just give them additional options as needed. For this reason, most of your commands will start with:
OpcCmd uaSubscriber subscribeDataSet
Parameters of the subscribeDataSet command can be influenced by various options given after it on the command line. They can be entered using the long form (starts with --) or the short form (starts with -). The options are (obtained through OpcCmd uaSubscriber subscribeDataSet --help):
Usage: OpcCmd uaSubscriber subscribeDataSet [options] Options: --SleepTimeMilliseconds|-stm <milliseconds> Sleep time (-1 for Infinite, default=1 minute) --SleepTimeSpan|-sts <timespan> Sleep timespan (e.g. hh:mm, or hh:mm:ss) --ResolverPublisherEndpointUri|-rpeu <uri> Resolver publisher endpoint URI --ResolverPublisherFileResourceUri|-rpfru <uri> Resolver publisher file resource URI --ResolverKind|-rk <None/Discovery/PublisherEndpoint/PublisherFile> Resolver kind [DISCOVERY NOT IMPLEMENTED] --ConnectionNetworkInterface|-cni <name> PubSub connection network interface --ConnectionName|-cn <name> PubSub connection name --ConnectionResourceUri|-cru <uri> PubSub connection resource URI --ConnectionTransportProfile|-ctp <uri> PubSub connection transport profile --PcapReaderCaptureFile|-prcf <fileName> Pcap reader capture file (requires OpcLabs.Pcap) --ConnectionBrokerAuthenticationProfileUri|-cbapu <uri> PubSub connection broker authentication profile URI --ConnectionBrokerResourceUri|-cbru <uri> PubSub connection broker resource URI --ConnectionDatagramDiscoveryUri|-cddu <uri> PubSub connection datagram discovery URI --MaximumNetworkMessageSize|-mnms <uint32> Maximum network message size (ignored) --MessageReceiveTimeout|-mrt <double> Message receive timeout (milliseconds) --SecurityGroupId|-sgi <name> Security group Id --SecurityKeyServiceEndpointUris|-skseu <uris> Security key service endpoint URIs --SecurityMode|-sm <securityMode> Security mode (None/SecurityNone/SecuritySign/SecuritySignAndEncrypt) --BrokerAuthenticationProfileUri|-bapu <uri> Broker authentication profile URI --BrokerMetaDataQueueName|-bmdqn <name> Broker metadata queue name --BrokerQueueName|-bqn <name> Broker queue name --BrokerRequestedDeliveryGuarantee|-brdg <guarantee> Broker requested delivery guarantee (NotSpecified/BestEffort/AtLeastOnce/AtMostOnce/ExactlyOnce) --BrokerResourceUri|-bru <uri> Broker resource URI --DataSetOffset|-dso <uint16> Dataset offset --GroupVersion|-gv <uint32> Group version --NetworkMessageNumber|-nmn <uint16> Network message number --DataSetClassId|-dsci <guid> Dataset class Id --AllowDataMessages|-adm <bool> Allow data messages (default=true) --AllowEventMessages|-aem <bool> Allow event messages (default=true) --DataSetWriterId|-dswi <uint16> Dataset writer Id --DataSetWriterName|-dswn <name> Dataset writer name --PublisherIdNumeric8|-pin8 <byte> Publisher Id (Byte) --PublisherIdNumeric16|-pin16 <uint16> Publisher Id (UInt16) --PublisherIdNumeric32|-pin32 <uint32> Publisher Id (UInt32) --PublisherIdNumeric64|-pin64 <uint64> Publisher Id (UInt64) --PublisherIdString|-pis <string> Publisher Id (String) --WriterGroupId|-wgi <uint16> Writer group Id --WriterGroupName|-wgn <name> Writer group name --MessageOriginFilter|-mof <string> Message origin filter (ipaddress:port for UDP) --PublishedDataSetName|-pdsn <name> Published dataset name -?|-h|--help Show help information
Help text for the OpcCmd utility itself can by displayed using OpcCmd --help. Help text for the OpcCmd uaSubscriber command can be displayed using OpcCmd uaSubscriber --help (there are some less-frequently options directly on this command, such as resolution timeouts, which are not discussed here).
Explanation of all the options is outside the scope of this article. Use the provided examples to work with the tool, and add options to the examples when the need arises. The option generally fall into several categories:
- Execution
- The --SleepTimeMilliseconds (-stm) and --SleepTimeSpan (-sts) options determine how long the command runs.
- Resolver
- Allow the physical parameters be determined from logical parameters by a resolution process, from a configuration file or an OPC UA server with PubSub configuration model. Options in this category start with the word Resolver.
- Connection
- Specify how the PubSub connection is made. The main options in this category start with the word Connection.
- Communication parameters
- E.g. --MessageReceiveTimeout (-mrt), or most of the options that start with the word Broker.
- Filter
- Allows filtering of the incoming messages. Main options in this category are the options that specify the publisher ID - they start with words PublisherId, such as --PublisherIdNumeric16 (-pin16). Other options in this category include --WriterGroupId (-wgi) and --DataSetWriterId (-dswi).
Physical and Logical Parameters
The PubSub subscription can be specified using physical parameters, logical parameters, or a mix of them.
Physical parameters refer to data that is directly used to open the PubSub connection, and that appears "on the wire", in the PubSub messages. They include (only the most important parameters are listed; the list is not complete):
- --ConnectionNetworkInterface (-cni)
- --ConnectionResourceUri (-cru). This is the main parameter that always has to be specified. The scheme part is mandatory, always start the URI with "opc.udp://" in this version. Default port for OPC UA UDP is 4840 and does not have to be specified.
- --ConnectionTransportProfile (-ctp). You do not need to specify it, if it can be derived from the scheme, such as in "opc.udp:".
- --MessageReceiveTimeout (-mrt)
- --DataSetOffset (-dso)
- --GroupVersion (-gv)
- --NetworkMessageNumber (-nmn)
- --DataSetClassId (-dsci)
- --DataSetWriterId (-dswi)
- various PublisherIdXXXX (-piXX) options
- --WriterGroupId (-wgi)
Logical parameters refer to named objects in the PubSub configuration. They are:
- --ConnectionName (-cn)
- --DataSetWriterName (-dswn)
- --WriterGroupName (-wgn)
- --PublishedDataSetName (-pdsn)
When using logical parameters, you typically specify the first three (connection, dataset writer and writer group names), or the last one (published data set name). When published data set name is specified, OpcCmd finds the instances in the PubSub configuration where the dataset is published; the outcome must be unambiguous, otherwise an error occurs. Other logical parameters, and some physical parameters (such as transport profile URI) can be used to narrow down the outcome of this selection process.
The PubSub configuration information must somehow be available to OpcCmd, and a so-called resolver is used to transform the logical parameters to physical ones. There are currently two kinds of resolvers: One takes the PubSub configuration from a file (in a format given by OPC UA specification), the other works with a live PubSub configuration in an information model of a live OPC server that supports it (and is typically part of, of connected with or related to, the actual OPC UA PubSub publisher).
Following parameters are used to specify the resolver and its parameters:
- --ResolverPublisherEndpointUri (-rpeu). Use this option to resolve the logical parameters from an OPC UA server with PubSub configuration model.
- --ResolverPublisherFileResourceUri (-rpfru). Use this option to resolve the logical parameters from a PubSub configuration file.
- --ResolverKind (-rk). Not necessary unless you want to specify multiple resolvers, and then just switch between them.
The information you specify using the parameters must be valid for the subscription to work, but in some cases it does not have to be complete. For example, when using physical or logical parameters, you do not have to specify anything beyond the connection - the OpcCmd will then simply process all messages on that connection, without filtering. Or, you can filter just by publisher ID, but still receive different datasets provided by the given publisher.
Examples
Following examples show some typical OpcCmd use cases (obtained through OpcCmd uaSubscriber subscribeDataSet --help):
Usage examples: Subscribe to a dataset, specifying physical parameters: OpcCmd uaSubscriber subscribeDataSet -cru opc.udp://239.0.0.1:4840 OpcCmd uaSubscriber subscribeDataSet -cru opc.udp://224.0.0.22 -dswi 62541 OpcCmd uaSubscriber subscribeDataSet -sts 01:00 -cru opc.udp://239.0.0.1:4840 OpcCmd uaSubscriber subscribeDataSet -cru opc.udp://239.0.0.1:4840 -pin 20 Subscribe to a dataset, specifying logical parameters (and resolving them first): OpcCmd uaSubscriber subscribeDataSet -rpeu opc.tcp://192.168.0.85:4840 -cn UDP1 -wgn WriterGroupStatic -dswn WriterSimple OpcCmd uaSubscriber subscribeDataSet -rpeu opc.tcp://192.168.0.50:4842 -pdsn "PublishedDataSet #1" OpcCmd uaSubscriber subscribeDataSet -rfru unified_automation_cpp.bin -cn UDP1 -wgn WriterGroupDynamic -dswn WriterAllTypes
Subscribe to all messages generated by a default configuration of the UADemoPublisher utility (see UADemoPublisher Basics for more information):
OpcCmd uaSubscriber subscribeDataSet -cru opc.udp://239.0.0.1
For messages from a default configuration of UADemoPublisher utility, with specific publisher ID (31, in 64 bits) and dataset writer ID (4):
OpcCmd uaSubscriber subscribeDataSet -cru opc.udp://239.0.0.1 -pin64 31 -dswi 4
Sample Output
The following listing shows a sample output of the OpcCmd tool, when subscribed to data coming from the UADemoPublisher (shortened):
OPC Labs OpcCmd Utility (.NET Core) 5.55.0.3: OPC Command-line Tool (OPC-UA PubSub Subscriber). Copyright © 2019 CODE Consulting and Development, s.r.o., Plzen. All rights reserved. Subscribing dataset... Subscription handle: 12586001 Sleeping for 00:01:00 (press Ctrl+Break to abort)... DataSetMessage: Success DataSetMessage: Success; 0001-01-01T00:00:00.000,000,000,00; Good; Data; publisher="32", writer=1, class=eae79794-1af7-4f96-8401-4096cd1d8908, fields: 4 [#0, True {System.Boolean} @0001-01-01T00:00:00.000,000,000,00; Good] [#1, 229 {System.Int32} @0001-01-01T00:00:00.000,000,000,00; Good] [#2, 1109 {System.Int32} @0001-01-01T00:00:00.000,000,000,00; Good] [#3, 7/17/2019 3:29:54 PM {System.DateTime} @0001-01-01T00:00:00.000,000,000,00; Good] DataSetMessage: Success; 0001-01-01T00:00:00.000,000,000,00; Good; Data; publisher="32", writer=3, class=96976b7b-0db7-46c3-a715-0979884b55ae, fields: 100 [#0, 29 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#1, 129 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#2, 229 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#3, 329 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#4, 429 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#5, 529 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#6, 629 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#7, 729 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#8, 829 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#9, 929 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#10, 1029 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#11, 1129 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#12, 1229 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] ... DataSetMessage: Success; 0001-01-01T00:00:00.000,000,000,00; Good; Data; publisher="32", writer=4, class=cc7cb5f4-4272-45c2-9a4d-f85a8b331f6a, fields: 16 [#0, True {System.Boolean} @0001-01-01T00:00:00.000,000,000,00; Good] [#1, 230 {System.Byte} @0001-01-01T00:00:00.000,000,000,00; Good] [#2, 230 {System.Int16} @0001-01-01T00:00:00.000,000,000,00; Good] [#3, 230 {System.Int32} @0001-01-01T00:00:00.000,000,000,00; Good] [#4, 230 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#5, 102 {System.Int16} @0001-01-01T00:00:00.000,000,000,00; Good] [#6, 230 {System.Int32} @0001-01-01T00:00:00.000,000,000,00; Good] [#7, 230 {System.Int64} @0001-01-01T00:00:00.000,000,000,00; Good] [#8, 230 {System.Decimal} @0001-01-01T00:00:00.000,000,000,00; Good] [#9, 230 {System.Single} @0001-01-01T00:00:00.000,000,000,00; Good] [#10, 230 {System.Double} @0001-01-01T00:00:00.000,000,000,00; Good] [#11, Whiskey {System.String} @0001-01-01T00:00:00.000,000,000,00; Good] [#12, [20] {169, 225, 194, 251, 149, ...} {System.Byte[]} @0001-01-01T00:00:00.000,000,000,00; Good] [#13, d34c50d3-a8e0-4861-b1e7-1868ab97756d {System.Guid} @0001-01-01T00:00:00.000,000,000,00; Good] [#14, 7/17/2019 3:29:55 PM {System.DateTime} @0001-01-01T00:00:00.000,000,000,00; Good] [#15, [10] {230, 231, 232, 233, 234, ...} {System.Int64[]} @0001-01-01T00:00:00.000,000,000,00; Good] ... DataSetMessage: *** Failure -1 (0xFFFFFFFF): The toolkit UADP NetworkMessage processor does not have DataSetMetaData available (publisher ID: 30, writer group ID: 101). ... DataSetMessage: Success; 2019-07-17T15:29:55.329,733,500,00; Good; Event; publisher=(UInt64)31, writer=51, fields: 4 [#0, True {System.Boolean} @2019-07-17T15:29:55.329,733,500,00; Good] [#1, 230 {System.Int32} @2019-07-17T15:29:55.329,733,500,00; Good] [#2, 1219 {System.Int32} @2019-07-17T15:29:55.329,733,500,00; Good] [#3, 7/17/2019 3:29:55 PM {System.DateTime} @2019-07-17T15:29:55.329,733,500,00; Good] DataSetMessage: Success; 2019-07-17T15:29:57.333,255,400,00; Good; Event; publisher=(UInt64)31, writer=51, fields: 4 [#0, False {System.Boolean} @2019-07-17T15:29:57.333,255,400,00; Good] [#1, 232 {System.Int32} @2019-07-17T15:29:57.333,255,400,00; Good] [#2, 1571 {System.Int32} @2019-07-17T15:29:57.333,255,400,00; Good] [#3, 7/17/2019 3:29:57 PM {System.DateTime} @2019-07-17T15:29:57.333,255,400,00; Good] ... Unsubscribing dataset (subscription handle 12586001)... Finished.
Explanation to some of the output follows.
DataSetMessage: Success
This line indicates that a PubSub connection has been successfully established (there is no direct connection to the publisher - but, depending on the protocol, an IP socket need to be open, or similar "initiating" operation needs to be made, and the message indicates that the parameters used to specify the connections were OK in principle). If the connection could not have been established, there would be an error message instead.
DataSetMessage: Success; 0001-01-01T00:00:00.000,000,000,00; Good; Data; publisher="32", writer=1, class=eae79794-1af7-4f96-8401-4096cd1d8908, fields: 4
Similar lines precede each dataset message received. They contain the timestamp of the message, the status code, an indication whether the message contains Data or Event, and an identification of the dataset (depending on what is actually available).
[#0, True {System.Boolean} @0001-01-01T00:00:00.000,000,000,00; Good]
Similar lines contain the data fields of the message. '#' followed by a number indicates a field index. If metadata is available, there is a field name instead. Then, the actual data value is listed, followed by its type in '{ }' (this is .NET type; note that the values are converted to so-called CLS types, and therefore the .NET type may not be precisely the same as the type of the field). After that, a source timestamp preceded with '@' follows, and after a semicolon (';'), a status code.
The timestamps are formatted down to 10-picosecond level.
DataSetMessage: *** Failure -1 (0xFFFFFFFF): The toolkit UADP NetworkMessage processor does not have DataSetMetaData available (publisher ID: 30, writer group ID: 101).
This message indicates that a dataset message has been received, but because the data uses raw encoding and no metadata is available, it cannot be fully parsed. Metadata can be provided from a configuration file or by an OPC UA server with PubSub configuration model. The related command-line options for that are (among others) --ResolverPublisherFileResourceUri (-rpfru) and --ResolverPublisherEndpointUri (-rpeu).