实现QT6启动器,QT版本有qt5升级到qt6

This commit is contained in:
lixiaoyuan
2025-09-10 20:10:51 +08:00
parent 3d03bbe9b5
commit e822d57b67
188 changed files with 1376 additions and 219 deletions

View File

@@ -36,19 +36,19 @@ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG")
add_definitions(-DWIN32_LEAN_AND_MEAN)
# Qt_PATH 为 Qt 的安装地址
set(QT_PATH "D:/Programs/Qt5/5.15.2/msvc2019_64")
#set(QT_PATH "D:/Programs/Qt5/5.15.2/msvc2019_64")
set(QT_PATH "D:/Programs/Qt6/6.7.3/msvc2019_64")
set(CMAKE_PREFIX_PATH ${QT_PATH}/lib/cmake)
# 开启自动编译
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 COMPONENTS
find_package(Qt6 COMPONENTS
Core
Gui
Widgets
AxContainer
Network
SerialBus
SerialPort
Charts
WebEngineWidgets
REQUIRED)
@@ -56,7 +56,7 @@ REQUIRED)
set(ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set(THIRDPARTY_PATH ${ROOT_PATH}/../thirdparty)
set(PVLIBS_PATH ${ROOT_PATH}/../libs/pvb)
#set(PVLIBS_PATH ${ROOT_PATH}/../libs/pvb)
include_directories(
${ROOT_PATH}
@@ -69,8 +69,8 @@ include_directories(
${THIRDPARTY_PATH}/cpp-httplib-0.25.0
${THIRDPARTY_PATH}/paho_mqtt/include
${THIRDPARTY_PATH}/spdlog-1.13.0/include
${PVLIBS_PATH}/include/pvserver
${PVLIBS_PATH}/include/rllib
#${PVLIBS_PATH}/include/pvserver
#${PVLIBS_PATH}/include/rllib
)
# 设置编译源文件
@@ -81,8 +81,8 @@ ADD_SOURCE_GROUP(database)
ADD_SOURCE_GROUP(protocol)
#ADD_SOURCE_GROUP(widgets)
#ADD_SOURCE_GROUP(widgets/pages)
ADD_SOURCE_GROUP(pv)
ADD_SOURCE_GROUP(pv/pages)
#ADD_SOURCE_GROUP(pv)
#ADD_SOURCE_GROUP(pv/pages)
ADD_SOURCE_GROUP(qt)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
@@ -91,13 +91,12 @@ add_executable(${PROJECT_NAME} ${SOURCE_FILE} "resource.rc")
#set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
target_link_libraries(${PROJECT_NAME}
Qt5::Widgets
Qt5::AxContainer
Qt5::Network
Qt5::SerialBus
Qt5::SerialPort
Qt5::Charts
Qt5::WebEngineWidgets
Qt6::Core
Qt6::Gui
Qt6::Widgets
Qt6::Network
Qt6::Charts
Qt6::WebEngineWidgets
)
target_link_libraries(${PROJECT_NAME}
@@ -105,7 +104,7 @@ target_link_libraries(${PROJECT_NAME}
${THIRDPARTY_PATH}/mysql/lib/x64/libmysql.lib
${THIRDPARTY_PATH}/paho_mqtt/lib/paho-mqtt3a.lib
${THIRDPARTY_PATH}/paho_mqtt/lib/paho-mqtt3c.lib
${PVLIBS_PATH}/x64/serverlib.lib
${PVLIBS_PATH}/x64/rllib.lib
#${PVLIBS_PATH}/x64/serverlib.lib
#${PVLIBS_PATH}/x64/rllib.lib
)

View File

@@ -33,8 +33,6 @@ std::string ElectPeriod::dump()
}
void AppData::initFromDB()
{
auto dao = DaoEntity::create("");
@@ -250,10 +248,16 @@ void AppData::init()
for (auto& item : mapStation)
{
auto& station = item.second;
// "tcp://localhost:1883"
station->mqttCli->init(optionMqtt.host, station->code, optionMqtt.username, optionMqtt.password);
if (station->status == 1)
{
// "tcp://localhost:1883"
station->mqttCli->init(optionMqtt.host, station->code, optionMqtt.username, optionMqtt.password);
}
}
}
this->launchDate = Config::option.lunchDate;
}
std::shared_ptr<Station> AppData::getStation(int stationId)

View File

@@ -109,7 +109,7 @@ public:
public:
///////////////////////////////////////////////////////////////////////////////////////////////
// === 系统 ===
int64_t sysActivationTime {};
std::string launchDate;
///////////////////////////////////////////////////////////////////////////////////////////////
// === 数据库 ===

View File

@@ -117,7 +117,8 @@ void Application::runThreadStat()
int64_t delta = tTime-tDate;
int n = delta / 600;
int offset = delta % 600;
if (delta >=0 && delta < 86400 && offset <= 10 && n != nCachePos)
bool flagStore = (delta >=0 && delta < 86400 && offset <= 10 && n != nCachePos);
if (flagStore)
{
nCachePos = n;
std::string dt = Utils::dateStr(tDate);
@@ -128,7 +129,7 @@ void Application::runThreadStat()
}
else
{
spdlog::info("保存历史数据倒计时: {}", 600 - offset);
//spdlog::info("保存历史数据倒计时: {}", 600 - offset);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

View File

@@ -22,11 +22,11 @@ bool Config::init(std::string filename)
if (jsonroot.contains("database"))
{
njson json = jsonroot.at("database");
option.database.host = json.contains("host") ? json.at("host") : "";
option.database.port = json.contains("port") ? json.at("port") : 0;
option.database.user = json.contains("user") ? json.at("user") : "";
option.database.passwd = json.contains("passwd") ? json.at("passwd") : "";
option.database.dbname = json.contains("dbname") ? json.at("dbname") : "";
JSON::read(json, "host", option.database.host);
JSON::read(json, "port", option.database.port);
JSON::read(json, "user", option.database.user);
JSON::read(json, "passwd", option.database.passwd);
JSON::read(json, "dbname", option.database.dbname);
spdlog::info("[config] parse database success. host={}", option.database.host);
}
@@ -60,10 +60,8 @@ bool Config::init(std::string filename)
spdlog::info("[config] parse mqtt failed: not found.");
}
if (jsonroot.contains("weburl"))
{
JSON::read(jsonroot, "weburl", option.webSrvUrl);
}
JSON::read(jsonroot, "weburl", option.webSrvUrl);
JSON::read(jsonroot, "launchdate", option.lunchDate);
return true;
}

