Qt write gas safety management system 22 alarm linkage

Keywords: Database network Excel github

I. Preface

The alarm linkage function is not a conventional function, but a customized function for customers. For example, when the data collected by the detector is alarmed, it is not only necessary to play the alarm sound locally, store the alarm record, send the alarm message and e-mail, but also to trigger the alarm panel light to alarm. The indicator light of the alarm panel is also the communication of modbus protocol 485, which needs to be specified on the software side Send data on the communication port to light the alarm light, and this communication port can be used by the original equipment or an independent port, so this factor should be taken into account when making the alarm linkage information table, which should store the serial number, baud rate, module address and linkage address set.

In most alarm linkage application scenarios, there may be many to many requirements. For example, one device alarm can trigger multiple linkage, and multiple device alarms can trigger the same linkage. This application is very extensive, so when designing software, this function should be taken into account. The specific multi to many mapping relationship can be set flexibly by users, For example, the linkage address set of linkage information table here will trigger one by one once multiple linkage addresses are set.

Skin open source: https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo File name: styledemo

Experience address: https://gitee.com/feiyangqingyun/QWidgetExe https://github.com/feiyangqingyun/QWidgetExe File name: bin_sams.zip

II. Functional features

  1. Data collection port, supporting serial port + network port, serial port supporting free setting of serial port number + baud rate, network supporting free setting of IP address + communication port, each port supporting collection cycle, one address per second by default, supporting setting of communication timeout times, three times by default, supporting maximum reconnection time, for re reading offline devices.
  2. Controller information, can add controller name, select controller address + controller model, and set the number of detectors under the controller.
  3. Detector information, can add tag number, can freely choose detector model, gas type, gas symbol, high alarm value, low alarm value, buffer value, reset value, whether to enable, alarm sound, background map, storage cycle, number of decimal places for numerical conversion, alarm delay time, alarm type (HH,LL,HL), etc.
  4. The controller model + detector model + gas type + gas symbol can be configured freely.
  5. The map supports import and deletion, and the map positions corresponding to all detectors can be dragged and saved freely.
  6. Port information + controller information + detector information, support import and export + export to excel + print.
  7. Operation record + alarm record + user record, support multi condition combination query, such as time period + controller + detector, etc., all records support export to excel + print.
  8. The records exported to excel support all versions of excel+wps and other table files, and do not rely on Excel and other software.
  9. It can delete data within the specified time range, support automatic cleaning of early data, and set the maximum number of saved records.
  10. Support alarm SMS forwarding, support multiple receiving mobile phone numbers, and set the sending interval, such as instant sending or sending all alarm messages once every six hours, the content of SMS is too long, and multiple SMS will be split automatically.
  11. Support alarm mail forwarding, support multiple receiving mailboxes, and set the sending interval, such as instant sending or sending all alarm information once every six hours, and support the sending of attachments.
  12. High alarm color + low alarm color + normal color + 0 value color + curve background + curve color, etc. can be freely selected.
  13. The Chinese title + English title + logo path + copyright of the software can be set freely.
  14. Provide switch settings for startup operation + alarm sound + automatic login + remember password, etc.
  15. The alarm sound can set the playing times, and the interface provides 17 skin file options.
  16. It supports cloud data synchronization and can set information of cloud database, such as database name, user name + password, etc.
  17. Support network forwarding and network receiving. After network receiving is turned on, the software receives data from udp for analysis. The network forwarding supports multiple target IP S, so that the locally collected software can freely transfer the data to the client and view the detector data at any time.
  18. Automatically remember the last user interface + other information, and automatically apply after restart.
  19. The alarm automatically switches to the corresponding map, and the detector button flashes.
  20. Double click the detector icon to control back.
  21. Support user rights management, administrator + operator two categories, user login + user exit, can remember password and automatic login, more than three times error prompt and close the program.
  22. Four monitoring modes are supported: equipment panel monitoring + map monitoring + table data monitoring + curve data monitoring, which can be switched freely and applied synchronously.
  23. Support alarm relay linkage. A tag number can link multiple modules and relay numbers across serial ports, and support many to many.
  24. Local data storage supports sqlite+mysql and remote data synchronization to cloud database. Automatic reconnection.
  25. The data collected by the local device is uploaded to the cloud in real time for mobile APP or web and other methods to extract.
  26. Support two kinds of data sources, one is serial port and network through the protocol to collect equipment data, the other is database collection. Database collection mode can be used as a general system.
  27. Equipped with device simulation tools, support 16 device data simulation, and also with database data simulation, so as to test data when there is no device.
  28. The default communication protocol is modbus protocol, and the support of Internet of things protocol such as mqtt is added later to make a general system.
  29. Support all windows + linux and other operating systems.

