物联网实战--平台篇之(十四)物模型(用户端)

目录

一、底层数据解析

二、物模型后端

三、物模型前端

四、数据下行


本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.html

嵌入式文件 https://download.csdn.net/download/ypp240124016/89409505

APP文件 https://download.csdn.net/download/ypp240124016/89409506

一、底层数据解析

        手机端从MQTT服务器收到消息后,首先需要根据协议对数据进行解析,把最终的应用层数据找出并传递到具体的设备模型中去,具体过程如下。


void CenterMan::parseDeciceRecv(QByteArray msg_ba)
{
#define     OUT_BUFF_SIZE   1500
#define     IN_BUFF_SIZE       1500u8 head[]={0xAA, 0x55}, *pBuff=NULL, *pData=NULL;u8 pack_num=0, cmd_type=0;u32 app_id, curr_dev_sn, next_dev_sn, parent_sn;u16 in_len, out_len, crcValue, data_len=0;u8 out_buff[OUT_BUFF_SIZE]={0}, in_buff[IN_BUFF_SIZE]={0};if( (pBuff=drv_com.memstr((u8*)msg_ba.data(), msg_ba.size(), head, 2)) != NULL ){ServerHeadStruct *pSeverHead=(ServerHeadStruct*)pBuff;crcValue=pSeverHead->crc_h<<8|pSeverHead->crc_l;data_len=pSeverHead->data_len_h<<8|pSeverHead->data_len_l;pData=pBuff+8;//指到app_id地址if(data_len<8 ||  crcValue != drv_com.crc16(pData, data_len))//CRC校验{qDebug("deviceRecvProcess: crc error!\n");return;}app_id=pData[0]<<24|pData[1]<<16|pData[2]<<8|pData[3];pData+=4;curr_dev_sn=pData[0]<<24|pData[1]<<16|pData[2]<<8|pData[3];parent_sn=0;pData+=4;//指向数据区
//        qDebug("deviceRecvProcess: app_id=%u, gw_sn=%08X", app_id, curr_dev_sn);if(app_id==0 || curr_dev_sn==0){qDebug("deviceRecvProcess error: app_id==0 || curr_dev_sn==0");return;}in_len=data_len-8;//加密数据长度if(in_len>IN_BUFF_SIZE)//数据包过长{qDebug("deviceRecvProcess error: in_len>DATA_BUFF_SIZE, in_len=%d", in_len);return;}memcpy(in_buff, pData, in_len);//复制数据u8 deep_counts=1;while(curr_dev_sn>0){u8 encrypt_mode=ENCRYPT_MODE_DISABLE;u8 encrypt_index=0;u8 passwd_buff[20]={0};if(deep_counts==1)//网关设备{encrypt_index=pSeverHead->encrypt_index;//密码索引encrypt_mode=takeDevicePasswd(curr_dev_sn, encrypt_index, passwd_buff);//获取该设备的通讯密码} switch(encrypt_mode){case ENCRYPT_MODE_DISABLE: //不加密{out_len=in_len;if(out_len>OUT_BUFF_SIZE)out_len=0;memcpy(out_buff, in_buff, in_len);break;}case ENCRYPT_MODE_TEA: //TEA加密{out_len=drv_com.TEA_DecryptBuffer(in_buff, in_len, (u32*)passwd_buff);if(out_len>OUT_BUFF_SIZE)out_len=0;memcpy(out_buff, in_buff, out_len);break;}case ENCRYPT_MODE_AES: //AES加密{out_len=drv_com.aes_decrypt_buff(in_buff, in_len, out_buff, OUT_BUFF_SIZE, passwd_buff);break;}default: return;//出错}if(out_len>0){pBuff=pData=out_buff;data_len=pData[0]<<8|pData[1];pData+=2;pack_num=pData[0];pData++;cmd_type=pData[0];pData++;//指向数据区或者下一个数据单元
//                qDebug("data_len=%u, pack_num=%u, cmd_type=%u", data_len, pack_num, cmd_type);if(data_len<4 || (data_len>IN_BUFF_SIZE)){qDebug("deviceRecvProcess error: data_len<4 || data_len>IN_BUFF_SIZE, data_len=%d, pack_num=%d", data_len, pack_num);return;}crcValue=pBuff[data_len]<<8|pBuff[data_len+1];if(crcValue != drv_com.crc16(pBuff, data_len))//单元内校验{qDebug("deviceRecvProcess error: crcValue failed!");return;}if(cmd_type==100)//是否为数据包命令{next_dev_sn=pData[0]<<24|pData[1]<<16|pData[2]<<8|pData[3];
//                    qDebug("next_dev_sn=0x%08X", next_dev_sn);pData+=4;parent_sn=curr_dev_sn;curr_dev_sn=next_dev_sn;in_len=data_len-8;//下一个数据区的长度memset(in_buff, 0, IN_BUFF_SIZE);memcpy(in_buff, pData, in_len);//复制下一个数据单元}else//本机数据,进行处理{
//                    QByteArray msg_ba((char*)pData, data_len-4);
//                    qDebug()<<"msg_ba="<<msg_ba.toHex(':');if(app_id==m_currAppWork.appID)//本项目设备{WorkDevStruct *pWorkNode=searchWorkNode(curr_dev_sn);if(pWorkNode){if(parent_sn>0 && pWorkNode->parentSn != parent_sn)//节点父序列号改变{pWorkNode->parentSn=parent_sn;
//                                requestUpdateWorkName(curr_dev_sn, pWorkNode->devName);//更新父序列号}if(parent_sn==0){pWorkNode->encrypt_index=pSeverHead->encrypt_index;//记录网关的加密模式,方便数据下发}if(pWorkNode->pModel){pWorkNode->pModel->setRawData(app_id, curr_dev_sn, pack_num, cmd_type, pData, data_len-4);}return;}else//设备未存在{if(m_secCounts>10)//可能是还未从服务器请求下来{InitTypeStruct *pInittype=takeInitType(curr_dev_sn);if(pInittype){requestAddDevice(curr_dev_sn, parent_sn);//请求添加设备}}}}curr_dev_sn=0;return;}deep_counts++;if(deep_counts>=5)//嵌套层数{qDebug("deviceRecvProcess error: deep_counts>DEEP_MAX! parent_sn=%u", parent_sn);return;}}else{qDebug("deviceRecvProcess error: out_len<=0!");return;}}}else{qDebug("no found head AA 55");}
}

