Qt Write Gas Security Management System 16-Cloud Synchronization

Posted by cdm2 on Sun, 24 Nov 2019 03:50:52 +0100

1. Preface

Cloud synchronization function is preparation for later expansion. His purpose is to synchronize records from local databases, such as real-time collected data and stored running records, to the cloud database. By default, the mysql database of Ali Cloud is used. The speed of Ali Cloud is still very fast. I have bought low-match and high-match Ali Cloud servers. High-match is really a block.Fort, the processing speed above is much faster than my local computer. In a remotely connected desktop, it's not too cool to use. The disadvantage is that it costs money. Whether I bought it for use time or good, the server turns on when I need it, turns it off when I run out or when I don't use it.

As for Cloud Synchronization, a generic class DbTcpClientThread is deliberately encapsulated. Cloud data synchronization for various systems will automatically reconnect to the database. In the software, you only need to set up the server address database and other information at the time of initialization, then insert the corresponding sql statement where you need it, so that the remote side can execute the sql statement to synchronize the data.The basic application scenario is to synchronously collect data in real time, then refresh the app side of the mobile phone or the web side of the web page to view the corresponding data.

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

2. Functional features

  1. Collect data port, support serial port + network port, support free serial port + baud rate, network support free set IP address + communication port, each port supports collection cycle, default 1 second address, support set communication timeout, default 3 times, support maximum reconnection time, for re-reading offline devices.
  2. Controller information, the ability to add a controller name, select a controller address + controller model, and set the number of detectors under the controller.
  3. Detector information, can add bit number, freely select the type of detector, gas type, gas symbol, high report value, low report value, buffer value, zero value, whether enabled, alarm sound, background map, storage period, numeric conversion of decimal places, alarm delay time, alarm type (HH,LL,HL), etc.
  4. Controller model + detector model + gas type + gas symbol, can be freely configured.
  5. Maps support import and delete, and all detectors are free to drag and save map locations.
  6. Port information + Controller information + Detector information, support import export + export to excel + print.
  7. Run records + alarm records + user records, support multi-conditional combination queries, such as time period + controller + detector, all records support export to excel + print.
  8. Records exported to excel support all forms file versions such as excel+wps and do not rely on software such as excel.
  9. Data within a specified time range can be deleted, early data can be automatically cleaned up, and the maximum number of records can be saved.
  10. Supports alarm text message forwarding, supports multiple receiving mobile phone numbers, and can set the sending interval, such as sending all alarm messages instantly or once in 6 hours, the text message content is too long, and automatically splits multiple text messages.
  11. Supports alarm mail forwarding, supports multiple receiving mailboxes, and can set sending intervals, such as sending all alarm messages instantly or once in six hours, and supports attachment sending.
  12. High report color + low report color + normal color + 0 value color + curve background + curve color, etc., can be chosen freely.
  13. The Chinese title, English title, logo path and copyright of the software can be set freely.
  14. Provides switch settings for on-off operation + alarm sound + automatic logon + password remembering, etc.
  15. The alarm sound sets the number of playback times and the interface provides 17 skin file choices.
  16. Supports cloud data synchronization by setting up information about cloud databases, such as database name, user name + password, etc.
  17. Supports network forwarding and network reception. After network reception is turned on, the software receives data from udp for analysis.Network forwarding supports multiple target IP, which enables locally collected software to freely transfer data to the client and view detector data at any time.
  18. Automatically remember the user's last remaining interface + other information and apply it automatically after restart.
  19. The alarm automatically switches to the corresponding map, and the detector button flashes.
  20. Double-click the detector icon for control.
  21. Support user rights management, administrator + operator two categories, user login + user exit, can remember password and automatic login, more than three error prompts and close the program.
  22. Supports four monitoring modes, device panel monitoring + map monitoring + tabular data monitoring + curve data monitoring, can switch freely, and four simultaneous applications.
  23. Supports alarm relay linkage, a bit number can link multiple modules and relay numbers across the serial port, supporting many-to-many.
  24. Local data stores support sqlite+mysql and remote data synchronization to cloud databases.Automatic reconnection.
  25. Data collected by local devices is uploaded to the cloud in real time for extraction by other means such as mobile APP or web.
  26. Two kinds of data sources are supported, one is serial port and network to collect device data through protocol, the other is database collection.The database collection mode can be used as a common system.
  27. The built-in device emulation tool supports 16 device data emulation as well as database data emulation to test data when there is no device.
  28. The default communication protocol uses the modbus protocol, and later adds the support of Internet of Things protocols such as mqtt to make a universal system.
  29. Supports all windows operating systems + linux operating systems and other operating systems.

