一、前言

设备面板展示数据,相对于表格展示,可能在一个页面中能够展示的设备数据量少一些,但是有些用户和场景,又需要这种面板的形式,可能更生动形象一些。尤其是经过这么些年的社会的毒打,我的原则是:用户是上帝和大爷,尽量站在用户的角度换位思考,只要是合理或者基本合理的需求,甚至说只要不是太过分,给钱就干。

其实这种面板展示数据的需求,从我刚开始工作的时候,编写的软件,就已经有了,比如一台主机对应一个设备面板,除了显示对应的数值(电压值、电流值等),每个面板上还有按钮提供用户交互操作。对于通用的物联网平台来说,需要进行交互的场景很少,绝大部分都是用来展示采集到的数据,所以本系统的面板就显示对于的数据,如果需要回控操作的话,双击对应面板弹出详细面板信息进行操作。

设备面板几个特色功能:

  • 不同状态不同颜色,正常采用全局样式颜色、离线采用禁用颜色、低报黄色、高报红色等。
  • 双击分两种,离线状态下双击立即重新采集该设备,在线状态下双击弹出详情面板。
  • 面板可选多种样式,普通样式,仪表样式等。

二、功能特点

2.1 软件模块

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

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. 报警继电器联动,一个位号可以跨串口联动多个模块和继电器号,支持多对多。

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

三、体验地址

  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

四、效果图



五、相关代码