二、物模型后端

        数据协议解析完成后,就进入应用数据解析了,就是模型的setRawData函数,这是数据进入物模型的接口,至于模型内的数据和功能,完全是根据产品本身的定义决定的,与嵌入式端对应。


int ModelAp01::setRawData(u32 app_id, u32 dev_sn, u8 pack_num, u8 msg_type, u8 *msg_buff, u16 msg_len)
{if(dev_sn!=m_devSn)return 0;u8 *pData=msg_buff;msg_len=msg_len;if(m_upPackNum==pack_num)return 0;m_upPackNum=pack_num;m_appID=app_id;
//    qDebug()<<"msg_type="<<msg_type;switch(msg_type){case AP01_CMD_HEART:{break;}case AP01_CMD_DATA:{int temp=pData[0]<<8|pData[1];//温度 原始数据float temp_f=(temp-1000)/10.f;//温度浮点数据pData+=2;int humi=pData[0]<<8|pData[1];float humi_f=humi/10.f;pData+=2;int pm25=pData[0]<<8|pData[1];pData+=2;u8 speed=pData[0];pData+=1;u8 state=pData[0];pData+=1;qDebug("temp_f=%.1f C, humi_f=%.1f%%, pm25=%d ug/m3, speed=%d, state=%d", temp_f,  humi_f, pm25, speed,state);QString dev_sn_str=QString::asprintf("%08X", m_devSn);QString temp_str=QString::asprintf("%.0f", temp_f);QString humi_str=QString::asprintf("%.0f", humi_f);QString pm25_str=QString::asprintf("%03d", pm25);int alarm_level=0;if(pm25<20)alarm_level=0;else if(pm25<30)alarm_level=1;else alarm_level=2;emit siqUpdateSensorValues(dev_sn_str, temp_str, humi_str, pm25_str);emit siqUpdateAlarmLevel(alarm_level);emit siqUpdateSwitchState(state);break;}}QDateTime current_date_time = QDateTime::currentDateTime();m_updateTime=current_date_time.toString("hh:mm:ss");m_onlineTime=m_secTickets;m_onlineState=DEV_STATE_ON_LINE;return 0;
}

