欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

QT使用MQTT协议对接华为IOT平台

程序员文章站 2022-06-09 18:46:08
QT使用MQTT协议对接华为IOT平台文章目录QT使用MQTT协议对接华为IOT平台一、环境说明二、QMQTT源码编译三、对接华为IoT平台四、效果验证    最近想使用QT通过MQTT协议接入华为的IOT平台,实现数据的上报以及命令的接收,经过查找资料,可以使用QT的MQTT协议来完成这样的功能,下面是此次实验过程中的记录。一、环境说明开发环境:Ubuntu16.04 x64软件:Qt 5.5.1 for Embedded交叉编译工具链:arm-Linux-guneabihf硬件平台:正点...


    最近想使用QT通过MQTT协议接入华为的IOT平台,实现数据的上报以及命令的接收,经过查找资料,可以使用QT的MQTT协议来完成这样的功能,下面是此次实验过程中的记录。

一、环境说明

  1. 开发环境:Ubuntu16.04 x64
  2. 软件:Qt 5.5.1 for Embedded
  3. 交叉编译工具链:arm-Linux-guneabihf
  4. 硬件平台:正点原子ALPHA Linux开发板

二、QMQTT源码编译

    目前Qt5.11中已经提供了类似TCP或者UDP的MQTT类,但是想要在低于此版本的Qt中使用MQTT协议,就需要自行编译开源MQTT消息服务EMQTT为Qt提供的QMQTT源码。下面具体介绍在Ubuntu下使用该源码的方式。

  1. 下载QMQTT源码,在Linux终端中使用git 下载源码
git clone https://github.com/emqtt/qmqtt
  1. 网上有网友将QMQTT的源码编译成了.so或者dll的库文件,我在使用交叉编译工具链编译的时候出现了问题,没有解决,就采用了一位网友简单粗暴的方式,将所有的.cpp和.h文件copy到工程目录下并添加的到工程,编译出来的可执行文件大约7M。打开下载好的文件进入src目录下,将mqtt文件夹复制到工程目录下,并添加到工程中。
    QT使用MQTT协议对接华为IOT平台
  2. QT工程的修改
    (1)pro文件的修改
    QT使用MQTT协议对接华为IOT平台
    (2)在qt直接使用就可以了,包含头文件#include <mqtt/qmqtt.h>
    QT使用MQTT协议对接华为IOT平台

三、对接华为IoT平台

  1. 华为设备接入开发文档
    QT使用MQTT协议对接华为IOT平台
    QT使用MQTT协议对接华为IOT平台
    QT使用MQTT协议对接华为IOT平台
        在MQTT设备快速接入这篇文章中,详细说明了如何通过设备id以及设备密钥生成接入信息的步骤。下面将一步步的演示这些步骤。
  2. 创建产品并注册设备,这里直接借用华为文档中的图片。
    QT使用MQTT协议对接华为IOT平台
  3. 生成连接信息,这部分也是文档中的一部分,点击文档中的 连接信息生成工具 即可下载。
    QT使用MQTT协议对接华为IOT平台
        下载完成后,打开填入自己的设备ID和设备密钥,点击Generate生成,会在Message框中显示需要的 ClientID、username、password。(注:这个工具需要安装JDK,在华为云文档中有链接)。
    QT使用MQTT协议对接华为IOT平台
  4. QT工程中使用,完成上述步骤后,在QT中就可以直接编写一个MQTT Client来实现对接到华为云的功能。
    (1)初始化MQTT
//MqttClient.h
#ifndef MQTTCLIENT_H
#define MQTTCLIENT_H

#include <QObject>
#include <macroinclude.h>
#include <mqtt/qmqtt.h>

class MqttClient : public QObject
{
    Q_OBJECT
public:
    explicit MqttClient(QObject *parent = 0);
    void mqttInit(QString domainName, quint16 Port);
signals:

public slots:
    void onMQTT_Received(QMQTT::Message message);
    void connectTOHuaWeiIOT(QString domainName, quint16 Port);
    void disConnectTOHuaWeiIOT();
    void MQTT_SendMessage(QMQTT::Message msg);
private:
    QMQTT::Client mqttclient;
};

#endif // MQTTCLIENT_H
//MqttClient.pp
#include "MqttClient.h"

MqttClient::MqttClient(QObject *parent) : QObject(parent)
{

}
//mqtt 初始化
void MqttClient::mqttInit(QString domainName, quint16 Port)
{
    QHostInfo info = QHostInfo::fromName(domainName);
    QString host = info.addresses().first().toString(); // 代理服务器 IP
    qDebug() << host;

//    mqttclient = new QMQTT::Client(QHostAddress(host),Port);
    mqttclient.setKeepAlive(120);
    mqttclient.setHost(QHostAddress(host));
    mqttclient.setPort(Port);
    mqttclient.setClientId(CLIENTID);
    mqttclient.setUsername(USERNAME);
    mqttclient.setPassword(PASSWORD);
    mqttclient.cleanSession();
    mqttclient.setVersion(QMQTT::MQTTVersion::V3_1_1); // 设置mqtt版本
    connect(&mqttclient,SIGNAL(received(QMQTT::Message)),this,SLOT(onMQTT_Received(QMQTT::Message)));
}


//链接到华为物联网平台
void MqttClient::connectTOHuaWeiIOT(QString domainName, quint16 Port)
{
    //初始化 MQTT
    mqttInit(domainName,Port);
    mqttclient.connectToHost();
    qDebug()<<"connect to host success!!";
}

