当前位置: 移动技术网 > 网络运营>服务器>Linux > QT使用MQTT协议对接华为IOT平台

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

2020年08月12日  | 移动技术网网络运营  | 我要评论
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文件夹复制到工程目录下,并添加到工程中。
  2. QT工程的修改
    (1)pro文件的修改

    (2)在qt直接使用就可以了,包含头文件#include <mqtt/qmqtt.h>
    在这里插入图片描述

三、对接华为IoT平台

  1. 华为设备接入开发文档
    进入华为云官网,点击文档
    在这里插入图片描述
    在这里插入图片描述
        在MQTT设备快速接入这篇文章中,详细说明了如何通过设备id以及设备密钥生成接入信息的步骤。下面将一步步的演示这些步骤。
  2. 创建产品并注册设备,这里直接借用华为文档中的图片。
    在这里插入图片描述
  3. 生成连接信息,这部分也是文档中的一部分,点击文档中的 连接信息生成工具 即可下载。

        下载完成后,打开填入自己的设备ID和设备密钥,点击Generate生成,会在Message框中显示需要的 ClientID、username、password。(注:这个工具需要安装JDK,在华为云文档中有链接)。
    在这里插入图片描述
  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参考中有详细介绍。直接附图。
在这里插入图片描述

在这里插入图片描述
    根据开发文档给的示例格式,我们需要封装一个这样的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.
在这里插入图片描述

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

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网