后端模型文件基本上就是一个类文件,较为简单,开发展也只需集中精力完善这个模型即可。

三、物模型前端

        前端模型分为两部分,一个是简易网格模型,一个是具体模型,这个在上一节演示视频的APP界面上显而易见了。至于其它AP01开头的QML文件,就是延续了净化器项目的各个前端模块,比如开关、气泡等等。

        详细模型的代码如下:

import QtQuick 2.7
import QtQuick.Controls 1.4
import "../base"BaseModelView
{id:id_baseModelViewparent: theModelAp01.takeModelParent()devName: theModelAp01.takeDeviceName()devSnStr: theModelAp01.takeDevSnStr()ScrollView {id:id_zoneViewimplicitWidth: 400width: parent.widthclip: trueanchors{top:parent.toptopMargin:50bottom:parent.bottom}verticalScrollBarPolicy:Qt.ScrollBarAlwaysOffhorizontalScrollBarPolicy: Qt.ScrollBarAlwaysOffRectangle{id:id_centerRectwidth: parent.widthheight: 800color: "#FAFAFA"Ap01CenterShow//中心圆圈画面{id:id_airCenterShowwidth: parent.widthheight: parent.height*0.6anchors{top:parent.top}}Ap01SwitchItem//开关栏{id:id_switchItemwidth: parent.width*0.96anchors{horizontalCenter:parent.horizontalCentertop:id_airCenterShow.bottom}} Ap01ControlItem //风速控制{id:id_airControlItemanchors{top:id_switchItem.bottomtopMargin:5horizontalCenter:parent.horizontalCenter}}}}Component.onCompleted: {id_zoneView.width=widthid_centerRect.width=width
//        console.log("width=", width)}Connections{target: theModelAp01onSiqUpdateSensorValues:{id_airCenterShow.funUpdateThText(temp, humi)//更新温湿度数值id_airCenterShow.funUpdatePm25Text(pm25)//更新PM2.5数值}onSiqUpdateOnlineState:{funSetDevState(state)//更新在线状态}onSiqUpdateDeviceName:{devName=dev_name}}}

四、数据下行

        像设置开关、调速的指令都是通过信号从模型发送到处理中心的,这个在添加工作设备的时候已经进行信号槽的连接了。

这个槽函数的内容就是对数据进行封装下发


void CenterMan::slotSendDownMsg(u32 app_id, u32 dev_sn, u8 pack_num, u8 msg_type, u8 *msg_buff, u16 msg_len)
{//    qDebug()<<"slotSendDownMsg****";u8 data_buff[1500]={0}, make_buff[1500]={0};u16 make_len, data_len;data_len=msg_len;if(msg_len>sizeof(data_buff)){qDebug()<<"slotSendDownMsg error, msg_len>sizeof(data_buff)";return;}memcpy(data_buff, msg_buff, data_len);u32 currDevSn=dev_sn;if(app_id==m_currAppWork.appID)//自身设备{int deep=0;while(currDevSn>0){WorkDevStruct *pWorkNode=searchWorkNode(currDevSn);if(pWorkNode==nullptr){qDebug()<<"pWorkNode==nullptr";return;}if(deep>0){msg_type=200;//转发指令为200}qDebug("down curr_sn=0x%08X, parent_sn=0x%08X", pWorkNode->devSn, pWorkNode->parentSn);if(pWorkNode->parentSn==0)//网关设备{   make_len=makeGwSendBuff(app_id, currDevSn, pack_num, pWorkNode->encrypt_index,msg_type, data_buff, data_len, make_buff, sizeof(make_buff));publishDownMsg(app_id, currDevSn, make_buff, make_len);//发布currDevSn=0;}else//节点设备{make_len=makeNodeSendBuff(currDevSn, pack_num, msg_type, data_buff, data_len, make_buff, sizeof(make_buff));//组合节点数据if(make_len>0 && make_len<sizeof(data_buff)){data_len=make_len;memcpy(data_buff, make_buff, make_len);memset(make_buff, 0, sizeof(make_buff));}else{qDebug("error01, make_len=%u", make_len);return;}currDevSn=pWorkNode->parentSn;//父节点序列号}deep++;}}
}//发送设备下行数据 
void CenterMan::publishDownMsg(u32 app_id, u32 gw_sn, u8 *msg_buff, u16 msg_len)
{QString topic=QString(TOPIC_HEAD)+QString::asprintf("dev/sub/data/%u/%08X", app_id, gw_sn);QByteArray msg_ba((char*)msg_buff, msg_len);
//    qDebug()<<"000 pub topic="<<topic<<"\nmsg_ba="<<msg_ba.toHex(':');emit sigMqttPushMessage(topic, msg_ba);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/25059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB数学建模——数据拟合

文章目录 一、简介二、多项式拟合&#xff08;一&#xff09;指令介绍&#xff08;二&#xff09;代码 三、指定函数拟合&#xff08;一&#xff09;指令介绍&#xff08;二&#xff09;代码 一、简介 曲线拟合也叫曲线逼近&#xff0c;主要要求拟合的曲线能合理反映数据的基本…

如何有效释放Docker占用的存储空间

随着Docker的广泛应用&#xff0c;我们经常会遇到Docker占用过多存储空间的问题。这可能是由于频繁的镜像拉取、容器创建和删除等操作导致的。本文将介绍几种方法来有效释放Docker占用的存储空间&#xff0c;特别是docker system prune命令的使用。 Docker的存储机制 Docker使…

Linux 36.3 + JetPack v6.0@jetson-inference之目标检测

Linux 36.3 JetPack v6.0jetson-inference之目标检测 1. 源由2. detectnet2.1 命令选项2.2 下载模型2.3 操作示例2.3.1 单张照片2.3.2 多张照片2.3.3 视频 3. 代码3.1 Python3.2 C 4. 参考资料 1. 源由 从应用角度来说&#xff0c;目标检测是计算机视觉里面第二个重要环节。之…

开源项目学习——vnote

一、介绍 vnote是一款免费且开源的markdown编辑器&#xff0c;用C开发&#xff0c;基于Qt框架&#xff0c;windows/linux/mac都能用。 二、编译 $ git clone --recursive https://github.com/vnotex/vnote.git $ cd vnote && mkdir build $ cd build $ cmake ../ $ …

鲜为人知的英伟达创始人:早早退出,身价不如黄仁勋零头

内容提要 普里姆因为婚姻纠纷等个人生活的干扰无法专注在工作上&#xff0c;在成立公司的10年后&#xff0c;也就是2003年宣布退休离开英伟达&#xff0c;并在2006年出售剩余的所有英伟达股份&#xff0c;过上不与外界联系、离群索居的生活&#xff0c;在家中鼓捣着如何“拯救…

UML交互图-协作图

概述 协作图和序列图都表示出了对象间的交互作用&#xff0c;但是它们侧重点不同。序列图清楚地表示了交互作用中的时间顺序&#xff0c;但没有明确表示对象间的关系。协作图则清楚地表示了对象间的关系&#xff0c;但时间顺序必须从顺序号获得。序列图常常用于表示方案&#…

【云原生】基于windows环境搭建Docker

目录 一、Docker Desktop搭建 二、前置准备 2.1开启 Hyper-V 2.2 Hyper-V选项看不到问题解决 2.3 开启或升级wsl 三、安装过程 3.1 下载安装包 3.2 安装 Docker Desktop 3.2.1 Docker 图标一直处于starting状态问题解决 3.3 配置仓库与镜像 3.4 docker功能测试 四、…

HSC Mailinspector loader.php 任意文件读取漏洞复现(CVE-2024-34470)

0x01 产品简介 HSC Mailinspector是一款远程电子邮件检查工具&#xff0c;支持POP3/IMAP4协议。它允许用户远程扫描最新邮件&#xff0c;并进行浏览、垃圾邮件排除、编辑、删除等操作&#xff0c;无需实际登录邮箱。 0x02 漏洞概述 由于HSC Mailinspector /public/loader.ph…

揭秘:币圈黑科技私钥碰撞器的项目教程玩法,外面竟然收费200+

一、前言&#xff1a;探寻币圈私钥探测器神秘面纱 在风华正茂的币圈&#xff0c;不仅有无数高涨或者暴跌的数字货币&#xff0c;更有许多被誉为“黑科技”的工具备受热议。其中&#xff0c;私钥碰撞器就是这些黑科技中的一员&#xff0c;它能够搜索并碰撞出特定地址的私钥&…

【AI 高效问答系统】机器阅读理解实战内容

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

dockerhub不可用临时解决方案

近日&#xff0c;在拉取一些docker hub的镜像的时候死活拉不下来&#xff0c;要么超时&#xff0c;要么无法接站点地址&#xff0c;不管是docker hub,还是国内镜像站&#xff0c;统统都不行了。 经过各大媒体报道&#xff0c;以及自己的亲身验证&#xff0c;才知道&#xff0c…

状态方程ABCD矩阵如何确定例子

状态方程ABCD矩阵如何确定 确定状态空间表示中的状态矩阵A、输入矩阵 B、输出矩阵C 和直通矩阵D,需要从系统的动力学方程出发,并将其转换为状态方程的形式。我们可以通过一个具体的物理系统(如倒立摆系统)来说明这一过程 例子:倒立摆系统 系统描述 考虑一个倒立摆系统…

linux线程的同步与互斥

前面我们讲了线程的概念以及如何创建与控制线程&#xff0c;接下来我们来对线程的细节与线程之间的问题进行一些讲解&#xff1b; 1.线程的互斥 互斥就是相互排斥&#xff0c;我们可以理解为对立竞争不相容&#xff1b;线程的互斥则是线程之间在对于临界资源竞争时相互排斥的…

mathematica中针对三维图中的颜色和填充透明度进行指定

颜色指定使用的命令为&#xff1a;PlotStyle 填充的透明度使用的命令为&#xff1a;FillingStyle 示例代码&#xff1a; Clear["Global*"] Plot3D[{Sin[x^2 y], Sin[x^2 - y]}, {x, -2, 2}, {y, -2, 2}, PlotStyle -> {Directive[Red, Specularity[White, 100…

Java面试八股之组合、聚合和关联三者的区别是什么

组合、聚合和关联三者的区别是什么 关联&#xff08;Association&#xff09;: 最基本的一种关系&#xff0c;表示一个类知道另一个类的存在&#xff0c;或者说是类之间的某种联系。 关联可以是双向的也可以是单向的&#xff0c;且不规定参与关联的对象的生存周期。 实例&a…

使用命令给电脑添加虚拟网卡和IP

目录 1、添加网卡 1-1、windows系统添加网卡 1-2、Linux系统中添加网卡 2、添加IP和DNS 2-1、添加IP 2-2、 设置DNS 3、删除网卡 3-1、Windows: 3-2、Linux 3-3、macOS 4、示例&#xff1a; 首先以管理员方式进入CMD命令行&#xff1b; 点击“开始”->“管理员…

【数据分享】《中国文化文物与旅游统计年鉴》2022

最近老有同学过来询问《中国旅游年鉴》、《中国文化文物统计年鉴》、《中国文化和旅游统计年鉴》、《中国文化文物与旅游统计年鉴》&#xff0c;这四本年年鉴的关系以及怎么获取这四本年鉴。今天就在这里给大家分享一下这四本年鉴的具体情况。 实际上2018年&#xff0c;为适应…

java之面向对象

1 面向对象介绍 <span style"background-color:#f8f8f8"><span style"color:#333333">1.面向过程:自己的事情自己干,代表语言C语言洗衣服:每一步自己要亲力亲为 -> 找个盆,放点水,找个搓衣板,搓搓搓 2.面向对象:自己的事情别人帮忙去干,代…

什么是突发性耳聋?

72小时内突然发生、原因不明的感音神经性听力损失&#xff0c;至少在相邻的两个频率听力下降≥20dBHL。 特点&#xff1a; 1发生在数分钟、数小时或3天以内的听力下降&#xff1b; 2原因不明&#xff1b; 3多发生于单侧&#xff0c;可伴有耳鸣、耳堵塞感及耳周麻木感&#…

【ARM Cache 及 MMU 系列文章 6.1 -- Cache maintenance 相关寄存器及指令详细介绍】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cache Maintenance registers and instructionsDCZID_EL0DCZID_EL0寄存器字段解释 DCZ 使用场景Cache maintenance 范围选择 Cache maintenance 指令集 Cache Maintenance registers a…