//断开与平台的链接
void MqttClient::disConnectTOHuaWeiIOT()
{
    mqttclient.disconnectFromHost();
    qDebug()<<"disconnect huaweiIOT!!";
}

//接收消息的槽函数
void MqttClient::onMQTT_Received(QMQTT::Message message)
{
    QString str(message.payload());
    qDebug()<<"onMQTT_Received: "<<str;
    QMQTT::Message message();

}

//发送消息的槽函数
void MqttClient::MQTT_SendMessage(QMQTT::Message msg)
{
    mqttclient.publish(msg);
}

(2)Widget.cpp中使用,主要是连接按钮和断开连接按钮以及一个发送按钮信号槽的编写,这边直接展示槽函数,信号由Button触发。

//构造函数中
MqttClient *MQTTClient;
MQTTClient = new MqttClient(this);
//连接华为IOT
void Widget::connectToHuaweiIoT_slot(QString domainName,quint16 port)
{
    MQTTClient->connectTOHuaWeiIOT(domainName,port);
}

//断开连接华为Iot
void Widget::disconnectTOHuaweiIoT_slot()
{
    MQTTClient->disConnectTOHuaWeiIOT();
}
//设备属性上报
connect(ui->toolButton,&QToolButton::clicked,[this](){
        QString topic = EQUIPMENT_REPORT_TOPIC;
        qDebug()<<topic;
        QByteArray array = getEquipmentReportJson();
        qDebug()<<array;
        QMQTT::Message msg(0,topic,array);
        MQTTClient->MQTT_SendMessage(msg);

    });

    其中在设备属性上报中,EQUIPMENT_REPORT_TOPIC是华为IOT平台提供的一个topic,MQTT实质是一种发布订阅模式,此topic是设备上报属性时用的topic,其他topic在华为设备接入文档API参考中有详细介绍。直接附图。
QT使用MQTT协议对接华为IOT平台

QT使用MQTT协议对接华为IOT平台
    根据开发文档给的示例格式,我们需要封装一个这样的JSON数据包,在QT中有相关的JSON类,例如 JSONObject,JSONArray,JSONValue,JSONDocument等等,下面是我封装的一个设备属性上报的JSON数据包,并使用QJSONDocument转换为QByteArray(原因下面介绍)。

#include "JsonUtils.h"

//设备属性上报JSON封装
/*
 {
    "service_id": "Battery",
    "properties": {
        "batteryLevel": 80
    },
    "event_time": "20201212T121212Z"
 }
*/
QByteArray getEquipmentReportJson()
{
    //构建 JSON 对象 properties
    QJsonObject propertiesObj;
    propertiesObj.insert("batteryLevel",80);

    //构建 JSON 对象
    QJsonObject jsonObj;
    jsonObj.insert("service_id","Battery");
    jsonObj.insert("event_time",getSystemTime());
    jsonObj.insert("properties",QJsonValue(propertiesObj));

    //添加到JSON数组 services
    QJsonArray jsonarray;
    jsonarray.push_back(jsonObj);

    //构建 JSON 总体对象
    QJsonObject json;
    json.insert("services",QJsonValue(jsonarray));

    //构建 JSON 文档
    QJsonDocument document;
    document.setObject(json);
    QByteArray byteArray = document.toJson(QJsonDocument::Compact);
    return byteArray;
}

//获取当前系统时间 IOT平台那边接受的是格林威治时间,GMT+8.00
QString getSystemTime()
{
    QDateTime currentTime = QDateTime::currentDateTime();
    QString currentTimeStr = currentTime.toString("yyyyMMddThhmmssZ");
    QTime current_time =QTime::currentTime();
    int hour_int =  current_time.hour();
    if(hour_int >= 8) hour_int -= 8;
    else hour_int = 24 + hour_int - 8;
    QString hour = QString::number(hour_int);//当前的小时
    QString result = currentTimeStr.mid(0,9)+hour+currentTimeStr.mid(11);
    return result;
}

    这边的一个getSystemTime()是本人编写的一个获取系统时间的函数(写的有点复杂,好在能用),由于华为IOT平台那边使用的GMT+8.00,会在我们上报的时间基础上再加上8小时,所以我们上报时,要将上报时间减去八小时。
    通过getEquipmentReportJson()这个函数就输出了我们需要上报的数据,为什么要使用QByteArray这样的数据呢,这个是由QMQTT::Message的构造函数决定。我们上报数据使用的是

quint16 QMQTT::Client::publish(const Message& message);

    而QMQTT::Message的构造函数如下:

//qmqtt_message.cpp
Message::Message(const quint16 id, const QString &topic, const QByteArray &payload,
                 const quint8 qos, const bool retain, const bool dup)
    : d(new MessagePrivate(id, topic, payload, qos, retain, dup))
{
}
//qmqtt_message.h
explicit Message(const quint16 id, const QString &topic, const QByteArray &payload,
                     const quint8 qos = 0, const bool retain = false, const bool dup = false);

    Message的构造函数有六个参数,其中后三个参数都是有默认值的,第一个参数为id,第二个为发布的topic(由物联网平台或者用户自己订阅),第三个是要发送的数据,是一个QByteArray类型,因此就有了通过JSON来生成QByteArray这样的一个步骤。

四、效果验证

    这边可以看到在2020/08/09 23:54:18 GMT+08:00我上报的最新的消息为80.
QT使用MQTT协议对接华为IOT平台

本文地址:https://blog.csdn.net/qq_33685823/article/details/107908533