#include "frmdevicenode.h"
#include "ui_frmdevicenode.h"
#include "quihelper.h"
#include "iconhelper.h"
#include "dbquery.h"
#include "deviceserver.h"
#include "frmdevicecontrol.h" frmDeviceNode::frmDeviceNode(QWidget *parent) : QWidget(parent), ui(new Ui::frmDeviceNode)
{
ui->setupUi(this);
this->initForm();
this->initStyle();
//this->initControl();
} frmDeviceNode::~frmDeviceNode()
{
delete ui;
} bool frmDeviceNode::eventFilter(QObject *watched, QEvent *event)
{
//要区分在线离线的情况
//在线双击则弹出具体详情面板
//离线双击则重连当前端口下的所有设备
if (event->type() == QEvent::MouseButtonDblClick) {
if (!online) {
QString deviceName = this->property("deviceName").toString();
QString portName = DbQuery::getPortName(deviceName);
DeviceServer::Instance()->readValue(portName, 255, true);
} else {
QString positionID = this->property("positionID").toString();
frmDeviceControl::Instance()->setPositionID(positionID);
frmDeviceControl::Instance()->show();
}
} return QWidget::eventFilter(watched, event);
} void frmDeviceNode::initForm()
{
value = 0;
online = true;
alarm = false;
select = false;
this->installEventFilter(this); QFont font;
font.setPixelSize(QUIConfig::FontSize + 2);
ui->labNodeInfo->setFont(font);
ui->labNodeInfo->setFixedHeight(30); //设置图形字体
QFont iconFont = IconHelper::getIconFontAwesome();
ui->labNodeNamex->setFont(iconFont);
ui->labPositionIDx->setFont(iconFont);
ui->labNodeTypex->setFont(iconFont);
ui->labNodeValuex->setFont(iconFont); ui->labNodeNamex->setText(QChar(0xf132));
ui->labPositionIDx->setText(QChar(0xf015));
ui->labNodeTypex->setText(QChar(0xf124));
ui->labNodeValuex->setText(QChar(0xf0c3)); //通过弱属性控制样式
ui->devicePanel2->setProperty("form", "panel");
ui->deviceTitle1->setProperty("form", "panel");
ui->devicePanel1->setProperty("form", "panel");
ui->deviceTitle1->setProperty("flag", "paneltitle");
ui->devicePanel1->setProperty("flag", "panelcontrol"); //可以自行根据项目需要调整范围值小数点等
ui->gaugeSpeed->setUnit("");
ui->gaugeSpeed->setPrecision(0);
ui->gaugeSpeed->setDigitCount(3);
ui->gaugeSpeed->setRange(0, 200);
ui->gaugeSpeed->setValue(ui->gaugeSpeed->getMinValue());
} void frmDeviceNode::initStyle()
{
//根据不同的面板样式隐藏对应的面板
if (AppConfig::PanelStyle == 0) {
ui->widget1->setVisible(true);
ui->widget2->setVisible(false);
} else if (AppConfig::PanelStyle == 1) {
ui->widget1->setVisible(false);
ui->widget2->setVisible(true);
} QString textColor, bgColor;
if (alarm) {
//判断低报还是高报
QString positionID = this->property("positionID").toString();
int index = DbData::NodeInfo_PositionID.indexOf(positionID);
bool alarmLimit = DbData::NodeInfo_AlarmLimit.at(index);
bool alarmUpper = DbData::NodeInfo_AlarmUpper.at(index);
//bool alarmOther = DbData::NodeInfo_AlarmOther.at(index); //报警面板颜色
textColor = "#EEEEEE";
if (alarmLimit) {
bgColor = AppConfig::ColorLimit;
} else if (alarmUpper) {
bgColor = AppConfig::ColorUpper;
} else {
bgColor = AppConfig::ColorOther;
} //报警状态下的选中将颜色加个透明度
if (select) {
QColor color(bgColor);
bgColor = QString("rgba(%1,%2,%3,150)").arg(color.red()).arg(color.green()).arg(color.blue());
}
} else {
//选中面板颜色
textColor = online ? QUIConfig::TextColor : QUIConfig::BorderColor;
bgColor = select ? QUIConfig::DarkColorStart : QUIConfig::NormalColorStart;
} QStringList qss;
//仪表盘中的数码管禁用样式
qss << QString("QLCDNumber:disabled{background:%1;}").arg(QUIConfig::NormalColorStart);
//仪表样式中的节点信息标签
qss << QString("#labNodeInfo{color:%1;background:%2;}").arg(textColor).arg(alarm ? bgColor : QUIConfig::DarkColorEnd);
//仪表样式面板需要调整下颜色
if (AppConfig::PanelStyle == 1 && alarm) {
textColor = QUIConfig::TextColor;
bgColor = select ? QUIConfig::DarkColorStart : QUIConfig::NormalColorStart;
} //全局文字颜色
qss << QString("*{color:%1;}GaugeSpeed{qproperty-textColor:%1;}").arg(textColor);
//整体面板背景颜色
qss << QString("#deviceTitle1,#devicePanel1,#devicePanel2{background:%1;}").arg(bgColor);
this->setStyleSheet(qss.join(""));
} void frmDeviceNode::initControl()
{
QString positionID = this->property("positionID").toString();
QString nodeName = this->property("nodeName").toString();
QString nodeType = this->property("nodeType").toString();
QString nodeSign = this->property("nodeSign").toString(); ui->labNodeName->setText("名称: " + nodeName);
ui->labPositionID->setText("位号: " + positionID);
ui->labNodeType->setText("型号: " + nodeType);
ui->labNodeValue->setText(QString("数值: %1 %2").arg(value).arg(nodeSign)); ui->gaugeSpeed->setText(nodeSign);
ui->gaugeSpeed->setValue(value);
ui->labNodeInfo->setText(positionID + " -- " + nodeName);
} void frmDeviceNode::setValue(float value)
{
this->value = value;
QString nodeType = this->property("nodeType").toString();
QString nodeSign = this->property("nodeSign").toString(); //有两个传感器是开关量,数值是1 2显示时用正常和异常代替
if (nodeType == "SJ-0001" || nodeType == "JG-0001") {
ui->labNodeValue->setText(QString("数值: %1").arg(value == 1 ? "正常" : "异常"));
ui->gaugeSpeed->setValue(value == 1 ? ui->gaugeSpeed->getMinValue() : ui->gaugeSpeed->getMaxValue());
} else {
ui->labNodeValue->setText(QString("数值: %1 %2").arg(value).arg(nodeSign));
ui->gaugeSpeed->setValue(value);
}
} void frmDeviceNode::setOnline(bool online)
{
if (this->online != online) {
this->online = online;
if (!online) {
this->value = 0;
this->alarm = false;
this->select = false;
} this->setEnabled(online);
this->initStyle();
this->initControl();
}
} void frmDeviceNode::setAlarm(bool alarm)
{
//可能由低报转为高报所以这里不要做过滤判断
this->alarm = alarm;
this->initStyle();
} void frmDeviceNode::setSelect(bool select)
{
if (this->select != select) {
this->select = select;
this->initStyle();
}
}

