Update 02.03.2018: the steps outlined below have become outdated.
Please see here for up to date build steps.
basysKom has initiated Qt OpcUa which is a module offering support for the industrial communication standard OPC UA. This module has been contributed by us to the Qt Project. The Qt OpcUa API wraps existing OPC UA implementations. Currently, implementations for freeopcua and open62541 are available.
Qt OpcUa will become part of the Qt 5.11 release as a Technology Preview. First alpha builds will be available by the end of February 2018. Qt 5.11 release is scheduled for end of May 2018.
Why not try out the current state of Qt OpcUa right now?
We have been asked by a number of people how to get started already now. We will provide short howtos for Ubuntu, Windows-MinGW and Visual Studio 2017 in the following article.
Two things are needed: Qt OpcUa itself and an OPC UA library. In this article, we use open62541 as it has very little dependencies (and is the more complete implementation anyway).
The easiest approach to build Qt OpcUa is as a drop-in for Qt 5.10. This spares us from creating a full Qt build based on the current dev branch.
The following recipes assume that you have cmake, python/pip, perl, git and other essential build tools installed. Paths used with the examples need to be adjusted to reflect your local situation.
Installation on Linux
These steps have been tested on Ubuntu 16.04 but can be applied to a wide range of desktop distributions.
$ sudo pip install six $ git clone https://github.com/open62541/open62541.git $ cd open62541 $ git checkout 302003d $ mkdir build && cd build $ cmake -DBUILD_SHARED_LIBS=ON -DUA_ENABLE_AMALGAMATION=ON .. $ make $ sudo make install $ git clone http://code.qt.io/qt/qtopcua.git $ cd qtopcua $ mkdir build && cd build $ /opt/Qt5.10/5.10.0/gcc_64/bin/qmake .. # has open62541 been detected? $ make $ sudo make install
Installation on Windows (Visual Studio 2017)
Start by running the Qt 5.10.0 64-bit for Desktop (MSVC 2017) shell shipped with Qt (have a look at the “Start Menu”). Use this shell to issue the following commands:
"c:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Auxiliary\Build\vcvarsx86_amd64.bat" pip install six git clone https://github.com/open62541/open62541.git cd open62541 git checkout 302003d mkdir build cd build cmake.exe -G "NMake Makefiles" -DUA_ENABLE_AMALGAMATION=ON .. nmake.exe git clone http://code.qt.io/qt/qtopcua.git cd qtopcua mkdir build cd build set INCLUDE=%INCLUDE%;c:\path\to\open62541\build set LIB=%LIB%;c:\path\to\open62541\build\bin qmake.exe .. # has open62541 been detected? nmake.exe nmame.exe install
Above recipe will also work for Visual Studio 2015. 2013 is not supported (and will be dropped by Qt 5.11 anyways).
Installation on Windows (MinGW as shipped with Qt 5.10)
Start by running the Qt 5.10.0 for Desktop (MinGW 5.3.0 32 bit) shell shipped with Qt (have a look at the “Start Menu”). Use this shell to issue the following commands:
pip install six git clone https://github.com/open62541/open62541.git cd open62541 git checkout 302003d mkdir build cd build cmake.exe -G "MinGW Makefiles" -DUA_ENABLE_AMALGAMATION=ON .. mingw32-make.exe git clone http://code.qt.io/qt/qtopcua.git cd qtopcua mkdir build cd build set CPLUS_INCLUDE_PATH=c:\path\to\open62541\build set LIBRARY_PATH=c:\path\to\open62541\build\bin qmake.exe .. mingw32-make.exe mingw32-make.exe install
Usage
After successful completion of above steps Qt OpcUa will be available from your existing Qt5.10 installation. A documentation snapshot can be found here.
The following “Hello Qt OpcUa” example shows how to read an attribute from a server (add QT += opcua to your .pro).
#include #include class QOpcUaReader : public QObject { Q_OBJECT public: QOpcUaReader(QObject *parent); bool init(); void handleStateChanged(QOpcUaClient::ClientState state); void handleAttributeRead(QOpcUa::NodeAttributes attr); signals: void done(); private: QScopedPointer m_client; QScopedPointer m_node; }; QOpcUaReader::QOpcUaReader(QObject *parent) : QObject(parent) {} bool QOpcUaReader::init() { QOpcUaProvider p; qDebug() << "Available backends:" << p.availableBackends(); if (p.availableBackends().size() == 0) { qDebug() << "No backends found"; return false; } m_client.reset(p.createClient(p.availableBackends()[0])); if (!m_client) { qDebug() << "Failed to create client"; return false; } QObject::connect(m_client.data(), &QOpcUaClient::stateChanged, this, &QOpcUaReader::handleStateChanged); m_client->connectToEndpoint(QUrl("opc.tcp://opcua.demo-this.com:51210/UA/SampleServer")); return true; } void QOpcUaReader::handleStateChanged(QOpcUaClient::ClientState state) { qDebug() << "Client state changed:" << state; switch(state) { case QOpcUaClient::ClientState::Connected: { m_node.reset(m_client->node("ns=0;i=84")); if (!m_node) { qDebug() << "Failed to get node"; emit done(); break; } QObject::connect(m_node.data(), &QOpcUaNode::attributeRead, this, &QOpcUaReader::handleAttributeRead); m_node->readAttributes(QOpcUa::NodeAttribute::BrowseName); break; } case QOpcUaClient::Disconnected: { emit done(); break; } default: break; } } void QOpcUaReader::handleAttributeRead(QOpcUa::NodeAttributes attr) { qDebug() << "Signal for attributes:" << attr; if (m_node->attributeError(QOpcUa::NodeAttribute::BrowseName) == QOpcUa::UaStatusCode::Good) qDebug() << "Browse name:" << m_node->attribute(QOpcUa::NodeAttribute::BrowseName).value().name; else qDebug() << "Failed to read attribute:" << m_node->attributeError(QOpcUa::NodeAttribute::BrowseName); m_client->disconnectFromEndpoint(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QOpcUaReader reader(&a); QObject::connect(&reader, &QOpcUaReader::done, &a, &QCoreApplication::quit); if (!reader.init()) return 1; return a.exec(); } #include "main.moc"
Conclusion
Most of the API envisioned for the Technology Preview is available. We are currently busy testing and polishing, as well as adding more comprehensive examples and improving the documentation. Please leave a comment or get in contact with us if you have any questions or comments – you still have the chance to influence the final shape of the API.