千家信息网

Qt如何编写气体安全管理系统实现短信告警

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,本篇内容介绍了"Qt如何编写气体安全管理系统实现短信告警"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成
千家信息网最后更新 2025年12月02日Qt如何编写气体安全管理系统实现短信告警

本篇内容介绍了"Qt如何编写气体安全管理系统实现短信告警"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、前言

短信告警这个模块在很多项目中都用上了,比如之前做过的安防系统,温湿度报警系统等,主要的流程就是收到数据判断属于某种报警后,组织短信字符串内容,发送到指定的多个手机号码上面,使用的是短信猫硬件设备,其实就是个短信模块,没有使用网络的发送短信的api,毕竟大部分的软件应用场景都不能要求连通外网,安全考虑,所以必须采用本地的硬件来实现发送短信。这个短信猫设备在8年前开始用过,当时用的C#去写了个纯协议解析短信的收发,后面用Qt重新写了个。特意写了个类SendMsgThread封装了所有的操作,这样就通用任何开发环境了,掌握了原理,从底层原理上着手,好处还是很多的,我看很多初学者热衷于去调用第三方厂家封装好的SDK,一旦换了操作系统,完蛋了歇菜,没有嵌入式linux系统的SDK开发包咋搞。

通用短信收到组件功能特点:

  1. 可设置收发短信模式

  2. 可批量发送短信以及支持长短信

  3. 可读取指定指定序号短信

  4. 可删除所有短信

  5. 可检测短信猫设备是否正常

  6. 支持中文短信发送

  7. 支持拨打电话+挂断电话+接听来电+识别用户按键反馈

  8. 支持批量发送给多个号码

二、功能特点

  1. 采集数据端口,支持串口端口+网络端口,串口支持自由设置串口号+波特率,网络支持自由设置IP地址+通讯端口,每个端口支持采集周期,默认1秒钟一个地址,支持设置通讯超时次数,默认3次,支持最大重连时间,用于重新读取离线的设备。

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

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

  4. 控制器型号+探测器型号+气体种类+气体符号,均可自由配置。

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

  6. 端口信息+控制器信息+探测器信息,支持导入导出+导出到excel+打印。

  7. 运行记录+报警记录+用户记录,支持多条件组合查询,比如时间段+控制器+探测器等,所有记录支持导出到excel+打印。

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

  9. 可删除指定时间范围内的数据,支持自动清理早期数据,设置最大保存记录数。

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

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

  12. 高报颜色+低报颜色+正常颜色+0值颜色+曲线背景+曲线颜色等,都可以自由选择。

  13. 软件的中文标题+英文标题+logo路径+版权所有都可以自由设置。

  14. 提供开关设置开机运行+报警声音+自动登录+记住密码等。

  15. 报警声音可设置播放次数,界面提供17种皮肤文件选择。

  16. 支持云端数据同步,可设置云端数据库的信息,比如数据库名称,用户名+密码等。

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

  18. 自动记住用户最后停留的界面+其他信息,重启后自动应用。

  19. 报警自动切换到对应的地图,探测器按钮闪烁。

  20. 双击探测器图标,可以进行回控。

  21. 支持用户权限管理,管理员+操作员两大类,用户登录+用户退出,可以记住密码和自动登录,超过三次报错提示并关闭程序。

  22. 支持四种监控模式,设备面板监控+地图监控+表格数据监控+曲线数据监控,可自由切换,四种同步应用。

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

  24. 本地数据存储支持sqlite+mysql,支持远程数据同步到云端数据库。自动重连。

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

  26. 支持两种数据源,一种是串口和网络通过协议采集设备数据,一种是数据库采集。数据库采集模式可以作为通用的系统使用。

  27. 自带设备模拟工具,支持16个设备数据模拟,同时还带数据库数据模拟,以便在没有设备的时候测试数据。

  28. 默认通信协议采用modbus协议,后期增加mqtt等物联网协议的支持,做成通用系统。

  29. 支持所有windows操作系统+linux操作系统和其他操作系统。

三、效果图

四、核心代码

