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

2024-06-10 10:04

本文主要是介绍物联网实战--平台篇之(十四)物模型(用户端),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、底层数据解析

二、物模型后端

三、物模型前端

四、数据下行


本项目的交流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.chinasem.cn/article/1047852

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了