更新为通过json文件定义解码,详细配置见json文件
parent
63b9f7d141
commit
33ab44bd08
|
@ -67,7 +67,7 @@ void CustomDisplayPanel::Build()
|
|||
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
|
||||
" font-family: 'Arial';"
|
||||
" font-size: 20px;"
|
||||
" color: #13396E;"
|
||||
" color: #20549E;"
|
||||
" font-weight: bold;"
|
||||
" font-style: black;"
|
||||
"}"
|
||||
|
@ -139,6 +139,8 @@ void CustomDisplayPanel::Build()
|
|||
tableWidget->setShowGrid(true); // 默认显示网格线[3](@ref)
|
||||
tableWidget->setStyleSheet("QTableWidget { gridline-color: #e0e0e0; background-color: white; border-radius: 10px;}");
|
||||
|
||||
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
// **应用阴影效果**
|
||||
QGraphicsDropShadowEffect *shadowTable = new QGraphicsDropShadowEffect(this);
|
||||
shadowTable->setBlurRadius(10);
|
||||
|
@ -169,7 +171,7 @@ void CustomDisplayPanel::UpdateData(OpenJson& json)
|
|||
void CustomDisplayPanel::UpdateTemperature(OpenJson &json)
|
||||
{
|
||||
auto& nodeLabel = json["text_panel"];
|
||||
qDebug() << nodeLabel.size();
|
||||
qDebug() << "text_panel: " << nodeLabel.size();
|
||||
for(size_t i=0; i<nodeLabel.size(); i++)
|
||||
{
|
||||
auto& node = nodeLabel[i];
|
||||
|
@ -180,10 +182,32 @@ void CustomDisplayPanel::UpdateTemperature(OpenJson &json)
|
|||
if (i == 0)
|
||||
{
|
||||
if (value == "1")
|
||||
{
|
||||
disp = QString("Online");
|
||||
m_txtLabels[i]->setStyleSheet(
|
||||
"QLabel {"
|
||||
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
|
||||
" font-family: 'Arial';"
|
||||
" font-size: 20px;"
|
||||
" color: #2E86C1;"
|
||||
" font-weight: bold;"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
disp = QString("Offline");
|
||||
|
||||
m_txtLabels[i]->setStyleSheet(
|
||||
"QLabel {"
|
||||
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
|
||||
" font-family: 'Arial';"
|
||||
" font-size: 20px;"
|
||||
" color: #FF0000;"
|
||||
" font-weight: bold;"
|
||||
" font-style: black"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -193,7 +217,7 @@ void CustomDisplayPanel::UpdateTemperature(OpenJson &json)
|
|||
}
|
||||
|
||||
auto& nodeTable = json["table"];
|
||||
qDebug() << nodeTable.size();
|
||||
qDebug() << "table: "<< nodeTable.size();
|
||||
|
||||
m_pTableWidget->clear();
|
||||
m_pTableWidget->setRowCount(nodeTable.size());
|
||||
|
@ -255,6 +279,8 @@ void CustomDisplayPanel::UpdateAlarm(OpenJson &json)
|
|||
|
||||
auto& nodeTable = json["alarm"];
|
||||
qDebug() << nodeTable.size();
|
||||
|
||||
m_pTableWidget->setUpdatesEnabled(false);
|
||||
for(size_t i=0; i<nodeTable.size(); i++)
|
||||
{
|
||||
m_pTableWidget->insertRow(0);
|
||||
|
@ -280,6 +306,22 @@ void CustomDisplayPanel::UpdateAlarm(OpenJson &json)
|
|||
m_pTableWidget->setItem(0, 1, item1);
|
||||
m_pTableWidget->setItem(0, 2, item2);
|
||||
}
|
||||
|
||||
m_pTableWidget->setUpdatesEnabled(true);
|
||||
|
||||
// 自动定位到首行
|
||||
if(m_pTableWidget->rowCount() > 0)
|
||||
{
|
||||
// 创建首行索引
|
||||
QModelIndex firstIndex = m_pTableWidget->model()->index(0, 0);
|
||||
|
||||
// 滚动到首行并置顶
|
||||
m_pTableWidget->scrollTo(firstIndex, QAbstractItemView::PositionAtTop);
|
||||
|
||||
// 选中整行(需提前设置选择模式)
|
||||
m_pTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_pTableWidget->setCurrentIndex(firstIndex);
|
||||
}
|
||||
}
|
||||
|
||||
////////
|
||||
|
|
|
@ -1,67 +1,36 @@
|
|||
;通用设置
|
||||
[version]
|
||||
ver="1_0_0"
|
||||
ver=1_0_0
|
||||
|
||||
[modbus]
|
||||
;1=RTU 0=TCP
|
||||
type=1
|
||||
|
||||
;if type=1, ignore ip and port setting
|
||||
ip="127.0.0.1"
|
||||
ip=127.0.0.1
|
||||
port=502
|
||||
|
||||
com="COM20"
|
||||
com=COM20
|
||||
baund=9600
|
||||
data=8
|
||||
|
||||
;0=None 1=Odd 2=Even
|
||||
parity=0
|
||||
|
||||
stop=1
|
||||
|
||||
[slaves]
|
||||
;如果从机数量多于1,则从机地址slave_id以:分隔(英文冒号)
|
||||
slave_id="1"
|
||||
|
||||
;每一个从机的配置
|
||||
;由两个节组成:slave_%d 和 slave_%d_function_%d
|
||||
slave_id=1
|
||||
|
||||
[slave_1]
|
||||
;支持的功能码数量
|
||||
function_code_counts=2
|
||||
|
||||
[slave_1_function_0]
|
||||
;功能码
|
||||
function_code=3
|
||||
|
||||
;起始地址,10进制
|
||||
start_addr=40000
|
||||
|
||||
;读取数量
|
||||
quantity=9
|
||||
|
||||
;扫描间隔,单位ms
|
||||
interval=1000
|
||||
|
||||
;serial_number与read_quantity的元素数量要一样
|
||||
equipment_code=81
|
||||
serial_number="0:1:2:3:4:5:6:7:8:9:10:11:12:13:14"
|
||||
read_quantity="1:1:1:1:1:1:1:1:1:1:1:1:1:1:1"
|
||||
serial_number=0:1:2:3:4:5:6:7:8:9:10:11:12:13:14
|
||||
read_quantity=1:1:1:1:1:1:1:1:1:1:1:1:1:1:1
|
||||
|
||||
[slave_1_function_1]
|
||||
;功能码
|
||||
function_code=3
|
||||
|
||||
;起始地址,10进制
|
||||
start_addr=40009
|
||||
|
||||
;读取数量
|
||||
quantity=6
|
||||
|
||||
;扫描间隔,单位ms
|
||||
interval=1000
|
||||
|
||||
;serial_number与read_quantity的元素数量要一样
|
||||
equipment_code=81
|
||||
serial_number="0:1:2:3:4:5:6:7:8:9:10:11:12:13:14"
|
||||
read_quantity="1:1:1:1:1:1:1:1:1:1:1:1:1:1:1"
|
||||
serial_number=0:1:2:3:4:5:6:7:8:9:10:11:12:13:14
|
||||
read_quantity=1:1:1:1:1:1:1:1:1:1:1:1:1:1:1
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
{
|
||||
"modbus":
|
||||
{
|
||||
"type":"rs485",
|
||||
"port":"COM1",
|
||||
"baudrate":9600,
|
||||
"parity":"N",
|
||||
"stopbits":1,
|
||||
"data":8,
|
||||
"ip":"127.0.0.1",
|
||||
"ip_port":502
|
||||
},
|
||||
"slaves":[
|
||||
{
|
||||
"id":1,
|
||||
"function_code":3,
|
||||
"address":[
|
||||
{
|
||||
"start_addr":40000,
|
||||
"quantity":9,
|
||||
"bytes_per_register":2,
|
||||
"device_name_chn":"温湿度",
|
||||
"device_name_eng":"Temperature",
|
||||
"device_type":1,
|
||||
"data": [
|
||||
{
|
||||
"comment":"在线状态",
|
||||
"order":0,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"在线状态",
|
||||
"title_eng":"Online",
|
||||
"display":1,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"温度",
|
||||
"order":1,
|
||||
"precision":10,
|
||||
"unit":"℃",
|
||||
"title_chn":"温度",
|
||||
"title_eng":"T (℃) ",
|
||||
"display":1,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"湿度",
|
||||
"order":2,
|
||||
"precision":10,
|
||||
"unit":"%",
|
||||
"title_chn":"湿度",
|
||||
"title_eng":"RH (%)",
|
||||
"display":1 ,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"露点",
|
||||
"order":3,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"露点",
|
||||
"title_eng":"DewPoint",
|
||||
"display":2,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"跳过",
|
||||
"order":4,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"",
|
||||
"title_eng":"",
|
||||
"display":0,
|
||||
"skip":1
|
||||
},
|
||||
{
|
||||
"comment":"跳过",
|
||||
"order":5,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"",
|
||||
"title_eng":"",
|
||||
"display":0,
|
||||
"skip":1
|
||||
},
|
||||
{
|
||||
"comment":"DO",
|
||||
"order":6,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"DO",
|
||||
"title_eng":"DO",
|
||||
"display":2,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"DI1",
|
||||
"order":7,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"DI1",
|
||||
"title_eng":"DI1",
|
||||
"display":2,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"DI2",
|
||||
"order":8,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"DI2",
|
||||
"title_eng":"DI2",
|
||||
"display":2,
|
||||
"skip":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"start_addr":40009,
|
||||
"quantity":6,
|
||||
"bytes_per_register":2,
|
||||
"device_name_chn":"温湿度告警",
|
||||
"device_name_eng":"Alarm",
|
||||
"device_type":6,
|
||||
"data": [
|
||||
{
|
||||
"comment":"温度阈值",
|
||||
"order":0,
|
||||
"precision":10,
|
||||
"unit":"",
|
||||
"title_chn":"温度阈值",
|
||||
"title_eng":"Temp_threshold",
|
||||
"display":0,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"温度偏移",
|
||||
"order":1,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"温度偏移",
|
||||
"title_eng":"Temp_offset",
|
||||
"display":0,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"跳过",
|
||||
"order":2,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"",
|
||||
"title_eng":"",
|
||||
"display":0,
|
||||
"skip":1
|
||||
},
|
||||
{
|
||||
"comment":"高温告警",
|
||||
"order":3,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"高温告警",
|
||||
"title_eng":"High Temp.",
|
||||
"display":1,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"高湿告警",
|
||||
"order":4,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"高湿告警",
|
||||
"title_eng":"High Humidity",
|
||||
"display":1,
|
||||
"skip":0
|
||||
},
|
||||
{
|
||||
"comment":"低温告警",
|
||||
"order":5,
|
||||
"precision":1,
|
||||
"unit":"",
|
||||
"title_chn":"低温告警",
|
||||
"title_eng":"Low Temp.",
|
||||
"display":0,
|
||||
"skip":0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -25,6 +25,10 @@
|
|||
#define TH08D_TEMPERATURE_EQUIPMENT_81_00_09 40000
|
||||
#define TH08D_TEMPERATURE_EQUIPMENT_81_09_06 40009
|
||||
|
||||
void DecodeWorker::setSlaveAddress(const slaveAddress& sa)
|
||||
{
|
||||
m_slaveAddress = sa;
|
||||
}
|
||||
// 处理数组的槽函数
|
||||
void DecodeWorker::processArray(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData)
|
||||
{
|
||||
|
@ -88,6 +92,31 @@ void DecodeWorker::processArray(const QVector<uint16_t>& array,int slave_id,int
|
|||
emit finished();
|
||||
}
|
||||
|
||||
void DecodeWorker::processRegisterData(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;
|
||||
ddi.title = iter->second.title_chn;
|
||||
ddi.unit = iter->second.unit;
|
||||
ddi.value = array[idx];
|
||||
pGeneralData->m_PanelDisplayDataItems.emplace_back(ddi);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
|
@ -153,6 +182,7 @@ void MainWindow::getConfiguration(QString iniFilePath)
|
|||
m_modbus_parity = m_pSettings->value("modbus/parity").toInt();
|
||||
m_modbus_stop = m_pSettings->value("modbus/stop").toInt();
|
||||
|
||||
#if 0
|
||||
m_modbus_slave_id = m_pSettings->value("slaves/slave_id").toInt();
|
||||
|
||||
QString app = QString("slave_%1/function_code_counts").arg(m_modbus_slave_id);
|
||||
|
@ -202,6 +232,61 @@ void MainWindow::getConfiguration(QString iniFilePath)
|
|||
m_SlaveData.push_back(pSlaveData);
|
||||
#endif
|
||||
}
|
||||
#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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::InitializeUI()
|
||||
|
@ -249,10 +334,12 @@ bool MainWindow::InitializeUI()
|
|||
m_pTemperaturePanel->Build();
|
||||
mainLayout->addWidget(m_pTemperaturePanel, 0, 0);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_TEMPERATURE,m_pTemperaturePanel));
|
||||
|
||||
//电源
|
||||
m_pPowerPanel = new CustomDisplayPanel(this);
|
||||
m_pPowerPanel->setImage(":/icons/main_power.png");
|
||||
QStringList l2{QStringList{tr("Online"),tr("Input Voltage"),tr("Output Voltage"),tr("Output Current"),tr("Module Temp.")}};
|
||||
QStringList l2{QStringList{tr("Online"),tr("Vin."),tr("Vout"),tr("Iout"),tr("T_mod")}};
|
||||
m_pPowerPanel->setLableCount(l2.count());
|
||||
m_pPowerPanel->setTableRowsCount(10);
|
||||
m_pPowerPanel->setLables(l2);
|
||||
|
@ -261,10 +348,12 @@ bool MainWindow::InitializeUI()
|
|||
m_pPowerPanel->Build();
|
||||
mainLayout->addWidget(m_pPowerPanel, 0, 1);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_POWER,m_pPowerPanel));
|
||||
|
||||
//电池
|
||||
m_pBatteryPanel = new CustomDisplayPanel(this);
|
||||
m_pBatteryPanel->setImage(":/icons/main_battery.png");
|
||||
QStringList l3{QStringList{tr("Online"),tr("SOC"),tr("SOH"),tr("Group Voltage"),tr("Cell V.Avg"),tr("Cell V.Max"),tr("Cell V.Min")}};
|
||||
QStringList l3{QStringList{tr("Online"),tr("SOC"),tr("SOH"),tr("Vpack")}};
|
||||
m_pBatteryPanel->setLableCount(l3.count());
|
||||
m_pBatteryPanel->setTableRowsCount(10);
|
||||
m_pBatteryPanel->setLables(l3);
|
||||
|
@ -273,6 +362,8 @@ bool MainWindow::InitializeUI()
|
|||
m_pBatteryPanel->Build();
|
||||
mainLayout->addWidget(m_pBatteryPanel, 0, 2);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_BATTERY,m_pBatteryPanel));
|
||||
|
||||
//空调
|
||||
m_pACPanel = new CustomDisplayPanel(this);
|
||||
m_pACPanel->setImage(":/icons/main_ac.png");
|
||||
|
@ -285,10 +376,12 @@ bool MainWindow::InitializeUI()
|
|||
m_pACPanel->Build();
|
||||
mainLayout->addWidget(m_pACPanel, 0, 3);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_AC,m_pACPanel));
|
||||
|
||||
//交流配电
|
||||
m_pInverterPanel = new CustomDisplayPanel(this);
|
||||
m_pInverterPanel->setImage(":/icons/main_invertor.png");
|
||||
QStringList l5{QStringList{tr("Online"),tr("Input Voltage"),tr("Input Current"),tr("Module Temp.")}};
|
||||
QStringList l5{QStringList{tr("Online"),tr("Vin"),tr("Iin"),tr("T_mod")}};
|
||||
m_pInverterPanel->setLableCount(l5.count());
|
||||
m_pInverterPanel->setTableRowsCount(10);
|
||||
m_pInverterPanel->setLables(l5);
|
||||
|
@ -297,10 +390,12 @@ bool MainWindow::InitializeUI()
|
|||
m_pInverterPanel->Build();
|
||||
mainLayout->addWidget(m_pInverterPanel, 1, 0);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_INVERTER,m_pInverterPanel));
|
||||
|
||||
//PV太阳能
|
||||
m_pPVPanel = new CustomDisplayPanel(this);
|
||||
m_pPVPanel->setImage(":/icons/main_pv.png");
|
||||
QStringList l6{QStringList{tr("Online"),tr("Output Voltage"),tr("Output Current"),tr("Module Temp.")}};
|
||||
QStringList l6{QStringList{tr("Online"),tr("Vout"),tr("Iout"),tr("T_mod")}};
|
||||
m_pPVPanel->setLableCount(l6.count());
|
||||
m_pPVPanel->setTableRowsCount(10);
|
||||
m_pPVPanel->setLables(l6);
|
||||
|
@ -309,10 +404,12 @@ bool MainWindow::InitializeUI()
|
|||
m_pPVPanel->Build();
|
||||
mainLayout->addWidget(m_pPVPanel, 1, 1);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_PV,m_pPVPanel));
|
||||
|
||||
//门禁
|
||||
m_pHomePanel = new CustomDisplayPanel(this);
|
||||
m_pHomePanel->setImage(":/icons/main_cab.png");
|
||||
QStringList l7{QStringList{tr("Online"),tr("Output Voltage"),tr("Output Current"),tr("Module Temp.")}};
|
||||
QStringList l7{QStringList{tr("Online"),tr("Vout"),tr("Iout"),tr("T_mod")}};
|
||||
m_pHomePanel->setLableCount(l7.count());
|
||||
m_pHomePanel->setTableRowsCount(10);
|
||||
m_pHomePanel->setLables(l7);
|
||||
|
@ -321,6 +418,8 @@ bool MainWindow::InitializeUI()
|
|||
m_pHomePanel->Build();
|
||||
mainLayout->addWidget(m_pHomePanel, 1, 2);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_HOME,m_pHomePanel));
|
||||
|
||||
//告警
|
||||
m_pAlarmPanel = new CustomWarningPanel(this);
|
||||
m_pAlarmPanel->setImage(":/icons/main_alarm.png");
|
||||
|
@ -334,6 +433,8 @@ bool MainWindow::InitializeUI()
|
|||
m_pAlarmPanel->Build();
|
||||
mainLayout->addWidget(m_pAlarmPanel, 1, 3);
|
||||
|
||||
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_ALARM,m_pAlarmPanel));
|
||||
|
||||
// 设置布局的间距和边距
|
||||
mainLayout->setSpacing(5);
|
||||
//mainLayout->setContentsMargins(10, 40, 10, 10); // 顶部留出工具栏空间
|
||||
|
@ -364,11 +465,7 @@ bool MainWindow::InitializeUI()
|
|||
QPixmap pixmap(":/icons/logo-en.png"); // 替换为实际图片路径
|
||||
logoLabel->setPixmap(pixmap.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
toolBar->addWidget(logoLabel);
|
||||
toolBar->addSeparator();
|
||||
|
||||
//添加按钮
|
||||
toolBar->addAction(actionRead);
|
||||
toolBar->addSeparator();
|
||||
//toolBar->addSeparator();
|
||||
|
||||
// 添加间隔控件
|
||||
QWidget *spacer = new QWidget();
|
||||
|
@ -388,6 +485,7 @@ bool MainWindow::InitializeUI()
|
|||
//customFont.setBold(true);
|
||||
//label->setFont(customFont);
|
||||
//label->setStyleSheet("color: #2E86C1;");
|
||||
|
||||
label->setStyleSheet(
|
||||
"QLabel {"
|
||||
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
|
||||
|
@ -404,6 +502,10 @@ bool MainWindow::InitializeUI()
|
|||
spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
toolBar->addWidget(spacerWidget);
|
||||
|
||||
//添加按钮
|
||||
toolBar->addAction(actionRead);
|
||||
toolBar->addSeparator();
|
||||
|
||||
toolBar->addAction(actionSetting);
|
||||
toolBar->addSeparator();
|
||||
|
||||
|
@ -429,6 +531,9 @@ bool MainWindow::InitializeModbus()
|
|||
|
||||
getConfiguration(iniFilePath);
|
||||
|
||||
QString jsonFilePath = appDir + QString::fromStdString("/emsshower.json");
|
||||
ReadConfiguration(jsonFilePath);
|
||||
|
||||
m_bInitializeModbus = true;
|
||||
switch (m_modbus_type)
|
||||
{
|
||||
|
@ -454,7 +559,7 @@ bool MainWindow::InitializeRtu()
|
|||
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);
|
||||
|
||||
#if 1
|
||||
int slave_id = m_modbus_slave_id;
|
||||
//modbus_set_debug(m_pModbus, true);
|
||||
modbus_set_slave(m_pModbus, slave_id); //设置modbus从机地址
|
||||
|
@ -468,7 +573,7 @@ bool MainWindow::InitializeRtu()
|
|||
t.tv_sec=0;
|
||||
t.tv_usec=1000000; //设置modbus超时时间为1000毫秒
|
||||
modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec);
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -559,6 +664,75 @@ bool MainWindow::readRegister(int addr,int nb,uint16_t* dest)
|
|||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
CreateJson2(pDevice,json);
|
||||
|
||||
m_Panels[iterAddress->device_type]->UpdateData(json);
|
||||
|
||||
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;
|
||||
ddi.title = iter->second.title_en;
|
||||
ddi.unit = iter->second.unit;
|
||||
ddi.value = array[idx];
|
||||
pGeneralData->m_PanelDisplayDataItems.emplace_back(ddi);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::startAsyncProcess(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity, DeviceData* pDevice)
|
||||
{
|
||||
QThread* thread = new QThread;
|
||||
|
@ -595,6 +769,42 @@ void MainWindow::startAsyncProcess(const QVector<uint16_t>& array,int slave_id,i
|
|||
qDebug() << "同步读取完成";
|
||||
}
|
||||
|
||||
void MainWindow::startAsyncProcess2(const QVector<uint16_t> &array, const slaveAddress& sa,DeviceData *pData)
|
||||
{
|
||||
QThread* thread = new QThread;
|
||||
DecodeWorker* worker = new DecodeWorker;
|
||||
worker->moveToThread(thread);
|
||||
|
||||
worker->setSlaveAddress(sa);
|
||||
|
||||
// 连接线程启动信号和槽函数
|
||||
connect(this, &MainWindow::startProcessing2, worker, &DecodeWorker::processRegisterData);
|
||||
|
||||
// 工作完成后退出线程
|
||||
connect(worker, &DecodeWorker::finished, thread, &QThread::quit);
|
||||
connect(worker, &DecodeWorker::finished, worker, &DecodeWorker::deleteLater);
|
||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
|
||||
//// 可选:连接进度信号更新UI
|
||||
//connect(worker, &DecodeWorker::progress, this, [](int index)
|
||||
//{
|
||||
// qDebug() << "进度更新,当前处理到索引:" << index;
|
||||
//});
|
||||
|
||||
thread->start();
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(worker, &DecodeWorker::finished, &loop, &QEventLoop::quit);
|
||||
|
||||
// 发射信号传递参数
|
||||
emit startProcessing2(array,sa, pData);
|
||||
|
||||
// 阻塞,等待线程结束
|
||||
loop.exec();
|
||||
|
||||
qDebug() << "同步读取完成";
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::ReadSerialPortData()
|
||||
{
|
||||
|
@ -608,9 +818,9 @@ void MainWindow::ReadSerialPortData()
|
|||
}
|
||||
else
|
||||
{
|
||||
m_pTimer->setInterval(10000); // 10秒
|
||||
m_pTimer->setInterval(10 * 1000); // 10秒
|
||||
connect(m_pTimer, &QTimer::timeout, this, &MainWindow::onTimeout);
|
||||
ui->statusbar->showMessage(tr("Begin Readding"));
|
||||
ui->statusbar->showMessage(tr("Begin Reading"));
|
||||
m_pTimer->start();
|
||||
onTimeout();
|
||||
}
|
||||
|
@ -618,7 +828,8 @@ void MainWindow::ReadSerialPortData()
|
|||
|
||||
void MainWindow::onTimeout()
|
||||
{
|
||||
readRegister(0,0,0);
|
||||
//readRegister(0,0,0);
|
||||
readRegister();
|
||||
}
|
||||
|
||||
void MainWindow::SettingSerialPort()
|
||||
|
@ -633,6 +844,7 @@ void MainWindow::SettingSerialPort()
|
|||
// QMessageBox::information(this, "Cancel Clicked", "Cancel was clicked!");
|
||||
}
|
||||
|
||||
|
||||
bool MainWindow::CreateJson(DeviceData* pData,OpenJson& json)
|
||||
{
|
||||
int data_type = pData->m_device_type;
|
||||
|
@ -648,10 +860,10 @@ bool MainWindow::CreateJson(DeviceData* pData,OpenJson& json)
|
|||
nodeLabel[0]["title"] = "Online";
|
||||
|
||||
nodeLabel[1]["value"] = pTempData->TempValue;
|
||||
nodeLabel[1]["title"] = "Temp(℃)";
|
||||
nodeLabel[1]["title"] = "T (℃) ";
|
||||
|
||||
nodeLabel[2]["value"] = pTempData->HumidityValue;
|
||||
nodeLabel[2]["title"] = "RH (%) ";
|
||||
nodeLabel[2]["title"] = "RH (%)";
|
||||
|
||||
auto& nodeTable = json["table"];
|
||||
int i = 0;
|
||||
|
@ -720,3 +932,64 @@ bool MainWindow::CreateJson(DeviceData* pData,OpenJson& json)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -42,12 +42,15 @@ public:
|
|||
this->pDevice = pDevice;
|
||||
}
|
||||
|
||||
void setSlaveAddress(const slaveAddress& sa);
|
||||
|
||||
private:
|
||||
QVector<uint16_t> array;
|
||||
int slave_id;
|
||||
int start_addr;
|
||||
int quantity;
|
||||
DeviceData* pDevice;
|
||||
slaveAddress m_slaveAddress;
|
||||
|
||||
signals:
|
||||
// 处理进度信号
|
||||
|
@ -59,6 +62,8 @@ public slots:
|
|||
// 处理数组的槽函数
|
||||
// 根据从机id、开始地址、寄存器数量三个变量进行辨别和解码处理
|
||||
void processArray(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData);
|
||||
|
||||
void processRegisterData(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData);
|
||||
};
|
||||
|
||||
//处理主界面
|
||||
|
@ -72,12 +77,15 @@ public:
|
|||
|
||||
protected:
|
||||
void getConfiguration(QString iniFilePath);
|
||||
void ReadConfiguration(QString jsonFilePath);
|
||||
bool InitializeUI();
|
||||
bool InitializeModbus();
|
||||
bool InitializeRtu();
|
||||
bool InitializeTcp();
|
||||
|
||||
bool readRegister(int addr,int nb,uint16_t* dest);
|
||||
bool readRegister();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
|
@ -99,9 +107,12 @@ protected:
|
|||
QSettings* m_pSettings;
|
||||
bool m_bInitializeModbus;
|
||||
|
||||
SlaveItems m_total_slave_items;
|
||||
|
||||
protected:
|
||||
//异步处理数据
|
||||
void startAsyncProcess(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData);
|
||||
void startAsyncProcess2(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData);
|
||||
|
||||
private slots:
|
||||
void ReadSerialPortData();
|
||||
|
@ -117,9 +128,12 @@ private:
|
|||
CustomDisplayPanel* m_pAlarmPanel; //告警
|
||||
CustomDisplayPanel* m_pInverterPanel; //逆变器
|
||||
CustomDisplayPanel* m_pPVPanel; //太阳能
|
||||
std::map<int,CustomDisplayPanel*> m_Panels;
|
||||
|
||||
private:
|
||||
bool CreateJson(DeviceData* pData,OpenJson& json);
|
||||
bool CreateJson2(DeviceData* pData,OpenJson& json);
|
||||
void DecodeSync(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData); //同步解码
|
||||
|
||||
signals:
|
||||
// 处理进度信号
|
||||
|
@ -129,5 +143,6 @@ signals:
|
|||
|
||||
signals:
|
||||
void startProcessing(const QVector<uint16_t>& array, int slave_id, int start_addr, int quantity, DeviceData* pData);
|
||||
void startProcessing2(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData);
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef SLAVE_DEFINE_H
|
||||
#ifndef SLAVE_DEFINE_H
|
||||
#define SLAVE_DEFINE_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
typedef struct _tagSlave
|
||||
{
|
||||
|
@ -14,6 +16,20 @@ typedef struct _tagSlave
|
|||
|
||||
typedef std::vector<SlaveItem*> SlaveData;
|
||||
|
||||
//存储解码后的数据
|
||||
typedef struct __DisplayDataItem
|
||||
{
|
||||
int device_type;
|
||||
int order;
|
||||
std::string title;
|
||||
int precision;
|
||||
int value;
|
||||
std::string unit;
|
||||
int display_location; //1:board 2:table
|
||||
} DisplayDataItem;
|
||||
|
||||
typedef std::vector<DisplayDataItem> DisplayDataItems;
|
||||
|
||||
class DeviceData
|
||||
{
|
||||
public:
|
||||
|
@ -29,6 +45,19 @@ public:
|
|||
int m_device_online_state;
|
||||
};
|
||||
|
||||
class GeneralDeviceData: public DeviceData
|
||||
{
|
||||
public:
|
||||
GeneralDeviceData()
|
||||
{
|
||||
m_device_type = 8899;
|
||||
m_device_online_state = 0;
|
||||
}
|
||||
virtual ~GeneralDeviceData() {}
|
||||
|
||||
public:
|
||||
DisplayDataItems m_PanelDisplayDataItems;
|
||||
};
|
||||
|
||||
class TemperatureData : public DeviceData
|
||||
{
|
||||
|
@ -43,8 +72,8 @@ public:
|
|||
virtual ~TemperatureData() {}
|
||||
|
||||
public:
|
||||
bool bDecodeAlarm;
|
||||
bool bDecodeTemp;
|
||||
bool bDecodeAlarm;
|
||||
bool bDecodeTemp;
|
||||
float TempValue;
|
||||
float HumidityValue;
|
||||
float DewPointValue;
|
||||
|
@ -56,4 +85,79 @@ public:
|
|||
int TempLowAlarm;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 以下数据结构是为了存取json配置文件设置 //
|
||||
// 保存串口的从机号、寄存器开始地址、数量、寄存器数据描述等等信息 //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
/****************************************************************
|
||||
* 逻辑结构
|
||||
*
|
||||
SlaveItems 定义有多少个从机
|
||||
slaveAddress 定义每一个从机有多少要读取的地址,每一个起始地址并不保证连续
|
||||
registryData 定义每一个起始地址需要读取的数据
|
||||
*
|
||||
*
|
||||
*****************************************************************/
|
||||
|
||||
//寄存器的数据,以及控制策略描述
|
||||
typedef struct __registryData
|
||||
{
|
||||
__registryData():
|
||||
comment(""), precision(1.0f), unit(""), title_chn("中文"), title_en("eng"), display(1), skip(0)
|
||||
{}
|
||||
|
||||
std::string comment; // ":"在线状态", 注释字段,为了方便读,无实际意义
|
||||
int order; // 定义解码的顺序,从0开始,数量 =slaveAddress.quantity,
|
||||
float precision; // " : 1, 精度,标注小数点用
|
||||
std::string unit; // " : "", 单位
|
||||
std::string title_chn; // " : 中文显示
|
||||
std::string title_en; // " : 英文显示
|
||||
int display; // " : 1, 是否显示,0不显示,1显示在board,2显示在表格
|
||||
int skip; //" : 0 //1跳过 0不跳过
|
||||
} registryData;
|
||||
|
||||
//寄存器的数据数组
|
||||
typedef std::map<int,registryData> RegisterDataItems;
|
||||
|
||||
typedef struct __slaveAddress
|
||||
{
|
||||
int start_addr; // ":40000, 寄存器地址
|
||||
unsigned short quantity; // " : 9, 连续读取多少个寄存器
|
||||
unsigned short bytes_per_register; // " : 2, 每个寄存器的字节数,缺省是uint16,两个字节
|
||||
std::string device_name_chn; // " : "温湿度", 该寄存器数组代表的设备名称
|
||||
std::string device_name_eng; // " : "温湿度", 该寄存器数组代表的设备名称,英文
|
||||
|
||||
//标识本地址的数据是哪一个类型的设备
|
||||
/*
|
||||
PANEL_TEMPERATURE = 1,
|
||||
PANEL_BATTERY = 2,
|
||||
PANEL_POWER = 3,
|
||||
PANEL_AC = 4,
|
||||
PANEL_PV = 5,
|
||||
PANEL_ALARM = 6,
|
||||
PANEL_INVERTER = 7,
|
||||
PANEL_OTHER = 88,
|
||||
PANEL_HOME = 99,
|
||||
* */
|
||||
int device_type;
|
||||
|
||||
RegisterDataItems register_data_items; //寄存器数据,数组
|
||||
} slaveAddress;
|
||||
|
||||
//需要读取的从机的地址信息
|
||||
typedef std::vector<slaveAddress> SlaveAddressItems;
|
||||
|
||||
typedef struct __slaveItem
|
||||
{
|
||||
int slave_id; //从机ID
|
||||
int function_code; //功能码,缺省是3
|
||||
SlaveAddressItems slave_address_items; //该从机ID需要读取的地址信息描述
|
||||
} slaveItem;
|
||||
|
||||
//需要处理的从机列表
|
||||
typedef std::vector<slaveItem> SlaveItems;
|
||||
|
||||
|
||||
#endif // SLAVE_DEFINE_H
|
||||
|
|
Loading…
Reference in New Issue