#include "sendserver.h"#include "quiwidget.h"#include "dbhelper.h"#include "devicehelper.h"#include "sendmsgthread.h"#include "sendemailthread.h"QScopedPointer SendServer::self;SendServer *SendServer::Instance(){    if (self.isNull()) {        static QMutex mutex;        QMutexLocker locker(&mutex);        if (self.isNull()) {            self.reset(new SendServer);        }    }    return self.data();}SendServer::SendServer(QObject *parent) : QObject(parent){    //初始化发送报警短信定时器    timerMsg = new QTimer(this);    connect(timerMsg, SIGNAL(timeout()), this, SLOT(checkMsg()));    changeMsgInterval();    //初始化发送报警邮件定时器    timerEmail = new QTimer(this);    connect(timerEmail, SIGNAL(timeout()), this, SLOT(checkEmail()));    changeEmailInterval();}SendServer::~SendServer(){    this->stop();}void SendServer::receiveMsgResult(const QString &result){    if (App::MsgInterval != 10000) {        //DeviceHelper::addMsg(result, 0);        DBHelper::addUserLog("设备上报", result);        if (result.contains("失败")) {            QUIHelper::showMessageBoxError(result, 3);        } else {            QUIHelper::showMessageBoxInfo(result, 3);        }    }}void SendServer::receiveEmailResult(const QString &result){    if (App::EmailInterval != 10000) {        //DeviceHelper::addMsg(result, 0);        DBHelper::addUserLog("设备上报", result);        if (result.contains("失败")) {            QUIHelper::showMessageBoxError(result, 3);        } else {            QUIHelper::showMessageBoxInfo(result, 3);        }    }}void SendServer::start(){    if (App::MsgInterval != 10000) {        QStringList tels = App::MsgTel.split(";");        foreach (QString tel, tels) {            if (!QUIHelper::isTel(tel)) {                //DeviceHelper::addMsg("转发手机号码错误", 0);                break;            }        }    }    //启动发送报警短信线程发送短信,防止界面卡住    if (SendMsgThread::Instance()->open(App::MsgPortName)) {        connect(SendMsgThread::Instance(), SIGNAL(receiveResult(QString)), this, SLOT(receiveMsgResult(QString)));        SendMsgThread::Instance()->init();        SendMsgThread::Instance()->start();        //DeviceHelper::addMsg("短信端口打开成功",0);        DBHelper::addUserLog("设备上报", "短信端口打开成功");    } else {        if (App::MsgInterval != 10000) {            //DeviceHelper::addMsg("短信端口打开失败",0);            DBHelper::addUserLog("设备上报", "短信端口打开失败");        }    }    if (App::MsgInterval != 10000) {        if (!QUIHelper::isEmail(App::SendEmailAddr)) {            //DeviceHelper::addMsg("发件人邮箱格式错误",0);            DBHelper::addUserLog("设备上报", "发件人邮箱格式错误");        }        QStringList emails = App::ReceiveEmailAddr.split(";");        foreach (QString email, emails) {            if (!QUIHelper::isEmail(email)) {                //DeviceHelper::addMsg("收件人邮箱格式错误",0);                DBHelper::addUserLog("设备上报", "收件人邮箱格式错误");                break;            }        }    }    //启动发送报警邮件线程发送邮件,防止界面卡住    connect(SendEmailThread::Instance(), SIGNAL(receiveEmailResult(QString)), this, SLOT(receiveEmailResult(QString)));    SendEmailThread::Instance()->setEmialTitle(App::LogoCn + "报警邮件");    SendEmailThread::Instance()->setSendEmailAddr(App::SendEmailAddr);    SendEmailThread::Instance()->setSendEmailPwd(App::SendEmailPwd);    SendEmailThread::Instance()->setReceiveEmailAddr(App::ReceiveEmailAddr);    SendEmailThread::Instance()->start();}void SendServer::stop(){    timerMsg->stop();    timerEmail->stop();}void SendServer::changeMsgInterval(){    //如果间隔是0则按照10秒间隔发送,如果是10000则不启动    if (App::MsgInterval == 0) {        timerMsg->start(10000);    } else if (App::MsgInterval == 10000) {        timerMsg->stop();    } else {        timerMsg->start(App::MsgInterval * 60 * 1000);    }}void SendServer::changeEmailInterval(){    //如果间隔是0秒则按照10秒间隔发送,如果是10000则不启动    if (App::EmailInterval == 0) {        timerEmail->start(10000);    } else if (App::EmailInterval == 10000) {        timerEmail->stop();    } else {        timerEmail->start(App::EmailInterval * 60 * 1000);    }}void SendServer::appendMsg(const QString &msg){    if (App::MsgInterval <= 1440 && listMsg.count() <= 30) {        listMsg << msg;    }}void SendServer::appendEmail(const QString &email){    if (App::EmailInterval <= 1440 && listEmail.count() <= 30) {        listEmail << email;    }}void SendServer::append(const QString &content){    appendMsg(content);    appendEmail(content);}void SendServer::clearMsg(){    listMsg.clear();}void SendServer::clearEmail(){    listEmail.clear();}void SendServer::checkMsg(){    int count = listMsg.count();    if (count == 0) {        return;    }    //一条短信最多70个汉字160个全英文数字字符,同时保证是一条完成的报警信息    //将要发送的手机号码和短信内容追加到发送报警短信线程中    for (int i = 0; i < count; i++) {        QString msg = listMsg.takeFirst();        QStringList tels = App::MsgTel.split(";");        foreach (QString tel, tels) {            SendMsgThread::Instance()->append(tel, msg);        }    }}void SendServer::checkEmail(){    int count = listEmail.count();    if (count == 0) {        return;    }    //邮件内容,无论多长都可以拼在一起发送,
用来换行显示 QStringList listContent, listFileName; for (int i = 0; i < count; i++) { QString str = listEmail.takeFirst(); if (str.contains("|")) { QStringList list = str.split("|"); listContent.append(list.at(0)); listFileName.append(list.at(1)); } else { listContent.append(str); } } //将字符串转换为表格形式,先取出字段名,然后取出内容 //位号: AT-40002 控制器: 1#调度室控制器 探测器: 2#阀站CO 触发值: 78.7 %LEL 类型: 浓度上限报警 时间: 2019-02-24 21:01:30
//位号: AT-40003 控制器: 1#调度室控制器 探测器: 3#阀站CO 触发值: 57 %VOL 类型: 浓度下限报警 时间: 2019-02-24 21:01:30
//位号: AT-40004 控制器: 1#调度室控制器 探测器: 4#阀站CO 触发值: 88 PPM 类型: 浓度下限报警 时间: 2019-02-24 21:01:30 //先取出字段名 QString str = listContent.first(); QStringList list = str.split(" "); QStringList columnNames; foreach (QString str, list) { columnNames << str.split(": ").first(); } //字段宽度 QList columnWidth; columnWidth << 150 << 200 << 180 << 130 << 160 << 200; //再遍历取出所有数据 QList rowContents; foreach (QString str, listContent) { QStringList list = str.split(" "); QStringList rowContent; foreach (QString temp, list) { rowContent << temp.split(": ").last(); } rowContents << rowContent; } //构建html字符串 QStringList html; //表格开始 html.append(""); //标题字段名称 QString title; for (int i = 0; i < columnNames.count(); i++) { title += QString("") .arg(columnWidth.at(i)).arg(columnNames.at(i)); } html.append(QString("%1").arg(title)); //内容 for (int j = 0; j < rowContents.count(); j++) { QString row; QStringList rowContent = rowContents.at(j); for (int i = 0; i < rowContent.count(); i++) { row += QString("") .arg(columnWidth.at(i)).arg(rowContent.at(i)); } html.append(QString("%1").arg(row)); } //表格结束 html.append("
%2
%2
"); qDebug() << html; //将邮件内容和附件链接追加到发送报警邮件线程中 SendEmailThread::Instance()->setSendEmailAddr(App::SendEmailAddr); SendEmailThread::Instance()->setSendEmailPwd(App::SendEmailPwd); SendEmailThread::Instance()->setReceiveEmailAddr(App::ReceiveEmailAddr); SendEmailThread::Instance()->append(html.join(""), listFileName.join(";")); //SendEmailThread::Instance()->append(listContent.join("
"), listFileName.join(";"));}

"Qt如何编写气体安全管理系统实现短信告警"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

支持 短信 数据 报警 设备 控制器 控制 探测器 探测 系统 信息 端口 自由 内容 网络 时间 用户 气体 多个 数据库 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 汕尾专业软件开发维修电话 甘肃租用gpu服务器报价表 软件开发ttt模型 来邦信息交互服务器软件 天津服务器防火墙 海淀区技术软件开发创新服务 软件开发社会健康安全法律因素 山西云手机服务器租用 腾讯云25端口邮件服务器 苏州idc施工服务器机房 上海昕天软件开发中心 服务器的集群控制器启动不了 网络技术岗做什么工作 软件开发定制哪家正规 1008611服务器出错 数据库报错74701 fm2020自定义数据库未找到 中国网络安全基础知识竞赛 我的世界如何建造一个服务器主城 复华网络技术有限公司招聘 win7怎么制作服务器 登录不上数据库是防火墙的原因吗 查询保存数据库文件sql 虹口区领用软件开发市场 网络技术需要数学基础吗 小学网络安全教育主题班会记录表 网络安全文明小诗歌 WINAMP下载软件开发 网络安全指数视频 我的世界如何建造一个服务器主城
0