basysKom Application Development Services

Want to give Qt OpcUa a try?
Essential Summary
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.

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.

Qt OpcUa

Picture of Frank Meerkötter

Frank Meerkötter

Frank Meerkoetter is the Development Lead for basysKom GmbH, where he is consulting customers on industrial and embedded applications, often in combination with Qt. He is responsible for the technical consulting, system- and software-architecture within basysKom. He used to be the the maintainer of Qt OPC UA (2017-2024) and a contributor to the Qt project. He has a strong background in Embedded Linux, systems programming, distributed systems and application development. He holds a Master of Computer Science from the University of Applied Sciences in Darmstadt.

Leave a Reply

Your email address will not be published. Required fields are marked *

More Blogarticles

basysKom Newsletter

We collect only the data you enter in this form (no IP address or information that can be derived from it). The collected data is only used in order to send you our regular newsletters, from which you can unsubscribe at any point using the link at the bottom of each newsletter. We will retain this information until you ask us to delete it permanently. For more information about our privacy policy, read Privacy Policy