2025-03-04 11:27:16 +08:00
|
|
|
|
#include "mainwindow.h"
|
|
|
|
|
#include "ui_mainwindow.h"
|
|
|
|
|
|
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
|
#include <QVector>
|
|
|
|
|
#include <QThread>
|
|
|
|
|
#include <QDebug>
|
2025-03-04 17:19:03 +08:00
|
|
|
|
#include <QGridLayout>
|
|
|
|
|
#include <QToolBar>
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QGraphicsDropShadowEffect>
|
2025-03-05 13:37:23 +08:00
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QSizePolicy>
|
|
|
|
|
#include <QFontDatabase>
|
2025-03-07 16:16:57 +08:00
|
|
|
|
#include <QDateTime>
|
2025-03-04 11:27:16 +08:00
|
|
|
|
|
|
|
|
|
#include "libmodbus/modbus.h"
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
#include "customdisplaypanel.h"
|
2025-03-05 13:37:23 +08:00
|
|
|
|
|
|
|
|
|
#include "formserialportsettingdialog.h"
|
|
|
|
|
|
2025-03-04 11:27:16 +08:00
|
|
|
|
#define _DEBUG_VSPD_
|
|
|
|
|
|
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
|
|
|
: QMainWindow(parent)
|
|
|
|
|
, ui(new Ui::MainWindow)
|
|
|
|
|
,m_pModbus(nullptr)
|
2025-03-07 16:16:57 +08:00
|
|
|
|
,m_pTimer(nullptr)
|
2025-03-04 11:27:16 +08:00
|
|
|
|
,m_pSettings(nullptr)
|
2025-03-07 16:16:57 +08:00
|
|
|
|
,m_bInitializeModbus(false)
|
2025-03-17 10:44:59 +08:00
|
|
|
|
,m_timer_interval(10)
|
2025-03-04 11:27:16 +08:00
|
|
|
|
{
|
|
|
|
|
ui->setupUi(this);
|
|
|
|
|
|
|
|
|
|
m_version= "1.0.0";
|
|
|
|
|
m_modbus_type = 1;
|
|
|
|
|
m_modbus_ip = "127.0.0.1";
|
|
|
|
|
m_modbus_port = 502;
|
|
|
|
|
m_modbus_com = "COM1";
|
|
|
|
|
m_modbus_baund = 9600;
|
|
|
|
|
m_modbus_data = 1;
|
|
|
|
|
m_modbus_parity = 0;
|
|
|
|
|
m_modbus_stop = 1;
|
|
|
|
|
m_modbus_slave_id = 1;
|
|
|
|
|
|
|
|
|
|
InitializeUI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MainWindow::~MainWindow()
|
|
|
|
|
{
|
|
|
|
|
if (m_pModbus)
|
|
|
|
|
{
|
|
|
|
|
modbus_close(m_pModbus);
|
|
|
|
|
modbus_free(m_pModbus);
|
|
|
|
|
m_pModbus = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (SlaveItem* ptr : m_SlaveData)
|
|
|
|
|
{
|
|
|
|
|
delete ptr;
|
|
|
|
|
ptr = nullptr;
|
|
|
|
|
}
|
|
|
|
|
m_SlaveData.clear();
|
2025-03-04 14:22:27 +08:00
|
|
|
|
|
|
|
|
|
if (m_pSettings!=nullptr)
|
|
|
|
|
{
|
|
|
|
|
delete m_pSettings;
|
|
|
|
|
m_pSettings = nullptr;
|
|
|
|
|
}
|
2025-03-05 13:37:23 +08:00
|
|
|
|
delete ui;
|
2025-03-04 11:27:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::getConfiguration(QString iniFilePath)
|
|
|
|
|
{
|
2025-03-17 12:24:48 +08:00
|
|
|
|
if (m_pSettings == nullptr)
|
|
|
|
|
m_pSettings = new QSettings(iniFilePath, QSettings::IniFormat);
|
2025-03-04 11:27:16 +08:00
|
|
|
|
|
|
|
|
|
m_version = m_pSettings->value("version/ver").toString();
|
|
|
|
|
m_modbus_type = m_pSettings->value("modbus/type").toInt();
|
|
|
|
|
|
|
|
|
|
m_modbus_ip = m_pSettings->value("modbus/ip").toString();
|
|
|
|
|
m_modbus_port = m_pSettings->value("modbus/port").toInt();
|
|
|
|
|
|
|
|
|
|
m_modbus_com = m_pSettings->value("modbus/com").toString();
|
|
|
|
|
m_modbus_baund = m_pSettings->value("modbus/baund").toInt();
|
|
|
|
|
m_modbus_data = m_pSettings->value("modbus/data").toInt();
|
|
|
|
|
m_modbus_parity = m_pSettings->value("modbus/parity").toInt();
|
|
|
|
|
m_modbus_stop = m_pSettings->value("modbus/stop").toInt();
|
|
|
|
|
|
2025-03-17 10:44:59 +08:00
|
|
|
|
m_timer_interval = m_pSettings->value("modbus/interval").toInt();
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
#if 0
|
2025-03-04 11:27:16 +08:00
|
|
|
|
m_modbus_slave_id = m_pSettings->value("slaves/slave_id").toInt();
|
|
|
|
|
|
|
|
|
|
QString app = QString("slave_%1/function_code_counts").arg(m_modbus_slave_id);
|
|
|
|
|
|
|
|
|
|
int functions_count = m_pSettings->value(app).toInt();
|
|
|
|
|
for(int i=0; i<functions_count; i++)
|
|
|
|
|
{
|
|
|
|
|
QString app2 = QString("slave_%1_function_%2").arg(m_modbus_slave_id).arg(i);
|
|
|
|
|
|
|
|
|
|
#ifndef _DEBUG_VSPD_
|
|
|
|
|
unsigned short equipmentCode = m_pSettings->value(app2 + "/equipment_code").toInt();
|
|
|
|
|
equipmentCode = equipmentCode << 9;
|
|
|
|
|
equipmentCode &= 0xFE00; // 二进制掩码: 1111 1110 0000 0000(保留高7位)
|
|
|
|
|
|
|
|
|
|
QStringList sn_list = m_pSettings->value(app2 + "/serial_number").toString().split(":", Qt::SkipEmptyParts);
|
|
|
|
|
QStringList quantity_list = m_pSettings->value(app2 + "/read_quantity").toString().split(":", Qt::SkipEmptyParts);
|
|
|
|
|
|
|
|
|
|
assert(sn_list.size() == quantity_list.size());
|
|
|
|
|
|
|
|
|
|
int j = 0;
|
|
|
|
|
foreach(const QString sn, sn_list)
|
|
|
|
|
{
|
|
|
|
|
SlaveItem* pSlaveData = new SlaveItem();
|
|
|
|
|
pSlaveData->id = m_modbus_slave_id;
|
|
|
|
|
pSlaveData->function_code = m_pSettings->value(app2 + "/function_code").toInt();
|
|
|
|
|
pSlaveData->interval = m_pSettings->value(app2 + "/interval").toInt();
|
|
|
|
|
|
|
|
|
|
unsigned short serialNumber = sn.toInt();
|
|
|
|
|
|
|
|
|
|
serialNumber &= 0x01FF; // 二进制掩码: 0000 0001 1111 1111(保留低9位)
|
|
|
|
|
|
|
|
|
|
// 组合操作:高7位左移9位,低9位直接填充
|
|
|
|
|
unsigned short address = pSlaveData->start_address = (equipmentCode ) | serialNumber; // 关键位操作
|
|
|
|
|
|
|
|
|
|
pSlaveData->start_address = address;
|
|
|
|
|
pSlaveData->quantity = quantity_list.at(j).toInt();
|
|
|
|
|
m_SlaveData.push_back(pSlaveData);
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
SlaveItem* pSlaveData = new SlaveItem();
|
|
|
|
|
pSlaveData->id = m_modbus_slave_id;
|
|
|
|
|
pSlaveData->function_code = m_pSettings->value(app2 + "/function_code").toInt();
|
|
|
|
|
pSlaveData->interval = m_pSettings->value(app2 + "/interval").toInt();
|
|
|
|
|
pSlaveData->quantity = m_pSettings->value(app2 + "/quantity").toInt();
|
|
|
|
|
pSlaveData->start_address = m_pSettings->value(app2 + "/start_addr").toInt();
|
|
|
|
|
m_SlaveData.push_back(pSlaveData);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2025-03-16 14:20:19 +08:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::ReadConfiguration(QString jsonFilePath)
|
|
|
|
|
{
|
|
|
|
|
OpenJson json;
|
|
|
|
|
json.decodeFile(jsonFilePath.toStdString());
|
|
|
|
|
auto& nodeSlaves = json["slaves"];
|
|
|
|
|
qDebug() << nodeSlaves.size();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nodeSlaves.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
auto& node = nodeSlaves[i];
|
|
|
|
|
|
|
|
|
|
slaveItem slave_item;
|
|
|
|
|
|
|
|
|
|
slave_item.slave_id = node["id"].i32();
|
|
|
|
|
slave_item.function_code = node["function_code"].i32();
|
|
|
|
|
|
|
|
|
|
auto& nodeAddress = node["address"];
|
|
|
|
|
for (size_t j = 0; j < nodeAddress.size(); j++)
|
|
|
|
|
{
|
|
|
|
|
auto& nodeAddrItem = nodeAddress[j];
|
|
|
|
|
|
|
|
|
|
slaveAddress address_item;
|
|
|
|
|
address_item.start_addr = nodeAddrItem["start_addr"].i32();
|
|
|
|
|
address_item.quantity = nodeAddrItem["quantity"].i32();
|
|
|
|
|
address_item.bytes_per_register = nodeAddrItem["bytes_per_register"].i32();
|
2025-03-17 09:58:54 +08:00
|
|
|
|
address_item.lang = nodeAddrItem["language"].s();
|
2025-03-16 14:20:19 +08:00
|
|
|
|
address_item.device_name_chn = nodeAddrItem["device_name_chn"].s();
|
|
|
|
|
address_item.device_name_eng = nodeAddrItem["device_name_eng"].s();
|
|
|
|
|
address_item.device_type = nodeAddrItem["device_type"].i32();
|
|
|
|
|
auto& nodeData = nodeAddrItem["data"];
|
|
|
|
|
for (size_t k = 0; k < nodeData.size(); k++)
|
|
|
|
|
{
|
|
|
|
|
auto& nodeRegister = nodeData[k];
|
|
|
|
|
|
|
|
|
|
registryData rdata;
|
|
|
|
|
rdata.comment = nodeRegister["comment"].s();
|
|
|
|
|
rdata.order = nodeRegister["order"].i32();
|
|
|
|
|
rdata.precision = (float)nodeRegister["precision"].d();
|
|
|
|
|
rdata.unit = nodeRegister["unit"].s();
|
|
|
|
|
rdata.title_chn = nodeRegister["title_chn"].s();
|
|
|
|
|
rdata.title_en = nodeRegister["title_eng"].s();
|
|
|
|
|
rdata.display = nodeRegister["display"].i32();
|
|
|
|
|
rdata.skip = nodeRegister["skip"].i32();
|
|
|
|
|
|
|
|
|
|
address_item.register_data_items.insert(std::make_pair(rdata.order,rdata));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
slave_item.slave_address_items.emplace_back(address_item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_total_slave_items.emplace_back(slave_item);
|
|
|
|
|
}
|
2025-03-04 11:27:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MainWindow::InitializeUI()
|
|
|
|
|
{
|
2025-03-05 13:37:23 +08:00
|
|
|
|
#ifndef NDEBUG
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//this->showMaximized();
|
2025-03-05 13:37:23 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
ui->statusbar->showMessage(tr("Ready"), 0);
|
|
|
|
|
|
2025-03-04 17:19:03 +08:00
|
|
|
|
//初始化窗口边框
|
2025-03-05 13:37:23 +08:00
|
|
|
|
QWidget *centralWidget = this->centralWidget(); // new QWidget(this);
|
|
|
|
|
QGridLayout *mainLayout = new QGridLayout(centralWidget);
|
|
|
|
|
|
|
|
|
|
this->setStyleSheet("background-color: white;");
|
2025-03-17 12:24:48 +08:00
|
|
|
|
this->setProperty("canMove",true);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
|
|
|
|
|
//设置窗体透明
|
2025-03-04 17:19:03 +08:00
|
|
|
|
this->setAttribute(Qt::WA_TranslucentBackground, true);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
//设置无边框
|
|
|
|
|
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
|
|
|
|
//实例阴影shadow
|
2025-03-04 17:19:03 +08:00
|
|
|
|
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
//设置阴影距离
|
2025-03-04 17:19:03 +08:00
|
|
|
|
shadow->setOffset(0, 0);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
//设置阴影颜色
|
|
|
|
|
shadow->setColor(QColor(44,44,44));
|
|
|
|
|
//设置阴影圆角
|
2025-03-04 17:19:03 +08:00
|
|
|
|
shadow->setBlurRadius(16);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
//给嵌套QDialog设置阴影
|
|
|
|
|
ui->centralwidget->setGraphicsEffect(shadow);
|
|
|
|
|
|
|
|
|
|
//给垂直布局器设置边距(此步很重要, 设置宽度为阴影的宽度)
|
|
|
|
|
//->setMargin(12);
|
2025-03-04 17:19:03 +08:00
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//温度
|
|
|
|
|
m_pTemperaturePanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pTemperaturePanel->setImage(":/icons/main_temp.png");
|
|
|
|
|
QStringList l1{tr("Online"),tr("Temperature"),tr("Humidity")};
|
|
|
|
|
m_pTemperaturePanel->setLableCount(l1.count());
|
|
|
|
|
m_pTemperaturePanel->setTableRowsCount(10);
|
|
|
|
|
m_pTemperaturePanel->setLables(l1);
|
|
|
|
|
m_pTemperaturePanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pTemperaturePanel->setMainLabel(tr("Temp&RH"));
|
|
|
|
|
m_pTemperaturePanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pTemperaturePanel, 0, 0);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_TEMPERATURE,m_pTemperaturePanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//电源
|
|
|
|
|
m_pPowerPanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pPowerPanel->setImage(":/icons/main_power.png");
|
2025-03-16 14:20:19 +08:00
|
|
|
|
QStringList l2{QStringList{tr("Online"),tr("Vin."),tr("Vout"),tr("Iout"),tr("T_mod")}};
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_pPowerPanel->setLableCount(l2.count());
|
|
|
|
|
m_pPowerPanel->setTableRowsCount(10);
|
|
|
|
|
m_pPowerPanel->setLables(l2);
|
|
|
|
|
m_pPowerPanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pPowerPanel->setMainLabel(tr("Power"));
|
|
|
|
|
m_pPowerPanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pPowerPanel, 0, 1);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_POWER,m_pPowerPanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//电池
|
|
|
|
|
m_pBatteryPanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pBatteryPanel->setImage(":/icons/main_battery.png");
|
2025-03-16 14:20:19 +08:00
|
|
|
|
QStringList l3{QStringList{tr("Online"),tr("SOC"),tr("SOH"),tr("Vpack")}};
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_pBatteryPanel->setLableCount(l3.count());
|
|
|
|
|
m_pBatteryPanel->setTableRowsCount(10);
|
|
|
|
|
m_pBatteryPanel->setLables(l3);
|
|
|
|
|
m_pBatteryPanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pBatteryPanel->setMainLabel(tr("Battery Pack"));
|
|
|
|
|
m_pBatteryPanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pBatteryPanel, 0, 2);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_BATTERY,m_pBatteryPanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//空调
|
|
|
|
|
m_pACPanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pACPanel->setImage(":/icons/main_ac.png");
|
|
|
|
|
QStringList l4{QStringList{tr("Online"),tr("Machine"),tr("IFM"),tr("Compressor"),tr("OFM"),tr("Discharge Temp."),tr("Room Temp.")}};
|
|
|
|
|
m_pACPanel->setLableCount(l4.count());
|
|
|
|
|
m_pACPanel->setTableRowsCount(10);
|
|
|
|
|
m_pACPanel->setLables(l4);
|
|
|
|
|
m_pACPanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pACPanel->setMainLabel(tr("HVACR"));
|
|
|
|
|
m_pACPanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pACPanel, 0, 3);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_AC,m_pACPanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//交流配电
|
|
|
|
|
m_pInverterPanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pInverterPanel->setImage(":/icons/main_invertor.png");
|
2025-03-16 14:20:19 +08:00
|
|
|
|
QStringList l5{QStringList{tr("Online"),tr("Vin"),tr("Iin"),tr("T_mod")}};
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_pInverterPanel->setLableCount(l5.count());
|
|
|
|
|
m_pInverterPanel->setTableRowsCount(10);
|
|
|
|
|
m_pInverterPanel->setLables(l5);
|
|
|
|
|
m_pInverterPanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pInverterPanel->setMainLabel(tr("AC Power"));
|
|
|
|
|
m_pInverterPanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pInverterPanel, 1, 0);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_INVERTER,m_pInverterPanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//PV太阳能
|
|
|
|
|
m_pPVPanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pPVPanel->setImage(":/icons/main_pv.png");
|
2025-03-16 14:20:19 +08:00
|
|
|
|
QStringList l6{QStringList{tr("Online"),tr("Vout"),tr("Iout"),tr("T_mod")}};
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_pPVPanel->setLableCount(l6.count());
|
|
|
|
|
m_pPVPanel->setTableRowsCount(10);
|
|
|
|
|
m_pPVPanel->setLables(l6);
|
|
|
|
|
m_pPVPanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pPVPanel->setMainLabel(tr("PV Module"));
|
|
|
|
|
m_pPVPanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pPVPanel, 1, 1);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_PV,m_pPVPanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//门禁
|
|
|
|
|
m_pHomePanel = new CustomDisplayPanel(this);
|
|
|
|
|
m_pHomePanel->setImage(":/icons/main_cab.png");
|
2025-03-16 14:20:19 +08:00
|
|
|
|
QStringList l7{QStringList{tr("Online"),tr("Vout"),tr("Iout"),tr("T_mod")}};
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_pHomePanel->setLableCount(l7.count());
|
|
|
|
|
m_pHomePanel->setTableRowsCount(10);
|
|
|
|
|
m_pHomePanel->setLables(l7);
|
|
|
|
|
m_pHomePanel->setRowItems(QStringList{tr("露点"),tr("DO"),tr("DI1"),tr("DI2"),tr("高温"),tr("低温"),tr("高湿")});
|
|
|
|
|
m_pHomePanel->setMainLabel(tr("Sensors"));
|
|
|
|
|
m_pHomePanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pHomePanel, 1, 2);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_HOME,m_pHomePanel));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//告警
|
|
|
|
|
m_pAlarmPanel = new CustomWarningPanel(this);
|
|
|
|
|
m_pAlarmPanel->setImage(":/icons/main_alarm.png");
|
|
|
|
|
QStringList l8{QStringList{tr("Warning Board")}};
|
|
|
|
|
m_pAlarmPanel->setLableCount(l8.count());
|
|
|
|
|
m_pAlarmPanel->setTableRowsCount(10);
|
|
|
|
|
m_pAlarmPanel->setTableRolCount(3);
|
|
|
|
|
m_pAlarmPanel->setLables(l8);
|
|
|
|
|
m_pAlarmPanel->setRowItems(QStringList{tr("")});
|
|
|
|
|
m_pAlarmPanel->setMainLabel(tr("Warning"));
|
|
|
|
|
m_pAlarmPanel->Build();
|
|
|
|
|
mainLayout->addWidget(m_pAlarmPanel, 1, 3);
|
2025-03-04 17:19:03 +08:00
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_ALARM,m_pAlarmPanel));
|
|
|
|
|
|
2025-03-04 17:19:03 +08:00
|
|
|
|
// 设置布局的间距和边距
|
|
|
|
|
mainLayout->setSpacing(5);
|
|
|
|
|
//mainLayout->setContentsMargins(10, 40, 10, 10); // 顶部留出工具栏空间
|
2025-03-05 13:37:23 +08:00
|
|
|
|
//setCentralWidget(centralWidget);
|
2025-03-04 17:19:03 +08:00
|
|
|
|
|
|
|
|
|
QToolBar *toolBar = new QToolBar(this);
|
|
|
|
|
toolBar->setMovable(false);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
2025-03-04 17:19:03 +08:00
|
|
|
|
toolBar->setIconSize(QSize(64,64));
|
2025-03-05 13:37:23 +08:00
|
|
|
|
// 设置按钮悬停效果(通过样式表)
|
|
|
|
|
// toolBar->setStyleSheet(
|
|
|
|
|
// "QToolButton { background: transparent; border: none; }"
|
|
|
|
|
// "QToolButton:hover { background: #e0e0e0; border-radius: 4px; }"
|
|
|
|
|
// );
|
2025-03-04 17:19:03 +08:00
|
|
|
|
|
|
|
|
|
// 添加工具栏按钮
|
|
|
|
|
QAction *actionRead = new QAction(QIcon(":/icons/modular.png"), tr("Read"), this);
|
|
|
|
|
actionRead->setToolTip(tr("Read Data"));
|
|
|
|
|
|
2025-03-05 13:37:23 +08:00
|
|
|
|
QAction *actionSetting = new QAction(QIcon(":/icons/setting.png"), tr("Setting"), this);
|
|
|
|
|
actionSetting->setToolTip(tr("Setting Modbud Port"));
|
|
|
|
|
|
2025-03-04 17:19:03 +08:00
|
|
|
|
QAction *actionClose = new QAction(QIcon(":/icons/close.png"), tr("Close"), this);
|
|
|
|
|
actionClose->setToolTip(tr("Close Application"));
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//添加logo
|
|
|
|
|
QLabel *logoLabel = new QLabel(this);
|
|
|
|
|
QPixmap pixmap(":/icons/logo-en.png"); // 替换为实际图片路径
|
|
|
|
|
logoLabel->setPixmap(pixmap.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
|
|
|
|
toolBar->addWidget(logoLabel);
|
2025-03-16 14:20:19 +08:00
|
|
|
|
//toolBar->addSeparator();
|
2025-03-05 13:37:23 +08:00
|
|
|
|
|
|
|
|
|
// 添加间隔控件
|
|
|
|
|
QWidget *spacer = new QWidget();
|
|
|
|
|
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
|
|
|
toolBar->addWidget(spacer);
|
|
|
|
|
|
|
|
|
|
// 添加中央标签
|
2025-03-07 16:16:57 +08:00
|
|
|
|
QLabel *label = new QLabel(tr("Integrated Power Cabinet Monitoring"), this);
|
|
|
|
|
|
|
|
|
|
// // 加载字体
|
|
|
|
|
// int fontId = QFontDatabase::addApplicationFont(":/fonts/Alimama_DongFangDaKai_Regular.ttf");
|
|
|
|
|
// if (fontId == -1)
|
|
|
|
|
// {
|
|
|
|
|
// ui->statusbar->showMessage(tr("Failed to load font"));
|
|
|
|
|
// }
|
2025-03-05 13:37:23 +08:00
|
|
|
|
//QFont customFont("Alimama DongFangDaKai", 48);
|
|
|
|
|
//customFont.setBold(true);
|
|
|
|
|
//label->setFont(customFont);
|
|
|
|
|
//label->setStyleSheet("color: #2E86C1;");
|
2025-03-16 14:20:19 +08:00
|
|
|
|
|
2025-03-05 13:37:23 +08:00
|
|
|
|
label->setStyleSheet(
|
|
|
|
|
"QLabel {"
|
2025-03-07 16:16:57 +08:00
|
|
|
|
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
|
|
|
|
|
" font-family: 'Arial';" // 需确保字体已加载
|
2025-03-05 13:37:23 +08:00
|
|
|
|
" font-size: 52px;"
|
|
|
|
|
" color: #2E86C1;"
|
2025-03-07 16:16:57 +08:00
|
|
|
|
" font-weight: bold;"
|
|
|
|
|
" font-style: black;"
|
2025-03-05 13:37:23 +08:00
|
|
|
|
"}"
|
|
|
|
|
);
|
|
|
|
|
toolBar->addWidget(label);
|
|
|
|
|
|
|
|
|
|
QWidget *spacerWidget = new QWidget();
|
|
|
|
|
spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
|
|
|
|
toolBar->addWidget(spacerWidget);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
//添加按钮
|
|
|
|
|
toolBar->addAction(actionRead);
|
|
|
|
|
toolBar->addSeparator();
|
|
|
|
|
|
2025-03-05 13:37:23 +08:00
|
|
|
|
toolBar->addAction(actionSetting);
|
2025-03-04 17:19:03 +08:00
|
|
|
|
toolBar->addSeparator();
|
|
|
|
|
|
2025-03-05 13:37:23 +08:00
|
|
|
|
toolBar->addAction(actionClose);
|
|
|
|
|
|
|
|
|
|
// 将工具栏定位到窗口顶部·
|
2025-03-04 17:19:03 +08:00
|
|
|
|
addToolBar(Qt::TopToolBarArea, toolBar);
|
|
|
|
|
|
|
|
|
|
connect(actionClose, &QAction::triggered, this, &QMainWindow::close);
|
2025-03-05 13:37:23 +08:00
|
|
|
|
connect(actionSetting, &QAction::triggered, this, &MainWindow::SettingSerialPort);
|
2025-03-04 17:19:03 +08:00
|
|
|
|
connect(actionRead, &QAction::triggered, this, &MainWindow::ReadSerialPortData);
|
|
|
|
|
|
2025-03-17 10:44:59 +08:00
|
|
|
|
//读一下配置
|
|
|
|
|
QString appDir = QCoreApplication::applicationDirPath();
|
|
|
|
|
QString iniFilePath = appDir + QString::fromStdString("/emsshower.ini");
|
|
|
|
|
|
|
|
|
|
getConfiguration(iniFilePath);
|
|
|
|
|
|
2025-03-05 13:37:23 +08:00
|
|
|
|
return true;
|
2025-03-04 11:27:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MainWindow::InitializeModbus()
|
|
|
|
|
{
|
2025-03-07 16:16:57 +08:00
|
|
|
|
if (m_bInitializeModbus)
|
|
|
|
|
return true;
|
|
|
|
|
|
2025-03-04 11:27:16 +08:00
|
|
|
|
QString appDir = QCoreApplication::applicationDirPath();
|
|
|
|
|
QString iniFilePath = appDir + QString::fromStdString("/emsshower.ini");
|
|
|
|
|
|
|
|
|
|
getConfiguration(iniFilePath);
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
QString jsonFilePath = appDir + QString::fromStdString("/emsshower.json");
|
|
|
|
|
ReadConfiguration(jsonFilePath);
|
|
|
|
|
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_bInitializeModbus = true;
|
2025-03-04 11:27:16 +08:00
|
|
|
|
switch (m_modbus_type)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return InitializeTcp();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
case 1:
|
|
|
|
|
return InitializeRtu();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MainWindow::InitializeRtu()
|
|
|
|
|
{
|
|
|
|
|
if(m_pModbus)
|
|
|
|
|
{
|
|
|
|
|
modbus_close(m_pModbus);
|
|
|
|
|
m_pModbus = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string com = std::string("\\\\.\\") + m_modbus_com.toStdString();
|
|
|
|
|
|
|
|
|
|
m_pModbus = modbus_new_rtu(com.c_str(), m_modbus_baund, 'N', m_modbus_data, m_modbus_stop);
|
2025-03-16 14:20:19 +08:00
|
|
|
|
#if 1
|
2025-03-04 11:27:16 +08:00
|
|
|
|
int slave_id = m_modbus_slave_id;
|
|
|
|
|
//modbus_set_debug(m_pModbus, true);
|
|
|
|
|
modbus_set_slave(m_pModbus, slave_id); //设置modbus从机地址
|
|
|
|
|
modbus_rtu_set_serial_mode(m_pModbus, MODBUS_RTU_RS485);
|
|
|
|
|
|
|
|
|
|
int rc = modbus_connect(m_pModbus);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
struct timeval t;
|
|
|
|
|
t.tv_sec=0;
|
|
|
|
|
t.tv_usec=1000000; //设置modbus超时时间为1000毫秒
|
|
|
|
|
modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec);
|
2025-03-16 14:20:19 +08:00
|
|
|
|
#endif
|
2025-03-04 11:27:16 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MainWindow::InitializeTcp()
|
|
|
|
|
{
|
|
|
|
|
if(m_pModbus)
|
|
|
|
|
{
|
|
|
|
|
modbus_close(m_pModbus);
|
|
|
|
|
m_pModbus = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string ip = m_modbus_ip.toStdString();
|
|
|
|
|
int port = m_modbus_port;
|
|
|
|
|
m_pModbus = modbus_new_tcp(ip.c_str(), port); //由于是tcp client连接,在同一个程序中相同的端口可以连接多次。
|
|
|
|
|
if (m_pModbus == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int slave_id = m_modbus_slave_id;
|
|
|
|
|
modbus_set_slave(m_pModbus, slave_id); //从机地址
|
|
|
|
|
|
|
|
|
|
int rc = modbus_connect(m_pModbus);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
struct timeval t;
|
|
|
|
|
t.tv_sec=0;
|
|
|
|
|
t.tv_usec=1000000; //设置modbus超时时间为1000毫秒
|
|
|
|
|
modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
bool MainWindow::readRegister()
|
|
|
|
|
{
|
|
|
|
|
if(!InitializeModbus()) //这里有问题,如果是虚拟串口,连接的通常会返回成功
|
|
|
|
|
{
|
|
|
|
|
ui->statusbar->showMessage(tr("Failed to open Modbus device,Check modbus connection please!")); //打开MODBUS设备失败,请检查设备连接情况!"));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//对每一个slave进行读取
|
|
|
|
|
//枚举每一个slave id;这里因为实际上只有一个slave,所以实际上只会执行一次循环
|
|
|
|
|
|
|
|
|
|
SlaveItems::iterator iter = m_total_slave_items.begin();
|
|
|
|
|
for(; iter!=m_total_slave_items.end(); iter++)
|
|
|
|
|
{
|
|
|
|
|
SlaveAddressItems::iterator iterAddress = iter->slave_address_items.begin();
|
|
|
|
|
for(; iterAddress!=iter->slave_address_items.end(); iterAddress++)
|
|
|
|
|
{
|
|
|
|
|
uint16_t* tab_reg = new uint16_t[iterAddress->quantity];
|
|
|
|
|
int regs = modbus_read_registers(m_pModbus, iterAddress->start_addr, iterAddress->quantity, tab_reg);
|
|
|
|
|
|
|
|
|
|
QVector<uint16_t> registers;
|
|
|
|
|
for (int i = 0; i < regs; ++i)
|
|
|
|
|
{
|
|
|
|
|
registers.push_back(tab_reg[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete []tab_reg;
|
|
|
|
|
|
|
|
|
|
DeviceData* pDevice = new GeneralDeviceData();
|
|
|
|
|
|
|
|
|
|
DecodeSync(registers, *iterAddress, pDevice);
|
|
|
|
|
|
|
|
|
|
OpenJson json;
|
2025-03-17 10:44:59 +08:00
|
|
|
|
if(CreateJson2(pDevice,json))
|
|
|
|
|
{
|
|
|
|
|
m_Panels[iterAddress->device_type]->UpdateData(json);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ui->statusbar->showMessage(tr("Failed to decode temperaure data")); //解析温度数据失败!"));
|
|
|
|
|
}
|
2025-03-16 14:20:19 +08:00
|
|
|
|
|
|
|
|
|
delete pDevice;
|
|
|
|
|
|
|
|
|
|
qDebug() << "decode an item";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::DecodeSync(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData)
|
|
|
|
|
{
|
|
|
|
|
GeneralDeviceData* pGeneralData = (GeneralDeviceData*)pData;
|
|
|
|
|
RegisterDataItems::const_iterator iter = sa.register_data_items.begin();
|
|
|
|
|
int idx = 0;
|
|
|
|
|
for(; iter!=sa.register_data_items.end(); iter++)
|
|
|
|
|
{
|
|
|
|
|
if (iter->second.skip ==0)
|
|
|
|
|
{
|
|
|
|
|
DisplayDataItem ddi;
|
|
|
|
|
ddi.device_type = sa.device_type;
|
|
|
|
|
ddi.display_location = iter->second.display;
|
|
|
|
|
ddi.order = iter->second.order;
|
|
|
|
|
ddi.precision = iter->second.precision;
|
2025-03-17 09:58:54 +08:00
|
|
|
|
if (QString::fromStdString(sa.lang.c_str()).toLower() == "chn")
|
|
|
|
|
ddi.title = iter->second.title_chn;
|
|
|
|
|
else
|
|
|
|
|
ddi.title = iter->second.title_en;
|
2025-03-16 14:20:19 +08:00
|
|
|
|
ddi.unit = iter->second.unit;
|
|
|
|
|
ddi.value = array[idx];
|
|
|
|
|
pGeneralData->m_PanelDisplayDataItems.emplace_back(ddi);
|
|
|
|
|
}
|
|
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 11:27:16 +08:00
|
|
|
|
|
2025-03-04 17:19:03 +08:00
|
|
|
|
void MainWindow::ReadSerialPortData()
|
2025-03-07 16:16:57 +08:00
|
|
|
|
{
|
|
|
|
|
if (!m_pTimer)
|
|
|
|
|
m_pTimer = new QTimer(this);
|
|
|
|
|
|
|
|
|
|
if (m_pTimer->isActive())
|
|
|
|
|
{
|
|
|
|
|
m_pTimer->stop();
|
|
|
|
|
ui->statusbar->showMessage(tr("Stop Reading"));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-03-17 10:44:59 +08:00
|
|
|
|
m_pTimer->setInterval(m_timer_interval * 1000);
|
2025-03-07 16:16:57 +08:00
|
|
|
|
connect(m_pTimer, &QTimer::timeout, this, &MainWindow::onTimeout);
|
2025-03-16 14:20:19 +08:00
|
|
|
|
ui->statusbar->showMessage(tr("Begin Reading"));
|
2025-03-07 16:16:57 +08:00
|
|
|
|
m_pTimer->start();
|
|
|
|
|
onTimeout();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onTimeout()
|
2025-03-04 11:27:16 +08:00
|
|
|
|
{
|
2025-03-16 14:20:19 +08:00
|
|
|
|
readRegister();
|
2025-03-04 11:27:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-05 13:37:23 +08:00
|
|
|
|
void MainWindow::SettingSerialPort()
|
|
|
|
|
{
|
|
|
|
|
FormSerialPortSettingDialog* dlg = new FormSerialPortSettingDialog(this);
|
|
|
|
|
dlg->setWindowFlags(dlg->windowFlags()&~(Qt::WindowMinMaxButtonsHint|Qt::WindowContextHelpButtonHint));
|
2025-03-07 16:16:57 +08:00
|
|
|
|
dlg->exec();
|
|
|
|
|
|
|
|
|
|
// if(dlg->exec() == QDialog::Accepted)
|
|
|
|
|
// QMessageBox::information(this, "OK Clicked", "Button 1 was clicked!");
|
|
|
|
|
// else
|
|
|
|
|
// QMessageBox::information(this, "Cancel Clicked", "Cancel was clicked!");
|
2025-03-05 13:37:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-16 14:20:19 +08:00
|
|
|
|
|
|
|
|
|
bool MainWindow::CreateJson2(DeviceData* pData,OpenJson& json)
|
|
|
|
|
{
|
|
|
|
|
assert(pData);
|
|
|
|
|
GeneralDeviceData* pDevice = (GeneralDeviceData*)pData;
|
|
|
|
|
DisplayDataItems::const_iterator iter = pDevice->m_PanelDisplayDataItems.begin();
|
|
|
|
|
|
|
|
|
|
int idx0=0;
|
|
|
|
|
int idx1=0;
|
|
|
|
|
json["panel_type"] = iter->device_type;
|
|
|
|
|
|
|
|
|
|
if (iter->device_type == 6) //告警,需要特别处理
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
auto& nodeTable = json["alarm"];
|
|
|
|
|
for(; iter!=pDevice->m_PanelDisplayDataItems.end(); iter++)
|
|
|
|
|
{
|
|
|
|
|
if(iter->display_location == 0)
|
|
|
|
|
continue;
|
|
|
|
|
nodeTable[idx0]["time"] = QDateTime::currentDateTime().toString("MM-dd HH:mm:ss").toStdString();
|
|
|
|
|
nodeTable[idx0]["signal"] = iter->title;
|
|
|
|
|
nodeTable[idx0]["value"] = iter->value * 1.0f / iter->precision;
|
|
|
|
|
idx0++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto& nodeLabel = json["text_panel"];
|
|
|
|
|
auto& nodeTable = json["table"];
|
|
|
|
|
for(; iter!=pDevice->m_PanelDisplayDataItems.end(); iter++)
|
|
|
|
|
{
|
|
|
|
|
if(iter->display_location == 1) //显示在面板
|
|
|
|
|
{
|
|
|
|
|
nodeLabel[idx0]["value"] = iter->value * 1.0f / iter->precision;
|
|
|
|
|
nodeLabel[idx0]["title"] = iter->title;
|
|
|
|
|
idx0++;
|
|
|
|
|
}
|
|
|
|
|
if (iter->display_location == 2) // 显示在表格
|
|
|
|
|
{
|
|
|
|
|
if (idx1 == 0)
|
|
|
|
|
{
|
|
|
|
|
nodeTable[idx1]["value"] = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss").toStdString();
|
|
|
|
|
nodeTable[idx1]["signal"] = "Time";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nodeTable[idx1]["value"] = iter->value * 1.0f / iter->precision;
|
|
|
|
|
nodeTable[idx1]["signal"] = iter->title;
|
|
|
|
|
}
|
|
|
|
|
idx1++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string a = json.encode();
|
|
|
|
|
|
|
|
|
|
qDebug() << QString::fromStdString(a);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|