View File

@@ -27,6 +27,7 @@ struct AppOption
} mqtt;
std::string webSrvUrl;
std::string lunchDate;
};

View File

@@ -182,9 +182,49 @@ void Device::storeDB(int npos)
{
}
void Device::setParam(std::string k, std::string v)
{
mapParams[k] = v;
if (type == 3 ) // 电表
{
if (k == "") this->err = Utils::toInt(v);
}
else if (type == 101) // EMS
{
}
else if (type == 102) // PCS
{
if (k == "0x1003") err = Utils::toInt(v); // 故障状态 R uint16 1故障0正常 0 0x1003
if (k == "0x1005") online = Utils::toInt(v); // 设备在线 R uint16 1在线0无效 1 0x1005
if (k == "0x1009") running = (v=="1" || v=="2"); //充放状态 R uint16 0待机, 1充电, 2放电, 3搁置 0 0x1009
}
else if (type == 103) // PCU
{
if (k == "0x1002") err = Utils::toInt(v); //故障状态 R uint16 1故障0正常 0 0x1002
if (k == "0x1004") online = Utils::toInt(v); //设备在线 R uint16 1在线0无效 1 0x1004
if (k == "0x1006") running = Utils::toInt(v); //启停状态 R uint16 1开机0关机 1 0x1006
}
else if (type == 104) // BMS
{
if (k == "0x004A") { err = (v=="1"); online = 1; } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x004A
if (k == "0x004B") running = (v=="1" || v=="2"); //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004B
}
else if (type == 105) // BCU
{
if (k == "0xA003") running = (v=="51" || v=="68"); //蓄电池充放电状态 R uint16 "0x11开路,0x22待机,0x33充电,0x44放电" 34 0xA003
if (k == "0xA004") err = (v=="85"); online=1; //电池组运行状态 R uint16 "0x11跳机,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" 102 0xA004
}
else if (type == 106) // 充电桩
{
}
else if (type == 109) // 光伏板
{
}
}
std::string Device::getParam(std::string k, std::string defaultVal)
@@ -197,6 +237,7 @@ std::string Device::getParam(std::string k, std::string defaultVal)
return defaultVal;
}
void Device::getRuntimeParams(std::vector<std::pair<std::string, std::string>>& params)
{
// 3 电表
@@ -208,35 +249,70 @@ void Device::getRuntimeParams(std::vector<std::pair<std::string, std::string>>&
// 106 充电桩
// 109 光伏板
if (this->type == 3)
{
params.push_back({"A相电压", getParam("0x000B", "0.0") + "V"});
params.push_back({"B相电", getParam("0x000D", "0.0") + "V"});
params.push_back({"C相电压", getParam("0x000F", "0.0") + "V"});
params.push_back({"A相电流", getParam("0x0011", "0.0") + "A"});
params.push_back({"B相电", getParam("0x0013", "0.0") + "A"});
params.push_back({"C相电流", getParam("0x0015", "0.0") + "A"});
params.push_back({"A相电压", getParam("0x000B", "0.0") + " V"});
params.push_back({"A相电", getParam("0x000D", "0.0") + " A"});
params.push_back({"B相电压", getParam("0x000F", "0.0") + " V"});
params.push_back({"B相电流", getParam("0x0011", "0.0") + " A"});
params.push_back({"C相电", getParam("0x0013", "0.0") + " V"});
params.push_back({"C相电流", getParam("0x0015", "0.0") + " A"});
}
else if (this->type == 101)
else if (this->type == 101) // EMS
{
params.push_back({"额定电压", getParam("0x0001", "0.0") + "V"});
params.push_back({"实时电压", getParam("0x0001", "0.0") + "V"});
params.push_back({"额定电流", getParam("0x0001", "0.0") + "A"});
params.push_back({"实时电流", getParam("0x0001", "0.0") + "A"});
params.push_back({"额定功率", getParam("0x0001", "0.0") + "kW"});
params.push_back({"实时功率", getParam("0x0001", "0.0") + "A"});
params.push_back({"A相电压", getParam("0x107E", "0.0") + " V"});
params.push_back({"A相电流", getParam("0x1084", "0.0") + " A"});
params.push_back({"B相电压", getParam("0x1080", "0.0") + " V"});
params.push_back({"B相电流", getParam("0x1086", "0.0") + " A"});
params.push_back({"C相电压", getParam("0x1082", "0.0") + " V"});
params.push_back({"C相电流", getParam("0x1088", "0.0") + " A"});
}
else if (this->type == 102) // PCS
{
params.push_back({"A相电压", getParam("0x0010", "0.0") + " V"});
params.push_back({"A相电流", getParam("0x0019", "0.0") + " A"});
params.push_back({"B相电压", getParam("0x0011", "0.0") + " V"});
params.push_back({"B相电流", getParam("0x001A", "0.0") + " A"});
params.push_back({"C相电压", getParam("0x0011", "0.0") + " V"});
params.push_back({"C相电流", getParam("0x001B", "0.0") + " A"});
}
else if (this->type == 103) // PCU
{
params.push_back({"A相电压", getParam("0x0013", "0.0") + " V"});
params.push_back({"A相电流", getParam("0x001C", "0.0") + " A"});
params.push_back({"B相电压", getParam("0x0014", "0.0") + " V"});
params.push_back({"B相电流", getParam("0x001D", "0.0") + " A"});
params.push_back({"C相电压", getParam("0x0015", "0.0") + " V"});
params.push_back({"C相电流", getParam("0x001E", "0.0") + " A"});
}
else if (this->type == 104) // BMS
{
params.push_back({"SOC", getParam("0x0001", "0") + " %"});
params.push_back({"SOH", getParam("0x0002", "0") + " %"});
params.push_back({"电压", getParam("0x0003", "0.0") + " V"});
params.push_back({"电流", getParam("0x0005", "0.0") + " A"});
params.push_back({"单体最大电压", getParam("0x0021", "0.0") + " V"});
params.push_back({"单体最小电压", getParam("0x0024", "0.0") + " V"});
params.push_back({"单体最大温度", getParam("0x0029", "0.0") + ""});
params.push_back({"单体最小温度", getParam("0x002C", "0.0") + ""});
}
else if (this->type == 105) // BCU
{
params.push_back({"簇电压", getParam("0x0003", "0.0") + " V"});
params.push_back({"簇电流", getParam("0x0005", "0") + " A"});
params.push_back({"簇温度", getParam("0x0007", "0.0") + ""});
params.push_back({"簇电阻", getParam("0x0009", "0.0") + " Ω"});
params.push_back({"簇SOC", getParam("0x000B", "0") + " %"});
params.push_back({"簇SOH", getParam("0x000C", "0") + " %"});
}
//else if (this->type == 101)
//{
//}
else
{
params.push_back({"额定电压", getParam("0x0001", "0.0") + "V"});
params.push_back({"实时电压", getParam("0x0001", "0.0") + "V"});
params.push_back({"额定电流", getParam("0x0001", "0.0") + "A"});
params.push_back({"实时电流", getParam("0x0001", "0.0") + "A"});
params.push_back({"额定功率", getParam("0x0001", "0.0") + "kW"});
params.push_back({"实时功率", getParam("0x0001", "0.0") + "A"});
params.push_back({"额定电压", getParam("0x0001", "0.0") + " V"});
params.push_back({"实时电压", getParam("0x0001", "0.0") + " V"});
params.push_back({"额定电流", getParam("0x0001", "0.0") + " A"});
params.push_back({"实时电流", getParam("0x0001", "0.0") + " A"});
params.push_back({"额定功率", getParam("0x0001", "0.0") + " W"});
params.push_back({"实时功率", getParam("0x0001", "0.0") + " W"});
}
}

View File

@@ -38,6 +38,7 @@ void Station::setFields(Fields& fields)
this->energyCapacity = fields.get<double>(DMStation::CAPACITY);
this->workModeId = fields.get<int>(DMStation::WORK_MODE);
this->code = fields.value(DMStation::CODE);
this->status = fields.get<int>(DMStation::STATUS);
}
void Station::addDevice(int deviceId, std::shared_ptr<Device> device)

