物联网实战--平台篇之(二)基础搭建

目录

一、Qt工程创建

二、数据库知识

三、通信协议

四、名词定义


本项目的交流QQ群:701889554

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

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

一、Qt工程创建

        Qt方面有三个工程需要创建,分别是应用服务器程序、数据服务器程序和客户端APP,他们各自的作用在上一篇已经说过了,这一篇主要创建工程的基础结构,主要是MQTT通讯和数据库相关等基础文件。对于应用服务器和数据服务器程序是不需要界面的,用控制台程序即可,所以它们的.pro文件都有一个:

QT -= gui

        对于MQTT之前已经有大概讲解过了,可以去参考之前的文章,我们这里主要还是对开源库进行封装,把域名解析、话题订阅、证书添加等内容进行内部处理。在这里我们主要介绍下数据库相关的内容。

物联网实战--入门篇之(七)嵌入式-MQTT_mqtt嵌入式-CSDN博客

项目工程集合 https://download.csdn.net/download/ypp240124016/89248704

二、数据库知识

        QT对各类数据库进行封装,可以驱动很多类型的数据,包括ODBC、SQLite、MySQL、PostgreSQL、SQL Server、Oracle等,不同类型的数据库驱动类型略有区别,一般数据库都需要另外安装软件,比如MySQL,可以参考这篇文章Mysql的安装配置教程(非常详细)从零基础入门到精通,看完这一篇就够了_mysql安装教程-CSDN博客

        对于没接触过数据库的同学会觉得比较麻烦,所以我们这个项目为了方便,直接使用SQLite作为数据库了,它无需额外安装软件,生成的数据库是独立文件,就像普通配置文件一样。数据库的操作,核心就是增删改查,利用数据库语句进行操作,这里可以大概看下教程SQLite 教程 | 菜鸟教程

        以下是数据库驱动SQLite的封装文件和代码:

#include "BaseSqlite.h"BaseSqlite::BaseSqlite(QObject *parent) : QObject(parent)
{
}BaseSqlite::~BaseSqlite()
{
//    closeDataBase();
}void BaseSqlite::closeDataBase(void)
{
//    qDebug()<<m_dbName<<" ## "<<m_connName<<"closeDataBase";
//    QSqlDatabase::removeDatabase(m_connName);m_sqlDataBase.close();
}//打开数据库
bool BaseSqlite::openDataBase(QString db_name, QString conn_name)
{if(m_sqlDataBase.isOpen()){qDebug()<<m_dbName<<" "<<m_connName<< " is opened.";return false;}m_dbName=db_name;m_connName=conn_name;if(QSqlDatabase::contains(m_connName))m_sqlDataBase = QSqlDatabase::database(m_connName);elsem_sqlDataBase = QSqlDatabase::addDatabase("QSQLITE", m_connName);//    m_sqlDataBase = QSqlDatabase::addDatabase("QSQLITE", conn_name);m_sqlDataBase.setDatabaseName(db_name);if(!m_sqlDataBase.open()){qDebug()<<m_dbName<<" "<<m_connName<< "Error: Failed to connect database." << m_sqlDataBase.lastError();return false;}else{m_sqlQuery = QSqlQuery(m_sqlDataBase);
//        qDebug()<<m_dbName<<" "<<m_connName<< "Succeed to open database." ;}return true;
}bool BaseSqlite::isOpened(void)
{return m_sqlDataBase.isOpen();
}//执行语句
bool BaseSqlite::runSqlQuery(QString str_query)
{
//    QSqlQuery query(m_sqlDataBase);if(!m_sqlQuery.exec(str_query)){qDebug()<<m_sqlQuery.lastError();}else{return true;}return false;
}//启动事务
bool BaseSqlite::beginTransaction(void)
{QString str_query = "BEGIN TRANSACTION";if(runSqlQuery(str_query)==false){return false;}return true;
}//停止事务
bool BaseSqlite::endTransaction(void)
{QString str_query = "COMMIT";if(runSqlQuery(str_query)==false){return false;}return true;
}

        看起来也很简单,主要就是打开、关闭数据库,执行数据库语句;另外还有启动和停止事务,主要是用于数据流比较大的场景,比如数据服务器的数据保存,用数据库的事务功能可以避免频繁打开、关闭数据库,浪费时间,可以累积数据或者定时写入数据,提高效率。

