• 【嵌入式linux开发】智能家居入门6:最新ONENET,物联网开放平台(QT、微信小程序、MQTT协议、ONENET云平台、旭日x3派)


    前言

    ONENET云平台更新之后,已经将以前的多协议接入这部分融合进了物联网开放平台,以前在多协议接入里创建的产品和设备,虽然还可以用,但实际上已经过时了,因为新用户根本没有多协议接入这个选项。我的这系列前几篇文章有的也已经失去了实际意义,但是使用mqtt服务器的这两篇(入门三入门四)仍然有效!因为它们使用mqtt服务器和onenet没关系。本篇文章给想接入最新版onenet的小伙伴提供参考。

    须知:新版的http协议接入已经跟之前的完全不一样了,看了官方文档和亲身实践,http协议只能上传数据至服务器,已经不能从服务器获取数据了,所以对于需要双向控制的智能家居而言已经没有啥价值了,本文使用MQTT协议接入,响应快、可靠度高,程序的健壮性也已经测试,在板端跑了几天也没有出问题!
    本文下位机(旭日x3派运行QT)与服务器的通信使用mqtt协议,而上位机(微信小程序)与服务器的通信使用的是标准http方法!这是因为官方文档中,服务器的API接口就是使用标准HTTP方法实现资源CURD操作,这个在本文第四节有介绍,如果有小伙伴在微信小程序端也使用mqtt协议与服务器通信的话,可以互相交流一下。

    ***最重要的参考就是官方文档:https://open.iot.10086.cn/doc/v5/fuse/detail/1464
    QT端的mqtt报文构建直接使用DS小龙哥的代码
    微信小程序在之前的基础上改改即可


    最终现象

    linux QT智能家居演示


    一、ONENET云平台创建产品与设备

    这部分直接以视频的形式给出:

    需要注意的点:
    ①数据协议:
    这里选择的是OneJson,当然也可以选择数据流,但是它们对应的发送数据和接收数据的topic是不一样的,所以如果想省事直接使用本文代码,那就选择OneJson。
    在这里插入图片描述

    ②新版三元组:
    按照视频创建完毕后,进入设备管理的详情中,可以看到后续会用到的三个参数:
    在这里插入图片描述


    二、使用MQTT客户端软件测试

    2.1 测试前的准备

    ①token:
    产品与设备创建完成之后,按照文档指示,需要计算token,在连接时会用到:
    在这里插入图片描述
    这里的clienid和username就是前面截图中包含的两个参数:设备名称、产品ID,这里的password就是使用官方软件计算生成的token。
    接下来视频演示如何计算token:

    重点如下:
    在这里插入图片描述
    纠错:上图中的时间过小,在后面多加随便一个数字既可:2810295937232。
    ②OneJson数据协议对应的发布、订阅topic:
    文档中有明确给出OneJson数据协议(物模型)的发布和订阅topic,如果数据协议选择数据流的小伙伴,在文档的这个界面往后翻翻就可以看到对应的。
    在这里插入图片描述
    在连上服务器之后,对这两个topic操作就可以上传和接收数据啦!

    2.2 测试

    下载客户端软件,提取码:q1a1,这是DS小龙哥开源的,填入自己的信息:
    在这里插入图片描述
    ①数据上传测试:
    点击登录即可连接上服务器,然后点击发布主题就可以把数据发布到特定的物模型中,可以在onenet云平台中观察是否成功:
    在这里插入图片描述
    ②数据下发测试:
    onenet中进入设备调试界面,将fan_ctl设置为true,然后点击属性期望值设置。客户端软件同样连接服务器之后,点击订阅主题,观察是否收到服务器下发的消息:
    在这里插入图片描述

    在这里插入图片描述
    这样双向测试就算完成了,接下来就是下位机与上位机的代码简介。

    三、LInux QT代码

    既然上面的MQTT客户端软件已经可以实现连接服务器、发布话题、订阅话题了,那说明在自己的界面中编写代码是可行的。如果不知道如何设计界面可以参考本系列第五篇文章
    项目的目录结构如下:
    在这里插入图片描述
    其中mqtt这两个文件是DS小龙哥开源的,具体哪篇文章我也找不见了,我加了一个信号来解析接收到的服务器下发的json数据。这个mqtt代码的好处就是短小精悍,完全够用,避免了使用官方库麻烦的缺点,当然喜欢使用官方qmqtt库的小伙伴可以参考网上的教程进行编译和移植,然后自己编写相关逻辑。
    由于找不到原文章,这里就给出原博主的代码:
    mqtt.cpp

    #include "mqtt.h"
    
    //连接成功服务器回应 20 02 00 00
    //客户端主动断开连接 e0 00
    const quint8 parket_connetAck[] = {0x20,0x02,0x00,0x00};
    const quint8 parket_disconnet[] = {0xe0,0x00};
    const quint8 parket_heart[] = {0xc0,0x00};
    const quint8 parket_heart_reply[] = {0xc0,0x00};
    const quint8 parket_subAck[] = {0x90,0x03};
    
    MQTT_WorkClass::~MQTT_WorkClass()
    {
        qDebug()<<"析构函数---TCP";
    }
    
    void MQTT_WorkClass::run()
    {
        qDebug()<<"执行:run";
    
        if(timer)
        {
            delete  timer;
            timer=nullptr;
        }
        timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(EndEvenLoop()));
    
        socket_type=0;
        //连接到服务器
        ConnectMqttServer(m_ip,m_port);
        //开始事件循环
        StartEvenLoop();
    
        //初始化mqtt协议
        MQTT_Init();
    
        //连接mqtt协议
        if(MQTT_Connect(m_MQTT_ClientID.toUtf8().data(),m_MQTT_UserName.toUtf8().data(),m_MQTT_PassWord.toUtf8().data()))
        {
            LogSend("MQTT服务器登录失败.\n");
        }
        else
        {
            LogSend("MQTT服务器登录成功.\n");
        }
    }
    
    
    void MQTT_WorkClass::MQTT_Init(void)
    {
        //缓冲区赋值
    	mqtt_rxbuf = _mqtt_rxbuf;
        mqtt_rxlen = sizeof(_mqtt_rxbuf);
    	mqtt_txbuf = _mqtt_txbuf;
        mqtt_txlen = sizeof(_mqtt_txbuf);
    	memset(mqtt_rxbuf,0,mqtt_rxlen);
    	memset(mqtt_txbuf,0,mqtt_txlen);
    }
    
    /*
    函数功能: 登录服务器
    函数返回值: 0表示成功 1表示失败
    */
    quint8 MQTT_WorkClass::MQTT_Connect(char *ClientID,char *Username,char *Password)
    {
        quint8 i,j;
        int ClientIDLen = strlen(ClientID);
        int UsernameLen = strlen(Username);
        int PasswordLen = strlen(Password);
        int DataLen;
    	mqtt_txlen=0;
    	//可变报头+Payload  每个字段包含两个字节的长度标识
        DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
    	
    	//固定报头
    	//控制报文类型
        mqtt_txbuf[mqtt_txlen++] = 0x10;		//MQTT Message Type CONNECT
    	//剩余长度(不包括固定头部)
    	do
    	{
            quint8 encodedByte = DataLen % 128;
    		DataLen = DataLen / 128;
    		// if there are more data to encode, set the top bit of this byte
    		if ( DataLen > 0 )
    			encodedByte = encodedByte | 128;
  • 相关阅读:
    【PyQt】12-滑块、计数控件
    大数据面试题:Spark和Flink的区别
    网易笔试题——mysql整理
    Windows本地mysql 的安装教程(一步一步进行安装)
    Linux重定向+管道命令+环境变量PATH
    UWB芯片DW3000之PDOA测向实现源码
    I.MX6U-驱动开发-4-linux设备树
    划词标注或打标签的实现方案
    [激光原理与应用-40]:《光电检测技术-7》- 常见光干涉仪及其应用
    不止硬件,苹果的软件也是频出问题!iOS 17.0.3使iPhone在一夜之间随机开关机
  • 原文地址:https://blog.csdn.net/m0_71523511/article/details/141276130