View File

@@ -113,6 +113,7 @@ public:
int stationId {};
std::string name;
std::string code;
int status {0};
bool isConnected {false};
int workModeId {}; // 运行模式

View File

@@ -1,6 +1,12 @@
#include "JsonN.h"
#include "common/Utils.h"
static std::string JsonValueToStr(njson& json)
{
}
bool JSON::load(std::string jsonfile, njson& json)
{
std::ifstream ifs(jsonfile);
@@ -65,4 +71,25 @@ void JSON::parse(std::string jsonstr, std::vector<std::string>& vd)
{
vd = jsonroot.get<std::vector<std::string>>();
}
}
std::string JSON::toStr(njson& json)
{
std::string v;
switch (json.type())
{
case njson::value_t::string: { v = json.get<std::string>(); } break;
case njson::value_t::boolean: { v = Utils::toStr(json.get<bool>()); } break;
case njson::value_t::number_integer: { v = Utils::toStr(json.get<int>()); } break;
case njson::value_t::number_unsigned: { v = Utils::toStr(json.get<int>()); } break;
case njson::value_t::number_float: { v = Utils::toStr(json.get<float>()); } break;
case njson::value_t::null: {} { v = "null"; } break;
case njson::value_t::object: {} break;
case njson::value_t::array: {} break;
case njson::value_t::binary: {} break;
case njson::value_t::discarded: {} break;
default:
break;
}
return v;
}

View File

@@ -57,10 +57,18 @@ public:
static bool parse(std::string jsonstr, njson& json);
template <typename T>
static void read(njson& json, std::string k, T& v)
static bool read(njson& json, std::string k, T& v)
{
try { if (json.contains(k)) { v = json.at(k).get<T>(); } }
try
{
if (json.contains(k))
{
v = json.at(k).get<T>();
return true;
}
}
catch (const nlohmann::detail::exception& e) { Spdlogger::info("JSON read error: k={}, err={}", k, e.what()); }
return false;
}
template <typename T>
@@ -84,6 +92,8 @@ public:
static std::string readStr(njson& json, std::string k);
static void parse(std::string jsonstr, std::vector<std::string>& vd);
static std::string toStr(njson& json);
};

View File