3. Effect Charts

4. Core Code

#pragma execution_character_set("utf-8")
#include "dbtcpclientthread.h"

QScopedPointer<DbTcpClientThread> DbTcpClientThread::self;
DbTcpClientThread *DbTcpClientThread::Instance()
{
    if (self.isNull()) {
        static QMutex mutex;
        QMutexLocker locker(&mutex);
        if (self.isNull()) {
            self.reset(new DbTcpClientThread);
        }
    }

    return self.data();
}

DbTcpClientThread::DbTcpClientThread(QObject *parent) : QThread(parent)
{
    stopped = false;

    dbOkNet = false;
    errorCount = 0;
    lastCheckTimeNet = QDateTime::currentDateTime();

    checkConn = false;
    checkInterval = 30;

    dbTypeNet = DbType_MySql;
    connNameNet = "dbClient";
    hostNameNet = "127.0.0.1";
    portNet = 3306;
    dbNameNet = "db_mysql";
    userNameNet = "root";
    userPwdNet = "root";

    maxCount = 1000;
    listSql.clear();
    initSql.clear();
}

DbTcpClientThread::~DbTcpClientThread()
{
    this->stop();
    this->wait();
}

void DbTcpClientThread::run()
{
    while (!stopped) {
        //Perform a periodic check to see if the database connection is working
        QDateTime now = QDateTime::currentDateTime();

        if (checkConn && lastCheckTimeNet.secsTo(now) >= checkInterval) {
            checkDb();
            lastCheckTimeNet = now;
            continue;
        }

        //Processing data if database connection is normal and reconnecting database if it is not
        if (dbOkNet) {
            checkData();
            msleep(500);
        } else if (errorCount >= 3) {
            closeDb();
            msleep(3000);
            openDb();
            emit debug(QString("Reconnect Cloud Real-Time Database%1").arg(dbOkNet ? "Success" : "fail"));
            msleep(3000);
        }
    }

    stopped = false;
}

bool DbTcpClientThread::openDb()
{
    //You can add support for other databases yourself
    if (dbTypeNet == DbType_MySql) {
        dbConnNet = QSqlDatabase::addDatabase("QMYSQL", connNameNet);
        dbConnNet.setConnectOptions("MYSQL_OPT_RECONNECT=1;MYSQL_OPT_CONNECT_TIMEOUT=1;MYSQL_OPT_READ_TIMEOUT=1;MYSQL_OPT_WRITE_TIMEOUT=1");
        dbConnNet.setHostName(hostNameNet);
        dbConnNet.setPort(portNet);
        dbConnNet.setDatabaseName(dbNameNet);
        dbConnNet.setUserName(userNameNet);
        dbConnNet.setPassword(userPwdNet);
    }

    errorCount = 0;
    dbOkNet = dbConnNet.open();
    return dbOkNet;
}

bool DbTcpClientThread::checkDb()
{
    QDateTime dtStart = QDateTime::currentDateTime();

    QString sql = "select 1";
    QSqlQuery query(dbConnNet);
    dbOkNet = query.exec(sql);
    dbOkNet ? (errorCount = 0) : errorCount++;

    QDateTime dtEnd = QDateTime::currentDateTime();
    double ms = dtStart.msecsTo(dtEnd);
    emit debug(QString("Check Cloud Real-Time Database Connections(common %1 strip/Time-consuming %2 second)").arg(1).arg(QString::number(ms / 1000, 'f', 3)));

    return dbOkNet;
}

