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

news2024/12/24 0:37:28

目录

一、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);
    else
      m_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.coloradmin.cn/o/1636704.html

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

相关文章

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…

kubectl_入门_Pod调整

Pod调度 在默认情况下&#xff0c;一个pod在哪个node节点上运行&#xff0c;是由scheduler组件采用相应的算法计算出来的&#xff0c;这个过程是不受人工控制的。 但是在实际过程中&#xff0c;这并不满足需求&#xff0c;因为很多情况下&#xff0c;我们想控制某些pod到达某…

基于昇腾AI | 英码科技EA500I使用AscendCL实现垃圾分类和视频物体分类应用

现如今&#xff0c;人工智能迅猛发展&#xff0c;AI赋能产业发展的速度正在加快&#xff0c;“AI”的需求蜂拥而来&#xff0c;但AI应用快速落地的过程中仍存在很大的挑战&#xff1a;向下需要适配的硬件&#xff0c;向上需要完善的技术支持&#xff0c;两者缺一不可。 基于此&…

【C语言】深入了解文件:简明指南

&#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自踏雪至山巅 文章目录 一、文件的概念1.1 文件名:1.2 程序文件和数据文件 二、数据文…

香港上市现货比特币及以太坊ETF,首日交易量不及预期

原创 | 刘教链 在BTC&#xff08;比特币&#xff09;继续回调至61k一线&#xff0c;眼见就要在连续7个月收涨后&#xff0c;终于迎来一个收跌的4月之际&#xff0c;香港如期上市了现货比特币ETF和以太坊ETF&#xff0c;成为全球继美国推出现货比特币ETF之后&#xff0c;亚洲首个…

Aker(安碁科技)晶振产品应用和选型

一、石英晶体振荡器简介 在电子电路系统中&#xff0c;特定的动作需要严格按照一定的顺序进行&#xff0c;以确保数据被正确处理和操作&#xff0c;时钟信号就成了系统工作的重要引导者。而且在多模块复杂电路系统中&#xff0c;为了确保不同功能模块能协调一致地工作&#xf…

网络安全是智能汽车下一个要卷的方向?

2024年一季度&#xff0c;中国汽车市场延续了2023年的风格&#xff0c;核心就是「卷」。 2023年&#xff0c;我国汽车市场爆发「最强价格战」&#xff0c;燃油车的市场空间不断被挤压&#xff0c;如今只剩下最后一口气。近日乘联会发布4月1-14日最新数据&#xff0c;新能源&am…

ARM功耗管理背景及挑战

安全之安全(security)博客目录导读

使用 scikit-learn 进行机器学习的基本原理-2

介绍 scikit-learn 估计器对象 每个算法都通过“Estimator”对象在 scikit-learn 中公开。 例如&#xff0c;线性回归是&#xff1a;sklearn.linear_model.LinearRegression 估计器参数&#xff1a;估计器的所有参数都可以在实例化时设置&#xff1a; 拟合数据 让我们用 nump…

频谱模拟器

频谱模拟器&#xff0c;特别是模拟频谱仪&#xff0c;是一种基于特定原理的频谱分析工具。以下是对其的详细介绍&#xff1a; 工作原理&#xff1a; 模拟频谱仪的工作原理主要基于频率转换原理&#xff0c;包括两个关键步骤&#xff1a;信号混频和滤波分析。 信号混频&#xf…

el-table-column 表格列自适应宽度的组件封装说明

针对组件业务上的需求&#xff0c;需要给 el-table-column 加上限制&#xff0c;需保证表头在一行展示&#xff0c;部分列的内容要一行展示&#xff0c;自适应单项列的宽度&#xff1b; 1、先计算数据渲染后的 el-table-column 文本宽度&#xff1b; 因列表的有些数据需要做到…

OpenCV的图像矩(64)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV如何为等值线创建边界旋转框和椭圆(63) 下一篇 :OpenCV系列文章目录&#xff08;持续更新中......&#xff09; Image Moments&#xff08;图像矩&#xff09;是 OpenCV 库中的一个…

后端方案设计文档结构模板可参考

文章目录 1 方案设计文档整体结构2 方案详细设计2.1 概要设计2.2 详细设计方案2.2.1 需求分析2.2.2 业务流程设计2.2.3 抽象类&#xff1a;实体对象建模2.2.4 接口设计2.2.5 存储设计 1 方案设计文档整体结构 一&#xff0c;现状&#xff1a;把项目的基本情况和背景都说清楚&a…

Golang | Leetcode Golang题解之第60题排列序列

题目&#xff1a; 题解&#xff1a; func getPermutation(n int, k int) string {factorial : make([]int, n)factorial[0] 1for i : 1; i < n; i {factorial[i] factorial[i - 1] * i}k--ans : ""valid : make([]int, n 1)for i : 0; i < len(valid); i {…

如何避免被恶意攻击的IP地址

随着互联网的普及和发展&#xff0c;网络安全问题日益受到关注&#xff0c;恶意攻击成为网络安全的一大威胁。而IP地址作为网络通信的基础&#xff0c;常常成为恶意攻击的目标之一。本文将探讨如何避免被恶意攻击的IP地址&#xff0c;提高网络安全水平。 1. 定期更新安全补丁 …

AC+AP三层组网实验(华为)

一&#xff0c;技术简介 APAC架构是一种常见的无线局域网&#xff08;WLAN&#xff09;组网方式&#xff0c;主要由接入点&#xff08;Access Point&#xff0c;简称AP&#xff09;和接入控制器&#xff08;Access Controller&#xff0c;简称AC&#xff09;组成。 在APAC架构…

Stable Diffusion教程:额外功能/后期处理/高清化

"额外功能"对应的英文单词是Extras&#xff0c;算是直译。但是部分版本中的翻译是“后期处理”或者“高清化”&#xff0c;这都是意译&#xff0c;因为它的主要功能是放大图片、去噪、修脸等对图片的后期处理。注意这里边对图片的处理不是 Stable Diffusion 本身的能…

使用docker创建rocketMQ主从结构,使用

1、 创建目录 mkdir -p /docker/rocketmq/logs/nameserver-a mkdir -p /docker/rocketmq/logs/nameserver-b mkdir -p /docker/rocketmq/logs/broker-a mkdir -p /docker/rocketmq/logs/broker-b mkdir -p /docker/rocketmq/store/broker-a mkdir -p /docker/rocketmq/store/b…

Python+PYGObject/PYGtk+CSS样式--2024python示例

隔久点不用老是会忘&#xff0c;留个笔记。。 PythonPYGObject/PYGtk&#xff0c;加载 CSS 样式的演示代码 demo 运行的效果截图&#xff1a; #!/usr/bin/env python3 import sys import gigi.require_version("Gtk", "3.0") from gi.repository import …

飞书API(6):使用 pandas 处理数据并写入 MySQL 数据库

一、引入 上一篇了解了飞书 28 种数据类型通过接口读取到的数据结构&#xff0c;本文开始探讨如何将这些数据写入 MySQL 数据库。这个工作流的起点是从 API 获取到的一个完整的数据&#xff0c;终点是写入 MySQL 数据表&#xff0c;表结构和维格表结构类似。在过程中可以有不同…