Qt OPC UA: Difference between revisions
(Fix names and typos) |
|||
Line 1: | Line 1: | ||
== | == Qt OPC UA as a wrapper == | ||
The current design of | The current design of the Qt OPC UA module assumes that it is a thin wrapper around an existing OPC UA (client) stack. | ||
=== Negative consequences === | === Negative consequences === | ||
* Open- | * Open-source stacks: There is as of today no (nearly) feature complete C/C++ open source stack with a suitable license. | ||
* Closed- | * Closed-source stacks: There are a number of feature complete stacks written in C/C++ but integration requires the cooperation of the respective vendor. This touches on topics such as | ||
** availability is limited to certain platforms | ** availability is limited to certain platforms | ||
** the stacks embed (static) copies of third parties such as libxml or | ** the stacks embed (static) copies of third parties such as libxml or OpenSSL. This can clash with Qt third-parties (OpenSSL is a known case). | ||
** vendors might not be too cooperative as it makes their stack replaceable. | ** vendors might not be too cooperative as it makes their stack replaceable. | ||
* One needs to create and maintain a CI-setup for 'x' different stacks | * One needs to create and maintain a CI-setup for 'x' different stacks | ||
* One needs to learn the client side API of 'x' different stacks to create the necessary backends. | * One needs to learn the client side API of 'x' different stacks to create the necessary backends. | ||
* Certain stacks only provide a synchronous API which creates a burden for the Qt-side (which needs to provide an asynchronous API) | * Certain stacks only provide a synchronous API which creates a burden for the Qt-side (which needs to provide an asynchronous API) | ||
* The | * The Qt IO/networking abstraction is bypassed. | ||
=== Positive consequences === | === Positive consequences === | ||
* A lot of heavy lifting has already been done as the existing stacks implement all the complicated things and we just provide a wrapper (unclear if there is actually so much complicated stuff on the client-side). | * A lot of heavy lifting has already been done as the existing stacks implement all the complicated things and we just provide a wrapper (unclear if there is actually so much complicated stuff on the client-side). | ||
== | == Qt OPC UA as a standalone implementation of (client-side) OPC UA == | ||
Assumption: most of the complicated stuff is on the server side. It might be a workable approach to re-implement the client-side of OPC | Assumption: most of the complicated stuff is on the server side. It might be a workable approach to re-implement the client-side of OPC UA from scratch. A lot of projects use a code generator to translate the XML-based protocol/interface description published by the OPC Foundation into code to provide protocol primitives (enums/structs) as well as serialization and deserialization. One could take an existing generator and modify it to generate Qt-ish code. | ||
=== Negative consequences === | === Negative consequences === | ||
* More actually knowledge of the inner workings of OPC | * More actually knowledge of the inner workings of OPC UA are needed. | ||
* The crypto transport might be a lot of work (it is not actually SSL/TLS but close). Open- | * The crypto transport might be a lot of work (it is not actually SSL/TLS but close). Open-source projects typically don't implement it. | ||
=== Positive consequences === | === Positive consequences === | ||
* Much less CI hassle | * Much less CI hassle | ||
* All Qt | * All Qt platforms are automatically supported | ||
* Better integrated with the rest of Qt (other modules like networking, | * Better integrated with the rest of Qt (other modules like networking, SSL or the event loop). | ||
* Full control over the API. It can be done asynchronous without threading constructs and other workarounds. | * Full control over the API. It can be done asynchronous without threading constructs and other workarounds. | ||
* No reliance on the goodwill of commercial vendors. | * No reliance on the goodwill of commercial vendors. | ||
Line 32: | Line 34: | ||
* Arrays are currently not correctly handled. We map them to a single QVariantList. This does not respect their dimensions. | * Arrays are currently not correctly handled. We map them to a single QVariantList. This does not respect their dimensions. | ||
* We give a bad example how to "address" nodes. "ns=1;someidstring" is bad practice. Namespace indexes can change. Hardcoding them in strings is brittle. The correct way to do this is by asking the server for its namespace array. It contains ns-URNs to index mappings. We should offer constructors which support this. | * We give a bad example how to "address" nodes. "ns=1;someidstring" is bad practice. Namespace indexes can change. Hardcoding them in strings is brittle. The correct way to do this is by asking the server for its namespace array. It contains ns-URNs to index mappings. We should offer constructors which support this. | ||
* What kind of node is the QOpcUaNode really? There are eight node types in OPC | * What kind of node is the QOpcUaNode really? There are eight node types in OPC UA. A base type inherited by the seven others. Should there be specialized node types in QOpcUa? Why does QOpcua offer a call() method? Isn't this one specific to MethodNodes? | ||
* Should the QOpcUa client offer "translateBrowsePath" functionality? This is a server-side way to find the nodeid of a node via a path of namespace-indexes/browsenames. | * Should the QOpcUa client offer "translateBrowsePath" functionality? This is a server-side way to find the nodeid of a node via a path of namespace-indexes/browsenames. | ||
* QOpcUaNode::name() returns the display name. What about the browseName? | * QOpcUaNode::name() returns the display name. What about the browseName? | ||
Line 38: | Line 40: | ||
== Handling large namespaces == | == Handling large namespaces == | ||
Sometimes a (QML) HMI only needs to deal with a handful of OPC | Sometimes a (QML) HMI only needs to deal with a handful of OPC UA nodes. It is possible to code this by hand. In other case there are hundreds of nodes (think a PLC/SPS providing access to its internal data). It would be very cumbersome to hand code this. It would be nice if it would be possible to just hand a tree/graph of QObjects - representing the nodes of the OPC UA namespace - into the QML application. | ||
If we look at modules such as | If we look at modules such as Qt D-Bus or Qt Remote Objects two approaches can be seen. | ||
=== Static === | === Static === | ||
A description of the remote-side is feed into a tool at build/compilation time and C++/Qt code is generated. For OPC | A description of the remote-side is feed into a tool at build/compilation time and C++/Qt code is generated. For OPC UA this could be an XML description of the namespace. There is established tooling for that on the OPC UA side. Caveat: this will not work for certain scenarios where nodes are added or removed during operations. This is AFAIK not a show stopper for the overall approach. It just doesn't provide for certain applications of OPC UA. | ||
=== Dynamic === | === Dynamic === | ||
A description of the remote-side is discovered at run-time. Unlike OPC | A description of the remote-side is discovered at run-time. Unlike OPC Classic, OPC UA is self-describing. It can be discovered/enumerated at runtime. |
Revision as of 05:18, 28 September 2017
Qt OPC UA as a wrapper
The current design of the Qt OPC UA module assumes that it is a thin wrapper around an existing OPC UA (client) stack.
Negative consequences
- Open-source stacks: There is as of today no (nearly) feature complete C/C++ open source stack with a suitable license.
- Closed-source stacks: There are a number of feature complete stacks written in C/C++ but integration requires the cooperation of the respective vendor. This touches on topics such as
- availability is limited to certain platforms
- the stacks embed (static) copies of third parties such as libxml or OpenSSL. This can clash with Qt third-parties (OpenSSL is a known case).
- vendors might not be too cooperative as it makes their stack replaceable.
- One needs to create and maintain a CI-setup for 'x' different stacks
- One needs to learn the client side API of 'x' different stacks to create the necessary backends.
- Certain stacks only provide a synchronous API which creates a burden for the Qt-side (which needs to provide an asynchronous API)
- The Qt IO/networking abstraction is bypassed.
Positive consequences
- A lot of heavy lifting has already been done as the existing stacks implement all the complicated things and we just provide a wrapper (unclear if there is actually so much complicated stuff on the client-side).
Qt OPC UA as a standalone implementation of (client-side) OPC UA
Assumption: most of the complicated stuff is on the server side. It might be a workable approach to re-implement the client-side of OPC UA from scratch. A lot of projects use a code generator to translate the XML-based protocol/interface description published by the OPC Foundation into code to provide protocol primitives (enums/structs) as well as serialization and deserialization. One could take an existing generator and modify it to generate Qt-ish code.
Negative consequences
- More actually knowledge of the inner workings of OPC UA are needed.
- The crypto transport might be a lot of work (it is not actually SSL/TLS but close). Open-source projects typically don't implement it.
Positive consequences
- Much less CI hassle
- All Qt platforms are automatically supported
- Better integrated with the rest of Qt (other modules like networking, SSL or the event loop).
- Full control over the API. It can be done asynchronous without threading constructs and other workarounds.
- No reliance on the goodwill of commercial vendors.
API limitations
- Events: the current API does not allow to specify select or where clauses. Select-clauses are used to select fields to be contained in the event notification. The where-clauses are used to filter which events should be notified. Its not uncommon to have a single object with an event notifier attribute for the whole server. Not having the possibility to specify where-clauses means that a client always gets all event notifications.
- Arrays are currently not correctly handled. We map them to a single QVariantList. This does not respect their dimensions.
- We give a bad example how to "address" nodes. "ns=1;someidstring" is bad practice. Namespace indexes can change. Hardcoding them in strings is brittle. The correct way to do this is by asking the server for its namespace array. It contains ns-URNs to index mappings. We should offer constructors which support this.
- What kind of node is the QOpcUaNode really? There are eight node types in OPC UA. A base type inherited by the seven others. Should there be specialized node types in QOpcUa? Why does QOpcua offer a call() method? Isn't this one specific to MethodNodes?
- Should the QOpcUa client offer "translateBrowsePath" functionality? This is a server-side way to find the nodeid of a node via a path of namespace-indexes/browsenames.
- QOpcUaNode::name() returns the display name. What about the browseName?
- QOpcUaNode has no method to access the node description.
Handling large namespaces
Sometimes a (QML) HMI only needs to deal with a handful of OPC UA nodes. It is possible to code this by hand. In other case there are hundreds of nodes (think a PLC/SPS providing access to its internal data). It would be very cumbersome to hand code this. It would be nice if it would be possible to just hand a tree/graph of QObjects - representing the nodes of the OPC UA namespace - into the QML application.
If we look at modules such as Qt D-Bus or Qt Remote Objects two approaches can be seen.
Static
A description of the remote-side is feed into a tool at build/compilation time and C++/Qt code is generated. For OPC UA this could be an XML description of the namespace. There is established tooling for that on the OPC UA side. Caveat: this will not work for certain scenarios where nodes are added or removed during operations. This is AFAIK not a show stopper for the overall approach. It just doesn't provide for certain applications of OPC UA.
Dynamic
A description of the remote-side is discovered at run-time. Unlike OPC Classic, OPC UA is self-describing. It can be discovered/enumerated at runtime.