void DbTcpClientThread::closeDb()
{
    dbConnNet.close();
    QSqlDatabase::removeDatabase(connNameNet);
    dbOkNet = false;
    emit debug("Close Cloud Real-Time Database");
}

void DbTcpClientThread::initDb()
{
    //Ensure at least one data
    int count = initSql.count();
    if (dbOkNet && count > 1) {
        QDateTime dtStart = QDateTime::currentDateTime();

        //Strictly state that the first sql statement empties all data in the table
        QSqlQuery query(dbConnNet);
        query.exec(initSql.first());

        //New Initial Value Data
        for (int i = 1; i < count; i++) {
            query.clear();
            query.exec(initSql.at(i));
        }

        QDateTime dtEnd = QDateTime::currentDateTime();
        double ms = dtStart.msecsTo(dtEnd);
        emit debug(QString("Remotely empty and create new data(common %1 strip/Time-consuming %2 second)").arg(count).arg(QString::number(ms / 1000, 'f', 3)));
    }
}

void DbTcpClientThread::stop()
{
    stopped = true;
}

void DbTcpClientThread::append(const QString &sql)
{
    mutex.lock();

    //Only different sql statements need to be processed
    if (!listSql.contains(sql)) {
        //If the maximum quantity is reached, remove the last item and append to the end
        if (listSql.count() >= maxCount) {
            listSql.removeLast();
        }

        listSql.append(sql);
    }

    mutex.unlock();
}

void DbTcpClientThread::clear()
{
    mutex.lock();
    listSql.clear();
    mutex.unlock();
}

bool DbTcpClientThread::checkData()
{
    mutex.lock();
    QStringList sqls = listSql;
    mutex.unlock();

    int count = sqls.count();
    if (count == 0) {
        return false;
    }

    //Remove all sql statements from the queue and commit one-time transactions to the remote database
    if (dbOkNet) {
        QDateTime dtStart = QDateTime::currentDateTime();
        dbConnNet.transaction();

        //Execute sql statements one by one
        foreach (QString sql, sqls) {
            QSqlQuery query(dbConnNet);
            query.exec(sql);
        }

        //Empty sql statement queue after successful submission
        //Commit failure requires transaction rollback
        dbOkNet = dbConnNet.commit();

        if (dbOkNet) {
            clear();
            QDateTime dtEnd = QDateTime::currentDateTime();
            double ms = dtStart.msecsTo(dtEnd);
            emit debug(QString("Remote Real-Time Update Data(common %1 strip/Time-consuming %2 second)").arg(count).arg(QString::number(ms / 1000, 'f', 3)));
        } else {
            dbConnNet.rollback();
            emit debug(QString("Failed to commit transaction: %1").arg(dbConnNet.lastError().text()));
        }
    }

    return dbOkNet;
}

void DbTcpClientThread::setConnInfo(DbType dbType, const QString &connName, const QString &hostName, int port,
                                    const QString &dbName, const QString &userName, const QString &userPwd)
{
    this->dbTypeNet = dbType;
    this->connNameNet = connName;
    this->hostNameNet = hostName;
    this->portNet = port;
    this->dbNameNet = dbName;
    this->userNameNet = userName;
    this->userPwdNet = userPwd;
}

void DbTcpClientThread::setCheckConn(bool checkConn)
{
    this->checkConn = checkConn;
}

void DbTcpClientThread::setCheckInterval(int checkInterval)
{
    if (checkInterval > 5 && this->checkInterval != checkInterval) {
        this->checkInterval = checkInterval;
    }
}

void DbTcpClientThread::setInitSql(const QStringList &initSql)
{
    this->initSql = initSql;
}

Topics: Database SQL network Excel