三、通信协议

        这里的通讯协议指的是应用层的协议,理论上各个公司都是自定义的,没有标准。在这里,我们从实际需求出发,也自定义了一种协议,具体如下:

        协议看着比较复杂,分成两部分来看,一个是整体定义,一个是数据包内容。首先协议采用二进制传输,整体上包含帧头,便于检索,校验码、数据长度该有的也都有了;1~16字节内容都是明文,都有相应解释,其中app_id和dev_sn稍后详细说明;17~N的数据区需要加密,我们整个系统采用一型多密的方案,即一种型号配套多组密码,根据自己需要使用,密码在设备生产定义时确定,需要注意保护,协议中的索引就是密码索引,这样可以明确数据包内用了哪一组的密码。

        协议的核心还是数据区里的内容,这里使用的是一种嵌套的思想,因为在实际项目中我们经常会用到无线组网的方式,一个网关加多个节点,对于节点数据是需要通过网关转发的,那就相当于把节点数据嵌套在网关数据内部,这时候网关的顶层命令固定为100,意思就是本次数据包是转发的节点数据,要根据数据包的内容进一步解析;下行的时候也是一样,节点的控制指令需要经过网关进行转发,转发命令固定为200,网关解析后会把数据提取出来,至于怎么转发是网关跟节点之间的事了,后面在做LoRa组网的时候会具体演示。

        理论上可以一直嵌套下去,不过一般就一层,网关+节点,节点后面再挂载节点的情况比较少见了。

        对于不同的设备会包含不同的命令类型,需要从设备的实际需求出发,一般来讲,针对每一种类型的设备或者新产品,都要有规范的协议文档,这样在开发和维护过程中比较清晰,出现问题容易定位。

        协议内容都是字节序的形式传输,避免大小端的问题,我们约定数据高位先传输,比如协议里的app_id是四个字节,以AABB1122为例,那传输顺序就是AA、BB、11、22;对于数据的定义可以参考之前的净化器数值,简单讲就是我们只传输正整数,产品定义的时候就要把某个数据的范围和精度确定好,这样就可以把这个数据转为正整数了,然后传输依然是高位在前,低位在后的原则。这样,整个协议的统一性就很高了,对于具体的代码在后续合适的章节会体现,不会很复杂。

四、名词定义

        整个体系会有一些专有名词,这里统一做一下解释。

        账户:这个不用过多解释了,就像微信号一样,在整个系统里是唯一的,一般采用字符和数字的形式,我们这个系统以手机号为核心,注册的时候需要跟手机绑定,用验证码的方式注册,属于比较常规的。

        子账户:有时候手机号就一个,账户又想要多个,那么就可以用主账户去新建子账户,子账户的使用上跟主账户类似,但是子账户不能再创建子账户了。

        应用ID:就是协议里的app_id,长度是4个字节,每个账户下可以创建多个应用,每个应用下包含多个设备,举例说明,一般来讲,智能家居中一套房子创建一个应用,这个应用下有空调、冰箱、净化器等设备,这时候假设你有多套房子,每套房子都要整一套智能家居产品,显然,如果把所有设备都放在一个应用下就不太好管理了,这时候就可以为每套房子新建一个应用,各自的设备放在对应的应用下,彼此就很好管理了,这就是应用ID存在的意义。从技术角度来讲,设备发布消息的话题形式是这样的dev/pub/data/123001,其中123001就是应用ID,这样对于用户端APP来讲,只要根据app_id来订阅,该应用下的设备数据就会发到正确的用户端。所以说,app_id在整个系统的管理上起到了一个很关键的作用。

        设备序列号:就是协议里的dev_sn,是设备的身份标识,长度是4个字节,对于dev_sn是需要规范的,不能随便定义,在这里我们定义,高2字节代表设备类型,低2字节代表地址码,例如16进制A3010001,其中A301代表设备类型,比如四路主机,这个在产品定义时就要确定,那么0001就是地址码,这是在生产时确定的,于是四路主机所有的序列号就是A3010001~A301FFFF,理论上可以生产6万多个。实际上,再加上app_id的区分,其实不要在同一个应用里使用相同的dev_sn就行了,这样一来,在实际项目中都是够用的了。我们的密码体系是一型多密原则,这里的型就是指dev_sn的高2字节,理论上可以创建6万多种型号,够用了。总体来讲,app_id和dev_sn是我们整个系统设计的核心,一切都是围绕这两个概念展开的。

        解析插件:每一种型号的设备对应一个解析插件,主要就是负责对设备数据进行解析和操作,后期的产品开发主要就是设备端和对应解析插件的开发,这也是端到端开发模式的由来。解析插件主要是对用户端APP的不断扩充,包含两个内容,一个是后端C++对数据进行解析,一个是前端QML做该型号设备的展示界面,就像入门篇里所展示的净化器界面一样。这样,平台端无需增加开发,一个简单的物联网开发模式就形成了。

        网关/主机:这一类设备是直接跟服务器连接的,它们一般带有网口、WIFI或者4G等互联网接口,设备端的加密/解密也是在这类设备中完成的;它们有时候是独立的个体,比如WiFi空调,有时候是作为其它设备的数据中转站,比如LoRa网关,主要作用就是对LoRa节点设备的数据进行转发。

        节点:与上面所述的网关配合使用,节点的特点一般是数量较多,每个都有联网功能的话成本较高,所以选择用网关作为统一的联网媒介,比如485温湿度、LoRa门磁等等。

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

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

