From e2995eff92c54b022ee1786f261ccdc560955a4e Mon Sep 17 00:00:00 2001 From: lixiaoyuan Date: Mon, 8 Sep 2025 19:34:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0MQTT=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=AE=A2=E9=98=85=E5=92=8C=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/AppData.cpp | 10 ++ src/app/AppData.h | 1 + src/app/Config.cpp | 6 + src/app/Config.h | 2 + src/app/Device.cpp | 218 +++++++++++++----------- src/app/Device.h | 32 ++-- src/app/Station.cpp | 17 +- src/app/Station.h | 3 +- src/common/Fields.cpp | 5 +- src/common/JsonN.cpp | 68 ++++++++ src/common/JsonN.h | 36 +--- src/common/Utils.h | 4 +- src/main.cpp | 78 ++++----- src/protocol/HttpEntity.cpp | 79 +++++++-- src/protocol/HttpEntity.h | 6 + src/protocol/MqttEntity.cpp | 319 ++++++++++++++++++++++++++++-------- src/protocol/MqttEntity.h | 46 +++--- 17 files changed, 642 insertions(+), 288 deletions(-) create mode 100644 src/common/JsonN.cpp diff --git a/src/app/AppData.cpp b/src/app/AppData.cpp index 1468c92..e8e3bc4 100644 --- a/src/app/AppData.cpp +++ b/src/app/AppData.cpp @@ -276,6 +276,16 @@ std::shared_ptr AppData::getDevice(int stationId, int deviceId) return nullptr; } +std::shared_ptr AppData::getDeviceByType(int stationId, int deviceType, std::string code) +{ + auto station = getStation(stationId); + if (station) + { + return station->getDeviceByType(deviceType, code); + } + return nullptr; +} + std::string AppData::getDeviceNameById(int typeId) { auto iter = mapDeviceType.find(typeId); diff --git a/src/app/AppData.h b/src/app/AppData.h index ece7d57..f9a46df 100644 --- a/src/app/AppData.h +++ b/src/app/AppData.h @@ -73,6 +73,7 @@ public: std::shared_ptr getStationByCode(std::string code); std::shared_ptr getDevice(int stationId, int deviceId); + std::shared_ptr getDeviceByType(int stationId, int deviceType, std::string code); std::string getDeviceNameById(int typeId); diff --git a/src/app/Config.cpp b/src/app/Config.cpp index 8d6ba2d..b1642fe 100644 --- a/src/app/Config.cpp +++ b/src/app/Config.cpp @@ -59,5 +59,11 @@ bool Config::init(std::string filename) { spdlog::info("[config] parse mqtt failed: not found."); } + + if (jsonroot.contains("weburl")) + { + JSON::read(jsonroot, "weburl", option.webSrvUrl); + } + return true; } \ No newline at end of file diff --git a/src/app/Config.h b/src/app/Config.h index 6da7a81..35e649a 100644 --- a/src/app/Config.h +++ b/src/app/Config.h @@ -26,6 +26,8 @@ struct AppOption std::string password; } mqtt; + std::string webSrvUrl; + }; class Config diff --git a/src/app/Device.cpp b/src/app/Device.cpp index 35983e8..88d2149 100644 --- a/src/app/Device.cpp +++ b/src/app/Device.cpp @@ -5,104 +5,6 @@ #include "protocol/CommEntity.h" #include "common/JsonN.h" -//int DeviceEntity::getAttrInt(std::string key) -//{ -// auto iter = mapAttrs.find(key); -// if (iter == mapAttrs.end()) { return 0; } -// return Utils::toInt(iter->second); -//} -// -//float DeviceEntity::getAttrFloat(std::string key) -//{ -// auto iter = mapAttrs.find(key); -// if (iter == mapAttrs.end()) { return 0.0f; } -// return Utils::toFloat(iter->second); -//} -// -//double DeviceEntity::getAttrDouble(std::string key) -//{ -// auto iter = mapAttrs.find(key); -// if (iter == mapAttrs.end()) { return 0.0; } -// return Utils::toDouble(iter->second); -//} -// -//std::string DeviceEntity::getAttrStr(std::string key) -//{ -// auto iter = mapAttrs.find(key); -// if (iter == mapAttrs.end()) { return ""; } -// return iter->second; -//} - -int Device::startComm() -{ - if (!isOpen) - { - if (commEntity && commEntity->alive) - { - commEntity->close(); - } - return 0; - } - - //// 从属性列表中获取通讯方式和通讯地址、端口 - //std::string commType = attrs.value("commType"); - // - //// 如果entity的通讯协议类型当前配置不一致,需要关闭连接删除通讯后创建新的通讯 - //if (commEntity && commEntity->type != commType) - //{ - // commEntity->close(); - // commEntity = nullptr; - //} - //// 创建新的通讯 - //if (!commEntity) - //{ - // commEntity = CommEntity::create(attrs); - // if (!commEntity) { return -1; } - //} - //commEntity->start(); - return 0; -} - -void Device::getRuntimeParams(std::vector>& params) -{ - params.push_back({"额定电压", "0.0V"}); - params.push_back({"实时电压", "0.0V"}); - params.push_back({"额定电流", "0.0A"}); - params.push_back({"实时电流", "0.0A"}); - params.push_back({"额定功率", "0.0kW"}); - params.push_back({"实时功率", "0.0A"}); -} - -void Device::getCacheVoltage(std::vector& vec) -{ - vec.resize(mapCacheVoltage.size()); - int i = 0; - for (auto iter = mapCacheVoltage.begin(); iter != mapCacheVoltage.end(); ++iter) - { - vec[i] = Utils::toStr(iter->second); - i++; - } -} -void Device::getCacheCurrent(std::vector& vec) -{ - vec.resize(mapCacheCurrent.size()); - int i = 0; - for (auto iter = mapCacheCurrent.begin(); iter != mapCacheCurrent.end(); ++iter) - { - vec[i] = Utils::toStr(iter->second); - i++; - } -} -void Device::getCachePower(std::vector& vec) -{ - vec.resize(mapCachePower.size()); - int i = 0; - for (auto iter = mapCachePower.begin(); iter != mapCachePower.end(); ++iter) - { - vec[i] = Utils::toStr(iter->second); - i++; - } -} std::shared_ptr Device::create(Fields& fields) { @@ -153,3 +55,123 @@ std::shared_ptr Device::create(Fields& fields) return device; } + +int Device::startComm() +{ + if (!isOpen) + { + if (commEntity && commEntity->alive) + { + commEntity->close(); + } + return 0; + } + + //// 从属性列表中获取通讯方式和通讯地址、端口 + //std::string commType = attrs.value("commType"); + // + //// 如果entity的通讯协议类型当前配置不一致,需要关闭连接删除通讯后创建新的通讯 + //if (commEntity && commEntity->type != commType) + //{ + // commEntity->close(); + // commEntity = nullptr; + //} + //// 创建新的通讯 + //if (!commEntity) + //{ + // commEntity = CommEntity::create(attrs); + // if (!commEntity) { return -1; } + //} + //commEntity->start(); + return 0; +} + +void Device::getCacheVoltage(std::vector& vec) +{ + vec.resize(mapCacheVoltage.size()); + int i = 0; + for (auto iter = mapCacheVoltage.begin(); iter != mapCacheVoltage.end(); ++iter) + { + vec[i] = Utils::toStr(iter->second); + i++; + } +} +void Device::getCacheCurrent(std::vector& vec) +{ + vec.resize(mapCacheCurrent.size()); + int i = 0; + for (auto iter = mapCacheCurrent.begin(); iter != mapCacheCurrent.end(); ++iter) + { + vec[i] = Utils::toStr(iter->second); + i++; + } +} +void Device::getCachePower(std::vector& vec) +{ + vec.resize(mapCachePower.size()); + int i = 0; + for (auto iter = mapCachePower.begin(); iter != mapCachePower.end(); ++iter) + { + vec[i] = Utils::toStr(iter->second); + i++; + } +} + +void Device::setParam(std::string k, std::string v) +{ + mapParams[k] = v; +} + +std::string Device::getParam(std::string k, std::string defaultVal) +{ + auto iter = mapParams.find(k); + if (iter != mapParams.end()) + { + return iter->second; + } + return defaultVal; +} + +void Device::getRuntimeParams(std::vector>& params) +{ + // 3 电表 + // 101 EMS + // 102 PCS + // 103 PCU + // 104 BMS + // 105 BCU + // 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"}); + } + else if (this->type == 101) + { + 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"}); + } + //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"}); + } +} diff --git a/src/app/Device.h b/src/app/Device.h index 1711d5c..cd5ed36 100644 --- a/src/app/Device.h +++ b/src/app/Device.h @@ -9,8 +9,24 @@ class CommEntity; + class Device { +public: + static std::shared_ptr create(Fields& fields); + + + int startComm(); + + void getCacheVoltage(std::vector& vec); + void getCacheCurrent(std::vector& vec); + void getCachePower(std::vector& vec); + + void setParam(std::string k, std::string v); + std::string getParam(std::string k, std::string defaultVal = ""); + + void getRuntimeParams(std::vector>& params); + public: int deviceId = -1; int type = -1; @@ -30,23 +46,9 @@ public: // 通讯entity std::shared_ptr commEntity; - //int getAttrInt(std::string key); - //float getAttrFloat(std::string key); - //double getAttrDouble(std::string key); - //std::string getAttrStr(std::string key); - - int64_t tsDataDate {}; std::map mapCacheVoltage; std::map mapCacheCurrent; std::map mapCachePower; - - // 启动通讯 - int startComm(); - void getRuntimeParams(std::vector>& params); - void getCacheVoltage(std::vector& vec); - void getCacheCurrent(std::vector& vec); - void getCachePower(std::vector& vec); - - static std::shared_ptr create(Fields& fields); + std::map mapParams; }; diff --git a/src/app/Station.cpp b/src/app/Station.cpp index d662804..2121fde 100644 --- a/src/app/Station.cpp +++ b/src/app/Station.cpp @@ -55,12 +55,25 @@ std::shared_ptr Station::getDevice(int deviceId) return nullptr; } -void Station::getDeviceByType(int typeId, std::vector>& res) +std::shared_ptr Station::getDeviceByType(int deviceType, std::string code) { for (auto iter = mapDevice.begin(); iter!=mapDevice.end(); ++iter) { auto device = iter->second; - if (device->type == typeId) + if (device->type == deviceType && device->code == code) + { + return device; + } + } + return nullptr; +} + +void Station::getDeviceByType(int deviceType, std::vector>& res) +{ + for (auto iter = mapDevice.begin(); iter!=mapDevice.end(); ++iter) + { + auto device = iter->second; + if (device->type == deviceType) { res.push_back(device); } diff --git a/src/app/Station.h b/src/app/Station.h index 044a587..7d80c33 100644 --- a/src/app/Station.h +++ b/src/app/Station.h @@ -96,7 +96,8 @@ public: void addDevice(int deviceId, std::shared_ptr device); std::shared_ptr getDevice(int deviceId); - + + std::shared_ptr getDeviceByType(int deviceType, std::string code); void getDeviceByType(int typeId, std::vector>& res); int getDeviceNumByGroup(int category); void getDeviceByGroup(int category, std::vector>& res); diff --git a/src/common/Fields.cpp b/src/common/Fields.cpp index d70deeb..56130dd 100644 --- a/src/common/Fields.cpp +++ b/src/common/Fields.cpp @@ -57,9 +57,10 @@ void Fields::clear() void Fields::check(string key, string val, string d) { - if (mapFields.count(key) > 0 && mapFields[key] == val) + auto iter = mapFields.find(key); + if (iter != mapFields.end() && iter->second == val) { - mapFields[key] = d; + iter->second = d; } } diff --git a/src/common/JsonN.cpp b/src/common/JsonN.cpp new file mode 100644 index 0000000..ee92cd7 --- /dev/null +++ b/src/common/JsonN.cpp @@ -0,0 +1,68 @@ +#include "JsonN.h" +#include "common/Utils.h" + +bool JSON::load(std::string jsonfile, njson& json) +{ + std::ifstream ifs(jsonfile); + if (!ifs.is_open()) { return false; } + try { ifs >> json; } + catch (nlohmann::json::parse_error& e) { return false; } + return true; +} + +bool JSON::parse(std::string jsonstr, njson& json) +{ + try + { + if (!jsonstr.empty()) { json = njson::parse(jsonstr); } + } + catch (nlohmann::json::parse_error& e) + { + std::cout << "JSON parse error: " << e.what() << "\n" << jsonstr << std::endl; + return false; + } + return true; +} + +std::string JSON::readStr(njson& json, std::string k) +{ + std::string v; + try + { + if (json.contains(k)) + { + switch (json[k].type()) + { + case njson::value_t::string: { v = json[k].get(); } break; + case njson::value_t::boolean: { v = Utils::toStr(json[k].get()); } break; + case njson::value_t::number_integer: { v = Utils::toStr(json[k].get()); } break; + case njson::value_t::number_unsigned: { v = Utils::toStr(json[k].get()); } break; + case njson::value_t::number_float: { v = Utils::toStr(json[k].get()); } 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; + } + + if (json.is_number()) { v = json.at(k).get(); } + else if (json.is_string()) { v = json.at(k).get(); } + } + } + catch (const nlohmann::detail::exception& e) + { + std::cout << "JSON read error: k=" << k << ", err=" << e.what() << std::endl; + } + return v; +} + +void JSON::parse(std::string jsonstr, std::vector& vd) +{ + njson jsonroot; + if (JSON::parse(jsonstr, jsonroot)) + { + vd = jsonroot.get>(); + } +} \ No newline at end of file diff --git a/src/common/JsonN.h b/src/common/JsonN.h index d792338..b24485d 100644 --- a/src/common/JsonN.h +++ b/src/common/JsonN.h @@ -51,28 +51,10 @@ using njson = nlohmann::json; class JSON { public: - static bool load(std::string jsonfile, njson& json) - { - std::ifstream ifs(jsonfile); - if (!ifs.is_open()) { return false; } - try { ifs >> json; } - catch (nlohmann::json::parse_error& e) { return false; } - return true; - } + static bool load(std::string jsonfile, njson& json); - static bool parse(std::string jsonstr, njson& json) - { - try - { - if (!jsonstr.empty()) { json = njson::parse(jsonstr); } - } - catch (nlohmann::json::parse_error& e) - { - std::cout << "JSON parse error: " << e.what() << "\n" << jsonstr << std::endl; - return false; - } - return true; - } + + static bool parse(std::string jsonstr, njson& json); template static void read(njson& json, std::string k, T& v) @@ -87,14 +69,10 @@ public: } } - static void parse(std::string jsonstr, std::vector& vd) - { - njson jsonroot; - if (JSON::parse(jsonstr, jsonroot)) - { - vd = jsonroot.get>(); - } - } + static std::string readStr(njson& json, std::string k); + + static void parse(std::string jsonstr, std::vector& vd); + }; diff --git a/src/common/Utils.h b/src/common/Utils.h index c90b588..5d20ed0 100644 --- a/src/common/Utils.h +++ b/src/common/Utils.h @@ -39,11 +39,11 @@ public: memcpy_s(&dest[start], len, &src, len); } - // 获取当前时间的时间戳(毫秒) + // 获取当前时间的时间戳(秒) static int64_t time(std::string s=""); // 获取当前时间的格式字符串 static string timeStr(int64_t ts=0, std::string fmt = "%Y-%m-%d %H:%M:%S"); - // 获取当前日期的时间戳(毫秒) + // 获取当前日期的时间戳(秒) static int64_t date(); // 获取当前日期的格式字符串 static string dateStr(int64_t ts = 0, std::string fmt = "%Y-%m-%d %H:%M:%S"); diff --git a/src/main.cpp b/src/main.cpp index 6c52932..03e6fa3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,9 @@ #include #include "DataStruct.h" +#include +#include + #define wsa rlwsa void rlSocketTest() { @@ -118,8 +121,9 @@ void memberJsonTest() //std::cout << to << std::endl; } + int main(int argc, char** argv) -{ +{ // 设置控制台输出为 UTF-8 编码 SetConsoleOutputCP(CP_UTF8); // 设置控制台输入为 UTF-8 编码(如果需要输入中文) @@ -138,33 +142,42 @@ int main(int argc, char** argv) // 运行后台服务 Application::instance().init(); - { - //REGInfo reg; - //std::string s = "BMS(电池堆)通信状态 R uint16 \"0:正常1:故障\" bit位从低到高分别对应1~16 0x2001"; - //int pos; - //if (std::string::npos != (pos = s.find("\t0x"))) - //{ - // reg.name = s.substr(pos+1); - // s = s.substr(0, pos); - // std::cout << reg.name << std::endl; - //} - //if (std::string::npos != (pos = s.find("\t"))) - //{ - // reg.remark = s.substr(0, pos); - // s = s.substr(pos+1); - // std::cout << reg.remark << std::endl; - //} - //if (std::string::npos != (pos = s.find("uint"))) - //{ - // std::string bytename = s.substr(pos, 6); - // std::cout << bytename << std::endl; - // s = s.substr(pos+6); - //} - //std::cout << s << std::endl; - //std::cout << s << std::endl; - - } + // 启动 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(); + QApplication qapp(argc, argv); + + QMainWindow mainWin; + mainWin.setWindowTitle("光储充站监控与运营管理平台"); + mainWin.setGeometry(0, 0, 1920, 1080); + QWebEngineView webView; + webView.setGeometry(0, 0, 1920, 1080); + // 默认设置透明, 解决加载时的白屏闪烁 + 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(); + mainWin.setCentralWidget(&webView); + + mainWin.show(); + qapp.exec(); // 运行QT主窗口 //QApplication qapp(argc, argv); @@ -173,16 +186,5 @@ int main(int argc, char** argv) //mainWin.resize(1920, 1080); //mainWin.show(); //qapp.exec(); - - // 运行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); - } return 0; } \ No newline at end of file diff --git a/src/protocol/HttpEntity.cpp b/src/protocol/HttpEntity.cpp index be8d803..3de980d 100644 --- a/src/protocol/HttpEntity.cpp +++ b/src/protocol/HttpEntity.cpp @@ -82,7 +82,7 @@ static void GetRequestParam(const httplib::Request& req, const std::vector g_mapHttpHandlerGet = {"/queryStatDayList", HandlerOptions(&HttpEntity::queryStatDayList, {})}, {"/queryEnvironment", HandlerOptions(&HttpEntity::queryEnvironment, { "station_id"})}, + + + {"/queryServiceApiList", HandlerOptions(&HttpEntity::queryServiceApiList, {})}, + {"/deleteServiceApi", HandlerOptions(&HttpEntity::deleteServiceApi, {"api_id"})}, //{"/insert", HandlerOptions(&HttpEntity::insert, {})}, //{"/update", HandlerOptions(&HttpEntity::update, {})}, @@ -194,6 +198,9 @@ static std::map g_mapHttpHandlerPost {"/insertPolicy", HandlerOptions(&HttpEntity::insertPolicy, { DMPolicy::NAME})}, {"/updatePolicy", HandlerOptions(&HttpEntity::updatePolicy, { DMPolicy::POLICY_ID})}, + + {"/insertServiceApi", HandlerOptions(&HttpEntity::insertServiceApi, {})}, + {"/updateServiceApi", HandlerOptions(&HttpEntity::updateServiceApi, {"api_id"})}, }; bool CheckHttpToken(const httplib::Request& req) @@ -495,6 +502,10 @@ Errcode HttpEntity::updateStation(const httplib::Request& req, njson& json, std: { Fields params; GetRequestParam(req, {"station_id", "name", "address", "lon", "lat", "tel", "capacity", "status"}, params); + params.check("capacity", "", "0.0"); + params.check("lon", "", "0.0"); + params.check("lat", "", "0.0"); + params.check("status", "", "1"); return DAO::updateStationById(params); }; @@ -683,6 +694,8 @@ Errcode HttpEntity::queryDevicByCategory(const httplib::Request& req, njson& jso jsonnode["name"] = device->name; jsonnode["code"] = device->code; jsonnode["type"] = device->type; + jsonnode["typename"] = Application::data().getDeviceNameById(device->type); + jsonnode["view"] = 1; jsonnode["is_online"] = device->online;// ? "在线" : "离线"; jsonnode["is_error"] = device->err;// ? "故障" : "正常"; @@ -799,19 +812,25 @@ Errcode HttpEntity::updateAlertLog(const httplib::Request& req, njson& json, std Errcode HttpEntity::queryPredictionDetail(const httplib::Request& req, njson& json, std::string& errmsg) { njson jsonData = njson::array(); - for (int i = 1; i<=5; i++) + + std::vector vecStoreIn(144), vecStoreOut(144), vecCharge(144), vecSolar(144), vecSolarP(144); + for (int i = 0; i<144; ++i) { - njson jnode; - jnode["datatype"] = i; - njson jsonValues = njson::array(); - for (int i = 0; i<1440; ++i) - { - jsonValues.push_back(float(Utils::random(50, 100))); - } - jnode["values"] = jsonValues; - jsonData.push_back(jnode); + vecStoreIn[i] = Utils::toStr(float(Utils::random(50, 100))); + vecStoreOut[i] = Utils::toStr(float(Utils::random(50, 100))); + vecCharge[i] = Utils::toStr(float(Utils::random(50, 100))); + vecSolar[i] = Utils::toStr(float(Utils::random(50, 100))); + vecSolarP[i] = Utils::toStr(float(Utils::random(50, 100))); } + json["data"] = jsonData; + json["data"] = { + {"W_store_in", vecStoreIn}, + {"W_store_out", vecStoreOut}, + {"W_charge", vecCharge}, + {"W_solar", vecSolar}, + {"P_solar", vecSolarP } + }; return Errcode::OK; } @@ -1010,4 +1029,42 @@ Errcode HttpEntity::queryEnvironment(const httplib::Request& req, njson& json, s } json["data"] = jsondata; return Errcode::OK; +} + + +Errcode HttpEntity::queryServiceApiList(const httplib::Request& req, njson& json, std::string& errmsg) +{ + PageInfo pageinfo; + pageinfo.index = Utils::toInt(req.get_param_value("page")); + pageinfo.size = Utils::toInt(req.get_param_value("page_size")); + std::vector result; + std::string sql = "SELECT * FROM serviceapi;" ; + auto err = DAO::exec(NULL, sql, result); + HttpHelper::setPagination(pageinfo, result, json); + return err; +} + +Errcode HttpEntity::insertServiceApi(const httplib::Request& req, njson& json, std::string& errmsg) +{ + Fields params; + GetRequestParam(req, {"name", "describe", "params", "is_open"}, params); + if (params.size() == 0) { return Errcode::ERR_PARAM; } + + return DAO::insert(NULL, "serviceapi", params); +} + +Errcode HttpEntity::updateServiceApi(const httplib::Request& req, njson& json, std::string& errmsg) +{ + Fields params; + GetRequestParam(req, {"api_id", "name", "describe", "params", "is_open"}, params); + if (params.size() == 0) { return Errcode::ERR_PARAM; } + + return DAO::update(NULL, "serviceapi", params, "api_id"); +} + +Errcode HttpEntity::deleteServiceApi(const httplib::Request& req, njson& json, std::string& errmsg) +{ + Fields params; + GetRequestParam(req, {"api_id"}, params); + return DAO::remove(NULL, "serviceapi", "api_id", params.value("api_id")); } \ No newline at end of file diff --git a/src/protocol/HttpEntity.h b/src/protocol/HttpEntity.h index 0e1c9df..4eff86b 100644 --- a/src/protocol/HttpEntity.h +++ b/src/protocol/HttpEntity.h @@ -85,4 +85,10 @@ public: Errcode queryStatDayList(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); + Errcode updateServiceApi(const httplib::Request& req, njson& json, std::string& errmsg); + Errcode deleteServiceApi(const httplib::Request& req, njson& json, std::string& errmsg); }; \ No newline at end of file diff --git a/src/protocol/MqttEntity.cpp b/src/protocol/MqttEntity.cpp index c5eee1b..ee3b7a3 100644 --- a/src/protocol/MqttEntity.cpp +++ b/src/protocol/MqttEntity.cpp @@ -1,10 +1,21 @@ #include "MqttEntity.h" #include "common/Spdlogger.h" -#include "common/JsonN.h" #include "common/Utils.h" +#include "app/Application.h" +#include "app/AppData.h" +#include "app/Station.h" +#include "app/Device.h" #define TIMEOUT 10000L +std::string REGAddrOffset(std::string addr, int offset) +{ + unsigned int val; + std::stringstream ss; + ss << std::hex << addr; + ss >> val; + return Utils::toHexStr(val + offset); +} static std::map> g_mapRegInfo; @@ -16,12 +27,28 @@ void MqttClient::loadDataStruct(std::string filename) // 遍历 JSON 对象 for (auto& jsonitem : json.items()) { - auto& mapItem = g_mapRegInfo[jsonitem.key()]; + std::string name = jsonitem.key(); + auto jsonnodeItem = jsonitem.value(); + int count = jsonnodeItem["count"]; + auto jsonaddrs = jsonnodeItem["addr"]; - for (auto& itemaddrs : jsonitem.value().items()) + auto& mapItem = g_mapRegInfo[name]; + int size = 0; + for (int i = 0; i<2; ++i) { - auto& jsonreg = itemaddrs.value(); - mapItem[jsonreg["key"]] = REGInfo(jsonreg["key"], jsonreg["datatype"], jsonreg["remark"]); + for (auto& item : jsonaddrs) + { + std::string addr = item["key"]; + if (i > 0) + { + addr = REGAddrOffset(addr, size*i); + } + mapItem[addr] = REGInfo(addr, item["datatype"], item["remark"]); + if (i ==0) + { + size += mapItem[addr].bytes; + } + } } } } @@ -188,7 +215,12 @@ std::string GetSubStr(std::string c, std::string& str) if (pos != string::npos) { v = str.substr(0, pos); - str = str.substr(pos); + str = str.substr(pos+1); + } + else + { + v = str; + str = ""; } return v; } @@ -208,51 +240,69 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m std::string deviceCode = GetSubStr("/", topicStr); - //EMS遥信 - //EMS遥测 - //EMS遥调 - //PCU遥信 - //PCU遥测 - //PCS遥信 - //PCS遥测 - //BMS遥测 - //BCU遥信 - //BCU遥测 - //电表遥测 - //温湿度遥测 - //消防遥信4.0 - //冷机遥信 - //冷机遥测 - //充电桩遥测 - //网关遥信 - //网关遥测 - //网关遥调 - //台区 + njson json; + bool ret = JSON::parse(payload, json); + if (!ret) + { + spdlog::error("[mqtt] json parse error."); + return 1; + } + auto station = Application::data().getStation(Utils::toInt(stationId)); + if (!station) + { + spdlog::error("[mqtt] get station error, clientId={}, stationId={}", clientId, stationId); + return 1; + } - if (command == "EMS_YX") { this->parseEMS_YX(payload); } - else if (command == "EMS_YC") { this->parseEMS_YC(payload); } - else if (command == "PCU_YX") { this->parsePCU_YX(payload); } - else if (command == "PCU_YC") { this->parsePCU_YC(payload); } - else if (command == "PCS_YX") { this->parsePCS_YX(payload); } - else if (command == "PCS_YC") { this->parsePCS_YC(payload); } - else if (command == "BMS_YC") { this->parseBMS_YC(payload); } - else if (command == "BCU_YX") { this->parseBCU_YX(payload); } - else if (command == "BCU_YC") { this->parseBCU_YC(payload); } - else if (command == "MEM_YC") { this->parseMEM_YC(payload); } - else if (command == "TH_YC") { this->parseTH_YC(payload); } - else if (command == "Fire40_YX") { this->parseFire40_YX(payload); } - else if (command == "Cooling_YX") { this->parseCooling_YX(payload); } - else if (command == "Cooling_YC") { this->parseCooling_YC(payload); } - else if (command == "Charger_YC") { this->parseCharger_YC(payload); } - else if (command == "Gateway_YX") { this->parseGateway_YX(payload); } - else if (command == "Gateway_YC") { this->parseGateway_YC(payload); } - else if (command == "Gateway_YT") { this->parseGateway_YT(payload); } - else if (command == "TQ") { this->parseTQ(payload); } + 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); + return 1; + } + std::map& mapRegInfo = iter->second; + + int deviceNo = -1; + JSON::read(json, "no", deviceNo); + auto device = station->getDeviceByType(101, Utils::toStr(deviceNo)); + if (!device) + { + return 1; + } + + for (auto& item: json.items()) + { + std::string key = item.key(); + if (key != "ts" && key != "no") + { + auto data = json.at(key); + if (data.is_array()) + { + auto iter = mapRegInfo.find(key); + for (int i = 0; ifirst; + device->setParam(addr, JSON::readStr(data[i], addr)); + ++iter; + } + } + } + else if (data.is_number()) + { + device->setParam(key, Utils::toStr(data.get())); + } + else if (data.is_string()) + { + device->setParam(key, Utils::toStr(data.get())); + } + } + } // 必须释放消息内存! MQTTAsync_freeMessage(&msg); MQTTAsync_free(topic); - return 1; // 1表示消息已经处理 } @@ -299,28 +349,159 @@ void MqttClient::onConnectFaiure(MQTTAsync_failureData* resp) this->destory(); } -void MqttClient::parseEMS_YX(std::string& text){} -void MqttClient::parseEMS_YC(std::string& text) {}; -void MqttClient::parsePCU_YX(std::string& text) {}; -void MqttClient::parsePCU_YC(std::string& text) {}; -void MqttClient::parsePCS_YX(std::string& text) {}; -void MqttClient::parsePCS_YC(std::string& text) {}; -void MqttClient::parseBMS_YC(std::string& text) {}; -void MqttClient::parseBCU_YX(std::string& text) {}; -void MqttClient::parseBCU_YC(std::string& text) {}; -void MqttClient::parseMEM_YC(std::string& text) {}; -void MqttClient::parseTH_YC(std::string& text) {}; -void MqttClient::parseFire40_YX(std::string& text) {}; -void MqttClient::parseCooling_YX(std::string& text) {}; -void MqttClient::parseCooling_YC(std::string& text) {}; -void MqttClient::parseCharger_YC(std::string& text) {}; -void MqttClient::parseGateway_YX(std::string& text) {}; -void MqttClient::parseGateway_YC(std::string& text) {}; -void MqttClient::parseGateway_YT(std::string& text) {}; -void MqttClient::parseTQ(std::string& text) {}; - -string MQTT::packEquipmentInfo() +void MqttClient::parseEMS_YX(std::shared_ptr station, njson& json, std::map& mapRegInfo) { - njson jsonroot; - return jsonroot.dump(); + int deviceNo = -1; + JSON::read(json, "no", deviceNo); + auto device = station->getDeviceByType(101, Utils::toStr(deviceNo)); + if (!device) + { + return; + } + + for (auto& item: json.items()) + { + std::string key = item.key(); + if (key != "ts" && key != "no") + { + auto data = json.at(key); + if (data.is_array()) + { + auto iter = mapRegInfo.find(key); + for (int i = 0; ifirst; + device->mapParams[addr] = JSON::readStr(data[i], addr); + ++iter; + } + } + } + else if (data.is_number()) + { + device->mapParams[key] = Utils::toStr(data.get()); + } + else if (data.is_string()) + { + device->mapParams[key] = Utils::toStr(data.get()); + } + } + } +} + + +string MQTT::pack(std::string name) +{ + njson json; + json["ts"] = Utils::time(); + json["no"] = 1; + + if (name == "EMS_YC") + { + //A相电压 R uint32 1V 0x107E + //B相电压 R uint32 1V 0x1080 + //C相电压 R uint32 1V 0x1082 + //A相电流 R int32 1A 0x1084 + //B相电流 R int32 1A 0x1086 + //C相电流 R int32 1A 0x1088 + + //储能系统SOC R uint16 0.1 0x107A + //储能系统SOH R uint16 0.1 0x107B + + json["addr"] = {"0x107A", "0x107B", "0x107E", "0x1080", "0x1082", "0x1084", "0x1086", "0x1088"}; + } + else if (name == "PCS_YC") + { + //总充电量 R uint32 1kWh 0x0003 + //总放电量 R uint32 1kWh 0x0005 + + //A相电压 R int16 1V 0x0010 + //B相电压 R int16 1V 0x0011 + //C相电压 R int16 1V 0x0012 + + //A相电流 R int16 1A 0x0019 + //B相电流 R int16 1A 0x001A + //C相电流 R int16 1A 0x001B + + //三相总有功功率 R int16 1kW 0x0025 + //三相总无功功率 R int16 1kVar 0x0026 + //三相总视在功率 R int16 1kVA 0x0027 + //三相总功率因数 R int16 1 0x0028 + + //充电功率 R int16 1kW 0x002C + //放电功率 R int16 1kW 0x002D + json["addr"] = {"0x0003", "0x0005", "0x0010", "0x0011", "0x0012", "0x0019", "0x001A", "0x001B", "0x0025", "0x0026", "0x0027", "0x0028", "0x002C", "0x002D"}; + } + else if (name == "PCU_YC") + { + //PCS侧线A相电压 R int16 1v 0x0013 + //PCS侧线B相电压 R int16 1v 0x0014 + //PCS侧线C相电压 R int16 1v 0x0015 + + //PCS侧功率因数A R int16 1 0x0019 + //PCS侧功率因数B R int16 1 0x001A + //PCS侧功率因数C R int16 1 0x001B + + //PCS侧相电流A R int16 1A 0x001C + //PCS侧相电流B R int16 1A 0x001D + //PCS侧相电流C R int16 1A 0x001E + + //PCS侧三相总有功功率 R int16 1kW 0x0028 + //PCS侧三相总无功功率 R int16 1kVar 0x0029 + //PCS侧三相总视在功率 R int16 1kVA 0x002A + //PCS侧三相总功率因数 R int16 1 0x002B + + json["addr"] = {"0x0013", "0x0014", "0x0015", "0x1080", "0x1082", "0x1084", "0x1086", "0x1088"}; + } + else if (name == "BMS_YC") + { + //SOC R uint16 0.1 0x0001 + //SOH R uint16 0.1 0x0002 + //电压 R uint32 0.1V 0x0003 + //电流 R int32 0.1A 0x0005 + //可充电量 R uint32 1kWh 0x0007 + //可放电量 R uint32 1kWh 0x0009 + //可充电状态 R uint16 1:可充电;0:不可充电 0x0047 + //可放电状态 R uint16 1:可放电;0:不可放电 0x0048 + //运行状态 R uint16 运行状态 0-正常 1-告警 2-保护 0x0049 + //充放电状态 R uint16 0-待机 1-充电 2-放电 0x004A + + json["addr"] = {"0x0001", "0x0002", "0x0003", "0x0005", "0x0007", "0x0009", "0x0047", "0x0048", "0x0049", "0x004A"}; + } + else if (name == "BCU_YC") + { + //电表类型 R uint16 "0:储能站总表 1:逆变前侧电表 2:逆变后侧电表 3:配电柜电表 4:并网口电表" 0x0008 + //A相电压 R uint32 1V 0x000B + //B相电压 R uint32 1V 0x000D + //C相电压 R uint32 1V 0x000F + //A相电流 R int32 1A 0x0011 + //B相电流 R int32 1A 0x0013 + //C相电流 R int32 1A 0x0015 + + //尖段电价 R uint32 1RMB 0x0027 + //峰段电价 R uint32 1RMB 0x0029 + //平段电价 R uint32 1RMB 0x002B + //谷段电价 R uint32 1RMB 0x002D + //日充电电量 R uint32 1kWh 0x002F + //日放电电量 R uint32 1kWh 0x0031 + //日充电费用 R uint32 1RMB 0x0033 + //日放电费用 R uint32 1RMB 0x0035 + //日收益 R int32 1RMB 0x0037 + + //总充电电量 R uint32 1kWh 0x004D + //总放电电量 R uint32 1kWh 0x004F + //总充电费用 R uint32 1RMB 0x0051 + //总放电费用 R uint32 1RMB 0x0053 + //总收益 R int32 1RMB 0x0055 + } + else if (name == "TH_YC") + { + //所属通道号 R uint16 1 0x0001 + //所属温湿度号 R uint16 1~10 0x0002 + //温度 R int16 0.1℃ 0x0003 + //湿度 R int16 0.1℃ 0x0004 + + } + return json.dump(); } diff --git a/src/protocol/MqttEntity.h b/src/protocol/MqttEntity.h index 75bbc69..e011e92 100644 --- a/src/protocol/MqttEntity.h +++ b/src/protocol/MqttEntity.h @@ -4,6 +4,9 @@ #include #include #include "MQTTAsync.h" +#include "common/JsonN.h" + +class Station; struct REGInfo { @@ -11,6 +14,7 @@ struct REGInfo std::string datatype; int bytes {0}; std::string remark; + int ratio {1}; REGInfo() {} REGInfo(std::string key, std::string datatype, std::string remark) @@ -41,32 +45,32 @@ public: void onConnectSuccess(MQTTAsync_successData* resp); void onConnectFaiure(MQTTAsync_failureData* resp); - void parseEMS_YX(std::string& text); - void parseEMS_YC(std::string& text); - void parsePCU_YX(std::string& text); - void parsePCU_YC(std::string& text); - void parsePCS_YX(std::string& text); - void parsePCS_YC(std::string& text); - void parseBMS_YC(std::string& text); - void parseBCU_YX(std::string& text); - void parseBCU_YC(std::string& text); - void parseMEM_YC(std::string& text); - void parseTH_YC(std::string& text); - 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); + void parseEMS_YX(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parseEMS_YC(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parsePCU_YX(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parsePCU_YC(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parsePCS_YX(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parsePCS_YC(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parseBMS_YC(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parseBCU_YX(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parseBCU_YC(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parseMEM_YC(std::shared_ptr station, njson& json, std::map& mapRegInfo); + //void parseTH_YC(std::shared_ptr station, njson& json, std::map& 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 vecTopic; std::string addr; // "tcp://localhost:1883" - int qos {1}; + int qos {0}; bool isConnected {false}; bool isSubscribed {false}; }; @@ -95,5 +99,5 @@ public: public: - static string packEquipmentInfo(); + static string pack(std::string name); }; \ No newline at end of file