III. renderings

IV. core code

#include "frmconfiglink.h"
#include "ui_frmconfiglink.h"
#include "quiwidget.h"
#include "dbhelper.h"
#include "dbdelegate.h"
#include "excelapi.h"
#include "printapi.h"
#include "api.h"

frmConfigLink::frmConfigLink(QWidget *parent) : QWidget(parent), ui(new Ui::frmConfigLink)
{
    ui->setupUi(this);
    this->initForm();
    this->initData();
    this->changeStyle();
}

frmConfigLink::~frmConfigLink()
{
    delete ui;
}

void frmConfigLink::showEvent(QShowEvent *)
{
    model->select();
}

void frmConfigLink::initForm()
{
    API::initTableView(ui->tableView);
    ui->widgetTop->setProperty("flag", "navbtn");
    if (QUIHelper::deskWidth() < 1440) {
        ui->labTip->setText("Tips → Restart application after modification");
    } else {
        ui->labTip->setText("Tips → Must be consistent with on-site linkage information,Restart application after modification");
    }
}

void frmConfigLink::initData()
{
    model = new QSqlTableModel(this);    
    model->setTable("AlarmLink");
    model->setSort(0, Qt::AscendingOrder);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    ui->tableView->setModel(model);
    ui->tableView->setProperty("model", true);

    columnNames.clear();
    columnNames << "Place number" << "Serial port number" << "Baud rate" << "Module address" << "Linkage address set" << "Is it enabled?";

    columnWidths.clear();
    columnWidths << 150 << 100 << 100 << 90 << 160 << 100;

    for (int i = 0; i < columnNames.count(); i++) {
        model->setHeaderData(i, Qt::Horizontal, columnNames.at(i));
        ui->tableView->setColumnWidth(i, columnWidths.at(i));
    }

    //Bit delegate
    d_cbox_positionID = new DbDelegate(this);
    d_cbox_positionID->setDelegateType("QComboBox");
    ui->tableView->setItemDelegateForColumn(0, d_cbox_positionID);
    positionIDChanged();

    //Enable disable delegation
    QStringList linkEnable;
    linkEnable << "Enable" << "Prohibit";
    DbDelegate *d_cbox_linkEnable = new DbDelegate(this);
    d_cbox_linkEnable->setDelegateType("QComboBox");
    d_cbox_linkEnable->setDelegateValue(linkEnable);
    ui->tableView->setItemDelegateForColumn(5, d_cbox_linkEnable);

    //Used to switch styles and change colors automatically
    delegates << d_cbox_positionID;
    delegates << d_cbox_linkEnable;
}

void frmConfigLink::changeStyle()
{
    foreach (DbDelegate *delegate, delegates) {
        delegate->setTextColor(QUIConfig::TextColor);
        delegate->setSelectBgColor(QUIConfig::NormalColorStart);
    }
}

void frmConfigLink::positionIDChanged()
{    
    d_cbox_positionID->setDelegateValue(DBData::NodeInfo_PositionID);    
}

void frmConfigLink::on_btnAdd_clicked()
{
    if (DBData::NodeInfo_Count == 0) {
        QUIHelper::showMessageBoxError("Detector not added yet,Please add the detector first!", 3);
        return;
    }

    int count = model->rowCount();
    model->insertRow(count);

    QString positionID = model->index(count - 1, 0).data().toString();
    QString comName = model->index(count - 1, 1).data().toString();
    int baudRate = model->index(count - 1, 2).data().toInt();
    quint8 modelAddr = model->index(count - 1, 3).data().toInt() + 1;
    QString linkAddr = model->index(count - 1, 4).data().toString();
    QString linkEnable = model->index(count - 1, 5).data().toString();

    if (count == 0) {
        positionID = DBData::NodeInfo_PositionID.first();
        comName = "COM1";
        baudRate = 9600;
        modelAddr = 1;
        linkAddr = "1";
        linkEnable = "Enable";
    }

    //Set new row defaults
    model->setData(model->index(count, 0), positionID);
    model->setData(model->index(count, 1), comName);
    model->setData(model->index(count, 2), baudRate);
    model->setData(model->index(count, 3), modelAddr);
    model->setData(model->index(count, 4), linkAddr);
    model->setData(model->index(count, 5), linkEnable);
    ui->tableView->setCurrentIndex(model->index(count, 0));
}