相关文章

完美解决AttributeError: module ‘backend_interagg‘ has no attribute ‘FigureCanvas‘

遇到这种错误通常是因为matplotlib的后端配置问题。在某些环境中&#xff0c;尤其是在某些特定的IDE或Jupyter Notebook环境中&#xff0c;可能会因为后端配置不正确而导致错误。错误信息提示 module backend_interagg has no attribute FigureCanvas 意味着当前matplotlib的后…

OPPO Reno10Pro/Reno11/K10手机强解BL刷root权限KSU内核抓包刷机救砖

OPPO Reno10Pro/Reno11/K10手机虽然发布时间并不久&#xff0c;但由于天玑处理器的体质&#xff0c;已经支持强制解锁BL了&#xff0c;该漏洞来自第三方工具适配&#xff0c;支持OPPO天机8100/8200刷机救砖解锁BL不需要等待官方深度测试直接实现。解锁BL后的OPPO Reno10Pro/Ren…

虚拟机安装与配置win7

一、安装镜像 Windows7 64位 ed2k://|file|cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso|3420557312|B58548681854236C7939003B583A8078|/ 建议迅雷下载 二、VMware 安装win7 1.新创自定义虚拟机 2.默认即可 3.iso文件我们自己下载&#xff0c;选择一个空的磁盘 4.…

GoLang Gin实际使用

所有代码同步到Admin/gitDemo - Gitee.comhttps://gitee.com/mec-deployment-team_0/git-demo/tree/dev/ 1.创建Gin框架 一般设计一个常规的web项目&#xff0c;都需要以下几个模块 runApp 主函数&#xff0c;运行整个项目routes 路由控制&#xff0c;管理跳转以及路由分组co…

Java | Leetcode Java题解之第62题不同路径

题目&#xff1a; 题解&#xff1a; class Solution {public int uniquePaths(int m, int n) {long ans 1;for (int x n, y 1; y < m; x, y) {ans ans * x / y;}return (int) ans;} }

jenkins教程

jenkins 一、简介二、下载安装三、配置jdk、maven和SSH四、部署微服务 一、简介 Jenkins是一个流行的开源自动化服务器&#xff0c;用于自动化软件开发过程中的构建、测试和部署任务。它提供了一个可扩展的插件生态系统&#xff0c;支持各种编程语言和工具。 Jenkins是一款开…

启发式搜索算法4 -遗传算法实战:吊死鬼游戏

相关文章: 启发式搜索算法1 – 最佳优先搜索算法 启发式搜索算法2 – A*算法 启发式搜索算法2 – 遗传算法 有一个小游戏叫吊死鬼游戏&#xff08;hangman&#xff09;&#xff0c;在学习英语的时候&#xff0c;大家有可能在课堂上玩过。老师给定一个英文单词&#xff0c;同学们…

从0到1手写注册中心Registry之集群选主

一、领域对象 Cluster&#xff1a;描述集群信息 port描述当前服务端口&#xff1b;host描述当前服务主机&#xff1b;myself描述当前服务本身&#xff1b;servers描述当前服务集群列表registryConfigProperties配置信息&#xff1b;executor定时任务&#xff0c;负责更新服务…

linux部署java1.8(java17)

两种方式&#xff1a; 方式一 1.输入查找命令&#xff1a; yum -y list java*2.输入安装命令&#xff1a; yum install -y java-1.8.0-openjdk.x86_643.测试是否已经安装&#xff1a; java -version方式二&#xff1a; 点击链接进入官网&#xff1a;https://www.oracle.com/…

Go 语言(三)【面向对象编程】

1、OOP 首先&#xff0c;Go 语言并不是面向对象的语言&#xff0c;只是可以通过一些方法来模拟面向对象。 1.1、封装 Go 语言是通过结构体&#xff08;struct&#xff09;来实现封装的。 1.2、继承 继承主要由下面这三种方式实现&#xff1a; 1.2.1、嵌套匿名字段 //Add…

24五一杯ABC题详细建模思路+可执行代码+成品论文+图表(免费参考资料)

比赛题目的完整版思路可执行代码数据参考论文都会在第一时间更新上传的&#xff0c;大家可以参考我往期的资料&#xff0c;所有的资料数据以及到最后更新的参考论文都是一次付费后续免费的。注意&#xff1a;&#xff08;建议先下单占坑&#xff0c;因为随着后续我们更新资料数…

TCP重传,滑动窗口,流量控制,拥塞控制

TCP重传&#xff0c;滑动窗口&#xff0c;流量控制&#xff0c;拥塞控制 TCP重传机制&#xff1a; 超时重传快速重传SACKD-SACK 通过序列号与确认应答判断是否要重传 超时重传&#xff1a; 超过指定时间没有收到确认应答报文&#xff0c;就会重发该数据 触发超时重传的情况…