From 2855b71060533bf4153ace840eafbc7df516afed Mon Sep 17 00:00:00 2001 From: feiyangqingyun Date: Wed, 3 Apr 2024 15:43:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/iotsystem/index.html | 54 ++++++++++++++++++++++---------- docs/iotsystem/snap/10-9-1.jpg | Bin 0 -> 101343 bytes docs/iotsystem/snap/8-3-3-7.jpg | Bin 23630 -> 18445 bytes docs/iotsystem/snap/8-3-3.jpg | Bin 10783 -> 11745 bytes 4 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 docs/iotsystem/snap/10-9-1.jpg diff --git a/docs/iotsystem/index.html b/docs/iotsystem/index.html index c3d7c0b..b211aa5 100644 --- a/docs/iotsystem/index.html +++ b/docs/iotsystem/index.html @@ -3,10 +3,11 @@ -物联网平台开发及使用手册
-
  • 0 前言说明

    0.1 编译说明

    1. 编译完成后记得将源码下的file目录下(切记是file目录下而不是file目录)的所有文件复制到可执行文件同一目录。可执行文件目录bin在当前源码下,和一堆core开头的目录同级别,编译后会自动生成bin目录。
    2. 打开pro文件,修改DEFINES中的 iottool1 为 iottool,则编译出来的是设备模拟工具,用于没有外接硬件设备时候模拟设备数据测试用。
    3. 编译完成后,先双击打开iottool.exe,这个是设备模拟工具,再打开iotsystem.exe,这个是主程序,主程序建议添加两个通信端口,一个串口端口和一个网络端口,设备模拟工具会自动打开串口和网络进行数据的模拟。
    4. db目录下的 iotsystem.mbs 为modbus模拟数据模板,可以用modbus slave软件打开。
    5. db目录为数据库文件夹,iotsystem.db为sqlite数据库文件,sql结尾的为建库脚本,可以自行改成mysql数据库。
    6. 在端口设置中如果不填写串口号则取网络地址,填了串口号则以串口号优先。
    7. 如果导出的数据到excel以后,打开文件有提示,请先执行db目录下的excel禁止提示.reg文件。
    8. 系统中的组态模块用到了designer模块,有些linux系统安装的Qt开发环境可能会不自带这个模块,编译的时候报错提示 Project ERROR: Unknown module(s) in QT: designer,需要手动打命令安装下,sudo apt-get install libqt5designer5 或者 sudo apt-get install qttools5-dev 。

    0.2 功能特点

    0.2.1 软件模块

    1. 设备监控模块,包括数据监控(表格形式展示)、设备面板(面板形式展示)、地图监控(地图形式展示)、曲线监控(曲线形式展示)。
    2. 数据查询模块,包括报警记录、运行记录、操作记录。
    3. 系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、报警联动、类型设置等。
    4. 其他设置模块,包括用户管理、地图管理、位置调整、组态设计、设备调试等。

    0.2.2 基础功能

    1. 设备数据采集,支持串口、网络,串口可设置串口号、波特率,网络可设置IP地址、通讯端口。
    2. 每个端口支持采集周期时间,默认1秒钟一个设备。
    3. 支持设置通讯超时次数,默认3次。
    4. 支持最大重连时间,用于重新读取离线的设备。
    5. 控制器信息,能够添加控制器名称,选择控制器地址、控制器型号,设置该控制器下面的探测器数量。
    6. 探测器信息,能够添加位号、探测器型号、气体种类、气体符号、高报值、低报值、缓冲值、清零值、是否启用、报警声音、背景地图、存储周期、数值换算小数点位数、报警延时时间、报警的类型(HH,LL,HL)等。
    7. 类型管理可配置控制器型号、探测器型号、气体种类、气体符号等。
    8. 地图支持导入和删除,所有的探测器在地图上的位置可自由拖动保存。
    9. 端口信息、控制器信息、探测器信息、类型信息、用户信息等,都支持导入、导出、导出到excel、打印。
    10. 运行记录、报警记录、操作记录,都支持多条件组合查询,比如时间段、控制器、探测器等,所有记录支持导出到excel/pdf和打印。
    11. 运行记录、报警记录、操作记录都可删除指定时间范围内的数据。
    12. 系统设置可选择对应表最大保存记录数,自动清理早期数据,留出足够的空间存储重要的数据。
    13. 报警短信转发,支持多个接收手机号码,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,短信内容过长,自动拆分多条短信。
    14. 报警邮件转发,支持多个接收邮箱,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,支持附件发送。
    15. 设置软件的中文标题、英文标题、logo路径、版权所有等。
    16. 开关设置开机运行、报警声音、自动登录、记住密码等。
    17. 报警声音可设置播放次数,界面风格样式提供18套皮肤文件选择。
    18. 用户管理,包括用户权限配置,不同用户可以有不同模块的权限。
    19. 用户登录和用户退出,可以记住密码和自动登录,超过三次报错提示并关闭程序。
    20. 四种监控模式,设备面板监控、地图监控、表格数据监控、曲线数据监控,可自由切换,四种模式下都实时展示采集到的数据,报警闪烁等。
    21. 报警继电器联动,一个位号可以跨串口联动多个模块和继电器号,支持多对多。

    0.2.3 特色功能

    1. 通信协议支持modbus_com、modbus_tcp_rtu,后期拓展mqtt等协议。
    2. 数据源除了真实的硬件设备采集,还可选数据库采集,这样用户可以安排其他程序员比如java程序员将前端采集好的数据放到数据库,本系统直接从数据库采集即可。数据库采集模式可以作为通用的系统使用,更适合多人多系统协作。
    3. 智能跳过超时的设备,加快对在线设备的采集速度,当设备数量很多的时候尤其有用。
    4. 对智能跳过的超时的设备,在设定的重连时间自动采集一次,以便探测设备是否又重新上线。
    5. 每个探测器可控是否启用,不启用则不会采集,也不会在界面显示,相当于运行阶段临时关闭。
    6. 探测器可设置缓冲值和报警延时时间,在该值附近波动产生的报警,不计入报警,只有持续处于报警值且超过报警延时时间才算真正报警,这样可以规避很多波动导致的误报。
    7. 探测器可设置存储周期,按照设定的时间来存储一条运行记录,可以按照重要程度对重要性高的设定存储周期短一些,不重要的设定大一些,这样可以节省不少的存储空间,也保证了重要的数据及时存储。
    8. 探测器可设置清零值,在一些高精度高灵敏的设备可能出厂的时候默认值未必是0,需要设定清零值来表示初始值。
    9. 探测器可设置小数点,用于计算后的真实数据控制小数点点位显示,相当于除以10、除以100、除以1000,这样大部分的探测器数据直接通过小数点位设置控制真实换算后的值,极个别的需要特殊转换的可以在通信协议中约定。
    10. 探测器报警的类型支持多种,有些设备是高于某个值高报,低于某个值低报,而有些设备是在最小值最大值范围内是高报,低于最小值低报,高于最大值正常。这样可以分情况处理,涵盖各种报警类型。
    11. 原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。
    12. 导出到excel的记录支持所有excel、wps等表格文件版本,不依赖excel等软件。
    13. 高报颜色、低报颜色、正常颜色、默认值颜色等,都可以自由设置。
    14. 支持云端数据同步,将本地采集到的数据实时同步到云端。
    15. 支持网络转发和网络接收,网络接收开启后,软件从udp接收数据进行解析。网络转发支持多个目标IP,这样就实现了本地采集的软件,自由将数据转到客户端,随时查看采集到的数据。
    16. 自动记住用户最后停留的界面以及其他配置信息,重启后自动应用。
    17. 报警自动切换到对应的地图,探测器按钮闪烁,表格数据对应颜色显示。
    18. 双击探测器图标,弹出对应探测器详细信息,可以根据需要定制回控操作。
    19. 数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。
    20. 本地设备采集到的数据实时上传到云端,以便手机APP或者web等其他方式提取。
    21. 自带设备模拟工具,支持不同型号的多个设备数据模拟,支持串口和网络,同时还带数据库数据模拟,以便在没有设备的时候测试数据。
    22. 标准modbus协议,各种控制器类型、探测器类型、种类、符号等全部自定义,非常灵活和强大,通信协议示例数据非常完整,通用各种modbus协议系统,适用于各种应用场景接入。
    23. 同时集成了串口通信、网络通信、数据库通信、数据导入导出打印、通信协议解析、界面UI、全局换肤等众多组件和知识点,非常适合新手入门和进阶。
    24. 支持xp、win7、win10、、win11、linux、mac、树莓派、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。
    25. 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。

    0.3 相关站点

    1. 国内站点:https://gitee.com/feiyangqingyun
    2. 国际站点:https://github.com/feiyangqingyun
    3. 个人主页:https://blog.csdn.net/feiyangqingyun
    4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun
    5. 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652
    6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/iotsystem/
    7. 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_iotsystem.zip。
    8. 文章导航:https://qtchina.blog.csdn.net/article/details/121330922

    0.4 特别说明

    1. 主界面顶部为一级菜单导航,单击切换页面,软件的左侧为二级菜单导航。
    2. 在左侧菜单中,单击按钮可以切换到对应的页面。
    3. 软件会记住最后停留的页面,下次启动后自动切换。
    4. 发现数据不对或者有误,可以直接在设备调试界面查看具体的通信数据。
    5. 离线状态下双击设备面板或者设备按钮会主动立即重连一次,在线双击弹出详细信息。
    6. 本系统中的控制器相当于主设备,探测器相当于子设备节点。软件采集是和控制器之间通信。
    7. 系统采用纯QtWidget(非qml)编写,所有源码开放,并非有封装的库。
    8. 同时集成了数据库、多线程、串口通信、网络通信、协议解析、界面美化、UI布局等众多知识点。
    9. 未经本人许可不可将本项目源码扩散,如有发现本人将追究法律责任,谢谢配合。
    10. 高分屏缩放设置说明 https://qtchina.blog.csdn.net/article/details/124860909

    0.5 简易操作

    1. 第一步:从顶部一级菜单切换到系统设置,然后左侧二级菜单切换到端口管理。
    2. 第二步:添加好端口信息。
    3. 第三步:切换到控制器管理,添加好控制器信息。
    4. 第四步:切换到探测器管理,添加好探测器信息。
    5. 第五步:如果需要地图,则切换到地图管理,导入地图,默认已经有5张地图。
    6. 第六步:重启软件。

    0.6 版本说明

    V20220625

    1. 报警记录界面增加右键菜单选择全部、取消选中,和之前的批量删除一起。
    2. 测试批量删除sql语句in关键字在所有数据库中的表现,比如sqlite、mysql、postgres、sqlserver等全部测试通过。
    3. 优化报警邮件转发流程,过滤空报警信息只发送报警日志xls文件。
    4. 修复在postgresql数据库和oracle数据库下,QSqlTableModel对应setTable设置表名严格区分大小写的BUG。
    5. 大幅度优化mysql数据库分页查询效率,百万级别以上数据量下测试速度提升500倍+。
    6. 分页查询增加查询用时,每次翻页的查询都有用时计算。

    V20220522

    1. 增加配置参数记录设备模拟工具是否已经通过主程序调用,已经打开了则不用重复打开。
    2. 修正数据库脚本文件,以便支持其他数据库,其他数据库全部测试过一遍。
    3. 增加各种数据库效果图,同步更新文档。
    4. 增加网络转发和云端数据库同步说明及效果图。
    5. 网络转发将分隔符改成字段数据用 , 分隔,行数据用 ; 分隔,最前面标识符用 | 分隔。
    6. 判断模拟工具是否打开算法再次改进,从命令行执行结果查看是否存在该程序。
    7. 所有数据库执行出错打印增加打印错误信息和对应的sql语句。
    8. 修复开启自动行数的时候,如果默认页面停留在其他页面,消息行数计算不准确的BUG。改成了默认采用左侧堆栈控件的高度作为参照标准,因为该控件永远显示,可以拿到正确的高度。
    9. 报警记录表格增加支持多选删除,可以批量删除选中的记录。
    10. 修复报警声音播放的BUG,在Qt5中默认播放首次设置的声音文件成功其余有杂音。
    11. 修复设备按钮报警颜色中低报和高报颜色搞反了的BUG。

    V20220508

    1. 设备地图按钮增加报警颜色选项,低报黄色闪烁,高报红色闪烁,其他报警紫色闪烁,正常绿色。
    2. 修正低分辨率比如1366x768情况下默认配置文件窗体尺寸过大的问题。
    3. 修复设备面板在仪表盘样式情况下文字颜色没有和系统样式统一的BUG。
    4. 将设备面板统一到一个类,多种样式选择,普通样式、仪表样式等。
    5. 说明书中通信协议举例,重新整理,更丰富更完整。
    6. 消息栏改成0表示自动设置行数,100表示设置0行,其他表示选择的行数。
    7. 将面板样式切换直接移到主界面,方便直接切换立即应用。
    8. 删减合并一些冗余的代码。
    9. 修复离线后仪表盘的值没有清零的BUG。
    10. 修复有部分权限页面控制不准的BUG。
    11. 新增自启动设备模拟工具配置参数,可以在系统设置中功能激活启用。
    12. 将模拟工具启动放在主窗体加载完成后,之前的main函数中不妥当,会导致用户还没登录就运行了设备模拟工具。
    13. 探测器节点信息,系统设置新增排序规则,可以按照位号排序,或者种类+位号等方式。
    14. 增加在win以外的其他系统,自动new出来设备模拟工具。
    15. 改进默认地图算法,取第一个有背景地图的设备的图片作为默认图片,可能默认图片不存在则取图片列表中的第一张。

    V20220428

    1. 将项目统一命名为iotsystem,对应设备模拟工具iottool。
    2. 将多个模块提炼成通用模块,比如用户登录退出、数据库设置、用户管理等,这样可以和其他系统完全公用模块。
    3. 统一调整项目模块,统一规划。
    4. 重新截图,重新编写说明书和开发使用手册。
    5. 权限控制增加用户管理、组态设计等,替换之前备用的模块A、模块B。
    6. 将用户管理、组态设计、设备调试等模块移动到其他设置大类,方便管理。
    7. 修复非最大化界面,拖动设备按钮会触发界面移动并且乱跳的BUG。
    8. 修复本地电脑开启网络代理的情况下,网络链接本地IP地址报错提示 The proxy type is invalid for this operation 的BUG。
    9. 模拟工具增加一键复位和一键报警按钮,用于设置没有报警的值和报警的值。
    10. 修复Qt6中报警后重复触发报警声音会崩溃的BUG。
    11. 统一梳理所有数据库字段长度,留有足够的余地。
    12. 修复设备面板在低报高报互相切换状态的时候报警颜色不正确的BUG。

    V20190712

    1. 控制器型号+探测器型号+气体种类+气体符号改成表格存储,新增探测器数量字段。
    2. 当节点数量小于列数时候会宽度变宽的BUG。
    3. 新增阿里云数据库同步,数据库采集模式会将数据库数据实时同步到阿里云。

    V20190624

    1. nodeinfo表新增nodezero字段,用于存储消零值,小于该值则显示为0,大于则显示真实值。
    2. alarmlog表增加confirmuser、confirmtime、confirmcontent三个字段,存储报警记录的确认用户、确认时间、确认内容。
    3. 新增了数据库读取模式,用于数据库采集显示数据。
    4. 修复了Qt5.10版本以上,数据清理线程提示不能运行的BUG。不能在线程中用主线程创建的数据库。
    5. 改进了部分代码。
    6. 模拟器新增数据库模拟。
    7. 配置文件新增模拟器的配置信息。
    8. 修复表格中设置了单独的文字颜色,在选中时会被覆盖的BUG。
    9. 新增报警右下角弹框。可以配置文件更改是否开启以及显示多久,默认开启。
    10. 新增报警记录鼠标右键删除记录,支持多选批量删除。
    11. 设备表格,按照气体种类升序+位号升序排列,以前是按照位号。
    12. 控制器对应的最大探测器数量,已禁用,直接选择好探测器类型自动设置。

    1 用户登录退出

    1.1 用户登录

    -

    系统启动后,首先会弹出用户登录界面,从用户姓名的下拉框选择用户名,然后输入密码(默认用户名密码都是admin),单击登录按钮,密码正确则会进入到系统主界面,错误会弹出提示,错误超过三次自动关闭,需要重新打开软件。

    在登录界面可以勾选是否记住密码,是否自动登录,如果勾选了记住密码,则下次启用软件会自动填入最后用户的密码,勾选了自动登录(以最后的用户信息作为当前登录用户)则启动后直接进入主界面。如果开启了自动登录,不会弹出登录界面,可以在系统设置中关闭自动登录和记住密码。

    1.2 用户退出

    在主界面单击右上角的关闭按钮,会弹出用户退出界面,需要输入密码验证防止误关闭,会自动填入登录的用户名,密码输入正确才会退出软件。用户登录和退出都内置了超级密码a防止管理员忘记密码。

    2 系统设置

    2.1 基本设置

    2.1.1 常规设置

    基本设置中有部分参数的切换会自动重启应用。

    参数说明

    1. 开机运行:开启以后自动随着系统启动运行,默认开启。
    2. 自动登录:开启以后会自动以最后登录的用户信息登录到系统,默认关闭。
    3. 记住密码:开启以后会自动填入最后登录的用户信息到登录窗体,默认关闭。
    4. 中文标题:软件左上角标题栏的中文标题,改动立即应用。
    5. 英文标题:软件左上角标题栏的英文标题,改动立即应用。
    6. 版权所有:当前软件版权所有的公司,显示在软件的底部信息栏中。
    7. 调试日志:开启后会将打印日志输出到日志文件,默认关闭,日志文件存放在可执行文件夹下的log目录下。
    8. 运行时间:开启后会实时记录系统的运行时间,记录当前软件启动后运行了多久,运行时间文件存放在可执行文件夹下的log目录下。
    9. 工作模式:默认设备采集,可选数据库采集、数据库读取、设备采集2等,一般都是特殊定制需求的在这里切换工作模式。
    10. 导航样式:用于选择顶部导航栏和左侧导航栏的样式,上侧+左侧表示顶部导航栏上侧样式(图标在上面,文字在下面),左侧导航栏左侧样式(图标在左侧,文字在右侧)。
    11. 界面样式:系统自带17套皮肤,可以在这里自动换肤,默认视频黑。
    12. 软件图标:自动从logo文件夹读取,可以自行选择对应的logo文件。
    13. 报警声音:开启后当探测器报警后,会播放报警声音,默认开启。
    14. 播放次数:播放报警声音的次数,默认1次。
    15. 警情行数:主界面运行监测左侧显示报警信息的最大行数。新警情自动追加在最前面。0表示自动根据尺寸填充,100表示禁用。
    16. 自动确认:开启后自动确认警情存入报警记录,默认开启。
    17. 设备列数:设备监控主界面设备面板的列数。
    18. 记录行数:在数据查询的表格中,显示的记录的行数。

    工作模式

    1. 设备采集:本地直接采集网络和串口过来的数据,每个数据位2字节表示一个含义。
    2. 数据库采集:定时器读取数据库表NodeData,具体字段含义见数据库表说明。
    3. 数据库采集2:和数据库采集逻辑一样,就是具体的报警标志位含义不一样。
    4. 设备采集2:用户定制的一套解析协议,和上面设备采集的区别是收发协议两样,带有电源、报警标志位,每个探测器4寄存器=8字节。
    • 设备采集模式 nodeStatus 0-低报 1-低报恢复 2-高报 3-高报恢复 5-其他报警 6-其他报警恢复
    • 数据库采集模式 nodeStatus 0-离线 1-在线 2-低报 3-高报
    • 数据库采集2模式 nodeStatus 0-离线 1-正常 2-报警 3-高报 4-失效
    • 设备采集2模式 nodeStatus 0-预热中 1-工作中 2-低限报警 3-高限报警 4-传感器故障 7-探测器离线

    2.1.2 本地数据库设置

    参数说明

    1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。
    2. 主机类型:和本地数据库设置一样,可选多种。
    3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。
    4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。
    5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。
    6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。
    9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

    其他说明

    1. 默认提供了数据库脚本文件(拓展名sql结尾的文件)。
    2. 单击初始化数据按钮可以对整个数据库进行新建和重置,相当于恢复出厂。
    3. 系统支持多种数据库,默认sqlite(Qt内置的数据库,无需安装),可选mysql、postgresql、oracle、人大金仓等。
    4. 具体还需要对应Qt版本有数据库插件支持,没有插件支持可以自行编译对应缺失的插件比如mysql,也可选直接通过万能的ODBC来连接。
    5. 除了sqlite数据库外,其余数据库都需要输入数据库名称、主机地址、通信端口、用户名称、用户密码信息,输入好以后可以单击连接测试按钮测试下是否正常。
    6. 默认提供的是mysql的动态库libmysql.dll,需要放到可执行文件同一目录,严格区分32位和64位的动态库。

    2.1.3 云端数据库同步

    参数说明

    1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。
    2. 主机类型:和本地数据库设置一样,可选多种。
    3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。
    4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。
    5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。
    6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。
    8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。
    9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

    2.1.4 日志设置

    参数说明

    1. 报警记录:报警记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。
    2. 运行记录:运行记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。
    3. 操作记录:操作记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。
    4. 记录排序:在报警记录查询界面中,按照何种方式排序,默认按照时间降序,相当于最新的记录在最前面。
    5. 报警弹框:报警触发后在右下角弹框信息停留时间,0秒表示一直停留直到手动关闭,10000秒表示不弹出。
    6. 小数点位:设备采集到的数据,最后按照几位小数点显示。

    2.1.5 网络转发设置

    网络转发的功能,是用来将本地的采集的所有设备的数据,通过UDP协议转发到指定的IP和端口,对方只要开启网络接收即可查看到设备的实时运行数据。网络转发和网络接收不能同时开启,本地负责采集的软件开启网络转发,远程需要查看数据的电脑开启网络接收,转发的端口和接收的端口必须保持一致,支持多个IP,中间用英文的分号 ; 隔开。单击同步数据的按钮会将本地的端口+设备+节点信息传送到接收端,不需要手动设置。这样就保证了本地的信息和远程的信息完全一致。远程的IP必须保证可达,比如ping的通。

    参数说明

    1. 网络转发:开启后会将本地的数据通过udp协议发到指定的网络地址和端口。
    2. IP及端口:网络转发要去达的网络地址和端口,用英文冒号 : 隔开。
    3. 网络接收:开启后将采用接收端形式运行,接收转发过来的设备数据作为采集源。
    4. 接收端口:网络接收端口。
    5. 同步数据:开启网络转发后,单击该按钮,会将本地的端口信息、控制器信息、探测器信息发送到远端,这样远端接收到数据后不用手动添加。

    2.1.6 告警短信转发

    当探测器发生报警后,如果开启了短信告警,会将报警信息以短信的形式发送到预先设定的接收者的手机号码上,短信内容格式为:位号: AT400001 控制器: 控制器A 探测器: 探测器A 触发值: 70.8 PPM 类型: 浓度上限报警 时间: 2019-01-05 12:12:12。需要本地发短信的硬件支持。

    参数说明

    1. 串口名称:短信猫设备接入的串口号。
    2. 波 特 率:短信猫设备通信所使用的波特率。
    3. 接收号码:接收者的手机号码,可以填写多个,中间用英文的分号 ; 隔开。
    4. 发送间隔:短信发送的间隔,默认10000表示不开启,0表示实时发送。
    5. 测试短信:单击该按钮会立即发送一条测试短信到接收者手机用于测试功能是否正常。

    2.1.7 告警邮件转发

    当探测器发生报警后,如果开启了邮件转发告警,会将报警信息以邮件的形式发送到预先设定的接收者的邮箱中,邮件内容格式为:位号: AT400001 控制器: 控制器A 探测器: 探测器A 触发值: 70.8 PPM 类型: 浓度上限报警 时间: 2019-01-05 12:12:12。后期会将警情统计的报表数据以excel表格的形式发送到接收者邮箱。如果发现邮箱登录失败等,请先在邮箱后台设置开启smtp和pop3。

    参数说明

    1. 发件邮箱:发件人的邮箱地址,必须保证该邮箱开启过POP3。
    2. 发件密码:发件人的邮箱的密码,会以加密的形式存储在配置文件。
    3. 接收邮箱:接收者的邮箱地址,支持多个,用英文的分号 ; 隔开。
    4. 发送间隔:邮件发送的间隔,默认10000表示不开启,0表示实时发送。
    5. 测试邮件:单击该按钮会立即发送一条测试邮件到接收者邮箱用于测试功能是否正常。

    2.1.8 系统时间设置

    用来设置本地电脑的系统时间,为什么需要这个设置,因为软件很可能在嵌入式linux上运行,需要手动设置时间。

    2.1.9 功能激活

    参数说明

    1. 表格联动:开启后在数据监控的表格中会自动实时显示采集的设备数据。
    2. 面板联动:开启后在设备面板对应的设备会自动显示采集的设备数据。
    3. 按钮联动:开启后在地图监控上对应的按钮会自动显示采集的设备数据。
    4. 设备地图:开启后会显示设备地图模块,默认关闭,大部分场景用不上,只需要表格展示数据,最高效。

    2.1.10 颜色设置

    参数说明

    1. 离线颜色:探测器离线后对应文字显示的颜色。
    2. 高报颜色:探测器发生上限报警(高报)后对应文字显示的颜色。
    3. 低报颜色:探测器发生下限报警(低报)后对应文字显示的颜色。
    4. 正常颜色:探测器运行正常时对应文字显示的颜色。
    5. 曲线背景:探测器实时曲线界面背景颜色。
    6. 曲线文字:探测器实时曲线界面文字颜色。
    7. 曲线颜色:探测器实时曲线界面曲线的颜色。
    8. 待定颜色:目前备用的颜色。

    2.2 端口管理

    本系统支持串口接入和网络接入两种方式,对应的端口需要提前设置,后期可能还会新增mqtt等方式,选择不同的协议类型即可。

    字段说明

    1. 端口编号:端口的编号,从1开始。
    2. 端口名称:端口的别名,方便记忆。
    3. 协议类型:默认Modbus_Com为串口通信,TCP通信选择Modbus_Tcp_Rtu。
    4. 串 口 号:如果用的是串口通信,这里填入串口号即可。
    5. 波 特 率:串口通信使用的波特率。
    6. IP 地 址:设备的IP地址。
    7. 通讯端口:该设备网络通信所使用的端口,默认502,即modbus通信的端口。
    8. 采集周期:该通讯处理中对每个控制器轮询的间隔时间。单位秒,如果要0.2s=200毫秒则填0.2即可,默认浮点数处理。
    9. 通讯超时:该通讯处理中大于几次未收到回应消息则判断为离线,默认3次。
    10. 重连时间:如果某个设备离线状态,最大多长时间重新读取一次,默认60秒。

    2.2.1 端口添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.2.2 端口删除

    如果要删除某个端口信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.2.3 端口清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.2.4 端口信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.2.5 端口信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.2.6 端口信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.2.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.3 控制器管理

    字段说明

    1. 控制器编号:控制器的编号,从1开始。
    2. 通 讯 端口:通讯所采用的通讯端口名称,和端口管理中的端口名称一致。
    3. 控制器名称:控制器的别名,以便记忆。
    4. 控制器地址:控制器的地址,最大255。
    5. 控制器型号:控制器的型号,不一样的控制器可能通信的协议不一致。
    6. 探测器数量:该控制器下面挂载的探测器的数量,必须和真实安装的数量完全一致。

    2.3.1 控制器添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.3.2 控制器删除

    如果要删除某个控制器信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.3.3 控制器清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.3.4 控制器信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.3.5 控制器信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.3.6 控制器信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.3.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.4 探测器管理

    字段说明

    1. 编 号:节点的编号,从1开始。
    2. 位 号:探测器的位置编号,用于唯一标识一个探测器。
    3. 控 制 器:对应挂载的主设备名称。
    4. 探 测 器:探测器的名称,方便记忆,可以填写地理位置。
    5. 地 址:探测器对应在控制器的编号索引。
    6. 型 号:探测器的型号,从下拉框选择。
    7. 气体种类:探测器对应采集的气体的种类。
    8. 气体型号:探测器对应采集气体的型号。
    9. 上 限 值:报警的上限值。
    10. 下 限 值:报警的下限值
    11. 最 大 值:最大的警戒值,超过该值则显示为该值。
    12. 消 零:最小的警戒值,小于该值则显示0,大于显示真实值。
    13. 量 程:假设量程0.25则 实际数=模拟量/4000x量程 模拟量就是采集的值。
    14. 状 态:默认启用,当某个探测器未接时候可以选择禁用。
    15. 声 音:报警后对应的声音文件。
    16. 地 图:探测器所位于的地图文件。
    17. 存 储:探测器记录存储的周期,单位分钟。即隔多久存储一次记录到本地。
    18. 小 数 点:计算解析数据的数据位对应的小数点位数。
    19. 报警延时:报警后,延时多久处理,以便过滤数据抖动偏差造成的误报。默认0。
    20. 报警类型:HH LL HL。
    21. X坐 标:探测器位于地图上的X坐标。
    22. Y坐 标:探测器位于地图上的Y坐标。

    报警类型

    • 根据设定的不同的报警类型处理,假定上限值100,下限值25。
    • HH表示超过25是低报,超过100是高报,低于25正常。
    • HL表示低于25是低报,超过100是高报,25到100之间正常。
    • LL表示低于25是高报,低于100是低报,大于100正常。

    2.4.1 探测器添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.4.2 探测器删除

    如果要删除某个探测器信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.4.3 探测器清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.4.4 探测器信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.4.5 探测器信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.4.6 探测器信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.4.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.5 报警联动

    在报警联动设置中,可以设置每个位号报警后,对应的继电器联动,支持探测器串口和新独立的串口(如果是和探测器并用的串口则不会重新打开串口,直接用原有的串口发数据联动,如果是新的串口则会重新打开串口),模块地址为继电器板子的地址,联动地址集合为需要联动报警的位,支持多个,多对多关系,一个探测器报警可以联动多个联动模块上的多个继电器地址,中间丨杠隔开。

    字段说明

    1. 位置编号:下拉选择,从探测器信息表取,表示哪个位置的探测器报警。
    2. 串 口 号:串口号,可以是之前端口信息中的串口,会自动检测切换。
    3. 波 特 率:报警端口转发串口对应的波特率,默认9600。
    4. 模块地址:对应联动模块的地址,挂在总线上的联动模块的唯一地址,该模块专门用来做继电器联动。
    5. 联动地址:联动模块上有一排继电器地址,对应报警后,可以触发联动一个或者多个继电器,需要哪个地址就填哪些地址。
    6. 启 用:可以动态关闭不需要的联动信息,但是不删除,这样只需要这里取消启用即可,而不是删除,不然又要重新添加。

    2.5.1 联动添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.5.2 联动删除

    如果要删除某个联动信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.5.3 联动清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.5.4 联动信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.5.5 联动信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.5.6 联动信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.5.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    2.6 类型设置

    参数说明

    • 本表格中的数据并不是严格的对应关系。
    • 其中控制器信号、探测器数量是一对,其余全部独立。
    • 用来在系统设置中对应下拉框中的信息。
    • 这样就非常灵活,用户后期增加了新的产品直接在这里添加好就行,其他地方都是自动下拉选择。

    2.6.1 类型添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    2.6.2 类型删除

    如果要删除某个类型信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

    2.6.3 类型清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    2.6.4 类型信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    2.6.5 类型信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

    2.6.6 类型信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    2.6.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    3 其他设置

    3.1 用户管理

    用户管理是后面增加的一个模块,用于设置不同的用户不同的类型+权限,可以细分到每个模块的权限,勾选表示具有该权限,内置了7种权限选择,后期还可以在此基础上增加其他权限等。

    3.1.1 用户添加

    单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

    3.1.2 用户删除

    如果要删除某个用户信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。不允许删除内置的admin用户。

    3.1.3 用户清空

    单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

    3.1.4 用户信息导入

    单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

    3.1.5 用户信息导出

    单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。

    3.1.6 用户信息打印

    单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

    3.1.7 导出到Excel

    单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

    3.1.8 权限验证

    -

    假设设置了用户没有系统设置和删除记录的权限,则关闭系统的时候会弹出错误信息提示当前用户没有权限。

    3.2 地图管理

    在地图管理中,可以导入和删除地图。

    3.3 位置调整

    位置调整中,可以拖动探测器到正确的位置,右侧单击地图切换可以看到对应的该地图对应的探测器,全部位置调整好之后,单击右下角保存按钮即可,会立即应用。

    3.4 组态设计

    组态设计模块中提供的是简单的示例,演示如何加载自定义控件动态库、将控件拖曳到背景地图上,配置好对应控件的属性,可定义用户属性,可导出控件的配置信息到xml文件,并支持导入xml文件自动加载上次保存的控件配置信息。目前是一个简单的组态雏形,等后期架构好如何应用再重写整个模块。

    本系统默认不包括里面控件的源码,提供动态库的形式使用,如果还想学习自定义控件大全的源码(目前共202个控件卖700元),需要额外单独购买。

    3.5 设备调试

    可以自行选择通讯端口+设备名称进行数据的过滤,可查看所有的通信数据。不同收发数据不同颜色,还可以指定关键字过滤数据,每个收发数据都有对应的中文解释。能够很方便的对运行中的系统查看设备数据,规避是下位机还是上位机问题扯皮的事情。

    4 设备监控

    设备监控界面主要包括4个模块,分别是数据监控、设备面板、地图监控、曲线监控,设备的实时数据可以同时反应到四个模块上面,相当于以4种不同的表现形式展现采集到的数据。

    模式说明

    • 数据监控:表格形式一行行展示数据。
    • 设备面板:每个探测器都是个独立的一个面板展示数据和信息。
    • 地图监控:设备按钮放在对应地图上,长条状显示数据和符号单位。
    • 曲线监控:对每个设备过滤曲线显示采集到的数据。
    • 设备报警后,如果设置了报警弹窗,则右下角都会弹出对应的报警信息。
    • 设备报警后,对应表格行、设备面板、地图按钮等都会突出颜色显示。

    4.1 数据监控

    本页面会是使用频率最高的页面,默认就是停留在本页面实时查看所有探测器的数据。左侧为警情信息栏,分别显示时间、位号、报警值。如果有探测器报警,则消息自动追加到最前面。 -表格依次显示序号、位号、控制器名称、控制器型号、探测器名称、探测器型号、气体种类、浓度值、气体符号。

    4.2 设备面板

    面板说明

    1. 探测器作为一个个独立的设备面板控件。
    2. 有多少个探测器就会生成多少个面板,放在面板容器中。
    3. 可以在系统设置中选择设备列数,按照该设备列数来排列,超过会自动产生滚动条拖动查看。
    4. 报警后整个设备面板会突出颜色显示比如高报是红色、低报是黄色等。
    5. 双击探测器面板,会跳转到该探测器的详细信息界面,在该界面上后期可以按照实际用户需求定制回控操作。
    6. 面板有多种样式可供选择,比如普通样式、仪表样式。可直接在右侧切换立即运用。

    4.2.1 普通样式

    4.2.2 仪表样式

    4.2.3 仪表样式2

    4.3 地图监控

    本页面以地图的形式显示所有探测器,右侧单击对应地图可以手动切换地图,当探测器报警后会自动切换到当前地图,探测器图标红色闪烁,探测器图标实时显示当前的浓度值。双击探测器按钮图标,会跳转到该探测器的详细信息界面,在该界面上后期可以按照实际用户需求定制回控操作。

    4.4 曲线监控

    在本页面可以查看某个探测器的实时曲线,第一步先选择通信端口,第二步选择控制器,第三步选择探测器,然后就可以在左侧看到实时曲线,颜色可以在系统设置中设置。单击打印按钮会将当前曲线以截图的形式打印出来。勾选暂停显示记录数据复选框会暂停显示当前的数据。

    4.4.1 实时曲线

    4.4.2 历史曲线

    5 数据查询

    5.1 报警记录

    在本页面,可以指定日期范围查询报警记录,还可以查询单个的控制器或者探测器的报警记录。也可以手动输入探测器的位号进行查询,下拉选择探测器后会自动填入位号。还可以选择报警类型(浓度上限报警、浓度下限报警)查询对应的类型,也可以输入报警值进行精准查询。

    如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

    双击对应的报警记录可以打开警情确认对话框,重新填写确认意见,鼠标右键弹出删除记录菜单,可以删除当前选中的记录,支持多选,例如按住Ctrl键选择多个记录。

    5.1.1 记录查询

    5.1.2 记录打印

    5.1.3 记录导出

    +

    • 0 前言说明

      0.1 编译说明

      1. 编译完成后记得将源码下的file目录下(切记是file目录下而不是file目录)的所有文件复制到可执行文件同一目录。可执行文件目录bin在当前源码下,和一堆core开头的目录同级别,编译后会自动生成bin目录。

      2. db目录下的 iotsystem.mbs 为modbus模拟数据模板,可以用modbus slave软件打开。

      3. db目录为数据库文件夹,iotsystem.db为sqlite数据库文件,sql结尾的为建库脚本,可以自行改成mysql数据库。

      4. 在端口设置中如果不填写串口号则取网络地址,填了串口号则以串口号优先。

      5. 如果导出的数据到excel以后,打开文件有提示,请先执行db目录下的excel禁止提示.reg文件。

      6. 系统中的组态模块用到了designer模块,有些linux系统安装的Qt开发环境可能会不自带这个模块,编译的时候报错提示 Project ERROR: Unknown module(s) in QT: designer,需要手动打命令安装下,sudo apt-get install libqt5designer5 或者 sudo apt-get install qttools5-dev 。

      7. 如果编译运行后发现某些模块没有比如图片地图,可以去系统设置中的功能激活处勾选重启应用。

      8. 组态设计中的控件是通过加载动态库插件文件产生,具体说明参考本手册中的 3其他设置/3.4组态设计。

      0.2 功能特点

      0.2.1 软件模块

      1. 设备监控模块,包括数据监控(表格形式展示)、设备面板(面板形式展示)、地图监控(地图形式展示)、曲线监控(曲线形式展示)。

      2. 数据查询模块,包括报警记录、运行记录、操作记录。

      3. 系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、报警联动、类型设置等。

      4. 其他设置模块,包括用户管理、地图管理、位置调整、组态设计、设备调试等。

      0.2.2 基础功能

      1. 设备数据采集,支持串口、网络,串口可设置串口号、波特率,网络可设置IP地址、通讯端口。

      2. 每个端口支持采集周期时间,默认1秒钟一个设备。

      3. 支持设置通讯超时次数,默认3次。

      4. 支持最大重连时间,用于重新读取离线的设备。

      5. 控制器信息,能够添加控制器名称,选择控制器地址、控制器型号,设置该控制器下面的探测器数量。

      6. 探测器信息,能够添加位号、探测器型号、气体种类、气体符号、高报值、低报值、缓冲值、清零值、是否启用、报警声音、背景地图、存储周期、数值换算小数点位数、报警延时时间、报警的类型(HH,LL,HL)等。

      7. 类型管理可配置控制器型号、探测器型号、气体种类、气体符号等。

      8. 地图支持导入和删除,所有的探测器在地图上的位置可自由拖动保存。

      9. 端口信息、控制器信息、探测器信息、类型信息、用户信息等,都支持导入、导出、导出到excel、打印。

      10. 运行记录、报警记录、操作记录,都支持多条件组合查询,比如时间段、控制器、探测器等,所有记录支持导出到excel/pdf和打印。

      11. 运行记录、报警记录、操作记录都可删除指定时间范围内的数据。

      12. 系统设置可选择对应表最大保存记录数,自动清理早期数据,留出足够的空间存储重要的数据。

      13. 报警短信转发,支持多个接收手机号码,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,短信内容过长,自动拆分多条短信。

      14. 报警邮件转发,支持多个接收邮箱,可设定发送间隔,比如即时发送或者6个小时发送一次所有的报警信息,支持附件发送。

      15. 设置软件的中文标题、英文标题、logo路径、版权所有等。

      16. 开关设置开机运行、报警声音、自动登录、记住密码等。

      17. 报警声音可设置播放次数,界面风格样式提供18套皮肤文件选择。

      18. 用户管理,包括用户权限配置,不同用户可以有不同模块的权限。

      19. 用户登录和用户退出,可以记住密码和自动登录,超过三次报错提示并关闭程序。

      20. 四种监控模式,设备面板监控、地图监控、表格数据监控、曲线数据监控,可自由切换,四种模式下都实时展示采集到的数据,报警闪烁等。

      21. 报警继电器联动,一个位号可以跨串口联动多个模块和继电器号,支持多对多。

      0.2.3 特色功能

      1. 支持多种协议,包括Modbus_Rtu_Com/Modbus_Rtu_Tcp/Modbus_Rtu_Udp/Modbus_Rtu_Web/Modbus_Tcp/Modbus_Udp/Modbus_Web等,其中web指websocket。

      2. 数据源除了真实的硬件设备采集,还可选数据库采集,这样用户可以安排其他程序员比如java程序员将前端采集好的数据放到数据库,本系统直接从数据库采集即可。数据库采集模式可以作为通用的系统使用,更适合多人多系统协作。

      3. 智能跳过超时的设备,加快对在线设备的采集速度,当设备数量很多的时候尤其有用。

      4. 对智能跳过的超时的设备,在设定的重连时间自动采集一次,以便探测设备是否又重新上线。

      5. 每个探测器可控是否启用,不启用则不会采集,也不会在界面显示,相当于运行阶段临时关闭。

      6. 探测器可设置缓冲值和报警延时时间,在该值附近波动产生的报警,不计入报警,只有持续处于报警值且超过报警延时时间才算真正报警,这样可以规避很多波动导致的误报。

      7. 探测器可设置存储周期,按照设定的时间来存储一条运行记录,可以按照重要程度对重要性高的设定存储周期短一些,不重要的设定大一些,这样可以节省不少的存储空间,也保证了重要的数据及时存储。

      8. 探测器可设置清零值,在一些高精度高灵敏的设备可能出厂的时候默认值未必是0,需要设定清零值来表示初始值。

      9. 探测器可设置小数点,用于计算后的真实数据控制小数点点位显示,相当于除以10、除以100、除以1000,这样大部分的探测器数据直接通过小数点位设置控制真实换算后的值,极个别的需要特殊转换的可以在通信协议中约定。

      10. 探测器报警的类型支持多种,有些设备是高于某个值高报,低于某个值低报,而有些设备是在最小值最大值范围内是高报,低于最小值低报,高于最大值正常。这样可以分情况处理,涵盖各种报警类型。

      11. 原创数据导入、导出、打印机制,跨平台不依赖任何组件,瞬间导出数据。

      12. 导出到excel的记录支持所有excel、wps等表格文件版本,不依赖excel等软件。

      13. 高报颜色、低报颜色、正常颜色、默认值颜色等,都可以自由设置。

      14. 支持云端数据同步,将本地采集到的数据实时同步到云端。

      15. 支持网络转发和网络接收,网络接收开启后,软件从udp接收数据进行解析。网络转发支持多个目标IP,这样就实现了本地采集的软件,自由将数据转到客户端,随时查看采集到的数据。

      16. 自动记住用户最后停留的界面以及其他配置信息,重启后自动应用。

      17. 报警自动切换到对应的地图,探测器按钮闪烁,表格数据对应颜色显示。

      18. 双击探测器图标,弹出对应探测器详细信息,可以根据需要定制回控操作。

      19. 数据库支持多种,包括sqlite、mysql、sqlserver、postgresql、oracle、人大金仓等。

      20. 本地设备采集到的数据实时上传到云端,以便手机APP或者web等其他方式提取。

      21. 自带设备模拟工具,支持不同型号的多个设备数据模拟,支持串口和网络,同时还带数据库数据模拟,以便在没有设备的时候测试数据。

      22. 标准modbus协议,各种控制器类型、探测器类型、种类、符号等全部自定义,非常灵活和强大,通信协议示例数据非常完整,通用各种modbus协议系统,适用于各种应用场景接入。

      23. 同时集成了串口通信、网络通信、数据库通信、数据导入导出打印、通信协议解析、界面UI、全局换肤等众多组件和知识点,非常适合新手入门和进阶。

      24. 支持xp、win7、win10、、win11、linux、mac、树莓派、各种国产系统(UOS、中标麒麟、银河麒麟等)、嵌入式linux等系统。

      25. 注释完整,项目结构清晰,超级详细完整的使用开发手册,精确到每个代码文件的功能说明,不断持续迭代版本。

      0.3 相关站点

      1. 国内站点:https://gitee.com/feiyangqingyun

      2. 国际站点:https://github.com/feiyangqingyun

      3. 个人主页:https://blog.csdn.net/feiyangqingyun

      4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun

      5. 产品主页:https://blog.csdn.net/feiyangqingyun/article/details/97565652

      6. 在线文档:https://feiyangqingyun.gitee.io/qwidgetdemo/iotsystem/

      7. 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_iotsystem.zip。

      8. 文章导航:https://qtchina.blog.csdn.net/article/details/121330922

      0.4 特别说明

      1. 主界面顶部为一级菜单导航,单击切换页面,软件的左侧为二级菜单导航。

      2. 在左侧菜单中,单击按钮可以切换到对应的页面。

      3. 软件会记住最后停留的页面,下次启动后自动切换。

      4. 发现数据不对或者有误,可以直接在设备调试界面查看具体的通信数据。

      5. 离线状态下双击设备面板或者设备按钮会主动立即重连一次,在线双击弹出详细信息。

      6. 本系统中的控制器相当于主设备,探测器相当于子设备节点。软件采集是和控制器之间通信。

      7. 系统采用纯QtWidget(非qml)编写,所有源码开放,并非有封装的库。

      8. 同时集成了数据库、多线程、串口通信、网络通信、协议解析、界面美化、UI布局等众多知识点。

      9. 未经本人许可不可将本项目源码扩散,如有发现本人将追究法律责任,谢谢配合。

      10. 高分屏缩放设置说明 https://qtchina.blog.csdn.net/article/details/124860909

      11. 系统中所有的图标,都采用的图形字体,对照表在doc目录下的FontAwesome.png、FontAliBaBa.png,对应图形字体类IconHelper中加载的图形字体,后期如果还有增加的其他图形字体也是放在这里,一个类支持多种图形字体,通过不同的值范围自动设置。

      0.5 简易操作

      1. 第一步:从顶部一级菜单切换到系统设置,然后左侧二级菜单切换到端口管理。

      2. 第二步:添加好端口信息。

      3. 第三步:切换到控制器管理,添加好控制器信息。

      4. 第四步:切换到探测器管理,添加好探测器信息。

      5. 第五步:如果需要地图,则切换到地图管理,导入地图,默认已经有5张地图。

      6. 第六步:重启软件。

      1 登录退出

      1.1 用户登录

      +

      系统启动后,首先会弹出用户登录界面,从用户姓名的下拉框选择用户名,然后输入密码(默认用户名密码都是admin),单击登录按钮,密码正确则会进入到系统主界面,错误会弹出提示,错误超过三次自动关闭,需要重新打开软件。

      在登录界面可以勾选是否记住密码,是否自动登录,如果勾选了记住密码,则下次启用软件会自动填入最后用户的密码,勾选了自动登录(以最后的用户信息作为当前登录用户)则启动后直接进入主界面。如果开启了自动登录,不会弹出登录界面,可以在系统设置中关闭自动登录和记住密码。

      1.2 用户退出

      在主界面单击右上角的关闭按钮,会弹出用户退出界面,需要输入密码验证防止误关闭,会自动填入登录的用户名,密码输入正确才会退出软件。用户登录和退出都内置了超级密码a防止管理员忘记密码。

      2 系统设置

      2.1 基本设置

      2.1.1 常规设置

      基本设置中有部分参数的切换会自动重启应用。

      参数说明

      1. 开机运行:开启以后自动随着系统启动运行,默认开启。

      2. 自动登录:开启以后会自动以最后登录的用户信息登录到系统,默认关闭。

      3. 记住密码:开启以后会自动填入最后登录的用户信息到登录窗体,默认关闭。

      4. 中文标题:软件左上角标题栏的中文标题,改动立即应用。

      5. 英文标题:软件左上角标题栏的英文标题,改动立即应用。

      6. 版权所有:当前软件版权所有的公司,显示在软件的底部信息栏中。

      7. 调试日志:开启后会将打印日志输出到日志文件,默认关闭,日志文件存放在可执行文件夹下的log目录下。

      8. 运行时间:开启后会实时记录系统的运行时间,记录当前软件启动后运行了多久,运行时间文件存放在可执行文件夹下的log目录下。

      9. 工作模式:默认设备采集,可选数据库采集、数据库读取、设备采集2等,一般都是特殊定制需求的在这里切换工作模式。

      10. 导航样式:用于选择顶部导航栏和左侧导航栏的样式,上侧+左侧表示顶部导航栏上侧样式(图标在上面,文字在下面),左侧导航栏左侧样式(图标在左侧,文字在右侧)。

      11. 界面样式:系统自带17套皮肤,可以在这里自动换肤,默认视频黑。

      12. 软件图标:自动从logo文件夹读取,可以自行选择对应的logo文件。

      13. 报警声音:开启后当探测器报警后,会播放报警声音,默认开启。

      14. 播放次数:播放报警声音的次数,默认1次。

      15. 警情行数:主界面运行监测左侧显示报警信息的最大行数。新警情自动追加在最前面。0表示自动根据尺寸填充,100表示禁用。

      16. 自动确认:开启后自动确认警情存入报警记录,默认开启。

      17. 设备列数:设备监控主界面设备面板的列数。

      18. 记录行数:在数据查询的表格中,显示的记录的行数。

      工作模式

      1. 设备采集:本地直接采集网络和串口过来的数据,每个数据位2字节表示一个含义。

      2. 数据库采集:定时器读取数据库表NodeData,具体字段含义见数据库表说明。

      3. 数据库采集2:和数据库采集逻辑一样,就是具体的报警标志位含义不一样。

      4. 设备采集2:用户定制的一套解析协议,和上面设备采集的区别是收发协议两样,带有电源、报警标志位,每个探测器4寄存器=8字节。

      • 设备采集模式 nodeStatus 0-低报 1-低报恢复 2-高报 3-高报恢复 5-其他报警 6-其他报警恢复

      • 数据库采集模式 nodeStatus 0-离线 1-在线 2-低报 3-高报

      • 数据库采集2模式 nodeStatus 0-离线 1-正常 2-报警 3-高报 4-失效

      • 设备采集2模式 nodeStatus 0-预热中 1-工作中 2-低限报警 3-高限报警 4-传感器故障 7-探测器离线

      2.1.2 本地数据库

      参数说明

      1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。

      2. 主机类型:和本地数据库设置一样,可选多种。

      3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。

      4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。

      5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。

      6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。

      7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。

      8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。

      9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

      其他说明

      1. 默认提供了数据库脚本文件(拓展名sql结尾的文件)。

      2. 单击初始化数据按钮可以对整个数据库进行新建和重置,相当于恢复出厂。

      3. 系统支持多种数据库,默认sqlite(Qt内置的数据库,无需安装),可选mysql、postgresql、oracle、人大金仓等。

      4. 具体还需要对应Qt版本有数据库插件支持,没有插件支持可以自行编译对应缺失的插件比如mysql,也可选直接通过万能的ODBC来连接。

      5. 除了sqlite数据库外,其余数据库都需要输入数据库名称、主机地址、通信端口、用户名称、用户密码信息,输入好以后可以单击连接测试按钮测试下是否正常。

      6. 默认提供的是mysql的动态库libmysql.dll,需要放到可执行文件同一目录,严格区分32位和64位的动态库。

      2.1.3 云端数据库

      参数说明

      1. 远程同步:开启后将会启用云端数据同步功能,将本地数据实时同步到远程数据库中。

      2. 主机类型:和本地数据库设置一样,可选多种。

      3. 数据库名:对应数据库的数据库名称,一个数据库系统中可以有多个数据库实例。

      4. 主机地址:数据库所在的网络地址,可以是IP地址或者网址。

      5. 通信端口:数据库开放通信的端口,不同数据库默认端口不同,比如mysql是3306,postgres是5432,sqlserver是1433。

      6. 用户名称:登录到网络数据库对应的用户名称,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。

      7. 用户密码:登录到网络数据库对应的用户密码,所有的网络型数据库都需要用户认证。sqlite是文件型数据库一般不需要认证。

      8. 连接测试:单击后主动连接一次当前填入的数据库信息,连接成功与失败都会弹框提示。

      9. 初始数据:单击后会执行sql脚本文件,重置数据库,会将原来的数据一并清空。务必记得只有需要的时候才执行。

      2.1.4 日志设置

      参数说明

      1. 报警记录:报警记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。

      2. 运行记录:运行记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。

      3. 操作记录:操作记录存储最大数量,超过会自动清理,相当于永远存储最近的记录,把早期数据清空,留给最新的数据,节约空间。

      4. 记录排序:在报警记录查询界面中,按照何种方式排序,默认按照时间降序,相当于最新的记录在最前面。

      5. 报警弹框:报警触发后在右下角弹框信息停留时间,0秒表示一直停留直到手动关闭,10000秒表示不弹出。

      6. 小数点位:设备采集到的数据,最后按照几位小数点显示。

      2.1.5 网络转发

      网络转发的功能,是用来将本地的采集的所有设备的数据,通过UDP协议转发到指定的IP和端口,对方只要开启网络接收即可查看到设备的实时运行数据。网络转发和网络接收不能同时开启,本地负责采集的软件开启网络转发,远程需要查看数据的电脑开启网络接收,转发的端口和接收的端口必须保持一致,支持多个IP,中间用英文的分号 ; 隔开。单击同步数据的按钮会将本地的端口+设备+节点信息传送到接收端,不需要手动设置。这样就保证了本地的信息和远程的信息完全一致。远程的IP必须保证可达,比如ping的通。

      参数说明

      1. 网络转发:开启后会将本地的数据通过udp协议发到指定的网络地址和端口。

      2. IP及端口:网络转发要去达的网络地址和端口,用英文冒号 : 隔开。

      3. 网络接收:开启后将采用接收端形式运行,接收转发过来的设备数据作为采集源。

      4. 接收端口:网络接收端口。

      5. 同步数据:开启网络转发后,单击该按钮,会将本地的端口信息、控制器信息、探测器信息发送到远端,这样远端接收到数据后不用手动添加。

      2.1.6 短信转发

      当探测器发生报警后,如果开启了短信告警,会将报警信息以短信的形式发送到预先设定的接收者的手机号码上,短信内容格式为:位号: AT400001 控制器: 控制器A 探测器: 探测器A 触发值: 70.8 PPM 类型: 浓度上限报警 时间: 2019-01-05 12:12:12。需要本地发短信的硬件支持。

      参数说明

      1. 串口名称:短信猫设备接入的串口号。

      2. 波 特 率:短信猫设备通信所使用的波特率。

      3. 接收号码:接收者的手机号码,可以填写多个,中间用英文的分号 ; 隔开。

      4. 发送间隔:短信发送的间隔,默认10000表示不开启,0表示实时发送。

      5. 测试短信:单击该按钮会立即发送一条测试短信到接收者手机用于测试功能是否正常。

      2.1.7 邮件转发

      当探测器发生报警后,如果开启了邮件转发告警,会将报警信息以邮件的形式发送到预先设定的接收者的邮箱中,邮件内容格式为:位号: AT400001 控制器: 控制器A 探测器: 探测器A 触发值: 70.8 PPM 类型: 浓度上限报警 时间: 2019-01-05 12:12:12。后期会将警情统计的报表数据以excel表格的形式发送到接收者邮箱。如果发现邮箱登录失败等,请先在邮箱后台设置开启smtp和pop3。

      参数说明

      1. 发件邮箱:发件人的邮箱地址,必须保证该邮箱开启过POP3。

      2. 发件密码:发件人的邮箱的密码,会以加密的形式存储在配置文件。

      3. 接收邮箱:接收者的邮箱地址,支持多个,用英文的分号 ; 隔开。

      4. 发送间隔:邮件发送的间隔,默认10000表示不开启,0表示实时发送。

      5. 测试邮件:单击该按钮会立即发送一条测试邮件到接收者邮箱用于测试功能是否正常。

      2.1.8 系统时间

      用来设置本地电脑的系统时间,为什么需要这个设置,因为软件很可能在嵌入式linux上运行,需要手动设置时间。

      2.1.9 功能激活

      参数说明

      1. 表格联动:开启后在数据监控的表格中会自动实时显示采集的设备数据。

      2. 面板联动:开启后在设备面板对应的设备会自动显示采集的设备数据。

      3. 按钮联动:开启后在地图监控上对应的按钮会自动显示采集的设备数据。

      4. 设备地图:开启后会显示设备地图模块,默认关闭,大部分场景用不上,只需要表格展示数据,最高效。

      2.1.10 颜色设置

      参数说明

      1. 离线颜色:探测器离线后对应文字显示的颜色。

      2. 高报颜色:探测器发生上限报警(高报)后对应文字显示的颜色。

      3. 低报颜色:探测器发生下限报警(低报)后对应文字显示的颜色。

      4. 正常颜色:探测器运行正常时对应文字显示的颜色。

      5. 曲线背景:探测器实时曲线界面背景颜色。

      6. 曲线文字:探测器实时曲线界面文字颜色。

      7. 曲线颜色:探测器实时曲线界面曲线的颜色。

      8. 待定颜色:目前备用的颜色。

      2.2 端口管理

      本系统支持串口接入和网络接入两种方式,对应的端口需要提前设置,后期可能还会新增mqtt等方式,选择不同的协议类型即可。

      字段说明

      1. 端口编号:端口的编号,从1开始。

      2. 端口名称:端口的别名,方便记忆。

      3. 协议类型:默认Modbus_Com为串口通信,TCP通信选择Modbus_Tcp_Rtu。

      4. 串 口 号:如果用的是串口通信,这里填入串口号即可。

      5. 波 特 率:串口通信使用的波特率。

      6. IP 地 址:设备的IP地址。

      7. 通讯端口:该设备网络通信所使用的端口,默认502,即modbus通信的端口。

      8. 采集周期:该通讯处理中对每个控制器轮询的间隔时间。单位秒,如果要0.2s=200毫秒则填0.2即可,默认浮点数处理。

      9. 通讯超时:该通讯处理中大于几次未收到回应消息则判断为离线,默认3次。

      10. 重连时间:如果某个设备离线状态,最大多长时间重新读取一次,默认60秒。

      2.2.1 添加端口

      单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

      2.2.2 删除端口

      如果要删除某个端口信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

      2.2.3 清空端口

      单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

      2.2.4 导入端口

      单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

      2.2.5 导出端口

      单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

      2.2.6 打印端口

      单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

      2.2.7 导出到表格

      单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

      2.3 控制器管理

      字段说明

      1. 控制器编号:控制器的编号,从1开始。

      2. 通 讯 端口:通讯所采用的通讯端口名称,和端口管理中的端口名称一致。

      3. 控制器名称:控制器的别名,以便记忆。

      4. 控制器地址:控制器的地址,最大255。

      5. 控制器型号:控制器的型号,不一样的控制器可能通信的协议不一致。

      6. 探测器数量:该控制器下面挂载的探测器的数量,必须和真实安装的数量完全一致。

      2.3.1 添加控制器

      单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

      2.3.2 删除控制器

      如果要删除某个控制器信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

      2.3.3 清空控制器

      单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

      2.3.4 导入控制器

      单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

      2.3.5 导出控制器

      单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

      2.3.6 打印控制器

      单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

      2.3.7 导出到表格

      单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

      2.4 探测器管理

      字段说明

      1. 编 号:节点的编号,从1开始。

      2. 位 号:探测器的位置编号,用于唯一标识一个探测器。

      3. 控 制 器:对应挂载的主设备名称。

      4. 探 测 器:探测器的名称,方便记忆,可以填写地理位置。

      5. 地 址:探测器对应在控制器的编号索引。

      6. 型 号:探测器的型号,从下拉框选择。

      7. 气体种类:探测器对应采集的气体的种类。

      8. 气体型号:探测器对应采集气体的型号。

      9. 上 限 值:报警的上限值。

      10. 下 限 值:报警的下限值

      11. 最 大 值:最大的警戒值,超过该值则显示为该值。

      12. 消 零:最小的警戒值,小于该值则显示0,大于显示真实值。

      13. 量 程:假设量程0.25则 实际数=模拟量/4000x量程 模拟量就是采集的值。

      14. 状 态:默认启用,当某个探测器未接时候可以选择禁用。

      15. 声 音:报警后对应的声音文件。

      16. 地 图:探测器所位于的地图文件。

      17. 存 储:探测器记录存储的周期,单位分钟。即隔多久存储一次记录到本地。

      18. 小 数 点:计算解析数据的数据位对应的小数点位数。

      19. 报警延时:报警后,延时多久处理,以便过滤数据抖动偏差造成的误报。默认0。

      20. 报警类型:HH LL HL。

      21. X坐 标:探测器位于地图上的X坐标。

      22. Y坐 标:探测器位于地图上的Y坐标。

      报警类型

      • 根据设定的不同的报警类型处理,假定上限值100,下限值25。

      • HH表示超过25是低报,超过100是高报,低于25正常。

      • HL表示低于25是低报,超过100是高报,25到100之间正常。

      • LL表示低于25是高报,低于100是低报,大于100正常。

      2.4.1 添加探测器

      单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

      2.4.2 删除探测器

      如果要删除某个探测器信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

      2.4.3 清空探测器

      单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

      2.4.4 导入探测器

      单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

      2.4.5 导出探测器

      单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

      2.4.6 打印探测器

      单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

      2.4.7 导出到表格

      单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

      2.5 报警联动

      在报警联动设置中,可以设置每个位号报警后,对应的继电器联动,支持探测器串口和新独立的串口(如果是和探测器并用的串口则不会重新打开串口,直接用原有的串口发数据联动,如果是新的串口则会重新打开串口),模块地址为继电器板子的地址,联动地址集合为需要联动报警的位,支持多个,多对多关系,一个探测器报警可以联动多个联动模块上的多个继电器地址,中间丨杠隔开。

      字段说明

      1. 位置编号:下拉选择,从探测器信息表取,表示哪个位置的探测器报警。

      2. 串 口 号:串口号,可以是之前端口信息中的串口,会自动检测切换。

      3. 波 特 率:报警端口转发串口对应的波特率,默认9600。

      4. 模块地址:对应联动模块的地址,挂在总线上的联动模块的唯一地址,该模块专门用来做继电器联动。

      5. 联动地址:联动模块上有一排继电器地址,对应报警后,可以触发联动一个或者多个继电器,需要哪个地址就填哪些地址。

      6. 启 用:可以动态关闭不需要的联动信息,但是不删除,这样只需要这里取消启用即可,而不是删除,不然又要重新添加。

      2.5.1 添加联动

      单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

      2.5.2 删除联动

      如果要删除某个联动信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

      2.5.3 清空联动

      单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

      2.5.4 导入联动

      单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

      2.5.5 导出联动

      单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

      2.5.6 打印联动

      单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

      2.5.7 导出到表格

      单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

      2.6 类型设置

      参数说明

      • 本表格中的数据并不是严格的对应关系。

      • 其中控制器信号、探测器数量是一对,其余全部独立。

      • 用来在系统设置中对应下拉框中的信息。

      • 这样就非常灵活,用户后期增加了新的产品直接在这里添加好就行,其他地方都是自动下拉选择。

      2.6.1 添加类型

      单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

      2.6.2 删除类型

      如果要删除某个类型信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。

      2.6.3 清空类型

      单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

      2.6.4 导入类型

      单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

      2.6.5 导出类型

      单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。  

      2.6.6 打印类型

      单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

      2.6.7 导出到表格

      单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

      3 其他设置

      3.1 用户管理

      用户管理是后面增加的一个模块,用于设置不同的用户不同的类型+权限,可以细分到每个模块的权限,勾选表示具有该权限,内置了7种权限选择,后期还可以在此基础上增加其他权限等。

      3.1.1 添加用户

      单击添加按钮,会自动规则生成默认的信息,直接表格中修改即可,修改好以后单击保存按钮保存所有的信息。

      3.1.2 删除用户

      如果要删除某个用户信息,需要先选中该行,然后单击删除按钮,删除后会自动保存。不允许删除内置的admin用户。

      3.1.3 清空用户

      单击清空按钮会对整个表进行清空操作,清空后数据不能恢复,慎用。

      3.1.4 导入用户

      单击导入按钮,可以选择之前导出的csv格式的文件导入数据。

      3.1.5 导出用户

      单击导出按钮,将表格数据导出到csv格式的文件,用户可以打开文件编辑,然后再次导入,这样可以作为简易的备份机制使用,也可将繁琐的基础数据录入交给小姑娘去做。

      3.1.6 打印用户

      单击打印按钮可以将表格中的内容打印出来,打印前会弹出打印预览界面,可以自行做边距的调整等,可以查看等待打印的内容,翻页切换。

      3.1.7 导出到表格

      单击导出按钮可以将表格中的内容导出到excel表格,独创的excel导出数据算法,极速导出,支持任意系统,无依赖。

      3.1.8 权限验证

      +

      假设设置了用户没有系统设置和删除记录的权限,则关闭系统的时候会弹出错误信息提示当前用户没有权限。

      3.2 地图管理

      在地图管理中,可以导入和删除地图。

      3.3 位置调整

      位置调整中,可以拖动探测器到正确的位置,右侧单击地图切换可以看到对应的该地图对应的探测器,全部位置调整好之后,单击右下角保存按钮即可,会立即应用。

      3.4 组态设计

      组态设计模块中提供的是简单的示例,演示如何加载自定义控件动态库、将控件拖曳到背景地图上,配置好对应控件的属性,可定义用户属性,可导出控件的配置信息到xml文件,并支持导入xml文件自动加载上次保存的控件配置信息。目前是一个简单的组态雏形,等后期架构好如何应用再重写整个模块。

      本系统默认不包括里面控件的源码,提供动态库的形式使用,如果还想学习自定义控件大全的源码(目前共205个控件卖700元,每个控件都有独立的使用示例,注释非常详细,有控件对照表),需要额外单独购买。

      3.5 设备调试

      可以自行选择通讯端口+设备名称进行数据的过滤,可查看所有的通信数据。不同收发数据不同颜色,还可以指定关键字过滤数据,每个收发数据都有对应的中文解释。能够很方便的对运行中的系统查看设备数据,规避是下位机还是上位机问题扯皮的事情。

      4 设备监控

      设备监控界面主要包括4个模块,分别是数据监控、设备面板、地图监控、曲线监控,设备的实时数据可以同时反应到四个模块上面,相当于以4种不同的表现形式展现采集到的数据。

      模式说明

      • 数据监控:表格形式一行行展示数据。

      • 设备面板:每个探测器都是个独立的一个面板展示数据和信息。

      • 地图监控:设备按钮放在对应地图上,长条状显示数据和符号单位。

      • 曲线监控:对每个设备过滤曲线显示采集到的数据。

      • 设备报警后,如果设置了报警弹窗,则右下角都会弹出对应的报警信息。

      • 设备报警后,对应表格行、设备面板、地图按钮等都会突出颜色显示。

      4.1 数据监控

      本页面会是使用频率最高的页面,默认就是停留在本页面实时查看所有探测器的数据。左侧为警情信息栏,分别显示时间、位号、报警值。如果有探测器报警,则消息自动追加到最前面。 +表格依次显示序号、位号、控制器名称、控制器型号、探测器名称、探测器型号、气体种类、浓度值、气体符号。

      4.2 设备面板

      面板说明

      1. 探测器作为一个个独立的设备面板控件。

      2. 有多少个探测器就会生成多少个面板,放在面板容器中。

      3. 可以在系统设置中选择设备列数,按照该设备列数来排列,超过会自动产生滚动条拖动查看。

      4. 报警后整个设备面板会突出颜色显示比如高报是红色、低报是黄色等。

      5. 双击探测器面板,会跳转到该探测器的详细信息界面,在该界面上后期可以按照实际用户需求定制回控操作。

      6. 面板有多种样式可供选择,比如普通样式、仪表样式。可直接在右侧切换立即运用。

      4.2.1 普通样式

      4.2.2 仪表样式

      4.2.3 仪表样式2

      4.3 地图监控

      本页面以地图的形式显示所有探测器,右侧单击对应地图可以手动切换地图,当探测器报警后会自动切换到当前地图,探测器图标红色闪烁,探测器图标实时显示当前的浓度值。双击探测器按钮图标,会跳转到该探测器的详细信息界面,在该界面上后期可以按照实际用户需求定制回控操作。

      4.4 曲线监控

      在本页面可以查看某个探测器的实时曲线,第一步先选择通信端口,第二步选择控制器,第三步选择探测器,然后就可以在左侧看到实时曲线,颜色可以在系统设置中设置。单击打印按钮会将当前曲线以截图的形式打印出来。勾选暂停显示记录数据复选框会暂停显示当前的数据。

      4.4.1 实时曲线

      4.4.2 历史曲线

      5 数据查询

      5.1 报警记录

      在本页面,可以指定日期范围查询报警记录,还可以查询单个的控制器或者探测器的报警记录。也可以手动输入探测器的位号进行查询,下拉选择探测器后会自动填入位号。还可以选择报警类型(浓度上限报警、浓度下限报警)查询对应的类型,也可以输入报警值进行精准查询。

      如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

      双击对应的报警记录可以打开警情确认对话框,重新填写确认意见,鼠标右键弹出删除记录菜单,可以删除当前选中的记录,支持多选,例如按住Ctrl键选择多个记录。

      5.1.1 记录查询

      5.1.2 记录打印

      5.1.3 记录导出

      5.2 运行记录

      在本页面,可以指定日期范围查询运行记录,还可以查询单个的控制器或者探测器的运行记录。也可以手动输入探测器的位号进行查询,下拉选择探测器后会自动填入位号。

      如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

      5.2.1 记录查询

      5.2.2 记录打印

      5.2.3 记录导出

      5.3 操作记录

      所有的用户操作都会记录到系统数据库,包括清空报警记录、删除记录、清空报警信息等操作。可以在本界面选择时间段范围查询,也可以选择日志类型(用户操作、设备上报)进行查询。

      如果数据超过一页,会自动分页处理,单击右侧的上一页、下一页、第一页、末一页进行翻页查看,所有查询的数据可以导出到excel表格,也可以直接打印。单击删除按钮会弹出时间范围选择框,选择该时间段后确定,会删除该时间段的所有记录。

      5.3.1 记录查询

      5.3.2 记录打印

      5.3.3 记录导出

      -

      6 通信协议

      6.1 通信流程

      1. 整体的结构是:控制器挂在通信端口,一个控制器下有多个探测器节点,相当于主设备、子设备。
      2. 因为是需要遍历轮询,所以一个通信端口上的控制器地址不能重复。
      3. 不同通信端口,控制器地址可以重复,所以如果控制器数量较多可以分在不同的通信端口。
      4. 一个控制器可以挂多个探测器,控制器平时也在不断轮询探测器的数据并记录,等待上位机程序的轮询命令后,将探测器数据一起打包发回。
      5. 本软件只和控制器通信,不和探测器通信,控制器负责和探测器通信。为何这样设计?因为这种架构最通用,可接的设备数量也是最大的。
      6. 本系统默认按照标准modbus协议进行通信,modbus是标准的通信框架协议,支持串口和网络等通信方式,至于具体是通过串口还是网络通信根据设备厂家选择。
      7. modbus是通信协议框架,至于具体数据位的每个字节对应的数据含义,每个厂家不一样,都是厂家自定义,一般2个字节表示一个数据。
      8. 端口可以是串口和网络,在添加端口时候可选择不同通信解析协议。

      6.1.1 FC1003-1

      6.1.2 FC1003-8

      6.1.3 FC1003-16

      6.1.4 FC1103显示板

      6.1.5 SAMS-4128

      6.1.6 FT21047P

      6.2 协议解释

      1. 主机发送是软件发送数据给设备,主动发送。
      2. 从机应答是设备根据收到的数据后作出应答数据,被动回复。
      3. 一条发送命令会对应一条应答命令。
      4. 寄存器地址2字节,高位在前低位在后。
      5. 读取长度2字节,高位在前低位在后。
      6. 数据位2字节,高位在前低位在后。
      7. CRC校验2字节,低位在前高位在后。
      8. 功能码有 03(读只读寄存器)、04(读可读可写寄存器)、06(写读写寄存器)。
      9. 主机发送的功能码和从机应答的功能码相同。

      6.2.1 主机发送

      地址功能码寄存器地址寄存器个数CRC校验
      010300 0000 0444 09

      6.2.2 从机应答

      地址功能码长度数据位1数据位2数据位3数据位4CRC校验
      01030800 0000 0000 0000 0095 D7

      6.2.3 读取长度

      设备型号长度说明
      FC1003-101 
      FC1003-808 
      FC1003-1608 08相当与两台FC1003-8,设备地址不同。
      FC1003显示板40长度根据所接设备数量不同需要调整,最大为64个。
      FC1003底板04 
      FT2104P01 
      SAMS-412808 

      6.2.4 数据举例

      提示说明

      1. 以下举例数据CRC校验位统一用 XX XX 表示,懒得计算。
      2. 本系统中填写的地址都是从1开始计数,所以填1则表示从0开始读取。
      3. 如果寄存器地址 01 01 ,则0101=257,本系统中要填258,填258实际是-1=257=0101发送。
      4. 寄存器个数,也可以说是节点设备的数量。
      5. 一个数据位或者说一个节点的数据是2个字节数据。
      6. 读取长度1则会返回1个数据位共2字节数据。
      7. 读取长度2则会返回2个数据位共4字节数据。
      8. 读取长度3则会返回3个数据位共6字节数据。

      示例数据1

      • 发送:01 03 00 00 00 02 XX XX
      • 解释:从寄存器地址0(00 00 = 0)开始,读取2个寄存器。
      • 返回:01 03 04 42 C7 FF EA XX XX
      • 解释:返回4字节数据 42 C7 FF EA ,对应寄存器地址 0、1 的数据。
      • 配置:控制器地址1,探测器地址1、2。

      示例数据2

      • 发送:01 03 01 01 00 01 XX XX
      • 解释:从寄存器地址257(01 01 = 257)开始,读取1个寄存器。
      • 返回:01 03 02 02 EF XX XX
      • 解释:返回2字节数据 02 EF ,对应寄存器地址257的数据。
      • 配置:控制器地址1,探测器地址258。

      示例数据3

      • 发送:AA 03 AA BB 00 04 XX XX
      • 解释:从寄存器地址43707(AA BB = 43707)开始,读取4个寄存器。
      • 返回:AA 03 08 55 AC 23 65 84 77 C3 3F XX XX
      • 解释:返回8字节数据 55 AC 23 65 84 77 C3 3F ,对应寄存器地址43707、43708、43709、43710的数据。
      • 配置:控制器地址170(AA = 170),探测器地址43708、43709、43710、43711。

      6.2.5 继电器联动

      发送返回说明
      01 03 00 00 00 01 84 0A01 03 02 00 00 B8 44读取设备状态
      01 06 00 00 00 01 48 0A01 06 00 00 00 01 48 0A打开继电器1
      01 06 00 00 00 03 C9 CB01 06 00 00 00 03 C9 CB打开继电器1、2
      01 06 00 00 00 07 C8 0801 06 00 00 00 07 C8 08打开继电器1、2、3
      01 06 00 00 00 06 09 C801 06 00 00 00 06 09 C8关闭继电器1
      01 06 00 00 00 04 88 0901 06 00 00 00 04 88 09关闭继电器1、2
      01 06 00 00 00 00 89 CA01 06 00 00 00 00 89 CA关闭继电器1、2、3

      7 各系统运行图

      7.0 样式风格

      +

      6 通信协议

      6.1 通信流程

      1. 整体的结构是:控制器挂在通信端口,一个控制器下有多个探测器节点,相当于主设备、子设备。

      2. 同一个端口下控制器地址唯一,同一个控制器下探测器寄存器地址唯一。

      3. 因为是需要遍历轮询,所以一个通信端口上的控制器地址不能重复。

      4. 不同通信端口,控制器地址可以重复,所以如果控制器数量较多可以分在不同的通信端口。

      5. 一个控制器可以挂多个探测器,控制器平时也在不断轮询探测器的数据并记录,等待上位机程序的轮询命令后,将探测器数据一起打包发回。

      6. 本软件只和控制器通信,不和探测器通信,控制器负责和探测器通信。为何这样设计?因为这种架构最通用,可接的设备数量也是最大的。

      7. 本系统默认按照标准modbus协议进行通信,modbus是标准的通信框架协议,支持串口和网络等通信方式,至于具体是通过串口还是网络通信根据设备厂家选择。

      8. modbus是通信协议框架,至于具体数据位的每个字节对应的数据含义,每个厂家不一样,都是厂家自定义,一般2个字节表示一个数据。

      9. 端口可以是串口和网络,在添加端口时候可选择不同通信解析协议。

      6.1.1 FC1003-1

      6.1.2 FC1003-8

      6.1.3 FC1003-16

      6.1.4 FC1103显示板

      6.1.5 SAMS-4128

      6.1.6 FT21047P

      6.2 协议解释

      1. 主机发送是软件发送数据给设备,主动发送。

      2. 从机应答是设备根据收到的数据后作出应答数据,被动回复。

      3. 一条发送命令会对应一条应答命令。

      4. 寄存器地址2字节,高位在前低位在后。

      5. 读取长度2字节,高位在前低位在后。

      6. 数据位2字节,高位在前低位在后。

      7. CRC校验2字节,低位在前高位在后。

      8. 功能码有 03(读只读寄存器)、04(读可读可写寄存器)、06(写读写寄存器)。

      9. 主机发送的功能码和从机应答的功能码相同。

      6.2.1 主机发送

      地址功能码寄存器地址寄存器个数CRC校验
      010300 0000 0444 09

      6.2.2 从机应答

      地址功能码长度数据位1数据位2数据位3数据位4CRC校验
      01030800 0000 0000 0000 0095 D7

      6.2.3 读取长度

      设备型号长度说明
      FC1003-101 
      FC1003-808 
      FC1003-1608 08相当与两台FC1003-8,设备地址不同。
      FC1003显示板40长度根据所接设备数量不同需要调整,最大为64个。
      FC1003底板04 
      FT2104P01 
      SAMS-412808 

      6.2.4 数据举例

      提示说明

      1. 以下举例数据CRC校验位统一用 XX XX 表示,懒得计算。

      2. 本系统中填写的地址都是从1开始计数,所以填1则表示从0开始读取。

      3. 如果寄存器地址 01 01 ,则0101=257,本系统中要填258,填258实际是-1=257=0101发送。

      4. 寄存器个数,也可以说是节点设备的数量。

      5. 一个数据位或者说一个节点的数据是2个字节数据。

      6. 读取长度1则会返回1个数据位共2字节数据。

      7. 读取长度2则会返回2个数据位共4字节数据。

      8. 读取长度3则会返回3个数据位共6字节数据。

      示例数据1

      • 发送:01 03 00 00 00 02 XX XX

      • 解释:从寄存器地址0(00 00 = 0)开始,读取2个寄存器。

      • 返回:01 03 04 42 C7 FF EA XX XX

      • 解释:返回4字节数据 42 C7 FF EA ,对应寄存器地址 0、1 的数据。

      • 配置:控制器地址1,探测器地址1、2。

      示例数据2

      • 发送:01 03 01 01 00 01 XX XX

      • 解释:从寄存器地址257(01 01 = 257)开始,读取1个寄存器。

      • 返回:01 03 02 02 EF XX XX

      • 解释:返回2字节数据 02 EF ,对应寄存器地址257的数据。

      • 配置:控制器地址1,探测器地址258。

      示例数据3

      • 发送:AA 03 AA BB 00 04 XX XX

      • 解释:从寄存器地址43707(AA BB = 43707)开始,读取4个寄存器。

      • 返回:AA 03 08 55 AC 23 65 84 77 C3 3F XX XX

      • 解释:返回8字节数据 55 AC 23 65 84 77 C3 3F ,对应寄存器地址43707、43708、43709、43710的数据。

      • 配置:控制器地址170(AA = 170),探测器地址43708、43709、43710、43711。

      6.2.5 继电器联动

      发送返回说明
      01 03 00 00 00 01 84 0A01 03 02 00 00 B8 44读取设备状态
      01 06 00 00 00 01 48 0A01 06 00 00 00 01 48 0A打开继电器1
      01 06 00 00 00 03 C9 CB01 06 00 00 00 03 C9 CB打开继电器1、2
      01 06 00 00 00 07 C8 0801 06 00 00 00 07 C8 08打开继电器1、2、3
      01 06 00 00 00 06 09 C801 06 00 00 00 06 09 C8关闭继电器1
      01 06 00 00 00 04 88 0901 06 00 00 00 04 88 09关闭继电器1、2
      01 06 00 00 00 00 89 CA01 06 00 00 00 00 89 CA关闭继电器1、2、3

      7 运行效果

      7.0 样式风格

      -

      7.1 windows-mingw

      7.2 windows-msvc

      7.3 linux-ubuntu

      7.4 linux-uos

      7.5 linux-kylin

      7.6 linux-neokylin

      7.7 linux-centos

      7.8 linux-fedora

      7.9 unix-mac

      8 程序框架说明

      • 下面的截图和说明未必是最新的,但是大部分是一致的。
      • 整体的框架不会改变,可能会有新增加子模块和代码,具体以最新的代码为准。
      • 程序会一直更新完善,不断迭代中。

      8.1 整体代码结构

      本系统采用模块化的设备,有用到第三方开源类库比如串口通信qextserialport,全部放在3rd下面,有用到很多自己封装完善的通用类库比如数据导入导出组件,全部放在core下面,设备通信和辅助处理全部放在class下面,所有界面全部放在ui下面,相当于一个个小的组件合起来,最终形成了整个监控系统的完整代码。

      8.2 主模块说明

      名称说明
      3rd一些第三方开源的类库,比如串口通信qextserialport。
      class存放系统初始化、样式控制、自定义控件、设备通信等。
      core本人一直持续更新完善的通用的类库,比如数据导入导出组件。
      ui所有的界面都分门别类放在这里。

      8.3 子模块说明

      8.3.1 第三方类库

      这里放的全部是第三方开源的轮子,感谢开源、感谢github、gitee等开源社区。具体代码不做过多说明,网上会有很多介绍和使用说明。

      名称说明
      3rd_qcustomplot第三方精美图表控件qcustomplot,Qt自带的qchart功能有限而且不支持大量数据。
      3rd_qextserialport第三方串口通信qextserialport,这个类比较稳定可靠,经过了几十个项目持续数十年运行的考验,不用Qt自带的串口类。
      3rd_qtpropertybrowser第三方属性控件,指定控件自动读取对应的属性形成属性栏。
      3rd_smtpclient第三方发送邮件组件,走底层socket协议发送邮件。

      8.3.2 通信及辅助类

      这里放的都是一些系统初始化、设备通信相关的类。

      名称说明
      api存放数据库表映射成对应的全局队列数据、数据库查询类,告警短信转发及告警邮件转发类。
      app全局配置参数管理类、全局变量类、全局事件转发器,通用函数等。
      device设备通信管理,比如设备采集处理、数据库采集、报警联动等。
      usercontrol当前系统的用到的自定义控件全部放在这里,项目通用的自定义控件放在core_control中。
      8.3.2.1 模块-api

      名称说明
      dbdata将数据库表映射到全局变量数据队列,比如将端口信息表portinfo转成QStringList存放一行行数据,这样在程序中运算比较速度极快,直接内存比较,不用每次都去读取数据库。
      dbquery所有的数据库查询插入更新等操作都在这里,比如查询探测器信息表、控制器信息表、插入日志记录等。
      sendserver通用的发送短信和邮件管理类,因为发送的内容是一致的所有统一一个类来管理,调用同一个函数就行。
      8.3.2.2 模块-app

      名称说明
      appconfig配置参数类,整个系统的配置参数存放在ini文件中,跨平台,所有参数都对应一个变量,读取配置参数的时候将值赋值给变量,写入的时候将变量值写入到配置文件。
      appdata全局变量类,系统中无可避免需要一些全局变量方便处理,都放在此类,比如版本号、当前用户信息、地图宽度高度、左侧右侧顶部底部宽高等。
      appevent全局事件转发类,系统越复杂信号需要传递的层级越多,所以需要一个全局事件转发类,用来中转这些事件,这样永远只需要两层就可以收到信号进行处理,而且整个系统看起来干净整洁,不会说一个信号传递到了N个地方乱七八糟,建议需要跨层级传递的信号都放在这里中转。比如软件退出信号,可能多个界面需要收到退出信号进行保存和其他处理,如果从关闭界面发出信号传递给需要的界面,那不知道要中间层层传递多少次,有了这个全局事件转发类,你只需要将事件传给appevent,需要接收事件的地方关联这个信号就行,appevent为全局单例类,整个系统唯一。 通用的一些信号有软件退出、全局样式改变、主窗体变化(0-最小化 1-最大化 2-恢复 3-关闭 4-移动 5-尺寸变化)等。
      appinit程序初始化类,在main函数中,会先执行这个初始化的类,比如初始化皮肤、字体、数据库、样式等操作,这些都是要优先在窗体加载前执行的,执行完毕以后再打开窗体主界面。
      appstyle全局样式管理类,整个系统的样式全部放在这里,一般加载流程是先读取样式表文件,然后将本系统独特的样式(比如开关按钮、视频监控、云台仪表盘)内容追加到后面,最后统一设置全局样式,在main函数中加载,和appinit类一样放在最前面执行。
      8.3.2.3 模块-device

      名称说明
      alarmlink报警联动处理类,探测器报警后,根据联动设置中设置的规则,将发送联动指令到总线上的设备。
      dbreceive数据库采集类,通过数据库采集的方式来读取设备的状态和值,系统默认是设备采集,通过485总线modbus协议等去轮询设备的状态,为了拓展兼容性,还有一种场景是用户自己有自己的采集和算法,然后将结果存储到了数据库表中,需要用UI界面将数据库中的值展现出来。
      deviceclient设备采集类,本系统的核心,所有的通信解析都在此类中,因为数据内容格式一致,所以串口和网络通信收发都放在一起,这样解析起来完全一致。
      devicedata获取采集发送指令类,为了应对不同的场景,针对不同的工作模式,会有发送不同的采集指令。
      devicehelper整个系统设备管理辅助类,比如插入窗口消息、加载设备列表、加载图片地图、加载设备按钮等。
      devicemap设备图片地图管理类,相当于一次性加载所有图片到内存,当要切换或者显示的时候,直接从内存取出来设置即可,速度极快,瞬间相应,纯粹是为了加快相应速度以及可能在图片上进行绘制增加的功能,比从文件系统读取图片文件显示快N倍。
      deviceserver设备通信服务类,对应上面的deviceclient类,这里面负责从数据库查询有多少个端口和设备,实例化对应的client,关联信号进行统一的处理,同时还包括定时器处理记录的存储,定时器处理报警等。
      udpreceive数据转发UDP接收端,接收到转发的数据以后解析并反映到界面上。
      udpsend数据转发UDP发送端,负责将采集到的数据转发出去。
      8.3.2.4 模块-usercontrol

      名称说明
      gaugecar汽车仪表盘,用来指示气体的值。
      gaugespeed速度仪表盘,用来指示气体的值。
      selectwidget描点跟随窗体控件,用在属性设计过程中拖曳控件,然后拉伸拖动。

      8.3.3 核心通用类库

      这里放的全部是个人一直持续更新完善的独创的轮子,所有的项目都公用这些轮子,用到哪个就包含哪个进来,更新只需要更新轮子代码就行。

      名称说明
      core_common通用函数,包括通用秘钥、通用导航、通用样式、声音播放、日志记录、运行时间记录等。
      core_control通用自定义控件,很多系统经常用到的控件全部放在这里,比如开关按钮、设备容器、设备按钮、颜色下拉框等。
      core_customplot继承自qcustomplot类的自定义图表组件,同时兼容各种qcustomplot版本,这样就可以在任意的Qt版本使用图表控件。
      core_dataout数据导入导出到xls/pdf和打印类库,极速、跨平台、无依赖。
      core_db数据库通用类库比如数据库线程管理、数据清理、数据采集等。
      core_form通用的窗体相关的组件,包括用户登录、用户退出、用户管理、权限管理、数据库管理,同时还包括封装的项目上直接用的导入导出、打印等。
      core_qui通用的辅助类,包括自定义对话框,全局辅助函数,图形字体等。
      core_send多线程短信发送和邮件发送类,功能类似所有放在一起。
      8.3.3.1 模块-core_common

      名称说明
      base64helper图片及文字和base64编码之间转换的类。
      commonkey通用秘钥管理类,指定校验秘钥文件,可设置运行时间、设备数量等限制,支持根据硬件指纹特征生成机器码文件等。
      commonnav通用菜单导航管理类,用来控制和显示顶部导航栏、左侧导航栏的样式。很多子界面需要用到,所以封装成一个专门管理这个的类。
      commonstyle通用样式管理类,比如Qt自带类窗体样式、自定义控件样式、分页导航样式、导航按钮样式、开关按钮样式等。相当于将多个项目常用的自定义样式封装一起做成通用。
      framelesswidget2无边框窗体拉伸类,边框四周八个方位都可以自由拉伸,可设置是否允许拖动和拉伸。
      playwav声音文件播放类,通用Qt456,自动识别当前Qt版本使用对应的类,Qt4采用QSound,Qt5以上采用QSoundEffect,嵌入式采用对应的命令行aplay、mpv来播放。
      savelog日志钩子类,将系统中所有的打印信息转为日志存储或者输出到网络等,可以开启用来打印输出日志信息。
      saveruntime保存运行时间类,用来存储系统启动后每隔一段时间就输出一条记录用来记录启动后软件运行了多久,方便分析问题。
      8.3.3.2 模块-core_control

      名称说明
      bottomwidget通用底部状态栏控件,可以设置软件名称、版本号、运行时间等。
      colorcombobox颜色下拉框控件,在系统设置中有。
      cpumemorylabelCPU和内存使用情况标签控件,主界面右上角显示。
      customtitlebar停靠窗体自定义标题栏控件。
      devicebutton设备按钮控件,比如图片地图模块中用到,可设置不同的图标样式和状态等,双击发出信号进行相应处理比如弹出对应窗体等。
      lcddatetime软件右上角显示时间的控件。
      panelwidget面板容器控件,主界面子模块表格消息,就用到此控件,用于将一堆widget放到此容器进行管理,自动形成滚动条等。
      switchbutton开关按钮控件,在系统设置中存在大量该控件。
      xslider滑动条控件,在原有滑动条基础上增加了鼠标按下立即定位等。
      8.3.3.3 模块-core_customplot

      名称说明
      customplot自定义图表控件主类,使用的时候只要new这个类就行。
      customplotbarh自定义形状-横向柱状图。
      customplotbarv自定义形状-垂直柱状图。
      customplothead当前组件通用头文件。
      customplothelper当前组件通用辅助函数文件。
      customplotline自定义形状-平滑曲线图。
      customplottracer自定义图层绘制十字线,也叫游标,定位线。
      smoothcurve平滑曲线算法类,内置多种平滑算法,可以自行增加其他算法。
      8.3.3.4 模块-core_dataout

      名称说明
      datacreat通用数据报表内容创建类,比如生成表格格式的html内容,然后赋值给dataprint直接打印,里面举例了图文混排的报告内容,后期会不断增加其他模板,也可以自行增加其他模板数据。
      datacsv导入导出数据,csv格式,可设置分隔符。拓展名。过滤条件等。
      datahead当前组件通用头文件。
      datahelper辅助类,比如校验规则函数,通用数据导出+打印函数。
      dataprint数据打印到pdf及纸张,支持多线程。
      dataxls数据导出到xls类,支持多线程导出。
      8.3.3.5 模块-core_db

      名称说明
      dbcleanthread自动清理数据线程类。
      dbconnthread数据库通信管理线程类。
      dbdelegate自定义委托全家桶,包括复选框、下拉框、密码框、按钮等。
      dbhead当前组件通用头文件。
      dbhelper各种数据库应用函数封装,比如初始化数据库、执行sql语句等。
      dbhttpthread网络请求数据采集类。
      dbpage数据库通用翻页类。
      dbpagemodel数据库翻页类数据模型。
      navpage分页导航控件。
      8.3.3.6 模块-core_form

      名称说明
      formhelper封装的导入导出、导出数据到xls/pdf和打印数据、自动备份数据、保存最后打开的文件夹等。
      frmconfigdb通用数据库管理界面类,可选不同的数据库类型,填入用户信息,执行检测连接和初始化数据操作。
      frmconfiguser通用用户管理界面类,可添加、删除、修改用户信息,包括权限分配等,可导入导出打印用户信息。
      frmlogin通用用户登录界面类,包括自动登录和记住密码复选框,多次密码错误校验,记住当前用户信息等。三次错误关闭,下拉可选用户,内置超级密码。
      frmlogout通用用户退出界面类,三次错误关闭,下拉可选用户,内置超级密码。
      userhelper通用用户权限管理类,内置7种类型权限,对应权限名称可自定义,一般在用户切换对应界面或者单击了对应功能按钮的时候触发。
      8.3.3.7 模块-core_qui

      本组件涵盖的功能较多,所以采用了分层管理代码结构。

      名称说明
      iconhelper万能图形字体类,可传入多种图形字体文件,一个类通用所有图形字体。
      quiconfig存储当前组件的配置参数信息,比如全局的字体名称、字号、无边框窗体的最小化最大化关闭等图标、样式表的颜色值。
      quihead当前组件通用头文件。
      quistyle当前组件通用样式设置管理类,可以指定枚举类型样式、传入样式内容设置、获取样式表文件对应的颜色值等。当前组件样式相关的处理函数都放在这里,统一管理。
      名称说明
      quiabout关于系统对话框,可传入软件标题、版本、版权、网址等信息。
      quidateselect自定义日期范围选择对话框。
      quiinputbox自定义输入框窗体,可指定不同的输入类型比如文本框、下拉框等。
      quimessagebox自定义信息消息框窗体,可设置关闭倒计时,不同的类型比如信息框、询问框、错误框等。
      quisplash自定义弹出提示信息,提示完自动消息关闭。
      quitipbox自定义右下角信息对话框,可设置对齐方式、关闭倒计时等。
      quiwidget自定义无边框窗体,可设置标题,各种图标等。
      名称说明
      quihelper项目通用辅助类,各种常用函数的封装,比如获取当前屏幕分辨率、设置字体、设置编码、加载翻译文件、各种进制数据转换、弹出各种对话框、设置延时时间等。
      quihelpercore获取当前桌面分辨率,设置编码、字体、翻译文件等。
      quihelperdata16进制、2进制、10进制互相转换,16进制字符串、字节数组互相转换,字节数组转int和short,CRC校验等。
      quihelperfile选择文件、保存文件、选择目录等对话框,复制文件、删除文件等。
      quihelperform设置无边框窗体、边框阴影,弹出信息框、错误框、询问框、日期选择框、关于对话框、中间提示框等。
      quihelperimage获取等比例缩放图片,通用设置logo图片,支持资源文件、本地图片、图形字体、svg自动变色等多种形式。
      quihelpernet获取本机IP地址集合,获取外网IP地址,判断IP、MAC等是否合法,下载网络文件,IP地址字符串与整型互相转换。
      quihelperother初始化数据库文件,设置系统时间、开机启动,设置图标到按钮,写入临时消息的文本文件等。
      8.3.3.8 模块-core_send
      名称说明
      sendemailthread多线程发送邮件类,支持附件,可设置多个抄送。
      sendmsgthread多线程收发短信类,支持长短信发送和多个收件人。

      8.3.4 界面UI

      界面说明

      • 这里分门别类存放的各种功能集合的界面类。
      • 每个类都一个ui文件、一个h头文件、一个cpp实现文件。
      • 可以方便快速查找对应功能的界面,也方便拓展增加界面。
      • 不仅分文件夹存放的,而且命名也尽量按照对应功能打头,比如系统设置模块中的都用frmconfig打头。
      • 外层文件夹是整齐的,内部代码也是整齐的。
      名称说明
      frmconfig系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、联动设置、类型管理等。
      frmconfig2其他设置模块,包括地图管理、用户管理、组态设计、设备调试等。
      frmdata日志查询模块,包括用户日志、运行日志、报警日志等。
      frmmain主界面模块,包括软件主界面、模拟调试工具等。
      frmother其他模块,包括封装的设备信息面板,设备回控等。
      frmview视图模块,包括数据监控、设备面板、地图监控、曲线监控等。
      8.3.4.1 模块-frmconfig

      名称说明
      frmconfig系统设置模块主界面,采用堆栈窗体形式,加载多个子界面比如控制器管理、探测器管理等。
      frmconfigdbnet远程数据库设置,用于将本地数据实时同步到远程服务器。
      frmconfigdevice控制器管理,可以增加、删除、修改、清空、导入、导出、打印控制器信息。
      frmconfiglink联动管理,可以增加、删除、修改、清空、导入、导出、打印联动信息。具体联动规则依据厂家约定。
      frmconfignode探测器管理,可以增加、删除、修改、清空、导入、导出、打印探测器信息。本系统设备的最终节点,可以设置非常详细的各种参数。
      frmconfigport端口管理,可以增加、删除、修改、清空、导入、导出、打印端口信息。可以下拉选择对应的通信协议模式。
      frmconfigsystem系统设置,包括基本设置、数据库设置、网络转发配置、日志设置、颜色配置、短信告警设置、邮件转发设置等。
      frmconfigtype类型设置,为了增强灵活性拓展性,系统中的控制器类型、探测器类型、气体种类、气体符号等信息都可以在这里自定义。
      8.3.4.2 模块-frmconfig2

      名称说明
      frmconfig2其他设置模块主界面,采用堆栈窗体形式,加载多个子界面比如用户管理、位置调整等。
      frmconfigdebug数据打印调试,所有的设备数据通信都可以在这里看到,可以选择针对某个控制器和探测器,也可以选择只看发送还是接收的数据,所有的数据都有对应的解析文字,方便理解。
      frmconfigmap地图管理,可以添加删除地图图片文件。
      frmconfigposition位置调整,可以对地图上的设备拖动调整到合适的位置。
      frmconfigscada自定义控件属性设计器,演示如何加载自定义控件然后拖曳,导入导出xml文件,自定义用户数据,组态的雏形,目前功能单一。
      8.3.4.3 模块-frmdata

      名称说明
      frmdata日志查询模块主界面,采用堆栈窗体形式,加载多个子界面包括用户日志、运行日志、报警日志等。
      frmdataalarm报警日志,可以按照日期范围、报警类型等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
      frmdatanode运行日志,可以按照日期范围、控制器等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
      frmdatauser用户日志,可以按照日期范围、操作类型等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
      8.3.4.4 模块-frmmain

      名称说明
      frmmain系统主界面,采用堆栈窗体,加载各个子模块。
      frmtool模拟调试工具,可选择设备采集模拟或者数据库模拟。
      frmtimecpu时间和CPU内存模块,一般放在系统的右上角。
      8.3.4.5 模块-frmother

      名称说明
      frmdevicecontrol设备回控模块,目前就显示具体的探测器信息,后期按照用户需求定制。
      frmdevicenode设备面板模块,同时包含了多种面板样式比如普通样式、仪表样式,可以在系统设置中动态切换并立即应用,每个探测器在设备监控界面中都占用这样一个面板,显示具体的信息,包括实时更新值。
      8.3.4.6 模块-frmview

      名称说明
      frmview系统视图主界面,采用堆栈窗体,加载各个子模块。
      frmviewdata数据监控,表格形式展示每个设备的各项数据和单位,报警不同颜色显示,具体颜色可以在系统设置中设置。
      frmviewdevice设备监控,每个探测器都对应一个设备面板,超出则滚动条显示。
      frmviewmap地图监控,设备在图片地图上,报警后红色闪烁,可以双击弹出探测器的详细信息,同时在设备按钮上显示对应的采集到的值。
      frmviewplot曲线监控,可以指定某个探测器设备查看实时曲线,还可以看该设备的历史记录曲线。

      9 数据库设计

      9.1 端口信息-PortInfo

      字段名中文名类型长度说明
      PortID编号INTEGER 主键自增
      PortName端口名称VARCHAR30不为空
      PortType协议类型VARCHAR15不为空
      ComName串口号VARCHAR10 
      BaudRate波特率INTEGER6 
      TcpIP网络地址VARCHAR16 
      TcpPort网络端口INTEGER6 
      ReadInterval采集周期INTEGER4不为空
      ReadTimeout通讯超时次数INTEGER4不为空
      ReadMaxtime超时重连时间INTEGER4不为空
      PortMark备注VARCHAR255 

      9.2 控制器信息-DeviceInfo

      字段名中文名类型长度说明
      DeviceID编号INTEGER 主键自增
      PortName端口名称VARCHAR30不为空
      DeviceName控制器名称VARCHAR30不为空
      DeviceAddr控制器地址INTEGER3不为空
      DeviceType控制器类型VARCHAR20不为空
      NodeNumber探测器数量INTEGER3不为空
      DeviceMark备注VARCHAR255 

      9.3 探测器信息-NodeInfo

      字段名中文名类型长度说明
      NodeID编号INTEGER 主键自增
      positionID位置编号VARCHAR20不为空
      DeviceName控制器名称VARCHAR30不为空
      NodeName探测器名称VARCHAR30不为空
      NodeAddr探测器地址INTEGER3不为空
      NodeType探测器类型VARCHAR20不为空
      NodeClass气体种类VARCHAR20不为空
      NodeSign单位符号VARCHAR20不为空
      NodeUpper上限值VARCHAR10不为空
      NodeLimit下限值VARCHAR10不为空
      NodeMax最大值VARCHAR10不为空
      NodeMin清零值VARCHAR10不为空
      NodeRange缓冲值VARCHAR10不为空
      NodeEnable启用禁用VARCHAR2不为空
      NodeSound报警声音VARCHAR10不为空
      NodeImage背景图片VARCHAR10不为空
      SaveInterval存储周期INTEGER3不为空
      DotCount小数点位数INTEGER1不为空
      AlarmDelay报警延时INTEGER3不为空
      AlarmType报警类型VARCHAR2不为空
      NodeXX坐标INTEGER4不为空
      NodeYY坐标INTEGER4不为空
      NodeMark备注VARCHAR255 
      字段名中文名类型长度说明
      PositionID位置编号VARCHAR20主键自增
      ComName串口名VARCHAR10不为空
      BaudRate波特率INTEGER5不为空
      ModelAddr模块地址INTEGER3不为空
      LinkAddr联动地址集合VARCHAR20不为空
      LinkEnable启用禁用VARCHAR2不为空
      LinkMark备注VARCHAR255 

      9.5 类型信息-TypeInfo

      字段名中文名类型长度说明
      TypeID编号INTEGER 主键自增
      DeviceType控制器类型VARCHAR20 
      NodeNumber探测器数量INTEGER5 
      NodeType探测器类型VARCHAR20 
      NodeClass气体种类VARCHAR20 
      NodeSign气体符号VARCHAR20 

      9.6 节点数据-NodeData

      1. 此表对应数据库采集模式和数据库读取模式。
      2. 节点状态含义:0-离线、1-在线、2-低报、3-高报、4-失效。
      3. 本表用于给其他程序存入采集到的数据,本程序通过读取数据库采集数据。
      字段名中文名类型长度说明
      PositionID位置编号VARCHAR20 
      NodeValue节点数据VARCHAR10不为空
      NodeStatus节点状态INTEGER2不为空
      SaveTime记录时间VARCHAR19不为空

      9.7 用户信息-UserInfo

      字段名中文名类型长度说明
      UserName用户名称VARCHAR20不为空
      UserPwd用户密码VARCHAR10不为空
      UserType用户类型VARCHAR10不为空
      Permission1用户权限1VARCHAR20 
      Permission2用户权限2VARCHAR20 
      Permission3用户权限3VARCHAR20 
      Permission4用户权限4VARCHAR20 
      Permission5用户权限5VARCHAR20 
      Permission6用户权限6VARCHAR20 
      Permission7用户权限7VARCHAR20 
      UserMark备注VARCHAR50 

      9.8 操作记录-UserLog

      字段名中文名类型长度说明
      LogID编号INTEGER 主键自增
      TriggerTime触发时间VARCHAR19 
      UserName用户名称VARCHAR20 
      UserType用户类型VARCHAR10 
      LogType事件类型VARCHAR20 
      LogContent事件内容VARCHAR255 

      9.9 运行记录-NodeLog

      字段名中文名类型长度说明
      LogID编号INTEGER 主键自增
      PositionID位置编号VARCHAR20 
      DeviceName控制器名称VARCHAR30 
      NodeName探测器名称VARCHAR30 
      NodeValue当前值VARCHAR10 
      NodeSign单位符号VARCHAR10 
      SaveTime保存时间VARCHAR19 
      LogMark备注VARCHAR255 

      9.10 报警记录-AlarmLog

      字段名中文名类型长度说明
      LogID编号INTEGER 主键自增
      PositionID位置编号VARCHAR20 
      DeviceName控制器名称VARCHAR30 
      NodeName探测器名称VARCHAR30 
      NodeValue当前值VARCHAR10 
      NodeSign单位符号VARCHAR10 
      Content报警内容VARCHAR20 
      StartTime开始时间VARCHAR19 
      EndTime结束时间VARCHAR19 
      ConfirmUser确认用户VARCHAR20 
      ConfirmTime确认时间VARCHAR19 
      ConfirmContent确认意见VARCHAR255 

      10 其他说明

      10.1 设备模拟工具

      +

      7.1 windows-mingw

      7.2 windows-msvc

      7.3 linux-ubuntu

      7.4 linux-uos

      7.5 linux-kylin

      7.6 linux-neokylin

      7.7 linux-centos

      7.8 linux-fedora

      7.9 unix-mac

      8 程序框架

      • 下面的截图和说明未必是最新的,但是大部分是一致的。

      • 整体的框架不会改变,可能会有新增加子模块和代码,具体以最新的代码为准。

      • 程序会一直更新完善,不断迭代中。

      8.1 整体代码结构

      本系统采用模块化的设备,有用到第三方开源类库比如串口通信qextserialport,全部放在3rd下面,有用到很多自己封装完善的通用类库比如数据导入导出组件,全部放在core下面,设备通信和辅助处理全部放在class下面,所有界面全部放在ui下面,相当于一个个小的组件合起来,最终形成了整个监控系统的完整代码。

      8.2 主模块说明

      名称说明
      3rd一些第三方开源的类库,比如串口通信qextserialport。
      class存放系统初始化、样式控制、自定义控件、设备通信等。
      core本人一直持续更新完善的通用的类库,比如数据导入导出组件。
      ui所有的界面都分门别类放在这里。

      8.3 子模块说明

      8.3.1 第三方类库

      这里放的全部是第三方开源的轮子,感谢开源、感谢github、gitee等开源社区。具体代码不做过多说明,网上会有很多介绍和使用说明。

      名称说明
      3rd_qcustomplot第三方精美图表控件qcustomplot,Qt自带的qchart功能有限而且不支持大量数据。
      3rd_qextserialport第三方串口通信qextserialport,这个类比较稳定可靠,经过了几十个项目持续数十年运行的考验,不用Qt自带的串口类。
      3rd_qtpropertybrowser第三方属性控件,指定控件自动读取对应的属性形成属性栏。
      3rd_smtpclient第三方发送邮件组件,走底层socket协议发送邮件。

      8.3.2 通信及辅助类

      这里放的都是一些系统初始化、设备通信相关的类。

      名称说明
      api存放数据库表映射成对应的全局队列数据、数据库查询类,告警短信转发及告警邮件转发类。
      app全局配置参数管理类、全局变量类、全局事件转发器,通用函数等。
      device设备通信管理,比如设备采集处理、数据库采集、报警联动等。
      usercontrol当前系统的用到的自定义控件全部放在这里,项目通用的自定义控件放在core_control中。
      8.3.2.1 模块-api

      名称说明
      dbdata将数据库表映射到全局变量数据队列,比如将端口信息表portinfo转成QStringList存放一行行数据,这样在程序中运算比较速度极快,直接内存比较,不用每次都去读取数据库。
      dbquery所有的数据库查询插入更新等操作都在这里,比如查询探测器信息表、控制器信息表、插入日志记录等。
      sendserver通用的发送短信和邮件管理类,因为发送的内容是一致的所有统一一个类来管理,调用同一个函数就行。
      8.3.2.2 模块-app

      名称说明
      appconfig配置参数类,整个系统的配置参数存放在ini文件中,跨平台,所有参数都对应一个变量,读取配置参数的时候将值赋值给变量,写入的时候将变量值写入到配置文件。
      appdata全局变量类,系统中无可避免需要一些全局变量方便处理,都放在此类,比如版本号、当前用户信息、地图宽度高度、左侧右侧顶部底部宽高等。
      appevent全局事件转发类,系统越复杂信号需要传递的层级越多,所以需要一个全局事件转发类,用来中转这些事件,这样永远只需要两层就可以收到信号进行处理,而且整个系统看起来干净整洁,不会说一个信号传递到了N个地方乱七八糟,建议需要跨层级传递的信号都放在这里中转。比如软件退出信号,可能多个界面需要收到退出信号进行保存和其他处理,如果从关闭界面发出信号传递给需要的界面,那不知道要中间层层传递多少次,有了这个全局事件转发类,你只需要将事件传给appevent,需要接收事件的地方关联这个信号就行,appevent为全局单例类,整个系统唯一。 通用的一些信号有软件退出、全局样式改变、主窗体变化(0-最小化 1-最大化 2-恢复 3-关闭 4-移动 5-尺寸变化)等。
      appinit程序初始化类,在main函数中,会先执行这个初始化的类,比如初始化皮肤、字体、数据库、样式等操作,这些都是要优先在窗体加载前执行的,执行完毕以后再打开窗体主界面。
      appstyle全局样式管理类,整个系统的样式全部放在这里,一般加载流程是先读取样式表文件,然后将本系统独特的样式(比如开关按钮、视频监控、云台仪表盘)内容追加到后面,最后统一设置全局样式,在main函数中加载,和appinit类一样放在最前面执行。
      8.3.2.3 模块-device

      名称说明
      alarmlink报警联动处理类,探测器报警后,根据联动设置中设置的规则,将发送联动指令到总线上的设备。
      dbreceive数据库采集类,通过数据库采集的方式来读取设备的状态和值,系统默认是设备采集,通过485总线modbus协议等去轮询设备的状态,为了拓展兼容性,还有一种场景是用户自己有自己的采集和算法,然后将结果存储到了数据库表中,需要用UI界面将数据库中的值展现出来。
      deviceclient设备采集类,本系统的核心,所有的通信解析都在此类中,因为数据内容格式一致,所以串口和网络通信收发都放在一起,这样解析起来完全一致。
      devicedata获取采集发送指令类,为了应对不同的场景,针对不同的工作模式,会有发送不同的采集指令。
      devicehelper整个系统设备管理辅助类,比如插入窗口消息、加载设备列表、加载图片地图、加载设备按钮等。
      devicemap设备图片地图管理类,相当于一次性加载所有图片到内存,当要切换或者显示的时候,直接从内存取出来设置即可,速度极快,瞬间相应,纯粹是为了加快相应速度以及可能在图片上进行绘制增加的功能,比从文件系统读取图片文件显示快N倍。
      deviceserver设备通信服务类,对应上面的deviceclient类,这里面负责从数据库查询有多少个端口和设备,实例化对应的client,关联信号进行统一的处理,同时还包括定时器处理记录的存储,定时器处理报警等。
      udpreceive数据转发UDP接收端,接收到转发的数据以后解析并反映到界面上。
      udpsend数据转发UDP发送端,负责将采集到的数据转发出去。
      8.3.2.4 模块-usercontrol

      名称说明
      gaugecar汽车仪表盘,用来指示气体的值。
      gaugespeed速度仪表盘,用来指示气体的值。
      selectwidget描点跟随窗体控件,用在属性设计过程中拖曳控件,然后拉伸拖动。

      8.3.3 核心通用类库

      这里放的全部是个人一直持续更新完善的独创的轮子,所有的项目都公用这些轮子,用到哪个就包含哪个进来,更新只需要更新轮子代码就行。

      名称说明
      core_common通用函数,包括通用秘钥、通用导航、通用样式、声音播放、日志记录、运行时间记录等。
      core_control通用自定义控件,很多系统经常用到的控件全部放在这里,比如开关按钮、设备容器、设备按钮、颜色下拉框等。
      core_customplot继承自qcustomplot类的自定义图表组件,同时兼容各种qcustomplot版本,这样就可以在任意的Qt版本使用图表控件。
      core_dataout数据导入导出到xls/pdf和打印类库,极速、跨平台、无依赖。
      core_db数据库通用类库比如数据库线程管理、数据清理、数据采集等。
      core_form通用的窗体相关的组件,包括用户登录、用户退出、用户管理、权限管理、数据库管理,同时还包括封装的项目上直接用的导入导出、打印等。
      core_iot物联网核心组件,modbus等各种协议解析,可以是串口和网络数据采集。
      core_qthelper通用的辅助类,包括自定义对话框,全局辅助函数,图形字体等。
      core_send多线程短信发送和邮件发送类,功能类似所有放在一起。
      8.3.3.1 模块-core_common

      名称说明
      base64helper图片及文字和base64编码之间转换的类。
      commonkey通用秘钥管理类,指定校验秘钥文件,可设置运行时间、设备数量等限制,支持根据硬件指纹特征生成机器码文件等。
      commonnav通用菜单导航管理类,用来控制和显示顶部导航栏、左侧导航栏的样式。很多子界面需要用到,所以封装成一个专门管理这个的类。
      commonstyle通用样式管理类,比如Qt自带类窗体样式、自定义控件样式、分页导航样式、导航按钮样式、开关按钮样式等。相当于将多个项目常用的自定义样式封装一起做成通用。
      framelesswidget2无边框窗体拉伸类,边框四周八个方位都可以自由拉伸,可设置是否允许拖动和拉伸。
      playwav声音文件播放类,通用Qt456,自动识别当前Qt版本使用对应的类,Qt4采用QSound,Qt5以上采用QSoundEffect,嵌入式采用对应的命令行aplay、mpv来播放。
      savelog日志钩子类,将系统中所有的打印信息转为日志存储或者输出到网络等,可以开启用来打印输出日志信息。
      saveruntime保存运行时间类,用来存储系统启动后每隔一段时间就输出一条记录用来记录启动后软件运行了多久,方便分析问题。
      8.3.3.2 模块-core_control

      名称说明
      bottomwidget通用底部状态栏控件,可以设置软件名称、版本号、运行时间等。
      colorcombobox颜色下拉框控件,在系统设置中有。
      cpumemorylabelCPU和内存使用情况标签控件,主界面右上角显示。
      customtitlebar停靠窗体自定义标题栏控件。
      devicebutton设备按钮控件,比如图片地图模块中用到,可设置不同的图标样式和状态等,双击发出信号进行相应处理比如弹出对应窗体等。
      lcddatetime软件右上角显示时间的控件。
      panelwidget面板容器控件,主界面子模块表格消息,就用到此控件,用于将一堆widget放到此容器进行管理,自动形成滚动条等。
      switchbutton开关按钮控件,在系统设置中存在大量该控件。
      xslider滑动条控件,在原有滑动条基础上增加了鼠标按下立即定位等。
      8.3.3.3 模块-core_customplot

      名称说明
      customplot自定义图表控件主类,使用的时候只要new这个类就行。
      customplotbarh自定义形状-横向柱状图。
      customplotbarv自定义形状-垂直柱状图。
      customplothead当前组件通用头文件。
      customplothelper当前组件通用辅助函数文件。
      customplotline自定义形状-平滑曲线图。
      customplottracer自定义图层绘制十字线,也叫游标,定位线。
      smoothcurve平滑曲线算法类,内置多种平滑算法,可以自行增加其他算法。
      8.3.3.4 模块-core_dataout

      名称说明
      datacreat通用数据报表内容创建类,比如生成表格格式的html内容,然后赋值给dataprint直接打印,里面举例了图文混排的报告内容,后期会不断增加其他模板,也可以自行增加其他模板数据。
      datacsv导入导出数据,csv格式,可设置分隔符。拓展名。过滤条件等。
      datahead当前组件通用头文件。
      datahelper辅助类,比如校验规则函数,通用数据导出+打印函数。
      dataprint数据打印到pdf及纸张,支持多线程。
      dataxls数据导出到xls类,支持多线程导出。
      8.3.3.5 模块-core_db

      名称说明
      dbcleanthread自动清理数据线程类。
      dbconnthread数据库通信管理线程类。
      dbdelegate自定义委托全家桶,包括复选框、下拉框、密码框、按钮等。
      dbhead当前组件通用头文件。
      dbhelper各种数据库应用函数封装,比如初始化数据库、执行sql语句等。
      dbhttpthread网络请求数据采集类。
      dbpage数据库通用翻页类。
      dbpagemodel数据库翻页类数据模型。
      navpage分页导航控件。
      8.3.3.6 模块-core_form

      名称说明
      formhelper封装的导入导出、导出数据到xls/pdf和打印数据、自动备份数据、保存最后打开的文件夹等。
      frmconfigdb通用数据库管理界面类,可选不同的数据库类型,填入用户信息,执行检测连接和初始化数据操作。
      frmconfiguser通用用户管理界面类,可添加、删除、修改用户信息,包括权限分配等,可导入导出打印用户信息。
      frmlogin通用用户登录界面类,包括自动登录和记住密码复选框,多次密码错误校验,记住当前用户信息等。三次错误关闭,下拉可选用户,内置超级密码。
      frmlogout通用用户退出界面类,三次错误关闭,下拉可选用户,内置超级密码。
      userhelper通用用户权限管理类,内置7种类型权限,对应权限名称可自定义,一般在用户切换对应界面或者单击了对应功能按钮的时候触发。
      8.3.3.7 模块-core_qthelper

      本组件涵盖的功能较多,所以采用了分层管理代码结构。

      名称说明
      iconhelper万能图形字体类,可传入多种图形字体文件,一个类通用所有图形字体。
      globalconfig存储当前组件的配置参数信息,比如全局的字体名称、字号、无边框窗体的最小化最大化关闭等图标、样式表的颜色值。
      globalhead当前组件通用头文件。
      globalstyle当前组件通用样式设置管理类,可以指定枚举类型样式、传入样式内容设置、获取样式表文件对应的颜色值等。当前组件样式相关的处理函数都放在这里,统一管理。
      名称说明
      qtabout关于系统对话框,可传入软件标题、版本、版权、网址等信息。
      qtdateselect自定义日期范围选择对话框。
      qtinputbox自定义输入框窗体,可指定不同的输入类型比如文本框、下拉框等。
      qtmessagebox自定义信息消息框窗体,可设置关闭倒计时,不同的类型比如信息框、询问框、错误框等。
      qtsplash自定义弹出提示信息,提示完自动消息关闭。
      qttipbox自定义右下角信息对话框,可设置对齐方式、关闭倒计时等。
      qtform自定义无边框窗体,可设置标题,各种图标等。
      名称说明
      qthelper项目通用辅助类,各种常用函数的封装,比如获取当前屏幕分辨率、设置字体、设置编码、加载翻译文件、各种进制数据转换、弹出各种对话框、设置延时时间等。
      qthelpercore获取当前桌面分辨率,设置编码、字体、翻译文件等。
      qthelperdata16进制、2进制、10进制互相转换,16进制字符串、字节数组互相转换,字节数组转int和short,CRC校验等。
      qthelperfile选择文件、保存文件、选择目录等对话框,复制文件、删除文件等。
      qthelperform设置无边框窗体、边框阴影,弹出信息框、错误框、询问框、日期选择框、关于对话框、中间提示框等。
      qthelperimage获取等比例缩放图片,通用设置logo图片,支持资源文件、本地图片、图形字体、svg自动变色等多种形式。
      qthelpernet获取本机IP地址集合,获取外网IP地址,判断IP、MAC等是否合法,下载网络文件,IP地址字符串与整型互相转换。
      qthelperother初始化数据库文件,设置系统时间、开机启动,设置图标到按钮,写入临时消息的文本文件等。
      8.3.3.8 模块-core_send
      名称说明
      sendemailthread多线程发送邮件类,支持附件,可设置多个抄送。
      sendmsgthread多线程收发短信类,支持长短信发送和多个收件人。
      8.3.3.9 模块-core_iot
      名称说明
      iotdatamodbus等协议的通用数据收发函数,传入地址和指令组合成要发送的数据。
      iothelper物联网组件中各种通用函数,比如获取端口协议集合,CRC校验,数据转换等。
      iotmodbusbasemodbus协议解析基类,收发数据并解析,同时支持RTU模式和网络模式的数据格式,传出对应信号。
      iotmodbuscommodbus串口com协议解析,打开和关闭串口,收发数据实现函数。
      iotmodbustcpmodbus网络tcp协议解析,连接设备,收发数据实现函数。
      iotmodbusudpmodbus网络udp协议解析,连接设备,收发数据实现函数。
      iotmodbuswebmodbus网络websocket协议解析,连接设备,收发数据实现函数。

      modbus子类都继承自iotmodbusbase基类,子类只负责打开对应的端口收发数据,具体的协议解析在基类中。后面如果还有其他的数据采集可以采用继承自iotmodbusbase基类就行。

      8.3.4 界面UI

      界面说明

      • 这里分门别类存放的各种功能集合的界面类。

      • 每个类都一个ui文件、一个h头文件、一个cpp实现文件。

      • 可以方便快速查找对应功能的界面,也方便拓展增加界面。

      • 不仅分文件夹存放的,而且命名也尽量按照对应功能打头,比如系统设置模块中的都用frmconfig打头。

      • 外层文件夹是整齐的,内部代码也是整齐的。

      名称说明
      frmconfig系统设置模块,包括基本设置、端口管理、控制器管理、探测器管理、联动设置、类型管理等。
      frmconfig2其他设置模块,包括地图管理、用户管理、组态设计、设备调试等。
      frmdata日志查询模块,包括用户日志、运行日志、报警日志等。
      frmmain主界面模块,包括软件主界面、模拟调试工具等。
      frmother其他模块,包括封装的设备信息面板,设备回控等。
      frmview视图模块,包括数据监控、设备面板、地图监控、曲线监控等。
      8.3.4.1 模块-frmconfig

      名称说明
      frmconfig系统设置模块主界面,采用堆栈窗体形式,加载多个子界面比如控制器管理、探测器管理等。
      frmconfigdbnet远程数据库设置,用于将本地数据实时同步到远程服务器。
      frmconfigdevice控制器管理,可以增加、删除、修改、清空、导入、导出、打印控制器信息。
      frmconfiglink联动管理,可以增加、删除、修改、清空、导入、导出、打印联动信息。具体联动规则依据厂家约定。
      frmconfignode探测器管理,可以增加、删除、修改、清空、导入、导出、打印探测器信息。本系统设备的最终节点,可以设置非常详细的各种参数。
      frmconfigport端口管理,可以增加、删除、修改、清空、导入、导出、打印端口信息。可以下拉选择对应的通信协议模式。
      frmconfigsystem系统设置,包括基本设置、数据库设置、网络转发配置、日志设置、颜色配置、短信告警设置、邮件转发设置等。
      frmconfigtype类型设置,为了增强灵活性拓展性,系统中的控制器类型、探测器类型、气体种类、气体符号等信息都可以在这里自定义。
      8.3.4.2 模块-frmconfig2

      名称说明
      frmconfig2其他设置模块主界面,采用堆栈窗体形式,加载多个子界面比如用户管理、位置调整等。
      frmconfigdebug数据打印调试,所有的设备数据通信都可以在这里看到,可以选择针对某个控制器和探测器,也可以选择只看发送还是接收的数据,所有的数据都有对应的解析文字,方便理解。
      frmconfigmap地图管理,可以添加删除地图图片文件。
      frmconfigposition位置调整,可以对地图上的设备拖动调整到合适的位置。
      frmconfigscada自定义控件属性设计器,演示如何加载自定义控件然后拖曳,导入导出xml文件,自定义用户数据,组态的雏形,目前功能单一。
      8.3.4.3 模块-frmdata

      名称说明
      frmdata日志查询模块主界面,采用堆栈窗体形式,加载多个子界面包括用户日志、运行日志、报警日志等。
      frmdataalarm报警日志,可以按照日期范围、报警类型等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
      frmdatanode运行日志,可以按照日期范围、控制器等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
      frmdatauser用户日志,可以按照日期范围、操作类型等查询日志,查询后的日志可打印和导出,还可以删除指定日期范围的日志以及清空所有日志。
      8.3.4.4 模块-frmmain

      名称说明
      frmmain系统主界面,采用堆栈窗体,加载各个子模块。
      frmtool模拟调试工具,可选择设备采集模拟或者数据库模拟。
      frmtimecpu时间和CPU内存模块,一般放在系统的右上角。
      8.3.4.5 模块-frmother

      名称说明
      frmdevicecontrol设备回控模块,目前就显示具体的探测器信息,后期按照用户需求定制。
      frmdevicenode设备面板模块,同时包含了多种面板样式比如普通样式、仪表样式,可以在系统设置中动态切换并立即应用,每个探测器在设备监控界面中都占用这样一个面板,显示具体的信息,包括实时更新值。
      8.3.4.6 模块-frmview

      名称说明
      frmview系统视图主界面,采用堆栈窗体,加载各个子模块。
      frmviewdata数据监控,表格形式展示每个设备的各项数据和单位,报警不同颜色显示,具体颜色可以在系统设置中设置。
      frmviewdevice设备监控,每个探测器都对应一个设备面板,超出则滚动条显示。
      frmviewmap地图监控,设备在图片地图上,报警后红色闪烁,可以双击弹出探测器的详细信息,同时在设备按钮上显示对应的采集到的值。
      frmviewplot曲线监控,可以指定某个探测器设备查看实时曲线,还可以看该设备的历史记录曲线。

      9 数据库设计

      9.1 端口信息-PortInfo

      字段名中文名类型长度说明
      PortID编号INTEGER 主键自增
      PortName端口名称VARCHAR30不为空
      PortType协议类型VARCHAR15不为空
      ComName串口号VARCHAR10 
      BaudRate波特率INTEGER6 
      TcpIP网络地址VARCHAR16 
      TcpPort网络端口INTEGER6 
      ReadInterval采集周期INTEGER4不为空
      ReadTimeout通讯超时次数INTEGER4不为空
      ReadMaxtime超时重连时间INTEGER4不为空
      PortMark备注VARCHAR255 

      9.2 控制器信息-DeviceInfo

      字段名中文名类型长度说明
      DeviceID编号INTEGER 主键自增
      PortName端口名称VARCHAR30不为空
      DeviceName控制器名称VARCHAR30不为空
      DeviceAddr控制器地址INTEGER3不为空
      DeviceType控制器类型VARCHAR20不为空
      NodeNumber探测器数量INTEGER3不为空
      DeviceMark备注VARCHAR255 

      9.3 探测器信息-NodeInfo

      字段名中文名类型长度说明
      NodeID编号INTEGER 主键自增
      positionID位置编号VARCHAR20不为空
      DeviceName控制器名称VARCHAR30不为空
      NodeName探测器名称VARCHAR30不为空
      NodeAddr探测器地址INTEGER3不为空
      NodeType探测器类型VARCHAR20不为空
      NodeClass气体种类VARCHAR20不为空
      NodeSign单位符号VARCHAR20不为空
      NodeUpper上限值VARCHAR10不为空
      NodeLimit下限值VARCHAR10不为空
      NodeMax最大值VARCHAR10不为空
      NodeMin清零值VARCHAR10不为空
      NodeRange缓冲值VARCHAR10不为空
      NodeEnable启用禁用VARCHAR2不为空
      NodeSound报警声音VARCHAR10不为空
      NodeImage背景图片VARCHAR10不为空
      SaveInterval存储周期INTEGER3不为空
      DotCount小数点位数INTEGER1不为空
      AlarmDelay报警延时INTEGER3不为空
      AlarmType报警类型VARCHAR2不为空
      NodeXX坐标INTEGER4不为空
      NodeYY坐标INTEGER4不为空
      NodeMark备注VARCHAR255 
      字段名中文名类型长度说明
      PositionID位置编号VARCHAR20主键自增
      ComName串口名VARCHAR10不为空
      BaudRate波特率INTEGER5不为空
      ModelAddr模块地址INTEGER3不为空
      LinkAddr联动地址集合VARCHAR20不为空
      LinkEnable启用禁用VARCHAR2不为空
      LinkMark备注VARCHAR255 

      9.5 类型信息-TypeInfo

      字段名中文名类型长度说明
      TypeID编号INTEGER 主键自增
      DeviceType控制器类型VARCHAR20 
      NodeNumber探测器数量INTEGER5 
      NodeType探测器类型VARCHAR20 
      NodeClass气体种类VARCHAR20 
      NodeSign气体符号VARCHAR20 

      9.6 节点数据-NodeData

      1. 此表对应数据库采集模式和数据库读取模式。

      2. 节点状态含义:0-离线、1-在线、2-低报、3-高报、4-失效。

      3. 本表用于给其他程序存入采集到的数据,本程序通过读取数据库采集数据。

      字段名中文名类型长度说明
      PositionID位置编号VARCHAR20 
      NodeValue节点数据VARCHAR10不为空
      NodeStatus节点状态INTEGER2不为空
      SaveTime记录时间VARCHAR19不为空

      9.7 用户信息-UserInfo

      字段名中文名类型长度说明
      UserName用户名称VARCHAR20不为空
      UserPwd用户密码VARCHAR10不为空
      UserType用户类型VARCHAR10不为空
      Permission1用户权限1VARCHAR20 
      Permission2用户权限2VARCHAR20 
      Permission3用户权限3VARCHAR20 
      Permission4用户权限4VARCHAR20 
      Permission5用户权限5VARCHAR20 
      Permission6用户权限6VARCHAR20 
      Permission7用户权限7VARCHAR20 
      UserMark备注VARCHAR50 

      9.8 操作记录-UserLog

      字段名中文名类型长度说明
      LogID编号INTEGER 主键自增
      TriggerTime触发时间VARCHAR19 
      UserName用户名称VARCHAR20 
      UserType用户类型VARCHAR10 
      LogType事件类型VARCHAR20 
      LogContent事件内容VARCHAR255 

      9.9 运行记录-NodeLog

      字段名中文名类型长度说明
      LogID编号INTEGER 主键自增
      PositionID位置编号VARCHAR20 
      DeviceName控制器名称VARCHAR30 
      NodeName探测器名称VARCHAR30 
      NodeValue当前值VARCHAR10 
      NodeSign单位符号VARCHAR10 
      SaveTime保存时间VARCHAR19 
      LogMark备注VARCHAR255 

      9.10 报警记录-AlarmLog

      字段名中文名类型长度说明
      LogID编号INTEGER 主键自增
      PositionID位置编号VARCHAR20 
      DeviceName控制器名称VARCHAR30 
      NodeName探测器名称VARCHAR30 
      NodeValue当前值VARCHAR10 
      NodeSign单位符号VARCHAR10 
      Content报警内容VARCHAR20 
      StartTime开始时间VARCHAR19 
      EndTime结束时间VARCHAR19 
      ConfirmUser确认用户VARCHAR20 
      ConfirmTime确认时间VARCHAR19 
      ConfirmContent确认意见VARCHAR255 

      10 其他说明

      10.1 设备模拟工具

      本系统专门配备了设备模拟工具,用来在没有外接真实设备的时候,模拟modbus协议数据,支持多个设备,支持串口和网络方式,可切换正常数据和报警数据,反应到主程序上。对应主程序中两种端口,一种是串口端口(这个可以用虚拟串口工具 Virtual Serial Port 虚拟一对串口用于测试),一种是网络端口(注意选择的监听主机地址和端口)。数据库模拟对应程序中的数据库采集运行模式,可以勾选自动模拟复选框。随机生成状态字段数据。

      10.2 modbus仿真

      作为国际知名的modbus模拟仿真工具Modbus Slave,本系统也提供了对应的数据配置文件iotsystem.mbs,在db目录下,对应添加FC-1003-8控制器。两边的通信方式必须一致,比如软件上设置的串口则两边都是串口。具体Modbus Slave工具详细使用可以自行搜索,比如这篇文章 https://blog.csdn.net/xuw_xy/article/details/81166305

      10.3 邮件转发设置

      本系统支持邮件转发,前提是对应的邮箱账号需要开通 POP3/SMTP 等服务,按照图示开启即可,一般开启后会设置独立的管理密码,记得在系统设置那边的邮件转发,填写密码的时候要填的是独立管理密码,而不是邮箱号的密码,这个机制和任何第三方邮箱管理软件都一样。

      10.4 短信转发设置

      本系统支持串口短信发送,需要发短信的硬件支持(俗称DXM),采用通用的标准的AT指令短信发送协议,支持任意厂家的串口短信设备。当设备报警后会自动组建报警短信发送给设定的收件人。支持中文短信发送和长短信发送,可以自行网上GM对应的硬件。

      10.5 代码行数统计

      本系统除去第三方库(串口通信3rd_qextserialport、曲线图表3rd_qcustomplot、属性控件3rd_qtpropertybrowser、邮件发送3rd_smtpclient)的代码,总代码行数约4W行,纯代码行数约3W行。

      10.6 多种数据库支持

      本系统支持多种数据库,包括sqlite、mysql、sqlserver、postgresql、oracle、kingbase等,直接在系统设置中的数据库配置中切换即可,切换完数据库以后记得初始化数据库,否则数据库不存在。

      10.6.1 sqlite

      10.6.2 mysql

      10.6.3 sqlserver

      10.6.4 postgresql

      10.6.5 oracle

      10.6.6 kingbase

      10.7 采集数据转发

      在系统设置中设置好网络转发参数后,可以在接收的地方开启网络数据接收,这样只需要接收数据解析反应到界面就行,相当于数据源不是硬件设备而是网络转发过来的数据,不需要直接接硬件设备。

      网络转发端,单击同步数据会把本地的端口信息、控制器信息、探测器信息发到远端。网络转发模块也可以作为无限级联使用,比如接收端还可以开启转发,继续转发给需要的地方,一个客户端上设置的转发也支持多个,用英文分号 ; 隔开,一对多关系,采用的无连接udp协议,几乎不占用系统资源。

      10.8 云端数据库同步

      -

      云端数据库同步,相当于把本地采集到的数据实时存储到云端,至于这些记录到了云端后什么用途,一般会用来做web请求访问,或者app请求获取数据,具体应用看用户需求。

      云端数据库也会存储到NodeData表中,意味着任意地方的客户端,都可以选择数据库采集模式,直接连接云端的数据库作为数据源。相当于可以无限级联。

      +

      云端数据库同步,相当于把本地采集到的数据实时存储到云端,至于这些记录到了云端后什么用途,一般会用来做web请求访问,或者app请求获取数据,具体应用看用户需求。

      云端数据库也会存储到NodeData表中,意味着任意地方的客户端,都可以选择数据库采集模式,直接连接云端的数据库作为数据源。相当于可以无限级联。

      10.9 秘钥控制

      本系统自带了秘钥控制机制,需要配套秘钥生成器管理秘钥,秘钥有两种,一种是控制设备数量、运行时间的秘钥,对应文件为key.db,一种是通过读取机器码生成对应唯一秘钥,对应文件为key.lic,默认开启的是key.db,如果需要开启机器码验证这种,需要在appinit.cpp的void AppInit::initOther()函数中开启,对应代码为 CommonKey::checkLicense(QUIHelper::appPath() + "/db/key.lic");默认注释的。

      如果开启了机器码秘钥验证,现场用户如果没有key.lic文件,运行会提示秘钥文件丢失,此时需要用秘钥生成器随便生成一个机器码文件,发给用户拷贝到可执行文件下的db目录下,和key.db文件一起。如果key.lic文件不正确,会提示秘钥文件错误,请联系供应商! 已自动复制机器码!\n机器码:xxxx,用户自动粘贴发给供应商,供应商自己用秘钥生成器填入机器码,单击生成即可。

      11 版本说明

      V20230927

      1. 彻底重写采集内核,单独模块core_iot,在原有的rtu_com/rtu_tcp基础上增加了rtu_udp/rtu_web/tcp/udp/web等多种方式的数据采集,同时支持RTU数据模式和网络数据模式。

      2.  

      V20230710

      1. 组态设计模块增加右键菜单,放到后面、放到前面、删除选中、删除所有,支持对选中的控件移到前面后面。

      2. 增加设备面板类型参数,0-单节点(每个节点一个面板) 1-多节点(一个控制器对应一个面板,里面多个节点)。

      3. 类型表格增加图标列,每个探测器可以自定义自己的图标,一般用于设备面板中探测器名称前面显示对应的图标。

      4. 控制器和探测器相关表格信息和报警数据,字样全部可以自定义,比如控制器和探测器可以定义为设备和参数,最明确的叫法可以是主设备和子设备,主设备负责把子设备的数据一起打包上报。

      5. 新增设备面板样式,所有子节点放在一个设备面板中,每个子节点都可以自定义图标和名称及符号等。设备面板的宽高可以在配置文件修改。这样可以最大限度的展示一个控制器下面的设备彩采集值。

      6. 修复当端口信息和设备信息中的端口不一致的时候,双击设备面板崩溃的BUG,不一致则不处理。

      7. 增加数据长度配置参数,一般2字节表示一个数据,也可以是4字节表示一个数据。可以修改配置参数来控制。

      8. 增加各种数据表检查,端口名称不能重复,控制器名称不能重复,同一个端口下控制器地址不能相同,同一个控制器下寄存器地址不能相同。

      V20220625

      1. 报警记录界面增加右键菜单选择全部、取消选中,和之前的批量删除一起。

      2. 测试批量删除sql语句in关键字在所有数据库中的表现,比如sqlite、mysql、postgres、sqlserver等全部测试通过。

      3. 优化报警邮件转发流程,过滤空报警信息只发送报警日志xls文件。

      4. 修复在postgresql数据库和oracle数据库下,QSqlTableModel对应setTable设置表名严格区分大小写的BUG。

      5. 大幅度优化mysql数据库分页查询效率,百万级别以上数据量下测试速度提升500倍+。

      6. 分页查询增加查询用时,每次翻页的查询都有用时计算。

      7. 修复debug模式下导出数据崩溃的BUG。

      V20220522

      1. 增加配置参数记录设备模拟工具是否已经通过主程序调用,已经打开了则不用重复打开。

      2. 修正数据库脚本文件,以便支持其他数据库,其他数据库全部测试过一遍。

      3. 增加各种数据库效果图,同步更新文档。

      4. 增加网络转发和云端数据库同步说明及效果图。

      5. 网络转发将分隔符改成字段数据用 , 分隔,行数据用 ; 分隔,最前面标识符用 | 分隔。

      6. 判断模拟工具是否打开算法再次改进,从命令行执行结果查看是否存在该程序。

      7. 所有数据库执行出错打印增加打印错误信息和对应的sql语句。

      8. 修复开启自动行数的时候,如果默认页面停留在其他页面,消息行数计算不准确的BUG。改成了默认采用左侧堆栈控件的高度作为参照标准,因为该控件永远显示,可以拿到正确的高度。

      9. 报警记录表格增加支持多选删除,可以批量删除选中的记录。

      10. 修复报警声音播放的BUG,在Qt5中默认播放首次设置的声音文件成功其余有杂音。

      11. 修复设备按钮报警颜色中低报和高报颜色搞反了的BUG。

      V20220508

      1. 设备地图按钮增加报警颜色选项,低报黄色闪烁,高报红色闪烁,其他报警紫色闪烁,正常绿色。

      2. 修正低分辨率比如1366x768情况下默认配置文件窗体尺寸过大的问题。

      3. 修复设备面板在仪表盘样式情况下文字颜色没有和系统样式统一的BUG。

      4. 将设备面板统一到一个类,多种样式选择,普通样式、仪表样式等。

      5. 说明书中通信协议举例,重新整理,更丰富更完整。

      6. 消息栏改成0表示自动设置行数,100表示设置0行,其他表示选择的行数。

      7. 将面板样式切换直接移到主界面,方便直接切换立即应用。

      8. 删减合并一些冗余的代码。

      9. 修复离线后仪表盘的值没有清零的BUG。

      10. 修复有部分权限页面控制不准的BUG。

      11. 新增自启动设备模拟工具配置参数,可以在系统设置中功能激活启用。

      12. 将模拟工具启动放在主窗体加载完成后,之前的main函数中不妥当,会导致用户还没登录就运行了设备模拟工具。

      13. 探测器节点信息,系统设置新增排序规则,可以按照位号排序,或者种类+位号等方式。

      14. 增加在win以外的其他系统,自动new出来设备模拟工具。

      15. 改进默认地图算法,取第一个有背景地图的设备的图片作为默认图片,可能默认图片不存在则取图片列表中的第一张。

      V20220428

      1. 将项目统一命名为iotsystem,对应设备模拟工具iottool。

      2. 将多个模块提炼成通用模块,比如用户登录退出、数据库设置、用户管理等,这样可以和其他系统完全公用模块。

      3. 统一调整项目模块,统一规划。

      4. 重新截图,重新编写说明书和开发使用手册。

      5. 权限控制增加用户管理、组态设计等,替换之前备用的模块A、模块B。

      6. 将用户管理、组态设计、设备调试等模块移动到其他设置大类,方便管理。

      7. 修复非最大化界面,拖动设备按钮会触发界面移动并且乱跳的BUG。

      8. 修复本地电脑开启网络代理的情况下,网络链接本地IP地址报错提示 The proxy type is invalid for this operation 的BUG。

      9. 模拟工具增加一键复位和一键报警按钮,用于设置没有报警的值和报警的值。

      10. 修复Qt6中报警后重复触发报警声音会崩溃的BUG。

      11. 统一梳理所有数据库字段长度,留有足够的余地。

      12. 修复设备面板在低报高报互相切换状态的时候报警颜色不正确的BUG。

      V20190712

      1. 控制器型号+探测器型号+气体种类+气体符号改成表格存储,新增探测器数量字段。

      2. 当节点数量小于列数时候会宽度变宽的BUG。

      3. 新增阿里云数据库同步,数据库采集模式会将数据库数据实时同步到阿里云。

      V20190624

      1. nodeinfo表新增nodezero字段,用于存储消零值,小于该值则显示为0,大于则显示真实值。

      2. alarmlog表增加confirmuser、confirmtime、confirmcontent三个字段,存储报警记录的确认用户、确认时间、确认内容。

      3. 新增了数据库读取模式,用于数据库采集显示数据。

      4. 修复了Qt5.10版本以上,数据清理线程提示不能运行的BUG。不能在线程中用主线程创建的数据库。

      5. 改进了部分代码。

      6. 模拟器新增数据库模拟。

      7. 配置文件新增模拟器的配置信息。

      8. 修复表格中设置了单独的文字颜色,在选中时会被覆盖的BUG。

      9. 新增报警右下角弹框。可以配置文件更改是否开启以及显示多久,默认开启。

      10. 新增报警记录鼠标右键删除记录,支持多选批量删除。

      11. 设备表格,按照气体种类升序+位号升序排列,以前是按照位号。

      12. 控制器对应的最大探测器数量,已禁用,直接选择好探测器类型自动设置。

      - + \ No newline at end of file diff --git a/docs/iotsystem/snap/10-9-1.jpg b/docs/iotsystem/snap/10-9-1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a87ebc05405f912840a5aee8a3e66a5da69c1db GIT binary patch literal 101343 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ઽ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 literal 0 HcmV?d00001 diff --git a/docs/iotsystem/snap/8-3-3-7.jpg b/docs/iotsystem/snap/8-3-3-7.jpg index ef60060e8ee37304002fca55a903bcc504144890..3f0a311dd94bfb747b2eaa0b33767d5501b3cfc5 100644 GIT binary patch literal 18445 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