Qt编写物联网管理平台33-设备面板的更多相关文章

  1. EMQ插件组合实现物联网边缘平台的设备通信管理

    上一篇随笔我简单的记录了我对EMQ插件开发的了解过程,最后发现还是可以组合复用已有插件,因此这篇随笔用于记录使用的情况以及是否达到预期. 首先测试mysql认证插件的使用方式: emqx_auth_m ...

  2. 年底奉献-QT编写视频监管平台(开源)

    忙忙碌碌又是一年,算算自己毕业四年半,一直在现在这家公司做研发外加总经理助理,研发起初用的VB.NET,而后全面转为C#,最后又全面转为QT,都是由于项目需要,算下来自己搞QT编程也已经四年了,201 ...

  3. Qt+imx6编写的楼宇对讲管理平台

    第一个初步版本. 1:楼宇对讲模块.住户报警模块.门禁控制模块.系统设置模块. 2:实时对讲信息卡片式展示,通话记录表格展示. 3:设备面板展示,实时显示上下线报警等信息. 4:设备查询.记录查询.运 ...

  4. 自学华为IoT物联网_10 IoT联接管理平台配置及开发实验1

    点击返回自学华为IoT物流网 自学华为IoT物联网_10 IoT联接管理平台配置及开发实验1 实验1:OceanConnect平台实验             通过基本的编程操作与配置,帮助读者熟悉O ...

  5. Qt编写气体安全管理系统29-跨平台

    一.前言 Qt的跨平台特性是非常厉害的,本来作为C++来说,跨平台的特性比JAVA还要好,只不过学习难度更大,所以大家更理解的跨平台是JAVA,Qt的跨平台特性是我见过的所有开发环境和语言中最厉害的, ...

  6. Qt编写气体安全管理系统24-地图管理

    一.前言 地图管理的主要功能是将系统中的地图文件做添加和删除,支持常见的jpg.png.bmp等格式图片,图片分辨率建议小于1080P,最好是和目标客户端电脑分辨率一致,这样在拉伸缩放的时候会比较清晰 ...

  7. Qt编写气体安全管理系统20-控制器管理

    一.前言 控制器管理,主要就是对控制器进行添加删除和修改,其中包括编号.端口名称.控制器名称.控制器地址.控制器型号.探测器数量这几个字段,端口名称表示当前控制器所属哪个端口,一个系统中可以有好多个端 ...

  8. Qt编写气体安全管理系统19-端口管理

    一.前言 所有设备的信息配置,主要就三大点:端口管理.控制器管理.探测器管理,整个硬件系统的架构是有多个不同的通信端口(主要是串口和网络),每个通信端口下面挂着多个控制器(每个控制器都有唯一的地址,从 ...

  9. 自学华为IoT物联网_08 IoT连接管理平台介绍

    点击返回自学华为IoT物流网 自学华为IoT物联网_08 IoT连接管理平台介绍 一.IoT连接管理平台的由来 1.1  物联网产业发展面临的挑战 新业务上线周期长,应用碎片化,开发周期长,场频上市慢 ...

  10. Qt编写气体安全管理系统21-探测器管理

    一.前言 探测器在整个系统中是最核心的关键的硬件,终端节点硬件,安装有探测芯片装置,负责探测前端对应气体浓度,并记录值,等待控制器轮训数据回复,控制器信息表也是字段最多的,要存储位号.控制器名称.探测 ...

随机推荐

  1. kotlin更多语言结构——>相等性

    Kotlin 中有两种类型的相等性: - 结构相等(用 equals() 检测); - 引用相等(两个引用指向同一对象).   结构相等 结构相等由 ==(以及其否定形式 !=)操作判断.按照惯例,像 ...

  2. Module Warning (from ./node_modules/postcss-loader/dist/cjs.js): Warning

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  3. nginx配置tomcat的负载均衡记录

    实现效果 (1)浏览器地址栏输入地址 http://192.168.17.129/edu/a.html,负载均衡效果,平均在 8080和 8081 端口中. 准备工作 (1)准备两台 tomcat 服 ...

  4. 使用FastAPI整合Gradio和Django

    大家好,我是每天分享AI应用的萤火君! 经常接触机器学习的同学可能都接触过Gradio这个框架,Gradio是一个基于Python的专门为机器学习项目创建的快速开发框架,可以让开发者快速发布自己的模型 ...

  5. 初识GO语言--基本规则

  6. C221027B

    B 抽 \(n\) 次卡, 连续 \(i\) 次没有抽中时, 第 \(i+1\) 次抽中的概率是 \(p_i\), 规定\(p_k=1\), 求期望抽中次数. 标签:矩阵加速递推, 动态规划. 暴力: ...

  7. SAM4MLLM:结合多模态大型语言模型和SAM实现高精度引用表达分割 | ECCV'24

    来源:晓飞的算法工程笔记 公众号,转载请注明出处 论文: SAM4MLLM: Enhance Multi-Modal Large Language Model for Referring Expres ...

  8. Codeforces Round 988 (Div. 3) E题解析

    E题 题目链接 Codeforces Round 988 (Div. 3) 题目描述 题目的思路 根据题目的意思,我们可以推断出算法时间复杂度应该在O(N) 对于这道题而言,我们可以分析下思路 首先我 ...

  9. P11233 CSP-S 2024 染色

    P11233 CSP-S 2024 染色 考试最后码方程忘记 \(a[i-1]\) 了,调不出来,只好 \(50pts\) 收尾. 思路 \(dp\) 的难点在于确定一段的颜色后,无法快速找到上一段相 ...

  10. 【一步步开发AI运动小程序】四、小程序如何抽帧

    随着人工智能技术的不断发展,阿里体育等IT大厂,推出的"乐动力"."天天跳绳"AI运动APP,让云上运动会.线上运动会.健身打卡.AI体育指导等概念空前火热.那 ...