void frmConfigLink::on_btnSave_clicked()
{
    model->database().transaction();
    if (model->submitAll()) {
        model->database().commit();
        DBHelper::loadAlarmLink();
    } else {
        model->database().rollback();
        QUIHelper::showMessageBoxError("Failed to save information,Information cannot be empty,Please fill in again!");
    }
}

void frmConfigLink::on_btnDelete_clicked()
{
    if (ui->tableView->currentIndex().row() < 0) {
        QUIHelper::showMessageBoxError("Please select linkage information to delete!");
        return;
    }

    if (QUIHelper::showMessageBoxQuestion("Are you sure you want to delete the linkage information?") == QMessageBox::Yes) {
        int row = ui->tableView->currentIndex().row();
        model->removeRow(row);
        model->submitAll();

        int count = model->rowCount();
        ui->tableView->setCurrentIndex(model->index(count - 1, 0));
    }
}

void frmConfigLink::on_btnReturn_clicked()
{
    model->revertAll();
}

void frmConfigLink::on_btnClear_clicked()
{
    int count = model->rowCount();
    if (count <= 0) {
        return;
    }

    if (QUIHelper::showMessageBoxQuestion("Are you sure to clear all linkage information?") == QMessageBox::Yes) {
        DBHelper::clearAlarmLink();
        model->select();
    }
}

void frmConfigLink::on_btnExcel_clicked()
{
    QString name = "Alarm linkage information";
    QString fileName = QString("%1_%2").arg(name).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"));
    QString file = API::getSaveFileNames(fileName, "Excel(*.xls)");
    if (file.isEmpty()) {
        return;
    }

    QString columns = "PositionID,ComName,BaudRate,ModelAddr,LinkAddr,LinkEnable";
    QString where = "order by PositionID asc";
    QStringList content = DBHelper::getContent("AlarmLink", columns, where, "", ";");

    int rowCount = content.count();
    if (rowCount == 0) {
        QUIHelper::showMessageBoxError("No data to process!");
        return;
    }

    ExcelAPI::Instance()->saveExcel(file, name, name, "", columnNames, columnWidths, content);
    QString msg = QString("export%1 reach Excel").arg(name);
    DBHelper::addUserLog("User operation", msg);

    if (QUIHelper::showMessageBoxQuestion(msg + "Success!Are you sure you want to open it now?") == QMessageBox::Yes) {
        QString url = QString("file:///%1").arg(file);
        QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
    }
}

void frmConfigLink::on_btnPrint_clicked()
{
    QString name = "Alarm linkage information";
    QString columns = "PositionID,ComName,BaudRate,ModelAddr,LinkAddr,LinkEnable";
    QString where = "order by PositionID asc";
    QStringList content = DBHelper::getContent("AlarmLink", columns, where, "", ";");

    int rowCount = content.count();
    if (rowCount == 0) {
        QUIHelper::showMessageBoxError("No data to process!");
        return;
    }

    PrintAPI::Instance()->print(name, "", columnNames, columnWidths, content);
    QString msg = QString("Printing%1").arg(name);
    DBHelper::addUserLog("User operation", msg);
}

void frmConfigLink::on_btnInput_clicked()
{
    QString fileName;
    bool ok = DBHelper::inputData(columnNames.count(), App::FileFilter, "AlarmLink", fileName, QUIHelper::appPath() + "/db", true);
    if (!fileName.isEmpty()) {
        DBHelper::addUserLog("User operation", "Import alarm linkage information");
        if (ok) {
            QUIHelper::showMessageBoxInfo("Import alarm linkage information succeeded!", 3);
            model->select();
        } else {
            QUIHelper::showMessageBoxError("Failed to import alarm linkage information!", 3);
        }
    }
}

void frmConfigLink::on_btnOutput_clicked()
{
    QString columns = "*";
    QString where = "order by PositionID asc";
    QString title = columnNames.join(App::FileSpliter);
    QStringList content = DBHelper::getContent("AlarmLink", columns, where, title);

    QString fileName;
    bool ok = DBHelper::outputData("Alarm linkage information", App::FileFilter, content, fileName, QUIHelper::appPath() + "/db");
    if (!fileName.isEmpty()) {
        DBHelper::addUserLog("User operation", "Export alarm linkage information");
        if (ok) {
            QUIHelper::showMessageBoxInfo("Export alarm linkage information succeeded!", 3);
        } else {
            QUIHelper::showMessageBoxError("Failed to export alarm linkage information!", 3);
        }
    }
}

Posted by corrupshun on Mon, 02 Dec 2019 13:33:51 -0800