@@ -30,7 +30,7 @@ void Spdlogger::init(spdlog::level::level_enum log_level, std::string filename)
//fileSink->set_pattern("[%T] [%l] %v"); // 设置日志格式
// 每日文件sink可选每天生成新文件
auto dailySink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/mcs.log", 0, 0);
auto dailySink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/ess.log", 0, 0);
dailySink->set_level(spdlog::level::debug);
//dailySink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");

View File

@@ -75,8 +75,8 @@ public:
static unsigned short crc16(unsigned char* data, unsigned int len);
static string Utils::gbkToUtf8(string s);
static string Utils::utf8ToGbk(string s);
static string gbkToUtf8(string s);
static string utf8ToGbk(string s);
static void sleep_ms(int ms);

View File

@@ -15,10 +15,7 @@
#include "widgets/MainWindow.h"
#include "pv/PvApp.h"
#include "pv/PvUser.h"
#include "rlsocket.h"
#include "common/Spdlogger.h"
#include "database/DaoEntity.h"
@@ -32,25 +29,25 @@
#include "qt/MainWeb.h"
#define wsa rlwsa
void rlSocketTest()
{
rlwsa();
rlSocket socket("127.0.0.1", 19801, 1);
int ret = socket.connect();
std::string s1 = "helloworld";
socket.write(s1.c_str(), s1.size());
std::vector<char> buf(1024, 0);
while (true)
{
int len = socket.read(&buf[0], 1, 0);
if (len > 0)
{
std::cout << "===>>> " << std::string(buf.begin(), buf.end());
}
}
}
//#define wsa rlwsa
//void rlSocketTest()
//{
// rlwsa();
// rlSocket socket("127.0.0.1", 19801, 1);
// int ret = socket.connect();
// std::string s1 = "helloworld";
// socket.write(s1.c_str(), s1.size());
//
// std::vector<char> buf(1024, 0);
// while (true)
// {
// int len = socket.read(&buf[0], 1, 0);
// if (len > 0)
// {
// std::cout << "===>>> " << std::string(buf.begin(), buf.end());
// }
// }
//}
void memberJsonTest()
{
@@ -142,27 +139,42 @@ int main(int argc, char** argv)
Application::instance().init();
// 启动 PV 服务主线程
std::thread([=]()
{
// 运行pv主流程
PARAM p;
int s;
pvInit(argc, argv, &p);
/* here you may interpret ac,av and set p->user to your data */
while (1)
{
s = pvAccept(&p);
if (s != -1) pvCreateThread(&p, s);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}).detach();
//std::thread([=]()
// {
// // 运行pv主流程
// PARAM p;
// int s;
// pvInit(argc, argv, &p);
// /* here you may interpret ac,av and set p->user to your data */
// while (1)
// {
// s = pvAccept(&p);
// if (s != -1) pvCreateThread(&p, s);
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
// }
// }).detach();
QApplication qapp(argc, argv);
qapp.setWindowIcon(QIcon("./yhicon.ico"));
MainWeb mainWin;
mainWin.show();
qapp.exec();
//QApplication a(argc, argv);
//QMainWindow w;
//QWebEngineView webView(&w);
//webView.load(QUrl("http://127.0.0.1:19600/"));
//w.setCentralWidget(&webView);
//w.setWindowTitle("Qt 6.7 WebEngine Demo");
//w.resize(1280, 720);
//w.show();
//webView.show();
//a.exec();
// 运行QT主窗口
//QApplication qapp(argc, argv);
//MainWindow mainWin;

View File

@@ -166,8 +166,8 @@ static std::map<std::string, HandlerOptions> g_mapHttpHandlerGet =
{"/queryStatSystem", HandlerOptions(&HttpEntity::queryStatSystem, {})},
{"/queryStatTotal", HandlerOptions(&HttpEntity::queryStatTotal, {})},
{"/queryStatStation", HandlerOptions(&HttpEntity::queryStatStation, {})},
{"/queryStatDayList", HandlerOptions(&HttpEntity::queryStatDayList, {})},
{"/queryStatCharts", HandlerOptions(&HttpEntity::queryStatCharts, {})},
{"/queryEnvironment", HandlerOptions(&HttpEntity::queryEnvironment, { "station_id"})},
@@ -300,6 +300,7 @@ Errcode HttpEntity::login(const httplib::Request& req, njson& json, std::string&
if (err == Errcode::OK)
{
json["token"] = token;
json["account"] = account;
std::vector<Fields> vecPermission;
int roleId = fields.get<int>(DMRole::ROLE_ID);
@@ -606,7 +607,7 @@ Errcode HttpEntity::queryStationOverview(const httplib::Request& req, njson& jso
{
return Errcode(ret);
}
njson jsonStorage = njson::parse(R"({"category":1, "count":0, "power":0.0})");
njson jsonStorage = njson::parse(R"({"category":1, "gateway":0, "count":0, "power":0.0})");
njson jsonCharge = njson::parse(R"({"category":2, "count":0, "power":0.0})");
njson jsonSolar = njson::parse(R"({"category":3, "count":0, "power":0.0})");
njson jsonSecurity = njson::parse(R"({"category":4, "count":0, "power":0.0})");
@@ -906,7 +907,7 @@ Errcode HttpEntity::queryStatSystem(const httplib::Request& req, njson& json, st
auto& appdata = Application::data();
njson jsondata;
jsondata["launch_date"] = "2025-01-01"; //: 系统上线启用日期格式yyyy-mm-dd
jsondata["launch_date"] = appdata.launchDate; //: 系统上线启用日期格式yyyy-mm-dd
jsondata["income_total"] = std::to_string(Utils::random(100, 200)); // : 累计收益精度0.01
jsondata["station_num"] = Utils::toStr(appdata.getStationCount()); // : 能源站数量
jsondata["storage_device_num "] = Utils::toStr(appdata.getStationCount()); //: 储能设备数量
@@ -924,49 +925,31 @@ Errcode HttpEntity::queryStatTotal(const httplib::Request& req, njson& json, std
{
std::string station_id = req.get_param_value("station_id");
std::string category = req.get_param_value("category");
njson jsondata;
jsondata["station_id"] = "1";
jsondata["launch_date"] = "2025-01-01"; //场站上线日期
jsondata["usage_rate"] = "12";
jsondata["storage_elect_in"] = "123.123"; //储能充电电量kWh精度0.001
jsondata["storage_elect_out"] = "123.123"; //储能放电电量kWh精度0.001
jsondata["storage_num_in"] = "1"; //储能设备充电次数
jsondata["storage_num_out"] = "1"; //储能设备放电次数
jsondata["storage_num_err"] = "1"; //储能设备故障次数
jsondata["solar_elect_gen"] = "123.123"; //光伏发电电量kWh精度0.001
jsondata["solar_elect_grid"] = "123.123"; //光伏入网电量kWh精度0.001
jsondata["solar_num_err"] = "1"; //光伏设备故障次数
jsondata["charge_elect"] = "123.123"; //充电设备充电电量kWh精度0.001
jsondata["charge_num"] = "1"; //充电设备充电次数
jsondata["charge_num_err"] = "1"; //充电设备故障次数
jsondata["income_elect"] = "123.123"; //发电收益(元精度0.01
jsondata["income_charge"] = "123.123"; //充电收益精度0.01
auto station = Application::data().getStation(Utils::toInt(station_id));
if (station)
{
jsondata["station_id"] = station_id;
jsondata["launch_date"] = "2025-09-01"; //场站上线日期
jsondata["usage_rate"] = "12";
jsondata["storage_elect_in"] = "123.123"; //储能充电电量kWh精度0.001
jsondata["storage_elect_out"] = "123.123"; //储能放电电量kWh精度0.001
jsondata["storage_num_in"] = "1"; //储能设备充电次数
jsondata["storage_num_out"] = "1"; //储能设备放电次数
jsondata["storage_num_err"] = "1"; //储能设备故障次数
jsondata["solar_elect_gen"] = "123.123"; //光伏发电电量kWh精度0.001
jsondata["solar_elect_grid"] = "123.123"; //光伏入网电量kWh精度0.001
jsondata["solar_num_err"] = "1"; //光伏设备故障次数
jsondata["charge_elect"] = "123.123"; //充电设备充电电量kWh精度0.001
jsondata["charge_num"] = "1"; //充电设备充电次数
jsondata["charge_num_err"] = "1"; //充电设备故障次数
jsondata["income_elect"] = "123.123"; //发电收益精度0.01
jsondata["income_charge"] = "123.123"; //充电收益精度0.01
json["data"] = jsondata;
return Errcode::OK;
}
Errcode HttpEntity::queryStatStation(const httplib::Request& req, njson& json, std::string& errmsg)
{
std::string station_id = req.get_param_value("station_id");
std::string category = req.get_param_value("category");
njson jsondata;
jsondata["station_id"] = "1";
jsondata["launch_date"] = "2025-01-01"; //场站上线日期
jsondata["usage_rate"] = "12";
jsondata["storage_elect_in"] = "123.123"; //储能充电电量kWh精度0.001
jsondata["storage_elect_out"] = "123.123"; //储能放电电量kWh精度0.001
jsondata["storage_num_in"] = "1"; //储能设备充电次数
jsondata["storage_num_out"] = "1"; //储能设备放电次数
jsondata["storage_num_err"] = "1"; //储能设备故障次数
jsondata["solar_elect_gen"] = "123.123"; //光伏发电电量kWh精度0.001
jsondata["solar_elect_grid"] = "123.123"; //光伏入网电量kWh精度0.001
jsondata["solar_num_err"] = "1"; //光伏设备故障次数
jsondata["charge_elect"] = "123.123"; //充电设备充电电量kWh精度0.001
jsondata["charge_num"] = "1"; //充电设备充电次数
jsondata["charge_num_err"] = "1"; //充电设备故障次数
jsondata["income_elect"] = "123.123"; //发电收益精度0.01
jsondata["income_charge"] = "123.123"; //充电收益精度0.01
}
json["data"] = jsondata;
return Errcode::OK;
@@ -1010,6 +993,65 @@ Errcode HttpEntity::queryStatDayList(const httplib::Request& req, njson& json, s
return Errcode::OK;
}
Errcode HttpEntity::queryStatCharts(const httplib::Request& req, njson& json, std::string& errmsg)
{
std::string dt = req.get_param_value("dt");
std::string stationId = req.get_param_value("station_id");
std::string category = req.get_param_value("category");
if (dt.empty()) { errmsg = "参数[dt]错误"; return Errcode::ERR_PARAM; }
if (stationId.empty()) { errmsg = "参数[station_id]错误"; return Errcode::ERR_PARAM; }
if (category.empty()) { errmsg = "参数[category]错误"; return Errcode::ERR_PARAM; }
njson jsondata;
std::string sql = R"(SELECT hd.*, d.`type` device_type, ddt.category FROM history_day hd
LEFT JOIN device d ON d.device_id = hd.device_id
LEFT JOIN def_device_type ddt ON d.`type` = ddt.device_type_id
WHERE dt=')" + dt + "' AND d.station_id='" + stationId + "' AND ddt.category='" + category + "';";
std::vector<Fields> result;
int ret = DaoEntity::execOnce(sql, result);
if (ret != 0)
{
return Errcode(ret);
}
std::vector<double> vecV;
std::vector<double> vecI;
std::vector<double> vecP;
for (auto fields : result)
{
int datetype = fields.get<int>("datatype"); // 1: 电压2电流3功率
std::string val = fields.value("value"); // JSON 数组(double)
njson jsonval;
if (JSON::parse(val, jsonval))
{
for (int i = 0; i<jsonval.size(); ++i)
{
double val = jsonval[i];
if (datetype == 1)
{
// 电压取最大
i >= vecV.size() ? vecV.push_back(val) : (val > vecV[i] ? (vecV[i] = val, (void)0) : (void)0);
}
else if (datetype == 2)
{
// 电流取最大
i >= vecI.size() ? vecI.push_back(val) : (val > vecI[i] ? (vecI[i] = val, (void)0) : (void)0);
}
else if (datetype == 3)
{
// 功率累加
i >= vecP.size() ? vecP.push_back(val) : (vecP[i] = vecP[i] + val, (void)0);
}
}
}
}
json["data"] = {{"V", vecV}, {"I", vecI}, {"P", vecP}};
return Errcode::OK;
}
Errcode HttpEntity::queryEnvironment(const httplib::Request& req, njson& json, std::string& errmsg)
{
std::string stationId = req.get_param_value("station_id");
@@ -1098,7 +1140,6 @@ Errcode HttpEntity::queryEnvironment(const httplib::Request& req, njson& json, s
return Errcode::OK;
}
Errcode HttpEntity::queryServiceApiList(const httplib::Request& req, njson& json, std::string& errmsg)
{
PageInfo pageinfo;

View File

@@ -80,13 +80,17 @@ public:
Errcode queryPredictionDetail(const httplib::Request& req, njson& json, std::string& errmsg);
// 系统总览所有场站统计
Errcode queryStatSystem(const httplib::Request& req, njson& json, std::string& errmsg);
// 一个场站的累计统计
Errcode queryStatTotal(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode queryStatStation(const httplib::Request& req, njson& json, std::string& errmsg);
// 场站按类别按天统计
Errcode queryStatDayList(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode queryEnvironment(const httplib::Request& req, njson& json, std::string& errmsg);
// 场站按类某一天的历史曲线数据
Errcode queryStatCharts(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode queryEnvironment(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode queryServiceApiList(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode insertServiceApi(const httplib::Request& req, njson& json, std::string& errmsg);

View File

@@ -52,25 +52,30 @@ void MqttClient::loadDataStruct(std::string filename)
}
}
}
//
int MqttClient::init(string addr, string clientId, string username, string password)
{
this->addr = addr;
this->clientId = clientId;
this->vecTopic = {
"up/json/" + clientId + "/EMS_YX",
"up/json/" + clientId + "/EMS_YC",
"up/json/" + clientId + "/EMS_YT",
"up/json/" + clientId + "/PCU_YX",
"up/json/" + clientId + "/PCU_YC",
"up/json/" + clientId + "/PCS_YX",
"up/json/" + clientId + "/PCS_YC",
"up/json/" + clientId + "/BCU_YX",
"up/json/" + clientId + "/BCU_YC",
"up/json/" + clientId + "/BMS_YX",
"up/json/" + clientId + "/BMS_YC",
"up/json/" + clientId + "/MEM_YC",
};
this->mapTopicInfo["EMS_YX"] = 101;
this->mapTopicInfo["EMS_YX"] = 101;
this->mapTopicInfo["EMS_YC"] = 101;
this->mapTopicInfo["EMS_YT"] = 101;
this->mapTopicInfo["PCS_YX"] = 102;
this->mapTopicInfo["PCS_YC"] = 102;
this->mapTopicInfo["PCU_YX"] = 103;
this->mapTopicInfo["PCU_YC"] = 103;
this->mapTopicInfo["BMS_YX"] = 104;
this->mapTopicInfo["BMS_YC"] = 104;
this->mapTopicInfo["BCU_YX"] = 105;
this->mapTopicInfo["BCU_YC"] = 105;
this->mapTopicInfo["MEM_YC"] = 3;
this->mapTopicInfo["Cooling_YC"] = 110;
this->mapTopicInfo["TH_YC"] = 111;
this->mapTopicInfo["Gateway_YX"] = 112;
this->mapTopicInfo["Charger_YC"] = 113;
MQTTAsync_connectOptions option = MQTTAsync_connectOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
@@ -163,9 +168,29 @@ void MqttClient::subscribe()
MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer;
options.onSuccess = funcSuccess;
options.onFailure = funcFailure;
for (auto& topic: vecTopic)
std::vector<std::string> vecTopic = {
//"up/json/" + clientId + "/EMS_YX",
"up/json/" + clientId + "/EMS_YC",
//"up/json/" + clientId + "/EMS_YT",
//"up/json/" + clientId + "/PCU_YX",
//"up/json/" + clientId + "/PCU_YC",
//"up/json/" + clientId + "/PCS_YX",
"up/json/" + clientId + "/PCS_YC",
//"up/json/" + clientId + "/BCU_YX",
//"up/json/" + clientId + "/BCU_YC",
//"up/json/" + clientId + "/BMS_YX",
//"up/json/" + clientId + "/BMS_YC",
//"up/json/" + clientId + "/MEM_YC",
//"up/json/" + clientId + "/Cooling_YC",
//"up/json/" + clientId + "/TH_YC",
//"up/json/" + clientId + "/Gateway_YX",
//"up/json/" + clientId + "/Charger_YC",
};
for (auto& item: mapTopicInfo)
{
options.context = topic.data();
std::string topic = "up/json/" + clientId + "/" + item.first;
options.context = (void*)&item.first;
int rc = MQTTAsync_subscribe(client, topic.data(), qos, &options);
if (rc != MQTTASYNC_SUCCESS)
{
@@ -174,9 +199,34 @@ void MqttClient::subscribe()
}
}
int MqttClient::publish(string topic, string text)
int MqttClient::polling()
{
spdlog::info("MQTT publish: topic={}, text={}", topic, text);
// 召测 发布
std::vector<std::string> vecTopic = {
"down/json/" + clientId + "/EMS_YX",
"down/json/" + clientId + "/EMS_YC",
//"down/json/" + clientId + "/EMS_YT",
//"down/json/" + clientId + "/PCU_YX",
//"down/json/" + clientId + "/PCU_YC",
//"down/json/" + clientId + "/PCS_YX",
"down/json/" + clientId + "/PCS_YC",
//"down/json/" + clientId + "/BCU_YX",
//"down/json/" + clientId + "/BCU_YC",
//"down/json/" + clientId + "/BMS_YX",
//"down/json/" + clientId + "/BMS_YC",
//"down/json/" + clientId + "/MEM_YC",
//"down/json/" + clientId + "/Cooling_YC",
//"down/json/" + clientId + "/TH_YC",
//"down/json/" + clientId + "/Gateway_YX",
//"down/json/" + clientId + "/Charger_YC",
};
njson json;
json["ts"] = Utils::time();
json["no"] = 1;
std::string text = json.dump();
MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer;
//options.onSuccess = onSend;
@@ -184,21 +234,24 @@ int MqttClient::publish(string topic, string text)
options.context = this;
MQTTAsync_message msg = MQTTAsync_message_initializer;
msg.qos = 1;
msg.qos = this->qos;
msg.payload = text.data();
msg.payloadlen = text.size();
msg.retained = 0;
int rc = MQTTAsync_sendMessage(client, topic.c_str(), &msg, &options);
if (rc == MQTTASYNC_SUCCESS)
for (auto& topic: vecTopic)
{
spdlog::info("MQTT send message success, topic={}, text={}", topic, text);
int rc = MQTTAsync_sendMessage(client, topic.c_str(), &msg, &options);
if (rc == MQTTASYNC_SUCCESS)
{
spdlog::info("MQTT send message success, topic={}, text={}", topic, msg.payload);
}
else
{
spdlog::error("MQTT send message error, topic={}, text={}", topic, msg.payload);
}
}
else
{
spdlog::error("MQTT send message error, topic={}, text={}", topic, text);
}
return rc;
return 0;
}
void MqttClient::onConnectionLost(char* cause)
@@ -229,16 +282,18 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m
{
std::string topicStr = topic;
int len = msg->payloadlen;
std::string payload = (char*)msg->payload;
spdlog::info("MQTT message arrived: topic=[{},{}], payload len={}, payload msg={}", topic, msg->qos, len, payload);
std::string payload((const char*)msg->payload, len);
// <数据方向>/<数据格式>/<厂家ID>/<指合>/<设备标识,上行可选>
std::string direction = GetSubStr("/", topicStr);
std::string datatype = GetSubStr("/", topicStr);
std::string stationId = GetSubStr("/", topicStr);
std::string stationNo = GetSubStr("/", topicStr);
std::string command = GetSubStr("/", topicStr);
std::string deviceCode = GetSubStr("/", topicStr);
spdlog::info("[mqtt] message arrived: topic=[{},{}], len={}, payload={}", topic, msg->qos, len, payload);
spdlog::info("[mqtt] parse topic: {}, stationNo={}, command={}", topic, stationNo, command);
njson json;
bool ret = JSON::parse(payload, json);
@@ -247,29 +302,31 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m
spdlog::error("[mqtt] json parse error.");
return 1;
}
auto station = Application::data().getStation(Utils::toInt(stationId));
auto station = Application::data().getStationByCode(stationNo);
if (!station)
{
spdlog::error("[mqtt] get station error, clientId={}, stationId={}", clientId, stationId);
spdlog::error("[mqtt] get station error, clientId={}, stationId={}", clientId, stationNo);
return 1;
}
auto iter = g_mapRegInfo.find(command);
if (iter == g_mapRegInfo.end())
{
spdlog::error("[mqtt] get register add info error, clientId={}, stationId={}, command={}", clientId, stationId, command);
spdlog::error("[mqtt] get register add info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
return 1;
}
std::map<std::string, REGInfo>& mapRegInfo = iter->second;
int deviceNo = -1;
JSON::read(json, "no", deviceNo);
auto device = station->getDeviceByType(101, Utils::toStr(deviceNo));
auto device = station->getDeviceByType(mapTopicInfo[command], Utils::toStr(deviceNo));
if (!device)
{
return 1;
}
spdlog::info("[mqtt] deviceNo={}", deviceNo);
for (auto& item: json.items())
{
std::string key = item.key();
@@ -284,7 +341,9 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m
if (iter != mapRegInfo.end())
{
auto addr = iter->first;
device->setParam(addr, JSON::readStr(data[i], addr));
std::string val = JSON::toStr(data[i]);
spdlog::info("[mqtt] read register addr: [{}]={}, {}", addr, val, iter->second.remark);
device->setParam(addr, val);
++iter;
}
}

View File

@@ -25,6 +25,17 @@ struct REGInfo
}
};
//struct TopicInfo
//{
// std::string name;
// std::string topic;
// int deviceType;
// TopicInfo() {};
// TopicInfo(std::string name, std::string topic, int deviceType)
// :name(name), topic(topic), deviceType(deviceType)
// {};
//};
using namespace std;
class MqttClient
@@ -36,7 +47,9 @@ public:
void destory();
void subscribe();
int publish(string topic, string text);
//int publish();
int polling();
void onConnectionLost(char* cause);
int onMessageArrived(char* topic, int len, MQTTAsync_message* msg);
@@ -46,33 +59,17 @@ public:
void onConnectFaiure(MQTTAsync_failureData* resp);
void parseEMS_YX(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseEMS_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parsePCU_YX(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parsePCU_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parsePCS_YX(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parsePCS_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseBMS_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseBCU_YX(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseBCU_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseMEM_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseTH_YC(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo);
//void parseFire40_YX(std::string& text);
//void parseCooling_YX(std::string& text);
//void parseCooling_YC(std::string& text);
//void parseCharger_YC(std::string& text);
//void parseGateway_YX(std::string& text);
//void parseGateway_YC(std::string& text);
//void parseGateway_YT(std::string& text);
//void parseTQ(std::string& text);
public:
std::string clientId;
MQTTAsync client = nullptr;
std::vector<std::string> vecTopic;
std::string addr; // "tcp://localhost:1883"
int qos {0};
bool isConnected {false};
bool isSubscribed {false};
std::map<std::string, int> mapTopicInfo;
};

View File

@@ -4,7 +4,10 @@
#include <QCoreApplication>
#include <QLabel>
#include <QThread>
#include <QWebEngineSettings>
#include <QWebEngineProfile>
#include <QAction>
#include <QToolBar>
void MySplash(MainWeb* mainWin)
{
@@ -28,6 +31,7 @@ void MySplash(MainWeb* mainWin)
{
splash.showMessage(QString("Loading... %1 ms").arg(i), Qt::AlignBottom | Qt::AlignRight, Qt::black);
labelProgress.setGeometry(100, 480, i*2*0.8, 20);
QCoreApplication::processEvents();
QThread::msleep(10);
}
@@ -39,19 +43,63 @@ MainWeb::MainWeb()
{
this->setWindowTitle("光储充站监控与运营管理平台");
this->setGeometry(0, 0, 1920, 1080);
this->hide();
// 在加载页面之前清除缓存
//QWebEngineProfile::defaultProfile()->clearHttpCache();
//QWebEngineSettings* settings = webView.settings();
//settings->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
//settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
//settings->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true); // 解决http资源加载问题
//settings->setAttribute(QWebEngineSettings::PluginsEnabled, true);
webView.setGeometry(0, 0, 1920, 1080);
// 默认设置透明, 解决加载时的白屏闪烁
webView.page()->setBackgroundColor(Qt::transparent);
webView.setContextMenuPolicy(Qt::NoContextMenu);
//webView.page()->setBackgroundColor(Qt::transparent);
//webView.setContextMenuPolicy(Qt::NoContextMenu);
webView.load(QUrl(Config::option.webSrvUrl.c_str()));
//webView.load(QUrl("file:///assets/html/main.html"));
//connect(wWebView.get(), &QWebEngineView::loadFinished, this, &MyWidget::slotLoadFinished);
//std::string htmlContent = "HelloWorld";
//webView->setHtml(htmlContent.c_str(), QUrl("file:///assets/html/"));
webView.show();
this->setCentralWidget(&webView);
MySplash(this);
this->show();
//===动态程序启动画面===
splash = std::make_shared<QSplashScreen>(QPixmap("./assets/ui/splash.png"));
QCoreApplication::processEvents();
label1.setParent(splash.get());
label1.setStyleSheet("background-color: gray");
label1.setGeometry(100, 480, 800, 20);
labelProgress.setParent(splash.get());
labelProgress.setStyleSheet("background-color: rgb(29, 54, 102)");
labelProgress.setGeometry(10, 10, 0, 20);
splash->show();
label1.show();
labelProgress.show();
QObject::connect(&webView, &QWebEngineView::loadFinished, [=](bool ok)
{
if (ok)
{
int i = 0;
while ((++i)<100)
{
splash->showMessage(QString("Loading... %1 ms").arg(i), Qt::AlignBottom | Qt::AlignRight, Qt::black);
labelProgress.setGeometry(100, 480, i*10*0.8, 20);
QCoreApplication::processEvents();
QThread::msleep(20);
}
splash->finish(this);//程序启动画面结束
this->show();
}
else
{
qDebug() << "页面加载失败!";
// 这里可以执行加载失败后的处理
}
});
//this->show();
}

View File

@@ -1,14 +1,16 @@
#include <QMainWindow>
#include <QtWebEngineWidgets/QWebEngineView>
#include <QSplashScreen>
#include <QLabel>
class MainWeb : public QMainWindow
{
Q_OBJECT
public:
MainWeb();
QWebEngineView webView;
std::shared_ptr<QSplashScreen> splash {};
QLabel label1;
QLabel labelProgress;
};

View File

@@ -24,7 +24,7 @@
#include <QLineEdit>
#include <QTextEdit>
using namespace QtCharts;
//using namespace QtCharts;
using MapLabelPair = std::map<std::string, std::pair<std::shared_ptr<QLabel>, std::shared_ptr<QLabel>>>;

4
src/windeployqt.bat Normal file
View File

@@ -0,0 +1,4 @@
cd %~dp0
cd ../bin/Release
@REM D:\Programs\Qt5\5.15.2\msvc2019_64\bin\windeployqt.exe
D:\Programs\Qt6\6.7.3\msvc2019_64\bin\windeployqt.exe ESS.exe