How to display data from MQTT server in real-time?



  • Hi Everyone!
    I am mostly into hardware side. Wanted to make a UI for my project but its not working. I am receiving a sensor data using a function on an interval of 1 sec. The code is written in C++.
    Now I want that data (Which is basically an output of a C++ function) to be displayed into QML widget. The data is continuously being outputted.
    I tried multiple ways to resolved this. For example:
    i) Q_Property
    ii) Q_Invokable etc.
    But not of them actually worked for me. I was able to connect Qt and receive a single output in QML.
    But I want the sensor data should continuously flow from Qt to QML. So that I could further plot them onto any Qml-widgit.

    I request you to please provide if any realtime example(code) if anybody has resolve similar kind of issue.
    Thanks in advance for the help.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Please show us your code (C++ and QML). Qt already provides several examples of integrating C++ with QML/QtQuick in its documentation. It would be best to find what is going on with your application.



  • @AntonioQt I would do this:

    • A backend class in C++
    • It has a signal with either no argument or the (simple) sensor data as argument
    • Because it already receives data once per second it can also send the signal once per second
    • The backend object is created in main.cpp and set as a context property to the QML engine
    • In QML the signal is received using Connections
    • If the data isn't in the signal it is fetched through a slot of the backend

    But as SGaist said if you have tried things already and have particular problems you should show us some code.



  • Thank you @SGaist and @Eeli-K . Sorry for not providing the code. Below are the code which is outputting data at every second. I am basically receiving data from MQTT cloud service.
    The function "onMQTT_Received" is actually responsible for providing me data (which is str) on console. I could not provide you my code in which I am trying to expose this data onto QML, because that is a mess and so ugly. However from the following code, I want the data (str) in QML. Please guide me. Below is the code:

    //MyDataClass.h
    
    class MyDataClass : public QObject
    {
        Q_OBJECT
    public:
        explicit MyDataClass(QObject *parent=0);
        ~MyDataClass();
    
    public slots:
        QString MQTT_Received();
        void onMQTT_Connected();
        void onMQTT_disconnected();
        void onMQTT_Received(const QMQTT::Message &message);
    
    private:
        QMQTT::Client *client;
    
    };
    

    //MyDataClass.cpp

    #include "MyDataClass.h"
    #include <QCoreApplication>
    #include <QDebug>
    #include <iostream>
    MyDataClass::MyDataClass(QObject *parent): QObject(parent)
    {
        client = new QMQTT::Client();
        QObject::connect(client, SIGNAL(connected()), this, SLOT(onMQTT_Connected()));
        QObject::connect(client, SIGNAL(disconnected()), this, SLOT(onMQTT_disconnected()));
        QObject::connect(client, SIGNAL(received(const QMQTT::Message &)), this, SLOT(onMQTT_Received(const QMQTT::Message &)));
        client->setHost("xxx.xxxx.com");
        client->setPort(xxxxx);
        client->setUsername("xxxxxx");
        client->setPassword("xxxxxxxxx");
        client->connect();
        qDebug() << "configured";
    }
    
    MyDataClass::~MyDataClass()
    {
    }
    
    void MyDataClass::onMQTT_Connected()
    {
        client->subscribe("python/test",0);
        qDebug() << "Subscribed";
    }
    
    void MyDataClass::onMQTT_Received(const QMQTT::Message &message)
    {
        QString str, m_message;
        str = message.payload();
        qDebug() << str;
    }
    
    void MyDataClass::onMQTT_disconnected()
    {
        qDebug() << "Disconnected";
    }
    
    
    


  • @AntonioQt So you have the C++ class ready, why don't you continue with the steps I mentioned? Do you have some specific problem?



  • I made the following changes in the above code:

    	//MyDataClass.h
    	    Q_INVOKABLE QString onMQTT_Received(const QMQTT::Message &message);
    
    	//MyDataClass.cpp
    	QString MyDataClass::onMQTT_Received(const QMQTT::Message &message)
    	{
    		QString str;
    		str = message.payload();
    		return str;
    	}
    
    	//main.qml
    	import QtQuick 2.6
    	ApplicationWindow {
    		id: root
    		width: 300
    		height: 480
    		visible: true
    		Text{
    			text:MyDataClass.onMQTT_Received()
    		}
    	}
    

    But not seeing any output in QML window. Do I need change anything else?



  • @AntonioQt http://doc.qt.io/qt-5/qtqml-cppintegration-overview.html#embedding-c-objects-into-qml-with-context-properties

    Send a signal from the C++ object and catch it in QML using Connections (see the Qt docs) type.



  • Tried with various combinations but not getting output. Kindly provide the code example. My code updates are as below:

    //main.cpp
    
        QQuickView view;
        MyDataClass data;
    
        view.rootContext()->setContextProperty("myobj", &data);
        view.setSource(QUrl::fromLocalFile("qrc:/main.qml"));
        view.show();
    
    //MyDataClass.cpp
    QString MyDataClass::onMQTT_Received(const QMQTT::Message &message)
    {
        QString str;
        str = message.payload();
        qDebug() << str;
        emit mySignal(str);
        return str;
    }
    
    //main.qml
    
    Item {
        width: 500; height: 800
        Connections {
        target: myobj
        onMySignal:console.log(str)
        }
    

    Am I making some mistakes? Kindly help me resolving this issue. I am not getting output in QML.


  • Lifetime Qt Champion

    What is the signature of your signal ?



  • Sorry for late response, I was away.
    As @SGaist asked below are my code snippet:

     QObject::connect(client, SIGNAL(received(const QMQTT::Message &)), this, SLOT(onMQTT_Received(const QMQTT::Message &)));
    

    I copied from my second comment above.
    I hope I understand your question correctly.
    How can I catch this signal in QML?


  • Lifetime Qt Champion

    Where's your QMQTT come from ?



  • @SGaist
    I got this library from here:
    https://github.com/emqtt/qmqtt/tree/master/src/mqtt

    I am using this library to receive data from cloud. This library is fulfilling the requirement - as I am getting the output in Qt as I commented above. Now I just wanted this data(output) in QML.


  • Lifetime Qt Champion

    I'd suggest taking a look at Qt's own module for that (it's all new), you can find it here and it might make things easier to integrate with QML.



  • @AntonioQt "What is the signature of your signal ?" like @SGaist asked - i.e. how it is declared in C++ header? QML sees the argument by the name which is in C++ declaration, not call time name. "onMySignal:console.log(str)" should work if you have

    signals: void mySignal(QString str);
    

    but not if you have e.g.

    signals: void mySignal(QString someString); //you must use "someString" in QML
    


  • Thinking of trying this @SGaist . But not getting exact link to download the library.



  • @Eeli-K Following the same. But not getting the output. I m trying now the latest library as @SGaist suggested.



  • @AntonioQt You've got:

    //MyDataClass.cpp
    QString MyDataClass::onMQTT_Received(const QMQTT::Message &message)
    {
        QString str;
        str = message.payload();
        qDebug() << str;
        emit mySignal(str);
        return str;
    }
    

    and if the str is seen in the debug output then the problem isn't in the mqtt library, it's in your C++ or QML code. So, provided that you have

    signals: void mySignal(QString str);
    

    in your class header, MyDataClass::onMQTT_Received as seen above,

    view.rootContext()->setContextProperty("myobj", &data);
    

    in main.cpp,

    Connections{
    target: myobj
    onMySignal: {console.log("String received! " + str)}
    }
    

    and you see the string in C++ debug output you should also see the "String received!" message plus the string in QML debug output. If not, there's something weird going on. You can also try adding

    Component.onCompleted: {console.log(myobj)}
    

    to an item in your main.qml to see if the C++ object is really recognized.

    EDIT: If you test something with debug output, please paste the real output here. Sometimes it gives an answer you don't notice and we can't tell without seeing.


  • Lifetime Qt Champion

    Looks like the repository is not yet on code.qt.io, but you can get it here.



  • @Eeli-K This worked! :D

    Thank you so much.
    There were two issues with the code, first was resolved by the snippet you provided above.
    The second I observed while copying the qDebug output for you guys. There was an error message :

    file:qrc:/main.qml: No such file or directory
    

    Means that, no signals were being passed into "main.qml". Then I searched for the resolution and the solution was, modifying the following code in "main.cpp":

    view.setSource (QUrl("qrc:///main.qml"));
    

    I did not dig much about how/why it happened?

    The next thing I am looking for -to use the str (variable) in Qml. I just want to use this (or any other single) variable with Qml widget. Do we have any quickest way to achieve this?
    Once again thank you very much @Eeli-K and @SGaist for your efforts and guidance.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.