diff --git a/bin/Release/assets/config/app.json b/bin/Release/assets/config/app.json index 20ac721..9bb99f7 100644 --- a/bin/Release/assets/config/app.json +++ b/bin/Release/assets/config/app.json @@ -1,11 +1,6 @@ { - "database": { - "host": "localhost", - "port": 3306, - "user": "root", - "passwd": "123456", - "dbname": "ees" - }, + "database": {"host": "localhost", "port": 3306, "user": "root", "passwd": "123456", "dbname": "ees"}, "token":"", - "http": { "port": 19800} + "http": {"port": 19800}, + "mqtt": {"host":"tcp://localhost:1883","username":"","password":""} } \ No newline at end of file diff --git a/doc/光储充站控系统-HTTP管理接口.docx b/doc/光储充站控系统-HTTP管理接口.docx index 890561e..964fbfe 100644 Binary files a/doc/光储充站控系统-HTTP管理接口.docx and b/doc/光储充站控系统-HTTP管理接口.docx differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4a7f76e..1955f0d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,7 @@ 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(Qt5 COMPONENTS Widgets AxContainer Network diff --git a/src/app/AppData.cpp b/src/app/AppData.cpp index e7dad45..df908d1 100644 --- a/src/app/AppData.cpp +++ b/src/app/AppData.cpp @@ -7,7 +7,7 @@ #include "common/JsonN.h" #include "common/Snowflake.h" #include "common/Spdlogger.h" - +#include "protocol/MqttEntity.h" void ElectPeriod::parse(std::string jsonstr) { @@ -217,6 +217,17 @@ void AppData::initFromDB() void AppData::init() { this->initFromDB(); + + auto& optionMqtt = Config::option.mqtt; + if (!optionMqtt.host.empty()) + { + for (auto& item : mapStation) + { + auto& station = item.second; + // "tcp://localhost:1883" + station->mqttCli->init(optionMqtt.host, station->code, optionMqtt.username, optionMqtt.password); + } + } } std::shared_ptr AppData::getStation(int stationId) @@ -245,6 +256,17 @@ std::shared_ptr AppData::getStationByName(std::string name) return nullptr; } +std::shared_ptr AppData::getStationByCode(std::string code) +{ + for (auto iter = mapStation.begin(); iter!=mapStation.end(); ++iter) + { + if (iter->second->code == code) + { + return iter->second; + } + } + return nullptr; +} std::shared_ptr AppData::getDevice(int stationId, int deviceId) { @@ -423,4 +445,27 @@ std::string AppData::getElectPreiodVal(int month, int hour) } } return ""; +} + +void AppData::storeRuntimeDB() +{ + auto t = Utils::date(); + + std::string valStr; + for (auto iter=mapDataDay.begin(); iter!=mapDataDay.end(); ++iter) + { + auto& v = iter->second; + if (v != 0.0) + { + if (!valStr.empty()) valStr += ","; + valStr += ("[" + std::to_string(iter->first) + "," + Utils::toStr(v, 2) + "]"); + } + } + valStr = "[" + valStr + "]"; + Fields fields; + fields.set("dt", Utils::dateStr(t)); + fields.set("device_id", 1); + fields.set("datatype", 1); + fields.set("value", valStr); + DAO::insertRuntimeData(NULL, fields); } \ No newline at end of file diff --git a/src/app/AppData.h b/src/app/AppData.h index cbfdf8f..ece7d57 100644 --- a/src/app/AppData.h +++ b/src/app/AppData.h @@ -70,6 +70,7 @@ public: int getStationCount(); std::shared_ptr getStationByName(std::string name); + std::shared_ptr getStationByCode(std::string code); std::shared_ptr getDevice(int stationId, int deviceId); @@ -101,6 +102,8 @@ public: std::string getElectPreiodVal(int month, int hour); + void storeRuntimeDB(); + public: /////////////////////////////////////////////////////////////////////////////////////////////// @@ -156,4 +159,6 @@ public: // 电力峰谷分段 (12个月,每个月按小时分成24个时段) std::vector> vecElectPeriods; + std::map mapDataDay; + }; diff --git a/src/app/Application.cpp b/src/app/Application.cpp index b233fd5..87358b2 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -39,9 +39,6 @@ void Application::init() // 创建HTTP服务线程 std::thread([=]() { while (!isQuit) { - MqttClient mqttCli; - mqttCli.init("tcp://localhost:1883", "AAAAAAAAA", "", "", {"topic/test"}); // 不阻塞 - HttpEntity http; http.listen("0.0.0.0", Config::option.http.port); // 阻塞 } @@ -63,37 +60,41 @@ void Application::runThreadDevice() void Application::runThreadMain() { std::string addr = "tcp://localhost:1883"; - mqttCli = std::make_shared(); - mqttCli->init(addr, "ESS", "", "", {}); + //mqttCli = std::make_shared(); + //mqttCli->init(addr, "ESS", "", "", {}); while (!isQuit) { - // 连接场站 - static TimeTick ttStation; - if (ttStation.elapse(10000)) - { - if (!mqttCli->isConnected) - { - } - else - { - for (auto& item: appdata.mapStation) - { - auto station = item.second; - if (station && !station->isConnected) - { - std::vector vecTopics = {"topic/test" + std::to_string(station->id)}; - mqttCli->subscribe(vecTopics, [=](int id) - { - station->isConnected = (id == 0); - }); - } - break; - } - } - - } - + //// 连接场站 + //static TimeTick ttStation; + //if (ttStation.elapse(10000)) + //{ + // if (!mqttCli->isConnected) + // { + // } + // else + // { + // for (auto& item: appdata.mapStation) + // { + // auto station = item.second; + // if (station && !station->isConnected) + // { + // std::string stationCode = station->code; + // std::vector vecTopics = { + // "up/json" + stationCode + "/EMS_YX", + // "up/json" + stationCode + "/EMS_YC", + // "up/json" + stationCode + "/PCU_YX", + // "up/json" + stationCode + "/PCU_YC", + // }; + // mqttCli->subscribe(vecTopics, [=](int id) + // { + // station->isConnected = (id == 0); + // }); + // } + // break; + // } + // } + //} std::this_thread::sleep_for(std::chrono::milliseconds(10)); } diff --git a/src/app/Config.cpp b/src/app/Config.cpp index 6dfd9a6..da13feb 100644 --- a/src/app/Config.cpp +++ b/src/app/Config.cpp @@ -32,7 +32,7 @@ bool Config::init(std::string filename) } else { - spdlog::info("[config] parse database failed: not found. host={}", option.database.host); + spdlog::info("[config] parse database failed: not found."); } if (jsonroot.contains("http")) @@ -43,6 +43,21 @@ bool Config::init(std::string filename) option.http.useToken = !token.empty(); NJson::read(json, "port", option.http.port); } + else + { + spdlog::info("[config] parse http failed: not found."); + } + if (jsonroot.contains("mqtt")) + { + NJsonNode json = jsonroot.at("mqtt"); + NJson::read(json, "host", option.mqtt.host); + NJson::read(json, "username", option.mqtt.username); + NJson::read(json, "password", option.mqtt.password); + } + else + { + spdlog::info("[config] parse mqtt failed: not found."); + } return true; } \ No newline at end of file diff --git a/src/app/Config.h b/src/app/Config.h index 558cf35..6da7a81 100644 --- a/src/app/Config.h +++ b/src/app/Config.h @@ -20,6 +20,12 @@ struct AppOption int port {0}; } http; + struct { + std::string host; + std::string username; + std::string password; + } mqtt; + }; class Config diff --git a/src/app/Constant.cpp b/src/app/Constant.cpp new file mode 100644 index 0000000..3b134c3 --- /dev/null +++ b/src/app/Constant.cpp @@ -0,0 +1,6 @@ +#include "Constant.h" + +namespace CONST +{ + const std::string VAR; +} diff --git a/src/app/Constants.h b/src/app/Constant.h similarity index 100% rename from src/app/Constants.h rename to src/app/Constant.h diff --git a/src/app/DataStruct.cpp b/src/app/DataStruct.cpp new file mode 100644 index 0000000..e9f0c79 --- /dev/null +++ b/src/app/DataStruct.cpp @@ -0,0 +1,62 @@ +#include "DataStruct.h" + +void EMSYX::fromJson(const std::string& str) +{ + NJsonNode jsonroot; + auto ret = NJson::parse(str, jsonroot); + if (!ret) { return; } + NJson::read(jsonroot, "mcu", mcu); + NJson::read(jsonroot, "pcs", pcs); + NJson::read(jsonroot, "electMeterMainPoint", electMeterMainPoint); + NJson::read(jsonroot, "electMeter", electMeter); + NJson::read(jsonroot, "fireSystem", fireSystem); + NJson::read(jsonroot, "ups", ups); + NJson::read(jsonroot, "temHumMainPoint", temHumMainPoint); + NJson::read(jsonroot, "temHum", temHum); + NJson::read(jsonroot, "aircMainPoint", aircMainPoint); + NJson::read(jsonroot, "airc", airc); + NJson::read(jsonroot, "controlDryContact", controlDryContact); + NJson::read(jsonroot, "statusDryContact", statusDryContact); + NJson::read(jsonroot, "bcuMain", bcuMain); + NJson::read(jsonroot, "pcuMain", pcuMain); + NJson::read(jsonroot, "electMeterMain", electMeterMain); + NJson::read(jsonroot, "fireSystemMain", fireSystemMain); + NJson::read(jsonroot, "upsMain", upsMain); + NJson::read(jsonroot, "temHumMain", temHumMain); + NJson::read(jsonroot, "aircMain", aircMain); + NJson::read(jsonroot, "emu", emu); + NJson::read(jsonroot, "chillerMain", chillerMain); + NJson::read(jsonroot, "chillerMainPoint", chillerMainPoint); + NJson::read(jsonroot, "chiller", chiller); +} + +std::string EMSYX::toJson() +{ + NJsonNode jsonroot; + jsonroot["bms"] = bms; + jsonroot["bcu"] = bcu; + jsonroot["mcu"] = mcu; + jsonroot["pcs"] = pcs; + jsonroot["electMeterMainPoint"] = electMeterMainPoint; + jsonroot["electMeter"] = electMeter; + jsonroot["fireSystem"] = fireSystem; + jsonroot["ups"] = ups; + jsonroot["temHumMainPoint"] = temHumMainPoint; + jsonroot["temHum"] = temHum; + jsonroot["aircMainPoint"] = aircMainPoint; + jsonroot["airc"] = airc; + jsonroot["controlDryContact"] = controlDryContact; + jsonroot["statusDryContact"] = statusDryContact; + jsonroot["bcuMain"] = bcuMain; + jsonroot["pcuMain"] = pcuMain; + jsonroot["electMeterMain"] = electMeterMain; + jsonroot["fireSystemMain"] = fireSystemMain; + jsonroot["upsMain"] = upsMain; + jsonroot["temHumMain"] = temHumMain; + jsonroot["aircMain"] = aircMain; + jsonroot["emu"] = emu; + jsonroot["chillerMain"] = chillerMain; + jsonroot["chillerMainPoint"] = chillerMainPoint; + jsonroot["chiller"] = chiller; + return jsonroot.dump(); +} \ No newline at end of file diff --git a/src/app/DataStruct.h b/src/app/DataStruct.h new file mode 100644 index 0000000..1da35a6 --- /dev/null +++ b/src/app/DataStruct.h @@ -0,0 +1,981 @@ +#pragma + +#include +#include "common/JsonN.h" + +struct REGInfo +{ + std::string name; + int byte; + std::string remark; +}; + +// EMS遥信 +struct EMSYX +{ + uint16_t bms; //BMS(电池堆)通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint64_t bcu; //BCU(电池簇)通信状态 R uint64 "0:正常 1:故障" bit位从低到高分别对应1~64 + uint16_t mcu; //PCU(主控)通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint64_t pcs; //PCS(模块)通信状态 R uint64 "0:正常 1:故障" bit位从低到高分别对应1~64 + uint16_t electMeterMainPoint; //电表总接点通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint32_t electMeter; //电表通信状态 R uint32 "0:正常 1:故障" bit位从低到高分别对应1~32 + uint16_t fireSystem; //消防通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint16_t ups; //UPS通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint16_t temHumMainPoint; //温湿度总接点通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint32_t temHum; //温湿度通信状态 R uint32 "0:正常 1:故障" bit位从低到高分别对应1~32 + uint16_t aircMainPoint; //空调总接点通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint32_t airc; //空调通信状态 R uint32 "0:正常 1:故障" bit位从低到高分别对应1~32 + uint16_t controlDryContact; //控制干接点(配电系统)状态 R uint16 "0:开路 1:闭合" bit位从低到高分别对应1~16 + uint16_t statusDryContact; //状态干接点(配电系统)状态 R uint16 "0:开路 1:闭合" bit位从低到高分别对应1~16 + uint16_t bcuMain; //BCU总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t pcuMain; //PCU总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t electMeterMain; //电表总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t fireSystemMain; //消防总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t upsMain; //UPS总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t temHumMain; //温湿度总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t aircMain; //空调总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t emu; //EMU通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t chillerMain; //冷机总通信状态 R uint16 0:正常 1:告警 2:故障 + uint16_t chillerMainPoint; //冷机总接点通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + uint16_t chiller; //冷机通信状态 R uint16 "0:正常 1:故障" bit位从低到高分别对应1~16 + //预留 + //预留 + uint16_t energyStatus; //判断总表的三相总有功 < -5.0fkW 充电 >5.0fkW放电 否则停机 R uint16 0:充电 1 : 放电 2 : 停机 储能状态 + + void fromJson(const std::string& str); + void toJson(); +}; + +// EMS遥测 +struct EMSYC +{ + //BMS(电池堆)个数 R uint16 1 0x1001 + //BCU通道个数 R uint16 1~2 0x1002 + //BCU(电池簇)个数 R uint16 1~40 0x1003 + //PCU(主控)个数 R uint16 1~4 0x1004 + //PCU通道个数 R uint16 1~4 0x1005 + //PCS(模块)个数 R uint16 1~40 0x1006 + //电表通道个数 R uint16 1 0x1007 + //电表个数 R uint16 1~10 0x1008 + //消防通道个数 R uint16 1~10 0x1009 + //消防个数 R uint16 1~10 0x100A + //UPS通道个数 R uint16 1~10 0x100B + //UPS个数 R uint16 1~10 0x100C + //温湿度通道个数 R uint16 1 0x100D + //温湿度个数 R uint16 1~10 0x100E + //空调通道个数 R uint16 1 0x100F + //空调个数 R uint16 1~10 0x1010 + //控制干接点(配电系统)个数 R uint16 16 0x1011 + //状态干接点(配电系统)个数 R uint16 16 0x1012 + //预留 0x1013~0x1071 + //预留 + //预留 + //预留 + //预留 + //预留 + //预留 + //预留 + //预留 + //系统最大可充电功率 R uint32 1KW Pcu数据 0x1072 储能侧 + //系统最大可放电功率 R uint32 1KW 0x1074 + //储能母线电压 R uint32 0.1V 堆数据 0x1076 + //储能母线电流 R int32 0.1A 0x1078 + //储能系统SOC R uint16 0.1 0x107A + //储能系统SOH R uint16 0.1 0x107B + //电流变比 R uint16 电表总表数据 0x107C + //电压变比 R uint16 0x107D + //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 + //AB相电压 R uint32 1V 0x108A + //BC相电压 R uint32 1V 0x108C + //CA相电压 R uint32 1V 0x108E + //A相有功功率 R int32 1kW 0x1090 + //B相有功功率 R int32 1kW 0x1092 + //C相有功功率 R int32 1kW 0x1094 + //三相总有功功率 R int32 1kW 0x1096 + //当前控制功率 R int32 0.1kW 堆数据 0x1098 + //负荷率 R uint32 1% 台区控制策略数据 0不拿 大于0 默认拿第一个 0x109A + //三相不平衡度  R uint32 1% 0x109C + //功率因素比率  R uint32 1% 0x109E + //进线开关柜功率 R int32 1kW 并网口电表 0x10A0 + //用户关口表功率 R int32 1kW 并网口电表 0x10A2 + //预留 0x10A4~0x1103 + //预留 + //正向总有功总需量 R int32 1kW 0x1104 收益 总表 + //尖段电价 R uint32 1RMB 0x1106 + //峰段电价 R uint32 1RMB 0x1108 + //平段电价 R uint32 1RMB 0x110A + //谷段电价 R uint32 1RMB 0x110C + //日充电电量 R uint32 1kWh 0x110E + //日放电电量 R uint32 1kWh 0x1110 + //日充电费用 R uint32 1RMB 0x1112 + //日放电费用 R uint32 1RMB 0x1114 + //日收益 R int32 1RMB 0x1116 + //日正向尖有功电能 R uint32 1kWh 0x1118 + //日正向峰有功电能 R uint32 1kWh 0x111A + //日正向平有功电能 R uint32 1kWh 0x111C + //日正向谷有功电能 R uint32 1kWh 0x111E + //日正向总有功电能 R uint32 1kWh 0x1120 + //日反向尖有功电能 R uint32 1kWh 0x1122 + //日反向峰有功电能 R uint32 1kWh 0x1124 + //日反向平有功电能 R uint32 1kWh 0x1126 + //日反向谷有功电能 R uint32 1kWh 0x1128 + //日反向总有功电能 R uint32 1kWh 0x112A + //总充电电量 R uint32 1kWh 0x112C + //总放电电量 R uint32 1kWh 0x112E + //总充电费用 R uint32 1RMB 0x1130 + //总放电费用 R uint32 1RMB 0x1132 + //总收益 R int32 1RMB 0x1134 + //总正向尖有功电能 R uint32 1kWh 0x1136 + //总正向峰有功电能 R uint32 1kWh 0x1138 + //总正向平有功电能 R uint32 1kWh 0x113A + //总正向谷有功电能 R uint32 1kWh 0x113C + //总正向总有功电能 R uint32 1kWh 0x113E + //总反向尖有功电能 R uint32 1kWh 0x1140 + //总反向峰有功电能 R uint32 1kWh 0x1142 + //总反向平有功电能 R uint32 1kWh 0x1144 + //总反向谷有功电能 R uint32 1kWh 0x1146 + //总反向总有功电能 R uint32 1kWh 0x1148 + //预留 0x114A~0x11AD + //预留 + //预留 + //交流A相电压 R int16 1V 0x11AE 电网侧 并网口电表 + //交流B相电压 R int16 1V 0x11AF + //交流C相电压 R int16 1V 0x11B0 + //交流A相频率 R int16 1Hz 0x11B1 Pcs + //交流B相频率 R int16 1Hz 0x11B2 + //交流C相频率 R int16 1Hz 0x11B3 + //总直流功率 R int32 1kW 0x11B4 堆 + //总直流电压 R uint32 0.1V 0x11B6 + //总直流电流 R int32 0.1A 0x11B8 + //预留 0x11B9~0x121A + //预留 + //预留 + //储能系统温度 R int16 0.1℃ 堆里面单体温度最高 0x121B 充放电运行状态 + //储能充放电时段hh R uint16 时 0x01 0x121C 普通控制功率取 默认给0 + //储能充放电时段mm R uint16 分 0x01 0x121D + //储能充放电时段ss R uint16 秒 0x01 0x121E + //储能系统各时段功率 R int16 1kW 0x01 0x121F +}; + +// EMS遥调 +struct EMSYT +{ + //EMS工作模式 RW uint16 - "0:无效 1:本地控制模式, EMS不接受平台调控 2 : 平台控制模式, EMS接收平台调控指令" 0x0001 + //有功功率 RW int16 kW "并网恒功率模式下交流侧功率值: <0 : 充电功率 0 : 静置 >0 : 放电功率" 0x0002 + //PCS开关机 RW uint16 - "0: 关机 1 : 开机" 软件开关机 0x0003 + //主控对象 RW uint16 "储能遥控对象:0:无效 1:华云 2:轻舟" 0x0004 + //A相有功功率 RW int16 1kW 0x0005 + //B相有功功率 RW int16 1kW 0x0006 + //C相有功功率 RW int16 1kW 0x0007 + //三相总有功功率 RW int16 1kW 0x0008 + //A相无功功率 RW int16 1kVar 0x0009 + //B相无功功率 RW int16 1kVar 0x000A + //C相无功功率 RW int16 1kVar 0x000B + //三相总无功功率 RW int16 1kVar 0x000C + //A相电流 RW int16 0.01A 在使用的时候除以100转float 0x000D + //B相电流 RW int16 0.01A 0x000E + //C相电流 RW int16 0.01A 0x000F + //A相电压 RW uint16 1V 0x0010 + //B相电压 RW uint16 1V 0x0011 + //C相电压 RW uint16 1V 0x0012 + //A相交流功率因数 RW int16 0.01 在使用的时候除以100转float 0x0013 + //B相交流功率因数 RW int16 0.01 0x0014 + //C相交流功率因数 RW int16 0.01 0x0015 + //A相视在功率 RW int16 1kVA 0x0016 + //B相视在功率 RW int16 1kVA 0x0017 + //C相视在功率 RW int16 1kVA 0x0018 + //正向总有功总需量 RW int16 1kW 0x0019 + //数据有效性 RW int16 0无效 1有效 0x001A + //EMS工作模式 RW uint16 - "0:无效 1:本地控制模式, EMS不接受平台调控 2 : 平台控制模式, EMS接收平台调控指令" 2413项目需求 0x001B + //有功功率 RW uint16 kW "并网恒功率模式下交流侧功率值:功率绝对值 没有正负" 2413项目需求 0x001C + //充放电类型 RW uint16 - "0: 关机 1 : 充电 2 : 放电 3 : 待机" "2413项目需求充放电类型" 0x001D + //最大SOC RW uint16 2413项目需求 0x001E + //最小SOC RW uint16 2413项目需求 0x001F + //自动并离网 RW uint16 "0:手动 1:自动" "2332项目需求(若为自动,则通过主控进行并离网切换)" 0x0020 + //并网离网 RW uint16 "0:并网 1:离网" "2332项目需求(该下发参数的前提为手动模式下)" 0x0021 +}; + + +// PCU遥信 +struct PCUYX +{ + //所属通道号 R uint16 1~4 0x1001 + //故障状态 R uint16 1故障,0正常 0x1002 + //告警状态 R uint16 1告警,0正常 0x1003 + //设备在线 R uint16 1在线,0无效 0x1004 + //本地远程 R uint16 1本地,0远程 0x1005 + //启停状态 R uint16 1开机,0关机 0x1006 + //电网状态 R uint16 1离网,0并网 0x1007 + //模块状态 R uint16 1开机,0待机 0x1008 + //EPO急停 R uint16 1故障,0正常 0x1009 + //防雷器异常 R uint16 1告警,0正常 0x100A + //负载电压反序 R uint16 1故障,0正常 0x100B + //市电电压反序 R uint16 1故障,0正常 0x100C + //输出相反序 R uint16 1故障,0正常 0x100D + //过载告警 R uint16 1告警,0正常 0x100E + //过载超时 R uint16 1故障,0正常 0x100F + //交流过流保护 R uint16 1故障,0正常 0x1010 + //逆变电压异常 R uint16 1故障,0正常 0x1011 + //内部串口异常 R uint16 1故障,0正常 0x1012 + //485通信故障 R uint16 1故障,0正常 0x1013 + //CAN通信故障 R uint16 1故障,0正常 0x1014 + //E2PROM故障 R uint16 1故障,0正常 0x1015 + //电网过压 R uint16 1故障,0正常 0x1016 + //电网欠压 R uint16 1故障,0正常 0x1017 + //电网过频 R uint16 1故障,0正常 0x1018 + //电网欠频 R uint16 1故障,0正常 0x1019 + //电网快检综合异常 R uint16 1故障,0正常 0x101A + //电网幅值快检异常 R uint16 1故障,0正常 0x101B + //电网拖尾异常 R uint16 1故障,0正常 0x101C + //消防输入信号NO R uint16 1闭合,0断开 0x101D + //急停按钮信号NC R uint16 1急停,0正常 0x101E + //避雷器NC R uint16 1故障,0正常 0x101F + //避雷器断路器NC R uint16 1故障,0正常 0x1020 + //PCS总断路器NC R uint16 1闭合,0断开 0x1021 + //电操状态NO R uint16 1闭合,0断开 0x1022 + //远程关机NO R uint16 1开机,0无效 0x1023 + //远程开机NO R uint16 1开机,0无效 0x1024 + //BA故障信号NO R uint16 1故障,0正常 0x1025 + //PCS_01状态 R uint16 1在线,0掉线 0x1026 + //PCS_02状态 R uint16 1在线,0掉线 0x1027 + //PCS_03状态 R uint16 1在线,0掉线 0x1028 + //PCS_04状态 R uint16 1在线,0掉线 0x1029 + //PCS_05状态 R uint16 1在线,0掉线 0x102A + //PCS_06状态 R uint16 1在线,0掉线 0x102B + //PCS_07状态 R uint16 1在线,0掉线 0x102C + //PCS_09状态 R uint16 1在线,0掉线 0x102D + //PCS_10状态 R uint16 1在线,0掉线 0x102E + //PCS_01下发设置 R uint16 1故障,0正常 0x102F + //PCS_02下发设置 R uint16 1故障,0正常 0x1030 + //PCS_03下发设置 R uint16 1故障,0正常 0x1031 + //PCS_04下发设置 R uint16 1故障,0正常 0x1032 + //PCS_05下发设置 R uint16 1故障,0正常 0x1033 + //PCS_06下发设置 R uint16 1故障,0正常 0x1034 + //PCS_07下发设置 R uint16 1故障,0正常 0x1035 + //PCS_08下发设置 R uint16 1故障,0正常 0x1036 + //PCS_09下发设置 R uint16 1故障,0正常 0x1037 + //PCS_10下发设置 R uint16 1:故障,0正常 0x1038 + //内部DSP通信故障 R uint16 1 : 故障,0正常 0x1039 + //BMS CAN通信故障 R uint16 1 : 故障,0正常 0x103A + //下发设置失败 R uint16 1 : 故障,0正常 0x103B +}; + +// PCU 遥测 +struct PCUYC +{ + //所属通道号 R uint16 1~4 0x0001 + //充电功率最大许可 R uint32 1KW 0x0002 + //放电功率最大许可 R uint32 1KW 0x0004 + //交流日总充电量 R uint32 1KWh 0x0006 + //交流日总放电量 R uint32 1KWh 0x0008 + //交流总充电量 R uint32 1KWh 0x000A + //交流总放电量 R uint32 1KWh 0x000C + //有功功率期望值 R int16 1KW 0x000E + //无功功率期望值 R int16 1kVar 0x000F + //PCS侧线电压VAB R int16 1v 0x0010 + //PCS侧线电压VBC R int16 1v 0x0011 + //PCS侧线电压VCA R int16 1v 0x0012 + //PCS侧线A相电压 R int16 1v 0x0013 + //PCS侧线B相电压 R int16 1v 0x0014 + //PCS侧线C相电压 R int16 1v 0x0015 + //PCS侧A相频率 R int16 1Hz 0x0016 + //PCS侧B相频率 R int16 1Hz 0x0017 + //PCS侧C相频率 R int16 1Hz 0x0018 + //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侧有功功率A R int16 1kW 0x001F + //PCS侧有功功率B R int16 1kW 0x0020 + //PCS侧有功功率C R int16 1kW 0x0021 + //PCS侧无功功率A R int16 1kVar 0x0022 + //PCS侧无功功率B R int16 1kVar 0x0023 + //PCS侧无功功率C R int16 1kVar 0x0024 + //PCS侧视在功率A R int16 1kVar 0x0025 + //PCS侧视在功率B R int16 1kVar 0x0026 + //PCS侧视在功率C R int16 1kVar 0x0027 + //PCS侧三相总有功功率 R int16 1kW 0x0028 + //PCS侧三相总无功功率 R int16 1kVar 0x0029 + //PCS侧三相总视在功率 R int16 1kVA 0x002A + //PCS侧三相总功率因数 R int16 1 0x002B + //PCU模块温度 R int16 1℃ 0x002C + //外部温度NTC1 R int16 1℃ 0x002D + //外部温度NTC2 R int16 1℃ 0x002E + //外部温度NTC3 R int16 1℃ 0x002F + //台区负载侧A相电流 R int16 1A 0x0030 + //台区负载侧B相电流 R int16 1A 0x0031 + //台区负载侧C相电流 R int16 1A 0x0032 + //台区负载侧A相有功功率 R int16 1kW 0x0033 + //台区负载侧B相有功功率 R int16 1kW 0x0034 + //台区负载侧C相有功功率 R int16 1kW 0x0035 + //台区负载侧总有功功率 R int16 1kW 0x0036 + //台区负载侧A相无功功率 R int16 1kVar 0x0037 + //台区负载侧B相无功功率 R int16 1kVar 0x0038 + //台区负载侧C相无功功率 R int16 1kVar 0x0039 + //台区负载侧总无功功率 R int16 1kVar 0x003A + //台区负载侧A相视在功率 R int16 1kVA 0x003B + //台区负载侧B相视在功率 R int16 1kVA 0x003C + //台区负载侧C相视在功率 R int16 1kVA 0x003D + //台区负载侧总视在功率 R int16 1kVA 0x003E + //台区负载侧A相功率因数 R int16 1 0x003F + //台区负载侧B相功率因数 R int16 1 0x0040 + //台区负载侧C相功率因数 R int16 1 0x0041 + //台区负载侧总功率因数 R int16 1 0x0042 + //负载侧线电压AB R int16 1V 0x0043 + //负载侧线电压BC R int16 1V 0x0044 + //负载侧线电压CA R int16 1V 0x0045 + //负载侧相电压AN R int16 1V 0x0046 + //负载侧相电压BN R int16 1V 0x0047 + //负载侧相电压CN R int16 1V 0x0048 + //负载侧A功率因素 R int16 1 0x0049 + //负载侧B功率因素 R int16 1 0x004A + //负载侧C功率因素 R int16 1 0x004B + //负载侧A视在功率 R int16 1kVA 0x004C + //负载侧B视在功率 R int16 1kVA 0x004D + //负载侧C视在功率 R int16 1kVA 0x004E +}; + +// PCS 遥信 +struct PCSYX +{ + //所属主控号 R uint16 1~4 0x1001 + //所属PCS号 R uint16 1~40 0x1002 + //故障状态 R uint16 1故障,0正常 0x1003 + //告警状态 R uint16 1告警,0正常 0x1004 + //设备在线 R uint16 1在线,0无效 0x1005 + //禁止充电 R uint16 1禁止,0无效 0x1006 + //禁止放电 R uint16 1禁止,0无效 0x1007 + //运行状态 R uint16 1开机,0关机 0x1008 + //充放状态 R uint16 0:待机, 1:充电, 2:放电, 3:搁置 0x1009 + //电网状态 R uint16 1离网,0并网 0x100A + //逆变供电 R uint16 0禁止,1使能 0x100B + //缓启动完成 R uint16 0禁止,1使能 0x100C + //主机标志 R uint16 0禁止,1使能 0x100D + //并离网状态 R uint16 0:并网, 1:离网 0x100E + //同步请求标志 R uint16 0:无效;1:动作 0x100F + //绝缘故障 R uint16 1:故障,0正常 0x1010 + //漏电保护 R uint16 1 : 故障,0正常 0x1011 + //直流过压 R uint16 1 : 故障,0正常 0x1012 + //市电幅值异常 R uint16 1 : 故障,0正常 0x1013 + //市电相序异常 R uint16 1 : 故障,0正常 0x1014 + //温度开关异常 R uint16 1 : 故障,0正常 0x1015 + //市电频率异常 R uint16 1 : 故障,0正常 0x1016 + //IGBT过温 R uint16 1 : 故障,0正常 0x1017 + //交流接地故障 R uint16 1 : 故障,0正常 0x1018 + //逆变过流异常 R uint16 1 : 故障,0正常 0x1019 + //直流缓起故障 R uint16 1 : 故障,0正常 0x101A + //直流主继电器故障 R uint16 1 : 故障,0正常 0x101B + //风机异常 R uint16 1 : 故障,0正常 0x101C + //主接触器异常 R uint16 1 : 故障,0正常 0x101D + //均浮充切换超时 R uint16 1 : 故障,0正常 0x101E + //硬件故障 R uint16 1 : 故障,0正常 0x101F + //机内过温 R uint16 1 : 故障,0正常 0x1020 + //软启动故障 R uint16 1 : 故障,0正常 0x1021 + //触摸屏通讯故障 R uint16 1 : 故障,0正常 0x1022 + //防雷器故障 R uint16 1 : 故障,0正常 0x1023 + //急停故障 R uint16 1 : 故障,0正常 0x1024 + //BMS系统故障 R uint16 1 : 故障,0正常 0x1025 + //BMS通讯故障 R uint16 1 : 故障,0正常 0x1026 + //BMS干接点通讯故障 R uint16 1 : 故障,0正常 0x1027 + //远程通讯故障 R uint16 1 : 故障,0正常 0x1028 + //门禁告警 R uint16 1 : 故障,0正常 0x1029 + //锁相异常 R uint16 1 : 故障,0正常 0x102A + //IGBT过温告警 R uint16 1 : 故障,0正常 0x102B + //硬件过流保护 R uint16 1 : 故障,0正常 0x102C + //驱动故障 R uint16 1 : 故障,0正常 0x102D + //ID冲突 R uint16 1 : 故障,0正常 0x102E + //电池过压 R uint16 1 : 故障,0正常 0x102F + //电池欠压 R uint16 1 : 故障,0正常 0x1030 + //直流过流保护 R uint16 1 : 故障,0正常 0x1031 + //输出电压异常 R uint16 1 : 故障,0正常 0x1032 + //离网输出电压不符合 R uint16 1 : 故障,0正常 0x1033 + //输出过载保护 R uint16 1 : 故障,0正常 0x1034 + //输出短路保护 R uint16 1 : 故障,0正常 0x1035 + //并机通信异常 R uint16 1 : 故障,0正常 0x1036 + //电池保险异常 R uint16 1 : 故障,0正常 0x1037 + //电池重载低压 R uint16 1 : 故障,0正常 0x1038 + //电池低压告警 R uint16 1 : 故障,0正常 0x1039 + //一拖二压差过大 R uint16 1 : 故障,0正常 0x103A + //电池反接故障 R uint16 1 : 故障,0正常 0x103B + //电池电压异常 R uint16 1 : 故障,0正常 0x103C + //过载告警 R uint16 1 : 故障,0正常 0x103D + //外部接触器异常 R uint16 1 : 故障,0正常 0x103E + //IGBT温度传感器异常 R uint16 1 : 故障,0正常 0x103F + //整机温度传感器异常 R uint16 1 : 故障,0正常 0x1040 + //市电CT异常 R uint16 1 : 故障,0正常 0x1041 + //逆变电流三相不平衡 R uint16 1 : 故障,0正常 0x1042 + //逆变电流直流分量异常 R uint16 1 : 故障,0正常 0x1043 + //母线不平衡 R uint16 1 : 故障,0正常 0x1044 + //逆变电压直流分量异常 R uint16 1 : 故障,0正常 0x1045 + //主接触器控制异常 R uint16 1 : 故障,0正常 0x1046 + //逆变电压控制异常 R uint16 1 : 故障,0正常 0x1047 + //直流霍尔异常 R uint16 1 : 故障,0正常 0x1048 + //电池单体过压 R uint16 1 : 故障,0正常 0x1049 + //电池单体欠压 R uint16 1 : 故障,0正常 0x104A + //电网过压 R uint16 1 : 故障,0正常 0x104B + //电网欠压 R uint16 1 : 故障,0正常 0x104C + //电网过频 R uint16 1 : 故障,0正常 0x104D + //电网欠频 R uint16 1 : 故障,0正常 0x104E + //市电不平衡 R uint16 1 : 故障,0正常 0x104F + //参数设置不匹配 R uint16 1 : 故障,0正常 0x1050 + //SPI通信异常 R uint16 1 : 故障,0正常 0x1051 + //SCI通信异常 R uint16 1 : 故障,0正常 0x1052 + //IIC通信异常 R uint16 1 : 故障,0正常 0x1053 + //Xintf通信异常 R uint16 1 : 故障,0正常 0x1054 + //零偏校准异常 R uint16 1 : 故障,0正常 0x1055 + //烟雾告警 R uint16 1 : 故障,0正常 0x1056 + //无电池组故障 R uint16 1异常,0正常 0x1057 + //环温降频 R uint16 1异常,0正常 0x1058 + //交流过载 R uint16 1异常,0正常 0x1059 + //采样异常 R uint16 1异常,0正常 0x105A + //24V辅源故障 R uint16 1异常,0正常 0x105B + //直流欠压异常 R uint16 1异常,0正常 0x105C + //散热器过温 R uint16 1异常,0正常 0x105D + //CAN配置故障 R uint16 1异常,0正常 0x105E + //3.3V辅源故障 R uint16 1异常,0正常 0x105F + //环境过温 R uint16 1异常,0正常 0x1060 + //A相IGBT逆变过流 R uint16 1异常,0正常 0x1061 + //B相IGBT逆变过流 R uint16 1异常,0正常 0x1062 + //C相IGBT逆变过流 R uint16 1异常,0正常 0x1063 +}; + +// PCS 遥测 +struct PCSYC +{ + //所属主控号 R uint16 1~4 0x0001 + //所属PCS号 R uint16 1~40 0x0002 + //总充电量 R uint32 1kWh 0x0003 + //总放电量 R uint32 1kWh 0x0005 + //散热器温度 R int16 1℃ 0x0007 + //内部温度 R int16 1℃ 0x0008 + //最大允许充电功率 R int16 0.1kW 0x0009 + //最大允许放电功率 R int16 0.1kW 0x000A + //有功功率期望 R int16 1kWh 0x000B + //无功功率期望 R int16 1kVar 0x000C + //AB线电压 R int16 1V 0x000D + //BC线电压 R int16 1V 0x000E + //CA线电压 R int16 1V 0x000F + //A相电压 R int16 1V 0x0010 + //B相电压 R int16 1V 0x0011 + //C相电压 R int16 1V 0x0012 + //A相频率 R int16 1Hz 0x0013 + //B相频率 R int16 1Hz 0x0014 + //C相频率 R int16 1Hz 0x0015 + //A相功率因数 R int16 1 0x0016 + //B相功率因数 R int16 1 0x0017 + //C相功率因数 R int16 1 0x0018 + //A相电流 R int16 1A 0x0019 + //B相电流 R int16 1A 0x001A + //C相电流 R int16 1A 0x001B + //A相有功功率 R int16 1kW 0x001C + //B相有功功率 R int16 1kW 0x001D + //C相有功功率 R int16 1kW 0x001E + //A相无功功率 R int16 1kVar 0x001F + //B相无功功率 R int16 1kVar 0x0020 + //C相无功功率 R int16 1kVar 0x0021 + //A相视在功率 R int16 1kVA 0x0022 + //B相视在功率 R int16 1kVA 0x0023 + //C相视在功率 R int16 1kVA 0x0024 + //三相总有功功率 R int16 1kW 0x0025 + //三相总无功功率 R int16 1kVar 0x0026 + //三相总视在功率 R int16 1kVA 0x0027 + //三相总功率因数 R int16 1 0x0028 + //直流功率 R int16 1kW 0x0029 + //直流电压 R int16 1V 0x002A + //直流电流 R int16 1A 0x002B + //充电功率 R int16 1kW 0x002C + //放电功率 R int16 1kW 0x002D + //PF值 R int16 1 0x002E + //UV线/U相电网计量线电压 R int16 1V 0x002F + //VW线/V相电网计量线电压 R int16 1V 0x0030 + //WU线/W相电网计量线电压 R int16 1V 0x0031 + //U相电网计量电流 R int16 1A 0x0032 + //V相电网计量电流 R int16 1A 0x0033 + //W相电网计量电流 R int16 1A 0x0034 + //正母线电压 R int16 1V 0x0035 + //可用功率 R int16 1kVA 0x0036 + //负母线电压 R int16 1V 0x0037 + //A相IGBT温度 R int16 1℃ 0x0038 + //B相IGBT温度 R int16 1℃ 0x0039 + //C相IGBT温度 R int16 1℃ 0x003A + //逆变侧AB线电压 R int16 1V 0x003B + //逆变侧BC线电压 R int16 1V 0x003C + //逆变侧CA线电压 R int16 1V 0x003D + //逆变侧A相电压 R int16 1V 0x003E + //逆变侧B相电压 R int16 1V 0x003F + //逆变侧C相电压 R int16 1V 0x0040 + //逆变侧A相电流 R int16 1A 0x0041 + //逆变侧B相电流 R int16 1A 0x0042 + //逆变侧C相电流 R int16 1A 0x0043 + //逆变侧A相电流直流分量 R int16 1A 0x0044 + //逆变侧B相电流直流分量 R int16 1A 0x0045 + //逆变侧C相电流直流分量 R int16 1A 0x0046 + //离网频率 R int16 1Hz 0x0047 + //A相负载量 R int16 1 0x0048 + //B相负载量 R int16 1 0x0049 + //C相负载量 R int16 1 0x004A + //总负载量 R int16 1 0x004B + //逆变侧AB线电压直流分量 R int16 1A 0x004C + //逆变侧BC线电压直流分量 R int16 1A 0x004D + //逆变侧CA线电压直流分量 R int16 1A 0x004E + //在线数量 R int16 0x004F + //逆变数量 R int16 0x0050 +}; + +// BMS 遥测 +struct BMSYC +{ + //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 uint32 1kWh 0x000B + //单次可放电量 R uint32 1kWh 0x000D + //堆功率 R int32 1kW 0x000F + //充电量累加 R uint32 1kWh 0x0011 + //放电量累加 R uint32 1kWh 0x0013 + //簇最大SOC R uint16 0.1 0x0015 + //簇最小SOC R uint16 0.1 0x0016 + //簇最大SOC号 R uint16 0x0017 + //簇最小SOC号 R uint16 0x0018 + //簇SOC差值 R uint16 0.1 0x0019 + //簇最大电压 R uint16 0.1V 0x001A + //簇最小电压 R uint16 0.1V 0x001B + //簇最大电压号 R uint16 0x001C + //簇最小电压号 R uint16 0x001D + //簇电压差值 R uint16 0.1V 0x001E + //单体最大电压簇号 R uint16 0x001F + //单体最大电压节号 R uint16 0x0020 + //单体最大电压 R uint16 mV 0x0021 + //单体最小电压簇号 R uint16 0x0022 + //单体最小电压节号 R uint16 0x0023 + //单体最小电压 R uint16 mV 0x0024 + //单体平均电压 R uint16 mV 0x0025 + //单体电压差 R uint16 mV 0x0026 + //单体最大温度簇号 R uint16 0x0027 + //单体最大温度节号 R uint16 0x0028 + //单体最大温度 R int16 0.1℃ 0x0029 + //单体最小温度簇号 R uint16 0x002A + //单体最小温度节号 R uint16 0x002B + //单体最小温度 R int16 0.1℃ 0x002C + //单体平均温度 R int16 0.1℃ 0x002D + //单体温度差 R int16 0.1℃ 0x002E + //最大内阻簇号 R uint16 0x002F + //最大内阻节号 R uint16 0x0030 + //最大内阻 R uint16 mΩ 0x0031 + //最小内阻簇号 R uint16 0x0032 + //最小内阻节号 R uint16 0x0033 + //最小内阻 R uint16 mΩ 0x0034 + //单体平均内阻 R uint16 mΩ 0x0035 + //单体内阻差 R uint16 mΩ 0x0036 + //单体最大SOH簇号 R uint16 0x0037 + //单体最大SOH节号 R uint16 0x0038 + //单体最大SOH R uint16 0.10% 0x0039 + //单体最小SOH簇号 R uint16 0x003A + //单体最小SOH节号 R uint16 0x003B + //单体最小SOH R uint16 0.10% 0x003C + //单体最大SOc簇号 R uint16 0x003D + //单体最大SOc节号 R uint16 0x003E + //单体最大Soc R uint16 0.10% 0x0040 + //单体最小SOc簇号 R uint16 0x0041 + //单体最小SOc节号 R uint16 0x0042 + //单体最小SOc R uint16 0.10% 0x0043 + //系统剩余最大可充电功率 R uint32 1KW 0x0043 + //系统剩余最大可放电功率 R uint32 1KW 0x0045 + //可充电状态 R uint16 1:可充电;0:不可充电 0x0047 + //可放电状态 R uint16 1:可放电;0:不可放电 0x0048 + //运行状态 R uint16 运行状态 0-正常 1-告警 2-保护 0x0049 + //充放电状态 R uint16 0-待机 1-充电 2-放电 0x004A + +}; + + +// BCU遥信 +struct BCUYX +{ + //所属通道号 R uint16 1~4 0xA001 + //所属BCU号 R uint16 1~40 0xA002 + //蓄电池充放电状态 R uint16 "0x11开路 + //0x22待机 + //0x33充电 + //0x44放电" 0xA003 + //电池组运行状态 R uint16 "0x11跳机 + //0x22待机 + //0x33放空 + //0x44充满 + //0x55预警 + //0x66正常" 0xA004 + //簇DO1状态 R uint16 1:断开 2:闭合 0xA005 + //簇DO2状态 R uint16 1:断开 2:闭合 0xA006 + //继电器总正 R uint16 0:断开 1:闭合 2:粘连 0xA007 + //继电器总负 R uint16 0 : 断开 1:闭合 2:粘连 0xA008 + //继电器预充 R uint16 0 : 断开 1:闭合 2:粘连 0xA009 + //继电器bmu供电 R uint16 0 : 断开 1:闭合 2:粘连 0xA00A + //整簇总电压过高告警 R uint16 0:正常 1:告警 0xA00B + //整簇总电压过低告警 R uint16 0:正常 1:告警 0xA00C + //整簇中单体电压过高告警 R uint16 0:正常 1:告警 0xA00D + //整簇中单体电压过低告警 R uint16 0:正常 1:告警 0xA00E + //整簇中单体电压偏差过大告警 R uint16 0:正常 1:告警 0xA00F + //整簇中单体温度偏差过大告警 R uint16 0:正常 1:告警 0xA010 + //整簇中单体温度过高告警 R uint16 0:正常 1:告警 0xA011 + //整簇中单体温度过低告警 R uint16 0:正常 1:告警 0xA012 + //整簇总充电电流过高告警 R uint16 0:正常 1:告警 0xA013 + //整簇总放电电流过高告警 R uint16 0:正常 1:告警 0xA014 + //整簇总SOC过高告警 R uint16 0:正常 1:告警 0xA015 + //整簇总SOC过低告警 R uint16 0:正常 1:告警 0xA016 + //高压盒主正接触器粘连告警 R uint16 0:正常 1:告警 0xA017 + //高压盒主正接触器不能吸合告警 R uint16 0:正常 1:告警 0xA018 + //高压盒主负接触器粘连告警 R uint16 0:正常 1:告警 0xA019 + //高压盒主负接触器不能吸合告警 R uint16 0:正常 1:告警 0xA01A + //高压盒预充接触器粘连告警 R uint16 0:正常 1:告警 0xA01B + //高压盒预充接触器不能吸合告警 R uint16 0:正常 1:告警 0xA01C + //预充失败告警 R uint16 0:正常 1:告警 0xA01D + //BCU电压检测模块出现问题告警 R uint16 0:正常 1:告警 0xA01E + //BCU温度检测模块出现问题告警 R uint16 0:正常 1:告警 0xA01F + //BCU电流检测模块出现问题告警 R uint16 0:正常 1:告警 0xA020 + //BCU绝缘检测模块出现问题告警 R uint16 0:正常 1:告警 0xA021 + //高压盒内总压检测模块出现问题告警 R uint16 0:正常 1:告警 0xA022 + //高压盒外总压检测模块出现问题告警 R uint16 0:正常 1:告警 0xA023 + //PCS-CAN通信故障告警 R uint16 0:正常 1:告警 0xA024 + //高压盒供电电压过高告警 R uint16 0:正常 1:告警 0xA025 + //绝缘正极故障告警 R uint16 0:正常 1:告警 0xA026 + //绝缘负极故障告警 R uint16 0:正常 1:告警 0xA027 + //绝缘中间侧故障告警 R uint16 0:正常 1:告警 0xA028 + //绝缘故障告警 R uint16 0:正常 1:告警 0xA029 + //BMU中电压采样线开路告警 R uint16 0:正常 1:告警 0xA02A + //BMU中NTC采样线短开路告警 R uint16 0:正常 1:告警 0xA02B + //BMU中采样芯片故障告警 R uint16 0:正常 1:告警 0xA02C + //BMU中电池温度升高过快告警 R uint16 0:正常 1:告警 0xA02D + //BMU中电池内部短路告警 R uint16 0:正常 1:告警 0xA02E + //BMU充电均衡模块出现故障告警 R uint16 0:正常 1:告警 0xA02F + //BMU放电均衡模块出现故障告警 R uint16 0:正常 1:告警 0xA030 + //BMU通信故障告警 R uint16 0:正常 1:告警 0xA031 + //单体内阻过大告警 R uint16 0:正常 1:告警 0xA032 + //单体内阻过小告警 R uint16 0:正常 1:告警 0xA033 + //单体内阻阻差过大告警 R uint16 0:正常 1:告警 0xA034 + //簇内阻过大告警 R uint16 0:正常 1:告警 0xA035 + //簇内阻过小告警 R uint16 0:正常 1:告警 0xA036 + //SOC初始化无效告警 R uint16 0:正常 1:告警 0xA037 + //充电时soc降低故障告警 R uint16 0:正常 1:告警 0xA038 + //放电时soc升高告警 R uint16 0:正常 1:告警 0xA039 + //静止时SOC跳变告警 R uint16 0:正常 1:告警 0xA03A + //整簇总电压过高保护 R uint16 0:正常 1:保护 0xA03B + //整簇总电压过低保护 R uint16 0:正常 1:保护 0xA03C + //整簇中单体电压过高保护 R uint16 0:正常 1:保护 0xA03D + //整簇中单体电压过低保护 R uint16 0:正常 1:保护 0xA03E + //整簇中单体电压偏差过大保护 R uint16 0:正常 1:保护 0xA03F + //整簇中单体温度偏差过大保护 R uint16 0:正常 1:保护 0xA040 + //整簇中单体温度过高保护 R uint16 0:正常 1:保护 0xA041 + //整簇中单体温度过低保护 R uint16 0:正常 1:保护 0xA042 + //整簇总充电电流过高保护 R uint16 0:正常 1:保护 0xA043 + //整簇总放电电流过高保护 R uint16 0:正常 1:保护 0xA044 + //整簇总SOC过高保护 R uint16 0:正常 1:保护 0xA045 + //整簇总SOC过低保护 R uint16 0:正常 1:保护 0xA046 + //高压盒主正接触器粘连保护 R uint16 0:正常 1:保护 0xA047 + //高压盒主正接触器不能吸合保护 R uint16 0:正常 1:保护 0xA048 + //高压盒主负接触器粘连保护 R uint16 0:正常 1:保护 0xA049 + //高压盒主负接触器不能吸合保护 R uint16 0:正常 1:保护 0xA04A + //高压盒预充接触器粘连保护 R uint16 0:正常 1:保护 0xA04B + //高压盒预充接触器不能吸合保护 R uint16 0:正常 1:保护 0xA04C + //预充失败保护 R uint16 0:正常 1:保护 0xA04D + //BCU电压检测模块出现问题保护 R uint16 0:正常 1:保护 0xA04E + //BCU温度检测模块出现问题保护 R uint16 0:正常 1:保护 0xA04F + //BCU电流检测模块出现问题保护 R uint16 0:正常 1:保护 0xA050 + //BCU绝缘检测模块出现问题保护 R uint16 0:正常 1:保护 0xA051 + //高压盒内总压检测模块出现问题保护 R uint16 0:正常 1:保护 0xA052 + //高压盒外总压检测模块出现问题保护 R uint16 0:正常 1:保护 0xA053 + //PCS-CAN通信故障保护 R uint16 0:正常 1:保护 0xA054 + //高压盒供电电压过高保护 R uint16 0:正常 1:保护 0xA055 + //绝缘正极故障保护 R uint16 0:正常 1:保护 0xA056 + //绝缘负极故障保护 R uint16 0:正常 1:保护 0xA057 + //绝缘中间侧故障保护 R uint16 0:正常 1:保护 0xA058 + //绝缘故障保护 R uint16 0:正常 1:保护 0xA059 + //BMU中电压采样线开路保护 R uint16 0:正常 1:保护 0xA05A + //BMU中NTC采样线短开路保护 R uint16 0:正常 1:保护 0xA05B + //BMU中采样芯片故障保护 R uint16 0:正常 1:保护 0xA05C + //BMU中电池温度升高过快保护 R uint16 0:正常 1:保护 0xA05D + //BMU中电池内部短路保护 R uint16 0:正常 1:保护 0xA05E + //BMU充电均衡模块出现故障保护 R uint16 0:正常 1:保护 0xA05F + //BMU放电均衡模块出现故障保护 R uint16 0:正常 1:保护 0xA060 + //BMU通信故障保护 R uint16 0:正常 1:保护 0xA061 + //单体内阻过大保护 R uint16 0:正常 1:保护 0xA062 + //单体内阻过小保护 R uint16 0:正常 1:保护 0xA063 + //单体内阻阻差过大保护 R uint16 0:正常 1:保护 0xA064 + //簇内阻过大保护 R uint16 0:正常 1:保护 0xA065 + //簇内阻过小保护 R uint16 0:正常 1:保护 0xA066 + //SOC初始化无效保护 R uint16 0:正常 1:保护 0xA067 + //充电时soc降低故障保护 R uint16 0:正常 1:保护 0xA068 + //放电时soc升高保护 R uint16 0:正常 1:保护 0xA069 + //静止时SOC跳变保护 R uint16 0:正常 1:保护 0xA06A +}; + +// BCU遥测 +struct BCUYC +{ + //所属通道号 R uint16 1~4 0x0001 + //所属BCU号 R uint16 1~40 0x0002 + //簇电压 R uint32 0.1V 0x0003 + //簇电流 R int32 0.1A 0x0005 + //簇温度 R int32 0.1℃ 0x0007 + //簇电阻 R uint32 1mΩ 0x0009 + //簇SOC R uint16 0.1 0x000B + //簇SOH R uint16 0.1 0x000C + //簇正绝缘电阻 R uint32 1kΩ 0x000D + //簇负绝缘电阻 R uint32 1kΩ 0x000F + //簇允许最大充电电流 R int32 0.1A 0x0011 + //簇允许最大放电电流 R int32 0.1A 0x0013 + //簇允许最大充电功率 R uint32 1kW 0x0015 + //簇允许最大放电功率 R uint32 1kW 0x0017 + //簇可充容量 R uint32 0.1Ah 0x0019 + //簇可放容量 R uint32 0.1Ah 0x001B + //簇单次累计充容量 R uint32 0.1Ah 0x001D + //簇单次累计放容量 R uint32 0.1Ah 0x001F + //簇总累计充容量 R uint32 0.1Ah 0x0021 + //簇总累计放容量 R uint32 0.1Ah 0x0023 + //簇可充电量 R uint32 1kWh 0x0025 + //簇可放电量 R uint32 1kWh 0x0027 + //簇单次充电量 R uint32 1kWh 0x0029 + //簇单次放电量 R uint32 1kWh 0x002B + //簇累计充电量 R uint32 1kWh 0x002D + //簇累计放电量 R uint32 1kWh 0x002F + //pack累计簇总压 R uint32 0.1V 0x0031 + //簇与pack压差 R uint32 0.1V 0x0033 + //簇与PCS压差 R uint32 0.1V 0x0035 + //簇中BMU个数 R uint16 0x0037 + //簇中BMU中单体个数 R uint16 0x0038 + //簇中BMU中温度个数 R uint16 0x0039 + //簇中单体个数 R uint16 0x003A + //簇中温度个数 R uint16 0x003B + //单体最高SOC节号 R uint16 0x003C + //单体最高SOC R uint16 0.1 0x003D + //单体最低SOC节号 R uint16 0x003E + //单体最低SOC R uint16 0.1 0x003F + //单体最高SOH节号 R uint16 0x0040 + //单体最高SOH R uint16 0.1 0x0041 + //单体最低SOH节号 R uint16 0x0042 + //单体最低SOH R uint16 0.1 0x0043 + //单体最高电压节号 R uint16 0x0044 + //单体最高电压 R uint16 mV 0x0045 + //单体最低电压节号 R uint16 0x0046 + //单体最低电压 R uint16 mV 0x0047 + //单体电压差 R uint16 mV 0x0048 + //单体平均电压 R uint16 mV 0x0049 + //单体最高温度节号 R uint16 0x004A + //单体最高温度 R int16 0.1℃ 0x004B + //单体最低温度节号 R uint16 0x004C + //单体最低温度 R int16 0.1℃ 0x004D + //单体温度差 R int16 0.1℃ 0x004E + //单体平均温度 R int16 0.1℃ 0x004F + //单体最高内阻节号 R uint16 0x0050 + //单体最高内阻 R uint16 mΩ 0x0051 + //单体最低内阻节号 R uint16 0x0052 + //单体最低内阻 R uint16 mΩ 0x0053 + //单体内阻差 R uint16 mΩ 0x0054 + //单体平均内阻 R uint16 mΩ 0x0055 + //单体SOC R uint16[1000] 0.1 0x0056~0x043D + //单体SOH R uint16[1000] 0.1 0x043E~0x0825 + //单体电压 R uint16[1000] mV 0x0826~0x0C0D + //单体温度 R int16[1000] 0.01℃ 0x0C0E~0x0FF5 + //单体内阻 R uint16[1000] mΩ 0x0FF6~0x13DD +}; + +// 空调遥信 +struct AirCYX +{ + //所属通道号 R uint16 1 0x1001 + //所属空调号 R uint16 1~10 0x1002 + //开关 R uint16 0:关机,1:开机 0x1003 + //启动制冷指令 R uint16 0:关闭, 1:启动 0x1004 + //启动送风指令 R uint16 0:关闭, 1:启动 0x1005 + //启动待机指令 R uint16 0:关闭, 1:启动 0x1006 + //启动加热指令 R uint16 0:关闭, 1:启动 0x1007 + //传感器故障 R uint16 0:正常,1:告警 0x1008 + //高低电压告警 R uint16 0:正常,1:告警 0x1009 + //高低温告警 R uint16 0:正常,1:告警 0x100A + //高低压告警 R uint16 0:正常,1:告警 0x100B + //压缩机告警 R uint16 0:正常,1:告警 0x100C + +}; + +// 空调遥测 +struct AirCYC +{ + //所属通道号 R uint16 1 0x0001 + //所属空调号 R uint16 1~10 0x0002 + //制冷点 R int16 0.1℃ 0x0003 + //制冷偏差 R int16 0.1℃ 0x0004 + //高温告警值 R int16 0.1℃ 0x0005 + //低温告警值 R int16 0.1℃ 0x0006 + //制热点 R int16 0.1℃ 0x0007 + //制热偏差 R int16 0.1℃ 0x0008 + //当前温度 R int16 0.1℃ 0x0009 + //当前湿度 R int16 0.1℃ 0x000A + //除湿开启温度 R int16 0.1℃ 0x000B + //除湿停止温度 R int16 0.1℃ 0x000C + //除湿开启湿度 R int16 0.1℃ 0x000D + //除湿停止湿度 R int16 0.1℃ 0x000E +}; + +// 电表遥测 +struct EMeterYC +{ + //所属通道号 R uint16 1 0x0001 + //电表地址 R uint16[6] 0x0002~0x0007 + //电表类型 R uint16 "0:储能站总表 + //1:逆变前侧电表 + //2:逆变后侧电表 + //3:配电柜电表 + //4:并网口电表" 0x0008 + //电流变比 R uint16 0x0009 + //电压变比 R uint16 0x000A + //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 + //AB相电压 R uint32 1V 0x0017 + //BC相电压 R uint32 1V 0x0019 + //CA相电压 R uint32 1V 0x001B + //A相有功 R int32 1kW 0x001D + //B相有功 R int32 1kW 0x001F + //C相有功 R int32 1kW 0x0021 + //三相总有功 R int32 1kW 0x0023 + //正向总有功总需量 R int32 1kW 0x0025 + //尖段电价 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 0x0039 + //日正向峰有功电能 R uint32 1kWh 0x003B + //日正向平有功电能 R uint32 1kWh 0x003D + //日正向谷有功电能 R uint32 1kWh 0x003F + //日正向总有功电能 R uint32 1kWh 0x0041 + //日反向尖有功电能 R uint32 1kWh 0x0043 + //日反向峰有功电能 R uint32 1kWh 0x0045 + //日反向平有功电能 R uint32 1kWh 0x0047 + //日反向谷有功电能 R uint32 1kWh 0x0049 + //日反向总有功电能 R uint32 1kWh 0x004B + //总充电电量 R uint32 1kWh 0x004D + //总放电电量 R uint32 1kWh 0x004F + //总充电费用 R uint32 1RMB 0x0051 + //总放电费用 R uint32 1RMB 0x0053 + //总收益 R int32 1RMB 0x0055 + //总正向尖有功电能 R uint32 1kWh 0x0057 + //总正向峰有功电能 R uint32 1kWh 0x0059 + //总正向平有功电能 R uint32 1kWh 0x005B + //总正向谷有功电能 R uint32 1kWh 0x005D + //总正向总有功电能 R uint32 1kWh 0x005F + //总反向尖有功电能 R uint32 1kWh 0x0061 + //总反向峰有功电能 R uint32 1kWh 0x0063 + //总反向平有功电能 R uint32 1kWh 0x0065 + //总反向谷有功电能 R uint32 1kWh 0x0067 + //总反向总有功电能 R uint32 1kWh 0x0069 +}; + +// 温湿度遥测 +struct TemHumYC +{ + //所属通道号 R uint16 1 0x0001 + //所属温湿度号 R uint16 1~10 0x0002 + //温度 R int16 0.1℃ 0x0003 + //湿度 R int16 0.1℃ 0x0004 +}; + +struct Fire20YX +{ + // 测点太多(1000多个) +}; + +struct Fire30YX +{ + // 测点太多(1000多个) +}; + +struct Fire40YX +{ + //所属通道号 R uint16 1~10 0x0001 + //主控数量 R uint16 1 0x0002 + //主控ID R uint16 1 0x0003 + //主控状态 R uint16 0:正常 1:预警 2:火警 0x0004 + //主控硬件版本 R uint16[2] 主控硬件版本 0x0005~0x0006 + //主控软件版本 R uint16[2] 主控软件版本 0x0007~0x0008 + //主电状态 R uint16 0:使用市电 1:使用备电 0x0009 + //备电电流 R uint32 0.1A 0x000A + //备电电压 R uint32 0.1V 0x000C + //可用容量 R uint32 0.01Ah 0x000E + //可充放容量 R uint32 0.01Ah 0x0010 + //警铃是否使用 R uint16 0x0012 + //警铃状态 R uint16 0:无效 1:掉线 2:正常 3:启动 0x0013 + //瓶头阀是否使用 R uint16 0x0014 + //瓶头阀状态 R uint16 0:无效 1:掉线 2:正常 3:启动 0x0015 + //手报是否使用 R uint16 0x0016 + //手报状态 R uint16 0:无效 1:掉线 2:正常 3:启动 0x0017 + //簇控制器数量 R uint16 0x0018 + //复合探测器总数量 R uint16 0x0019 + //烟雾探测器总数量 R uint16 0x001A + //压力探测器总数量 R uint16 0x001B + //吸气式探测器总数量 R uint16 0x001C + //PACK探测器总数量 R uint16 0x001D + //电池总数量 R uint16 0x001E + +}; + +// 冷机遥信 +struct ChillerYX +{ + //所属通道号 R uint16 1 0x1001 + //所属冷机号 R uint16 1~10 0x1002 + //开关 R uint16 0:关机,1:开机 0x1003 + //采样模式 R uint16 0-出水温度 1-电芯温度 0x1004 + //制冷状态 R uint16 0:关闭, 1:启动 0x1005 + //制热状态 R uint16 0:关闭, 1:启动 0x1006 + //高温告警 R uint16 0:正常,1:告警 0x1007 + //低温告警 R uint16 0:正常,1:告警 0x1008 + //高压告警 R uint16 0:正常,1:告警 0x1009 + //低压告警 R uint16 0:正常,1:告警 0x100A + //进水温度传感器 R uint16 0:正常,1:告警 0x100B + //出水温度传感器 R uint16 0:正常,1:告警 0x100C + //进水压力传感器 R uint16 0:正常,1:告警 0x100D + //出水压力传感器 R uint16 0:正常,1:告警 0x100E +}; + +// 冷机遥测 +struct ChillerYC +{ + //所属通道号 R uint16 1 0x0001 + //所属冷机号 R uint16 1~10 0x0002 + //制冷点 R int16 0.1℃ 0x0003 + //制冷偏差 R int16 0.1℃ 0x0004 + //高温告警值 R int16 0.1℃ 0x0005 + //低温告警值 R int16 0.1℃ 0x0006 + //制热点 R int16 0.1℃ 0x0007 + //制热偏差 R int16 0.1℃ 0x0008 + //电芯温度 R int16 0.1℃ 0x0009 + //环境湿度 R int16 0.1℃ 0x000A + //吸气温度 R int16 0.1℃ 0x000B + //排气温度 R int16 0.1℃ 0x000C + //进水温度/供液温度 R int16 0.1℃ 0x000D + //出水温度/回液温度 R int16 0.1℃ 0x000E + //进水压力/供液压力 R int16 0.1 0x000F + //出水压力/回液压力 R int16 0.1 0x0010 + //高压压力 R int16 0.1 0x0011 + //低压压力 R int16 0.1 0x0012 + //循环水泵转速 R int16 0x0013 + //压缩机频率 R int16 0x0014 + //室外风机转速 R int16 0x0015 +}; \ No newline at end of file diff --git a/src/app/Device.h b/src/app/Device.h index d206f0e..bcaa76e 100644 --- a/src/app/Device.h +++ b/src/app/Device.h @@ -35,6 +35,10 @@ public: //double getAttrDouble(std::string key); //std::string getAttrStr(std::string key); + + int64_t tsDataDate {}; + std::map mapCacheData; + // 启动通讯 int startComm(); diff --git a/src/app/Station.cpp b/src/app/Station.cpp index ad7b79e..fa63d52 100644 --- a/src/app/Station.cpp +++ b/src/app/Station.cpp @@ -4,10 +4,30 @@ #include "common/fields.h" #include "app/Device.h" #include "common/Spdlogger.h" - +#include "common/Utils.h" +#include "protocol/MqttEntity.h" Station::Station() : id(0) { + mqttCli = std::make_shared(); + + // 测试,设置默认值 + for (int i = 1; i<=5; i++) { mapTempHumUnit[i] = TempHumUnit(Utils::random(20, 40), Utils::random(20, 80)); } + + for (int i = 1; i<=5; i++) { mapFire40Unit[i] = 0; } + + for (int i = 1; i<=5; i++) { + auto& unit = mapCoolingUnit[i]; + unit.powerOn = 1; + unit.mode = i%2; + } + + for (int i = 1; i<=5; i++) { + auto& unit = mapAircUnit[i]; + unit.powerOn = 1; + unit.temp = Utils::random(20, 40); + unit.hum = Utils::random(20, 80); + } } void Station::setFields(Fields& fields) @@ -15,7 +35,8 @@ void Station::setFields(Fields& fields) this->id = fields.get(DMStation::STATION_ID); this->name = fields.value(DMStation::NAME); this->energyCapacity = fields.get(DMStation::CAPACITY); - this->workModeId = fields.get(DMStation::WORK_MODE_ID); + this->workModeId = fields.get(DMStation::WORK_MODE); + this->code = fields.value(DMStation::CODE); } void Station::addDevice(int deviceId, std::shared_ptr device) @@ -67,7 +88,7 @@ void Station::setWorkMode(int modeId) { this->workModeId = modeId; std::string sql = SQL(SQL::TYPE::update).table(DMStation::TABLENAME) - .update(DMStation::WORK_MODE_ID, std::to_string(modeId)) + .update(DMStation::WORK_MODE, std::to_string(modeId)) .where(DMStation::STATION_ID + "=" + std::to_string(id)).str(); Errcode err = DAO::exec(NULL, sql); if (err != Errcode::OK) diff --git a/src/app/Station.h b/src/app/Station.h index 77f0d11..569a45d 100644 --- a/src/app/Station.h +++ b/src/app/Station.h @@ -5,6 +5,87 @@ #include "common/Fields.h" class Device; +class MqttClient; + +struct TempHumUnit +{ + int temp {0}; + int hum {0}; + TempHumUnit(int temp, int hum) : temp(temp), hum(hum) {}; + TempHumUnit() {} +}; + +struct Fire40Unit +{ + //主控数量 R uint16 1 0x0002 + //主控ID R uint16 1 0x0003 + //主控状态 R uint16 0:正常 1:预警 2:火警 0x0004 + //主控硬件版本 R uint16[2] 主控硬件版本 0x0005~0x0006 + //主控软件版本 R uint16[2] 主控软件版本 0x0007~0x0008 + //主电状态 R uint16 0:使用市电 1:使用备电 0x0009 + //备电电流 R uint32 0.1A 0x000A + //备电电压 R uint32 0.1V 0x000C + //可用容量 R uint32 0.01Ah 0x000E + //可充放容量 R uint32 0.01Ah 0x0010 + //警铃是否使用 R uint16 0x0012 + //警铃状态 R uint16 0:无效 1:掉线 2:正常 3:启动 0x0013 + //瓶头阀是否使用 R uint16 0x0014 + //瓶头阀状态 R uint16 0:无效 1:掉线 2:正常 3:启动 0x0015 + //手报是否使用 R uint16 0x0016 + //手报状态 R uint16 0:无效 1:掉线 2:正常 3:启动 0x0017 + //簇控制器数量 R uint16 0x0018 + //复合探测器总数量 R uint16 0x0019 + //烟雾探测器总数量 R uint16 0x001A + //压力探测器总数量 R uint16 0x001B + //吸气式探测器总数量 R uint16 0x001C + //PACK探测器总数量 R uint16 0x001D + //电池总数量 R uint16 0x001E + +}; + + +struct CoolingUnit +{ + int powerOn {0}; //开关 R uint16 0:关机,1:开机 0x1003 + int mode {0}; //采样模式 R uint16 0-出水温度 1-电芯温度 0x1004 + int cooling {0}; //制冷状态 R uint16 0:关闭, 1:启动 0x1005 + int heating {0}; //制热状态 R uint16 0:关闭, 1:启动 0x1006 + int highTemp {0}; //高温告警 R uint16 0:正常,1:告警 0x1007 + int lowTemp {0}; //低温告警 R uint16 0:正常,1:告警 0x1008 + int highPressure {0}; //高压告警 R uint16 0:正常,1:告警 0x1009 + int lowPressure {0}; //低压告警 R uint16 0:正常,1:告警 0x100A + //进水温度传感器 R uint16 0:正常,1:告警 0x100B + //出水温度传感器 R uint16 0:正常,1:告警 0x100C + //进水压力传感器 R uint16 0:正常,1:告警 0x100D + //出水压力传感器 R uint16 0:正常,1:告警 0x100E +}; + +struct AircUnit +{ + int powerOn {0}; //开关 R uint16 0:关机,1:开机 + int cooling {0}; //启动制冷指令 R uint16 0:关闭, 1:启动 + int airSupply {0}; //启动送风指令 R uint16 0:关闭, 1:启动 + int standby {0}; //启动待机指令 R uint16 0:关闭, 1:启动 + int heating {0}; //启动加热指令 R uint16 0:关闭, 1:启动 + int sensorAlarm {0}; //传感器故障 R uint16 0:正常,1:告警 + int voltageAlarm {0}; //高低电压告警 R uint16 0:正常,1:告警 + int tempAlarm {0}; //高低温告警 R uint16 0:正常,1:告警 + int pressureAlarm {0}; //高低压告警 R uint16 0:正常,1:告警 + int compressorAlarm {0};//压缩机告警 R uint16 0:正常,1:告警 + + //制冷点 R int16 0.1℃ 0x0003 + //制冷偏差 R int16 0.1℃ 0x0004 + //高温告警值 R int16 0.1℃ 0x0005 + //低温告警值 R int16 0.1℃ 0x0006 + //制热点 R int16 0.1℃ 0x0007 + //制热偏差 R int16 0.1℃ 0x0008 + int temp {0}; //当前温度 R int16 0.1℃ 0x0009 + int hum {0}; //当前湿度 R int16 0.1℃ 0x000A + //除湿开启温度 R int16 0.1℃ 0x000B + //除湿停止温度 R int16 0.1℃ 0x000C + //除湿开启湿度 R int16 0.1℃ 0x000D + //除湿停止湿度 R int16 0.1℃ 0x000E +}; class Station { @@ -28,6 +109,7 @@ public: public: int id {}; std::string name; + std::string code; bool isConnected {false}; int workModeId {}; // 运行模式 @@ -89,4 +171,17 @@ public: std::unordered_map> mapDevice; std::map mapDeviceGroupNum; + + // 温湿度信息 + std::map mapTempHumUnit; + // 消防4.0信息 + std::map mapFire40Unit; + // 冷机信息 + std::map mapCoolingUnit; + // 空调信息 + std::map mapAircUnit; + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// === MQTT client + std::shared_ptr mqttCli {nullptr}; }; \ No newline at end of file diff --git a/src/app/errcode.cpp b/src/app/errcode.cpp index 8878a00..d9c4113 100644 --- a/src/app/errcode.cpp +++ b/src/app/errcode.cpp @@ -7,6 +7,7 @@ static std::unordered_map mapErr = {Errcode::ERR_TOKEN, "TOKEN错误"}, {Errcode::ERR_PARAM, "参数错误"}, {Errcode::ERR_PARAM_NUL, "缺少参数"}, + {Errcode::ERR_DATA_NUL, "数据不存"}, {Errcode::ERR_LOGIN_USER_NOTEXIST, "用户不存在"}, {Errcode::ERR_LOGIN_PASSWD, "密码错误"}, diff --git a/src/app/errcode.h b/src/app/errcode.h index 003e7d4..32e9721 100644 --- a/src/app/errcode.h +++ b/src/app/errcode.h @@ -9,6 +9,7 @@ enum class Errcode ERR_TOKEN, // TOKEN错误 ERR_PARAM, // 参数错误 ERR_PARAM_NUL, // 缺少参数 + ERR_DATA_NUL, // 数据不存在 ERR_USER = 100, ERR_LOGIN_USER_NOTEXIST, // 登入错误,用户不存在 diff --git a/src/common/Fields.cpp b/src/common/Fields.cpp index 5c34f35..b580ddc 100644 --- a/src/common/Fields.cpp +++ b/src/common/Fields.cpp @@ -184,7 +184,6 @@ void Fields::parseJson(std::string jsonstr) { NJsonNode jsonroot; NJson::parse(jsonstr, jsonroot); - for (auto& item : jsonroot.items()) { this->set(item.key(), item.value()); diff --git a/src/common/JsonN.h b/src/common/JsonN.h index cc17059..7b42ca2 100644 --- a/src/common/JsonN.h +++ b/src/common/JsonN.h @@ -54,19 +54,17 @@ public: static bool load(std::string jsonfile, NJsonNode& json) { std::ifstream ifs(jsonfile); - if (ifs.is_open()) - { - ifs >> json; - return true; - } - return false; + if (!ifs.is_open()) { return false; } + try { ifs >> json; } + catch (nlohmann::json::parse_error& e) { return false; } + return true; } static bool parse(std::string jsonstr, NJsonNode& json) { try { - json = NJsonNode::parse(jsonstr); + if (!jsonstr.empty()) { json = NJsonNode::parse(jsonstr); } } catch (nlohmann::json::parse_error& e) { @@ -75,11 +73,6 @@ public: } return true; } - - static bool contains(NJsonNode& json, std::string key) - { - return json.contains("database"); - } template static void read(NJsonNode& json, std::string k, T& v) @@ -90,7 +83,7 @@ public: } catch (const nlohmann::detail::exception& e) { - std::cout << "JSON read error: " << e.what() << std::endl; + std::cout << "JSON read error: k=" << k << ", err=" << e.what() << std::endl; } } diff --git a/src/common/Snowflake.h b/src/common/Snowflake.h index 46b3a8a..7d98e2f 100644 --- a/src/common/Snowflake.h +++ b/src/common/Snowflake.h @@ -41,21 +41,13 @@ public: return inst; } - void setWorkerId(unsigned int workerId) { - this->workerId_ = workerId; - } + void setWorkerId(unsigned int workerId) { this->workerId = workerId; } - void setDatacenterId(unsigned int datacenterId) { - this->datacenterId_ = datacenterId; - } + void setDatacenterId(unsigned int datacenterId) { this->datacenterId = datacenterId; } - uint64_t getId() { - return nextId(); - } + uint64_t getId() { return nextId(); } - std::string getIdStr() { - return std::to_string(nextId()); - } + std::string getIdStr() { return std::to_string(nextId()); } /** * 获得下一个ID (该方法是线程安全的) @@ -72,38 +64,38 @@ public: timestamp = timetick(); // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 - if (timestamp < lastTimestamp_) { + if (timestamp < lastTimestamp) { std::ostringstream s; - s << "clock moved backwards. Refusing to generate id for " << lastTimestamp_ - timestamp << " milliseconds"; + s << "clock moved backwards. Refusing to generate id for " << lastTimestamp - timestamp << " milliseconds"; throw std::exception(std::runtime_error(s.str())); } - if (lastTimestamp_ == timestamp) { + if (lastTimestamp == timestamp) { // 如果是同一时间生成的,则进行毫秒内序列 - sequence_ = (sequence_ + 1) & sequenceMask; - if (0 == sequence_) { + sequence = (sequence + 1) & sequenceMask; + if (0 == sequence) { // 毫秒内序列溢出, 阻塞到下一个毫秒,获得新的时间戳 - timestamp = tilNextMillis(lastTimestamp_); + timestamp = tilNextMillis(lastTimestamp); } } else { - sequence_ = 0; + sequence = 0; } #ifndef SNOWFLAKE_ID_WORKER_NO_LOCK - lastTimestamp_ = timestamp; + lastTimestamp = timestamp; #else lastTimestamp_ = timestamp.load(); #endif // 移位并通过或运算拼到一起组成64位的ID - return ((timestamp - twepoch_) << timestampLeftShift) - | (datacenterId_ << datacenterIdShift) - | (workerId_ << workerIdShift) - | sequence_; + return ((timestamp - twepoch) << timestampLeftShift) + | (datacenterId << datacenterIdShift) + | (workerId << workerIdShift) + | sequence; } protected: - Snowflake() : workerId_(0), datacenterId_(0), sequence_(0), lastTimestamp_(0) {} + Snowflake() : workerId(0), datacenterId(0), sequence(0), lastTimestamp(0) {} /** * 返回以毫秒为单位的当前时间 @@ -139,7 +131,7 @@ private: /** * 开始时间截 2025-01-01 00:00:00.000 */ - const uint64_t twepoch_ = 1735660800000; + const uint64_t twepoch = 1735660800000; /** * 机器id所占的位数 @@ -189,22 +181,22 @@ private: /** * 工作机器id(0~31) */ - unsigned int workerId_; + unsigned int workerId; /** * 数据中心id(0~31) */ - unsigned int datacenterId_; + unsigned int datacenterId; /** * 毫秒内序列(0~4095) */ - AtomicUInt sequence_ {0}; + AtomicUInt sequence {0}; /** * 上次生成ID的时间截 */ - AtomicUInt64 lastTimestamp_ {0}; + AtomicUInt64 lastTimestamp {0}; }; #endif // _JW_CORE_ID_WORKER_H_ \ No newline at end of file diff --git a/src/common/Utils.cpp b/src/common/Utils.cpp index 788d760..0e8fed2 100644 --- a/src/common/Utils.cpp +++ b/src/common/Utils.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include using namespace std; string Utils::toStr(int v) @@ -147,18 +149,18 @@ string Utils::to_hex_text(string s, string d/* = " "*/) void time_point_to_duration() { - auto tp = std::chrono::system_clock::now(); + auto tp = chrono::system_clock::now(); - auto seconds = std::chrono::duration_cast(tp.time_since_epoch()); + auto seconds = chrono::duration_cast(tp.time_since_epoch()); cout << seconds.count() << " s" << endl;//seconds from 1970 - auto ms = std::chrono::duration_cast(tp.time_since_epoch()); + auto ms = chrono::duration_cast(tp.time_since_epoch()); cout << ms.count() << " ms" << endl; - auto us = std::chrono::duration_cast(tp.time_since_epoch()); + auto us = chrono::duration_cast(tp.time_since_epoch()); cout << us.count() << " us" << endl; - auto ns = std::chrono::duration_cast(tp.time_since_epoch()); + auto ns = chrono::duration_cast(tp.time_since_epoch()); cout << ns.count() << " ns" << endl; cout << tp.time_since_epoch().count() << " default is ns" << endl; @@ -167,17 +169,17 @@ void time_point_to_duration() void duration_to_time_point() { std::uint64_t ticker = 1609756793160376465; - auto ns = std::chrono::nanoseconds(ticker); + auto ns = chrono::nanoseconds(ticker); - auto tp1 = std::chrono::time_point(ns); - auto tp2 = tp1 - std::chrono::hours(1);//time point before one hour + auto tp1 = chrono::time_point(ns); + auto tp2 = tp1 - chrono::hours(1);//time point before one hour cout << "tp1=" << tp1.time_since_epoch().count() << endl << "tp2=" << tp2.time_since_epoch().count() << endl; } void format_time_point() { - auto tp = std::chrono::system_clock::now(); - auto time = std::chrono::system_clock::to_time_t(tp); + auto tp = chrono::system_clock::now(); + auto time = chrono::system_clock::to_time_t(tp); std::stringstream ss; ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S"); @@ -191,19 +193,44 @@ void parse_from_string() std::tm tm{}; ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S"); - auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm)); + auto tp = chrono::system_clock::from_time_t(std::mktime(&tm)); cout << tp.time_since_epoch().count() << endl; } -int64_t Utils::time() +int64_t Utils::time(std::string s/* = ""*/) { - return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - //return std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); + if (s.empty()) + { + //return chrono::time_point_cast(chrono::system_clock::now()).time_since_epoch().count(); + return chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); + } + + static const std::string T = "1987/01/01 00/00/00"; + // YYYY/mm/dd HH/MM/SS + int len = T.size(); + int size = s.size(); + if (size < len) { s += T.substr(size, len-size); } + s[4] = s[7] = s[13] = s[16] = '/'; + s[10] = ' '; + std::tm t; + std::stringstream ss(s); + ss >> std::get_time(&t, "%Y/%m/%d %H/%M/%S"); + auto tp = chrono::system_clock::from_time_t(std::mktime(&t)); + return chrono::duration_cast(tp.time_since_epoch()).count(); } -string Utils::timeStr(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) +string Utils::timeStr(int64_t ts, std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) { - auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + time_t t; + if (ts == 0) + { + t = chrono::system_clock::to_time_t(chrono::system_clock::now()); + } + else + { + auto tp = chrono::time_point(chrono::seconds(ts)); + t = chrono::system_clock::to_time_t(tp); + } std::stringstream ss; ss << std::put_time(std::localtime(&t), fmt.c_str()); return ss.str(); @@ -212,7 +239,7 @@ string Utils::timeStr(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) int64_t Utils::date() { // 获取当前时间戳 - std::time_t t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::time_t t = chrono::system_clock::to_time_t(chrono::system_clock::now()); // 转换为本地时间结构体,设置时分秒为0 std::tm* tmlocal = localtime(&t); @@ -220,27 +247,27 @@ int64_t Utils::date() tmlocal->tm_min = 0; tmlocal->tm_sec = 0; - auto tp = std::chrono::time_point_cast(std::chrono::system_clock::from_time_t(mktime(tmlocal))); + auto tp = chrono::time_point_cast(chrono::system_clock::from_time_t(mktime(tmlocal))); return tp.time_since_epoch().count(); } -string Utils::dateStr(std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/) +string Utils::dateStr(int64_t ts, std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/) { - return Utils::timeStr(fmt).substr(0, 10); + return Utils::timeStr(ts, fmt).substr(0, 10); } string Utils::timeStrMS(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) { - auto tpNow = std::chrono::system_clock::now(); - auto time = std::chrono::system_clock::to_time_t(tpNow); + auto tpNow = chrono::system_clock::now(); + auto time = chrono::system_clock::to_time_t(tpNow); std::stringstream ss; ss << std::put_time(std::localtime(&time), fmt.c_str()); auto epoch = tpNow.time_since_epoch(); - auto tms = std::chrono::duration_cast(epoch); - auto tseconds = std::chrono::duration_cast(epoch); + auto tms = chrono::duration_cast(epoch); + auto tseconds = chrono::duration_cast(epoch); ss << "." << std::setfill('0') << std::setw(3) << (tms - tseconds).count(); return ss.str(); } @@ -257,9 +284,9 @@ string Utils::timeStrMS(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) // //string Utils::time_to_string(int64_t dt, std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/) //{ -// auto ms = std::chrono::milliseconds(dt); -// auto tp = std::chrono::time_point(ms); -// time_t t = std::chrono::system_clock::to_time_t(tp); +// auto ms = chrono::milliseconds(dt); +// auto tp = chrono::time_point(ms); +// time_t t = chrono::system_clock::to_time_t(tp); // std::stringstream ss; // ss << std::put_time(std::localtime(&t), fmt.c_str()); // return ss.str(); @@ -270,7 +297,7 @@ string Utils::timeStrMS(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) //{ // if (dt.empty()) // { -// return std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); +// return chrono::time_point_cast(chrono::system_clock::now()).time_since_epoch().count(); // } // else // { @@ -303,9 +330,9 @@ string Utils::timeStrMS(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) // std::tm t {}; // ss >> std::get_time(&t, fmt.c_str()); // t.tm_hour += zone; -// auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t)); -// return std::chrono::duration_cast(tp.time_since_epoch()).count(); -// //return std::chrono::duration_cast(tp.time_since_epoch()).count(); +// auto tp = chrono::system_clock::from_time_t(std::mktime(&t)); +// return chrono::duration_cast(tp.time_since_epoch()).count(); +// //return chrono::duration_cast(tp.time_since_epoch()).count(); // } //} // @@ -346,11 +373,11 @@ string Utils::timeStrMS(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/) void Utils::sleep_ms(int ms) { // 计算时间间隔: - //auto start = std::chrono::high_resolution_clock::now(); - //auto end = std::chrono::high_resolution_clock::now(); - //std::chrono::duration elapsed = end - start; + //auto start = chrono::high_resolution_clock::now(); + //auto end = chrono::high_resolution_clock::now(); + //chrono::duration elapsed = end - start; //int64_t t = elapsed.count(); - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + std::this_thread::sleep_for(chrono::milliseconds(ms)); } @@ -445,3 +472,36 @@ void Utils::split(string buf, string c, vector& res) tmp = tmp.substr(pos + c.size()); } } + +std::string Utils::readFile(std::string filename) +{ + std::filesystem::path filePath = std::filesystem::u8path(filename); + //std::locale::global(locale(""));//将全局区域设为操作系统默认区域 + std::ifstream ifs(filePath, std::ios::binary); + //std::locale::global(locale("C"));//还原全局区域设定 + + if (ifs.is_open()) + { + // 将文件指针移动到末尾获取文件大小 + ifs.seekg(0, std::ios::end); + std::streamsize size = ifs.tellg(); + ifs.seekg(0, std::ios::beg); + + std::string buf(size, '\0'); + ifs.read(&buf[0], size); + return buf; + } + else + { + std::cout << "error" << std::endl; + return ""; + } +} + + +std::string Utils::toHexStr(int64_t val) +{ + std::stringstream ss; + ss << "0x" << std::uppercase << setw(4) << setfill('0') << std::hex << val; + return ss.str(); +} \ No newline at end of file diff --git a/src/common/Utils.h b/src/common/Utils.h index d0ba2ae..c90b588 100644 --- a/src/common/Utils.h +++ b/src/common/Utils.h @@ -40,13 +40,13 @@ public: } // 获取当前时间的时间戳(毫秒) - static int64_t time(); + static int64_t time(std::string s=""); // 获取当前时间的格式字符串 - static string timeStr(std::string fmt = "%Y-%m-%d %H:%M:%S"); + static string timeStr(int64_t ts=0, std::string fmt = "%Y-%m-%d %H:%M:%S"); // 获取当前日期的时间戳(毫秒) static int64_t date(); // 获取当前日期的格式字符串 - static string dateStr(std::string fmt = "%Y-%m-%d %H:%M:%S"); + static string dateStr(int64_t ts = 0, std::string fmt = "%Y-%m-%d %H:%M:%S"); static string timeStrMS(std::string fmt = "%Y-%m-%d %H:%M:%S"); //static string timeStr(int64_t ts, std::string fmt = "%Y-%m-%d %H:%M:%S"); @@ -83,6 +83,10 @@ public: static int random(int min, int max); static void split(string buf, string c, vector& res); + + static std::string readFile(std::string filename); + + static std::string toHexStr(int64_t val); }; class TimeTick diff --git a/src/database/Dao.cpp b/src/database/Dao.cpp index c2b1a62..46bf095 100644 --- a/src/database/Dao.cpp +++ b/src/database/Dao.cpp @@ -88,7 +88,7 @@ static Errcode QueryCount(DaoEntity& dao, std::string sqlFrom, int& count) { std::vector result; int ret = dao.exec("SELECT COUNT(*) count " + sqlFrom, result); - if (ret != 0) + if (ret == 0) { count = (result.size() > 0) ? result[0].get("count") : 0; } @@ -110,8 +110,9 @@ static Errcode QueryPagination(std::string sqlFields, std::string sqlCondition, return err; } + if (page.index < 1) page.index = 1; page.total = count; - std::string sql = "SELECT " + sqlFields + " " + sqlCondition + DAO::sqlPageLimit(page.index, page.size); + std::string sql = "SELECT " + sqlFields + " " + sqlCondition + DAO::sqlPageLimit(page.index -1, page.size); int ret = dao.exec(sql, result); return Errcode(ret); } @@ -555,4 +556,11 @@ Errcode DAO::queryPolicyTypeDef(std::shared_ptr dao, vector& { std::string sql = "SELECT * FROM " + DMDefPolicyType::TABLENAME + ";"; return DAO::exec(dao, sql, result); +} + +Errcode DAO::insertRuntimeData(std::shared_ptr dao, Fields& fields) +{ + if (!dao) { dao = DaoEntity::create("history1"); } + int ret = dao->duplicateUpdate(fields, {"value"}); + return Errcode(ret); } \ No newline at end of file diff --git a/src/database/Dao.h b/src/database/Dao.h index c5889e5..e8ecfd0 100644 --- a/src/database/Dao.h +++ b/src/database/Dao.h @@ -117,4 +117,6 @@ public: static Errcode queryWorkModeDef(std::shared_ptr dao, vector& result); static Errcode queryPolicyTypeDef(std::shared_ptr dao, vector& result); + + static Errcode insertRuntimeData(std::shared_ptr dao, Fields& fields); }; \ No newline at end of file diff --git a/src/database/DataModelDef.h b/src/database/DataModelDef.h index f28dbd0..a4b4ab3 100644 --- a/src/database/DataModelDef.h +++ b/src/database/DataModelDef.h @@ -89,8 +89,10 @@ namespace DMStation const string TEL = "tel"; const string CAPACITY = "capacity"; const string STATUS = "status"; - const string WORK_MODE_ID = "work_mode_id"; + const string WORK_MODE = "work_mode"; const string POLICY_ID = "policy_id"; + const string CODE = "code"; + const string ATTR = "attr"; } namespace DMDefDeviceType @@ -178,4 +180,14 @@ namespace DMStatStation const string CHARGE_ELECT = "charge_elect"; const string CHARGE_NUM = "charge_num"; const string CHARGE_NUM_ERR = "charge_num_err"; -} \ No newline at end of file +} + +namespace DMHistory1 +{ + const string TABLENAME = "history1"; + const string DT = "dt"; + const string STATION_ID = "station_id"; + const string DEVICE_ID = "device_id"; + const string DATATYPE = "datatype"; + const string VALUE = "value"; +} diff --git a/src/main.cpp b/src/main.cpp index 15eba99..ffa931a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,108 +20,150 @@ #include "rlsocket.h" #include "common/Spdlogger.h" - - - +#include "database/DaoEntity.h" #include #include #include +#include +#include +#include +#include "DataStruct.h" #define wsa rlwsa -int main(int argc, char** argv) +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 buf(1024, 0); + while (true) { - NJsonNode jsonroot; - NJson::parse(R"({"name": "Alice", "age": 25, "data":[["1","1","1"],["1","1","1"],["1","1","1"]]})", jsonroot); + int len = socket.read(&buf[0], 1, 0); + if (len > 0) + { + std::cout << "===>>> " << std::string(buf.begin(), buf.end()); + } + } +} - std::vector> v1; - NJson::read>>(jsonroot, "data", v1); +void memberJsonTest() +{ + std::string fromJson = "fromJson(const std::string& str) {\nNJsonNode jsonroot;\nauto ret = NJson::parse(str, jsonroot);\nif (!ret) { return; }\n"; + std::string toJson = "toJson() {\nNJsonNode jsonroot;"; - std::vector> vec = { - {"1", "1", "1", "1", "1", "1", "1", "1"}, - {"1", "1", "1", "1", "1", "1", "1", "1"}, - {"1", "1", "1", "1", "1", "1", "1", "1"}, - {"1", "1", "1", "1", "1", "1", "1", "1"} - }; - - NJsonNode jsonroot1; - jsonroot1["price_super_peak"] = 0.53; - jsonroot1["price_peak"] = 0.53; - jsonroot1["price_shoulder"] = 0.53; - jsonroot1["price_off_peak"] = 0.53; - jsonroot1["periods"] = vec; - - std::cout << jsonroot1.dump() << std::endl; + std::ifstream ifs("", std::ios::in); + std::string line; + std::string cpp = "#include \"DataStruct.h\"\n\n"; + if (ifs.is_open()) + { + std::string s1; + std::string s2; + while (std::getline(ifs, line)) + { + int pos = line.find("struct"); + if (pos != std::string::npos) + { + std::string className = line.substr(pos+7); + s1 = "void " + className + "::" + fromJson; + s2 = "}\nstd::string " + className + "::" + toJson; + } + else + { + std::string key; + pos = line.find("uint"); + if (pos != std::string::npos) { key = line.substr(pos+9); } + if (!key.empty()) + { + pos = key.find(";"); + if (pos != std::string::npos) { key = key.substr(0, pos); } + } + if (!key.empty()) + { + s1 += ("NJson::read(jsonroot, \"" + key + "\", " + key + ");\n"); + s2 += ("jsonroot[\"" + key + "\"] = " + key + ";\n"); + } + } + } + ifs.close(); } + + //std::string strTmp = R"()"; + //std::vector vecTmp; + //Utils::split(strTmp, "\n", vecTmp); + + //std::string from = "void fromJson(const std::string& str) {\nNJsonNode jsonroot;\nauto ret = NJson::parse(str, jsonroot);\nif (!ret) { return; }\n"; + //std::string to = "std::string toJson() {\nNJsonNode jsonroot;"; + //for (auto& item: vecTmp) + //{ + // std::string key; + // int pos = item.find_first_of("_"); + // if (pos != std::string::npos) { key = item.substr(pos+3); } + // pos = key.find_first_of(";"); + // if (pos != std::string::npos) { key = key.substr(0, pos); } + + // if (!key.empty()) + // { + // from += ("NJson::read(jsonroot, \"" + key + "\", " + key + ");\n"); + // to += ("jsonroot[\"" + key + "\"] = " + key + ";\n"); + // } + //} + //from += "}"; + //to += "return jsonroot.dump();\n}"; + //std::cout << from << std::endl; + //std::cout << to << std::endl; +} + +int main(int argc, char** argv) +{ // 设置控制台输出为 UTF-8 编码 SetConsoleOutputCP(CP_UTF8); // 设置控制台输入为 UTF-8 编码(如果需要输入中文) SetConsoleCP(CP_UTF8); Spdlogger::init(spdlog::level::debug, ""); - spdlog::info("[main] start ... ===================================================================================================="); - spdlog::info("spd info"); - spdlog::debug("spd debug"); - spdlog::error("spd error"); + spdlog::info("[main] start ... ======================================================================"); - - //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 buf(1024, 0); - //while (true) - //{ - // int len = socket.read(&buf[0], 1, 0); - // if (len > 0) - // { - // std::cout << "===>>> " << std::string(buf.begin(), buf.end()); - // } - //} - - ////std::cout << Snowflake::instance().getId() << std::endl; - //for (int i = 0; i<=10; ++i) { - // //std::cout << Snowflake::instance().getId() << std::endl; - //} - - - //DaoEntity dao(""); - // - //std::string filename = "assets/html/data中文.txt"; - // - //std::filesystem::path filePath = std::filesystem::u8path("assets/html/data中文.txt"); - ////std::locale::global(locale(""));//将全局区域设为操作系统默认区域 - //std::ifstream ifs(filePath, std::ios::binary); - ////std::locale::global(locale("C"));//还原全局区域设定 - - //if (ifs.is_open()) - //{ - // // 将文件指针移动到末尾获取文件大小 - // ifs.seekg(0, std::ios::end); - // std::streamsize size = ifs.tellg(); - // ifs.seekg(0, std::ios::beg); - - // std::string buf(size, '\0'); - // ifs.read(&buf[0], size); - // std::cout << "文件内容: " << buf << std::endl; - //} - //else - //{ - // std::cout << "error" << std::endl; - //} - - //TcpEntity tcpEntity; - //tcpEntity.setHost("127.0.0.1", 9901, true); - //tcpEntity.setReconnect(5000); - //tcpEntity.start(); + std::cout << Snowflake::instance().getId() << std::endl; + for (int i = 0; i<=10; ++i) { + std::cout << Snowflake::instance().getId() << std::endl; + } // 运行后台服务 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; + + } + + // 运行QT主窗口 //QApplication qapp(argc, argv); //MainWindow mainWin; diff --git a/src/protocol/HttpEntity.cpp b/src/protocol/HttpEntity.cpp index 151376a..f93f148 100644 --- a/src/protocol/HttpEntity.cpp +++ b/src/protocol/HttpEntity.cpp @@ -6,8 +6,17 @@ #include "app/Application.h" #include "app/AppData.h" #include "app/Config.h" +#include "app/Station.h" -static NJsonNode FieldsToJsonArray(std::vector vecFields) +static void FieldsToJson(Fields& fields, NJsonNode& json) +{ + for (auto& item : fields.map()) + { + json[item.first] = item.second; + } +} + +static NJsonNode FieldsToJsonArray(std::vector& vecFields) { NJsonNode jsonnode = NJsonNode::array(); for (auto& fields : vecFields) @@ -24,13 +33,45 @@ static NJsonNode FieldsToJsonArray(std::vector vecFields) static void GetRequestParam(const httplib::Request& req, const std::vector& vecKeys, Fields& fields) { - for (auto& key : vecKeys) + + if (req.method == "GET") { - if (req.has_param(key)) + for (auto& key : vecKeys) { - fields.set(key, req.get_param_value(key)); + if (req.has_param(key)) + { + fields.set(key, req.get_param_value(key)); + } } } + else if (req.method == "POST") + { + NJsonNode json; + NJson::parse(req.body, json); + for (auto& key : vecKeys) + { + if (json.contains(key)) { + + switch (json[key].type()) + { + case NJsonNode::value_t::string: { fields.set(key, json[key].get()); } break; + case NJsonNode::value_t::boolean: { fields.set(key, json[key].get()); } break; + case NJsonNode::value_t::number_integer: { fields.set(key, json[key].get()); } break; + case NJsonNode::value_t::number_unsigned: { fields.set(key, json[key].get()); } break; + case NJsonNode::value_t::number_float: { fields.set(key, json[key].get()); } break; + case NJsonNode::value_t::null: {} break; + case NJsonNode::value_t::object: {} break; + case NJsonNode::value_t::array: {} break; + case NJsonNode::value_t::binary: {} break; + case NJsonNode::value_t::discarded: {} break; + default: + break; + } + + } + } + } + } class HttpHelper @@ -77,86 +118,106 @@ struct HandlerOptions } }; -static std::map g_mapHttpHandler = +static std::map g_mapHttpHandlerGet = { {"/login", HandlerOptions(&HttpEntity::login, {DMUser::ACCOUNT, DMUser::PASSWD})}, - {"/queryUserList", HandlerOptions(&HttpEntity::queryUserList, {"token"})}, - {"/insertUser", HandlerOptions(&HttpEntity::insertUser, {"token", DMUser::ACCOUNT})}, - {"/updateUser", HandlerOptions(&HttpEntity::updateUser, {"token", DMUser::USER_ID})}, - {"/deleteUser", HandlerOptions(&HttpEntity::deleteUser, {"token", DMUser::USER_ID})}, + {"/queryUserList", HandlerOptions(&HttpEntity::queryUserList, {})}, + {"/deleteUser", HandlerOptions(&HttpEntity::deleteUser, { DMUser::USER_ID})}, - {"/queryPermissionList", HandlerOptions(&HttpEntity::queryPermissionList, {"token"})}, - {"/insertPermission", HandlerOptions(&HttpEntity::insertPermission, {"token", DMPermission::NAME})}, - {"/updatePermission", HandlerOptions(&HttpEntity::updatePermission, {"token", DMPermission::PERMISSION_ID})}, - {"/deletePermission", HandlerOptions(&HttpEntity::deletePermission, {"token", DMPermission::PERMISSION_ID})}, + {"/queryPermissionList", HandlerOptions(&HttpEntity::queryPermissionList, {})}, + {"/deletePermission", HandlerOptions(&HttpEntity::deletePermission, { DMPermission::PERMISSION_ID})}, - {"/queryRoleList", HandlerOptions(&HttpEntity::queryRoleList, {"token"})}, - {"/insertRole", HandlerOptions(&HttpEntity::insertRole, {"token", DMRole::NAME})}, - {"/updateRole", HandlerOptions(&HttpEntity::updateRole, {"token", DMRole::ROLE_ID})}, - {"/deleteRole", HandlerOptions(&HttpEntity::deleteRole, {"token", DMRole::ROLE_ID})}, + {"/queryRoleList", HandlerOptions(&HttpEntity::queryRoleList, {})}, + {"/deleteRole", HandlerOptions(&HttpEntity::deleteRole, { DMRole::ROLE_ID})}, - {"/queryStationList", HandlerOptions(&HttpEntity::queryStationList, {"token"})}, - {"/insertStation", HandlerOptions(&HttpEntity::insertStation, {"token", DMStation::NAME})}, - {"/updateStation", HandlerOptions(&HttpEntity::updateStation, {"token", DMStation::STATION_ID})}, - {"/deleteStation", HandlerOptions(&HttpEntity::deleteStation, {"token", DMStation::STATION_ID})}, - - {"/queryDeviceList", HandlerOptions(&HttpEntity::queryDeviceList, {"token"})}, - {"/insertDevice", HandlerOptions(&HttpEntity::insertDevice, {"token", DMDevice::NAME})}, - {"/updateDevice", HandlerOptions(&HttpEntity::updateDevice, {"token", DMDevice::DEVICE_ID})}, - {"/deleteDevice", HandlerOptions(&HttpEntity::deleteDevice, {"token", DMDevice::DEVICE_ID})}, - {"/queryDevicTypeDef", HandlerOptions(&HttpEntity::queryDevicTypeDef, {"token"})}, - - {"/queryPolicyList", HandlerOptions(&HttpEntity::queryPolicyList, {"token"})}, - {"/insertPolicy", HandlerOptions(&HttpEntity::insertPolicy, {"token", DMPolicy::NAME})}, - {"/updatePolicy", HandlerOptions(&HttpEntity::updatePolicy, {"token", DMPolicy::POLICY_ID})}, - {"/deletePolicy", HandlerOptions(&HttpEntity::deletePolicy, {"token", DMPolicy::POLICY_ID})}, + {"/queryStationList", HandlerOptions(&HttpEntity::queryStationList, {})}, + {"/deleteStation", HandlerOptions(&HttpEntity::deleteStation, { DMStation::STATION_ID})}, - {"/querySystemLogList", HandlerOptions(&HttpEntity::querySystemLogList, {"token"})}, + {"/queryStationInfo", HandlerOptions(&HttpEntity::queryStationInfo, { DMStation::STATION_ID})}, + {"/queryStationRuntime", HandlerOptions(&HttpEntity::queryStationRuntime, { DMStation::STATION_ID})}, - {"/queryAlertLogList", HandlerOptions(&HttpEntity::queryAlertLogList, {"token"})}, + {"/queryDeviceList", HandlerOptions(&HttpEntity::queryDeviceList, {})}, + {"/deleteDevice", HandlerOptions(&HttpEntity::deleteDevice, { DMDevice::DEVICE_ID})}, + {"/queryDevicTypeDef", HandlerOptions(&HttpEntity::queryDevicTypeDef, {})}, + + {"/queryPolicyList", HandlerOptions(&HttpEntity::queryPolicyList, {})}, - {"/queryPredictionDetail", HandlerOptions(&HttpEntity::queryPredictionDetail, {"token"})}, + + {"/deletePolicy", HandlerOptions(&HttpEntity::deletePolicy, { DMPolicy::POLICY_ID})}, + + {"/querySystemLogList", HandlerOptions(&HttpEntity::querySystemLogList, {})}, - {"/queryStatSystem", HandlerOptions(&HttpEntity::queryStatSystem, {"token"})}, - {"/queryStatTotal", HandlerOptions(&HttpEntity::queryStatTotal, {"token"})}, - {"/queryStatDayList", HandlerOptions(&HttpEntity::queryStatDayList, {"token"})}, + {"/queryAlertLogList", HandlerOptions(&HttpEntity::queryAlertLogList, {})}, + + {"/queryPredictionDetail", HandlerOptions(&HttpEntity::queryPredictionDetail, {})}, + + {"/queryStatSystem", HandlerOptions(&HttpEntity::queryStatSystem, {})}, + {"/queryStatTotal", HandlerOptions(&HttpEntity::queryStatTotal, {})}, + {"/queryStatStation", HandlerOptions(&HttpEntity::queryStatStation, {})}, + {"/queryStatDayList", HandlerOptions(&HttpEntity::queryStatDayList, {})}, + + {"/queryEnvironment", HandlerOptions(&HttpEntity::queryEnvironment, { "station_id"})}, //{"/insert", HandlerOptions(&HttpEntity::insert, {})}, //{"/update", HandlerOptions(&HttpEntity::update, {})}, //{"/delete", HandlerOptions(&HttpEntity::delete, {})}, }; +static std::map g_mapHttpHandlerPost +{ + {"/insertUser", HandlerOptions(&HttpEntity::insertUser, { DMUser::ACCOUNT})}, + {"/updateUser", HandlerOptions(&HttpEntity::updateUser, { DMUser::USER_ID})}, + + {"/insertPermission", HandlerOptions(&HttpEntity::insertPermission, { DMPermission::NAME})}, + {"/updatePermission", HandlerOptions(&HttpEntity::updatePermission, { DMPermission::PERMISSION_ID})}, + + {"/insertRole", HandlerOptions(&HttpEntity::insertRole, { DMRole::NAME})}, + {"/updateRole", HandlerOptions(&HttpEntity::updateRole, { DMRole::ROLE_ID})}, + + {"/insertStation", HandlerOptions(&HttpEntity::insertStation, { DMStation::NAME})}, + {"/updateStation", HandlerOptions(&HttpEntity::updateStation, { DMStation::STATION_ID})}, + + {"/insertDevice", HandlerOptions(&HttpEntity::insertDevice, { DMDevice::NAME})}, + {"/updateDevice", HandlerOptions(&HttpEntity::updateDevice, { DMDevice::DEVICE_ID})}, + + {"/insertPolicy", HandlerOptions(&HttpEntity::insertPolicy, { DMPolicy::NAME})}, + {"/updatePolicy", HandlerOptions(&HttpEntity::updatePolicy, { DMPolicy::POLICY_ID})}, +}; + +bool CheckHttpToken(const httplib::Request& req) +{ + // 验证token + std::string token = req.get_param_value("token"); + if (!token.empty()) + { + User user = Application::data().getUser(token); + if (!user.userId.empty()) + { + return true; + } + } + return false; +} + + HttpEntity::HttpEntity() { bool useToken = Config::option.http.useToken; - for (auto& item : g_mapHttpHandler) + for (auto& item : g_mapHttpHandlerGet) { std::string name = item.first; HandlerOptions& handler = item.second; this->httpsvr.Get(name, [=, &handler](const httplib::Request& req, httplib::Response& resp) { spdlog::info("[http] request: {}", name); - NJsonNode json; Errcode errcode = Errcode::OK; - if (name != "/login" && useToken) { - // 验证token - std::string token = req.get_param_value("token"); - if (token.empty()) - { - errcode = Errcode::ERR_TOKEN; - } - else - { - User user = Application::data().getUser(token); - if (user.userId.empty()) - { - errcode = Errcode::ERR_TOKEN; - } - } + bool ret = CheckHttpToken(req); + errcode = ret ? Errcode::OK : Errcode::ERR_TOKEN; } + NJsonNode json; std::string errmsg; if (errcode == Errcode::OK) { @@ -169,7 +230,38 @@ HttpEntity::HttpEntity() errcode = (this->*(handler.func))(req, resp, json); } } + json["errcode"] = errcode; + json["errmsg"] = ErrcodeStr(errcode) + (errmsg.empty() ? "" : (":"+errmsg)); + resp.set_content(json.dump(), "text/plain; charset=utf-8"); + resp.status = 200; + }); + } + for (auto& item : g_mapHttpHandlerPost) + { + std::string name = item.first; + HandlerOptions& handler = item.second; + this->httpsvr.Post(name, [=](const httplib::Request& req, httplib::Response& resp) + { + Errcode errcode = Errcode::OK; + std::string errmsg; + if (name != "/login" && useToken) + { + bool ret = CheckHttpToken(req); + errcode = ret ? Errcode::OK : Errcode::ERR_TOKEN; + } + + if (errcode == Errcode::OK) + { + NJsonNode jsonparam; + bool ret = NJson::parse(req.body, jsonparam); + if (ret) + { + errcode = (this->*(handler.func))(req, resp, jsonparam); + } + } + + NJsonNode json; json["errcode"] = errcode; json["errmsg"] = ErrcodeStr(errcode) + (errmsg.empty() ? "" : (":"+errmsg)); resp.set_content(json.dump(), "text/plain; charset=utf-8"); @@ -383,6 +475,61 @@ Errcode HttpEntity::deleteStation(const httplib::Request& req, httplib::Response return DAO::remove(NULL, DMStation::TABLENAME, primaryKey, req.get_param_value(primaryKey)); }; +Errcode HttpEntity::queryStationInfo(const httplib::Request& req, httplib::Response& resp, NJsonNode& json) +{ + // 查询场站的基础配置信息 + std::string stationId = req.get_param_value("station_id"); + if (stationId.empty()) + { + return Errcode::ERR_PARAM; + } + + std::string sql = "SELECT * FROM " + DMStation::TABLENAME + " WHERE station_id=" + stationId + ";"; + std::vector result; + Errcode err = DAO::exec(NULL, sql, result); + if (err != Errcode::OK) + { + return err; + } + if (result.size() == 0) + { + return Errcode::ERR_DATA_NUL; + } + auto& fields = result[0]; + + NJsonNode jsondata; + std::string attr = fields.remove(DMStation::ATTR); + NJson::parse(attr, jsondata); + + FieldsToJson(fields, jsondata); + json["data"] = jsondata; + return Errcode::OK; + + // work_mode: 运行模式: + // capacity: 储能容量: + + // {"batttey_type": "磷酸铁锂", "cooling_type":"风冷", "voltage_rated":"300", "power_rated": "1500"} + // batttey_type: 电池类型: + // cooling_type: 冷却方式: + // voltage_rated: 电池额定电压: + // power_rated: PCS额定功率 +} +Errcode HttpEntity::queryStationData(const httplib::Request& req, httplib::Response& resp, NJsonNode& json) +{ + // 温度, 电压、电流、功率、功率因数、 + NJsonNode jsondata; + jsondata["voltage"] = Utils::toStr(200.32); + jsondata["current"] = Utils::toStr(20.56); + jsondata["power"] = Utils::toStr(200.32); + jsondata["powerFactor"] = Utils::toStr(1); + jsondata["envTemp"] = Utils::toStr(200.32); + jsondata["envhum"] = Utils::toStr(200.32); + jsondata["aircStatus"] = Utils::toStr(1); + jsondata["coolingStatus"] = Utils::toStr(0); + + json["data"] = jsondata; + return Errcode::OK; +} Errcode HttpEntity::queryDeviceList(const httplib::Request& req, httplib::Response& resp, NJsonNode& json) { @@ -513,40 +660,70 @@ Errcode HttpEntity::queryStatSystem(const httplib::Request& req, httplib::Respon { auto& appdata = Application::data(); - json["launch_date"] = "2025-01-01"; //: 系统上线启用日期,格式:yyyy-mm-dd - json["income_total"] = "0.00"; // : 累计收益(元),精度0.01 - json["station_num"] = Utils::toStr(appdata.getStationCount()); // : 能源站数量 - json["storage_device_num "] = Utils::toStr(appdata.getStationCount()); //: 储能设备数量 - json["solar_device_num"] = "0"; // : 光伏设备数量 - json["capacity_total"] = "0.000"; // : 储能总容量(kWh),精度0.001 - json["elect_gen"] = "0.000"; // : 发电总电量(kWh),精度0.001 - json["elect_grid"] = "0.000"; // : 入网种电量(kWh),精度0.001 - json["storage_elect_in"] = "0.000"; // : 储能充电总电量(kWh),精度0.001 - json["storage_elect_out"] = "0.000"; // : 储能放电总电量(kWh),精度0.001 + NJsonNode jsondata; + jsondata["launch_date"] = "2025-01-01"; //: 系统上线启用日期,格式: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()); //: 储能设备数量 + jsondata["solar_device_num"] = "0"; // : 光伏设备数量 + jsondata["capacity_total"] = std::to_string(Utils::random(100, 200)); // : 储能总容量(kWh),精度0.001 + jsondata["solar_elect_gen"] = std::to_string(Utils::random(100, 200)); // : 发电总电量(kWh),精度0.001 + jsondata["solar_elect_grid"] = std::to_string(Utils::random(100, 200)); // : 入网种电量(kWh),精度0.001 + jsondata["storage_elect_in"] = std::to_string(Utils::random(100, 200)); // : 储能充电总电量(kWh),精度0.001 + jsondata["storage_elect_out"] = std::to_string(Utils::random(100, 200)); // : 储能放电总电量(kWh),精度0.001 + json["data"] = jsondata; return Errcode::OK; } - Errcode HttpEntity::queryStatTotal(const httplib::Request& req, httplib::Response& resp, NJsonNode& json) { std::string station_id = req.get_param_value("station_id"); std::string category = req.get_param_value("category"); - json["dt"] = "2025-01-01"; //日期 - json["storage_elect_in"] = "123.123"; //储能充电电量(kWh),精度:0.001 - json["storage_elect_out"] = "123.123"; //储能放电电量(kWh),精度:0.001 - json["storage_num_in"] = "1"; //储能设备充电次数 - json["storage_num_out"] = "1"; //储能设备放电次数 - json["storage_num_err"] = "1"; //储能设备故障次数 - json["solar_elect_gen"] = "123.123"; //光伏发电电量(kWh),精度:0.001 - json["solar_elect_grid"] = "123.123"; //光伏入网电量(kWh),精度:0.001 - json["solar_num_err"] = "1"; //光伏设备故障次数 - json["charge_elect"] = "123.123"; //充电设备充电电量(kWh),精度:0.001 - json["charge_num"] = "1"; //充电设备充电次数 - json["charge_num_err"] = "1"; //充电设备故障次数 - json["income_elect"] = ""; //发电收益(元),精度:0.01 - json["income_charge"] = ""; //充电收益(元),精度:0.01 - json["usage"] = ""; + NJsonNode 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; +} +Errcode HttpEntity::queryStatStation(const httplib::Request& req, httplib::Response& resp, NJsonNode& json) +{ + std::string station_id = req.get_param_value("station_id"); + std::string category = req.get_param_value("category"); + NJsonNode 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; } @@ -554,12 +731,124 @@ Errcode HttpEntity::queryStatDayList(const httplib::Request& req, httplib::Respo { std::string station_id = req.get_param_value("station_id"); std::string category = req.get_param_value("category"); - std::string dt_start = req.get_param_value("dt_start"); - std::string dt_end = req.get_param_value("dt_end"); + std::string dt_start = req.get_param_value("start_date"); + std::string dt_end = req.get_param_value("end_date"); - if (!dt_start.empty() && dt_end.empty()) + int64_t t1 = Utils::time(dt_start)/1000; + int64_t t2 = Utils::time(dt_end)/1000; + + int64_t tMax = t1+ 86400 * 30; + NJsonNode jsondata = NJsonNode::array(); + for (int64_t t = t1; t<=t2 && t<=tMax; t += 86400) { + NJsonNode jnode; + jnode["station_id"] = station_id; + if (!category.empty()) jnode["category"] = category; + jnode["dt"] = Utils::dateStr(t*1000); //日期 + jnode["storage_elect_in"] = std::to_string(Utils::random(100, 200)); //储能充电电量(kWh),精度:0.001 + jnode["storage_elect_out"] = std::to_string(Utils::random(100, 200)); //储能放电电量(kWh),精度:0.001 + jnode["storage_num_in"] = std::to_string(Utils::random(1,5)); //储能设备充电次数 + jnode["storage_num_out"] = std::to_string(Utils::random(1, 5)); //储能设备放电次数 + jnode["storage_num_err"] = std::to_string(Utils::random(1, 5)); //储能设备故障次数 + jnode["solar_elect_gen"] = std::to_string(Utils::random(100, 200)); //光伏发电电量(kWh),精度:0.001 + jnode["solar_elect_grid "] = std::to_string(Utils::random(100, 200)); //光伏入网电量(kWh),精度:0.001 + jnode["solar_num_err"] = std::to_string(Utils::random(1, 5)); //光伏设备故障次数 + jnode["charge_elect"] = std::to_string(Utils::random(100, 200)); //充电设备充电电量(kWh),精度:0.001 + jnode["charge_num"] = std::to_string(Utils::random(1, 5)); //充电设备充电次数 + jnode["charge_num_err"] = std::to_string(Utils::random(1, 5)); //充电设备故障次数 + jnode["income_elect"] = std::to_string(Utils::random(100, 200)); //发电收益(元),精度:0.01 + jnode["income_charge"] = std::to_string(Utils::random(100, 200)); //充电收益(元),精度:0.01 + jnode["usage_rate"] = std::to_string(Utils::random(10, 50)); //利用率 + jsondata.push_back(jnode); } + json["data"] = jsondata; + return Errcode::OK; +} +Errcode HttpEntity::queryEnvironment(const httplib::Request& req, httplib::Response& resp, NJsonNode& json) +{ + std::string stationId = req.get_param_value("station_id"); + auto& appdata = Application::data(); + + auto station = appdata.getStation(Utils::toInt(stationId)); + if (!station) + { + spdlog::error("[http] request queryEnvironment failed, get station info error, station_id={}", stationId); + return Errcode::ERR_PARAM; + } + + NJsonNode jsondata; + + { // 温湿度 + auto& mapTempHumUnit = station->mapTempHumUnit; + NJsonNode nodearray = NJsonNode::array(); + for (auto iter = mapTempHumUnit.begin(); iter!=mapTempHumUnit.end(); iter++) + { + auto& unit = iter->second; + NJsonNode node; + node["pos"] = "#" + std::to_string(iter->first); + node["temp"] = unit.temp; + node["hum"] = unit.hum; + nodearray.push_back(node); + } + jsondata["temp_hum"] = nodearray; + } + { //空调 + auto& mapAircUnit = station->mapAircUnit; + AircUnit unitTmp; + AircUnit* unit = (mapAircUnit.size() > 0) ? &(mapAircUnit[0]) : &unitTmp; + NJsonNode nodearray = NJsonNode::array(); + if (unit) + { + NJsonNode node; + nodearray.push_back({{"pos", "开关"}, {"status", unit->powerOn == 0 ? "关机" : "开机"}}); + nodearray.push_back({{"pos", "启动制冷指令"}, {"status", unit->cooling == 0 ? "启动" : "关闭"}}); + nodearray.push_back({{"pos", "启动送风指令"}, {"status", unit->airSupply == 0 ? "关闭" : "启动"}}); + nodearray.push_back({{"pos", "启动待机指令"}, {"status", unit->standby == 0 ? "关闭" : "启动"}}); + nodearray.push_back({{"pos", "启动加热指令"}, {"status", unit->heating == 0 ? "关闭" : "启动"}}); + nodearray.push_back({{"pos", "传感器故障"}, {"status", unit->sensorAlarm == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "高低电压告警"}, {"status", unit->voltageAlarm == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "高低温告警"}, {"status", unit->tempAlarm == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "高低压告警"}, {"status", unit->pressureAlarm == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "压缩机告警"}, {"status", unit->compressorAlarm == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "当前温度"}, {"status", std::to_string(unit->temp) + "℃"}}); + nodearray.push_back({{"pos", "当前湿度"}, {"status", std::to_string(unit->hum) + "%"}}); + } + jsondata["airc"] = nodearray; + } + { // 消防 + static std::map mapFireStatusDef = { {0, "正常"}, {1,"预警"}, {2,"火警"} }; + + auto& mapFire40Unit = station->mapFire40Unit; + NJsonNode nodearray = NJsonNode::array(); + for (auto iter = mapFire40Unit.begin(); iter!=mapFire40Unit.end(); ++iter) + { + NJsonNode node; + node["pos"] = "#" + std::to_string(iter->first); + node["status"] = mapFireStatusDef[iter->second]; // 0:正常 1:预警 2:火警 + nodearray.push_back(node); + } + jsondata["fire40"] = nodearray; + } + { // 冷机 + auto& mapCoolingUnit = station->mapCoolingUnit; + CoolingUnit unitTmp; + CoolingUnit* unit = (mapCoolingUnit.size() > 0) ? &(mapCoolingUnit[0]) : &unitTmp; + NJsonNode nodearray = NJsonNode::array(); + if (unit) + { + NJsonNode node; + nodearray.push_back({{"pos", "开关"}, {"status", unit->powerOn == 0 ? "关机" : "开机"}}); + nodearray.push_back({{"pos", "采样模式"}, {"status", unit->mode == 0 ? "出水温度" : "电芯温度"}}); + nodearray.push_back({{"pos", "制冷状态"}, {"status", unit->cooling == 0 ? "关闭" : "启动"}}); + nodearray.push_back({{"pos", "制热状态"}, {"status", unit->heating == 0 ? "关闭" : "启动"}}); + nodearray.push_back({{"pos", "高温告警"}, {"status", unit->highTemp == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "低温告警"}, {"status", unit->lowTemp == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "高压告警"}, {"status", unit->highPressure == 0 ? "正常" : "告警"}}); + nodearray.push_back({{"pos", "低压告警"}, {"status", unit->lowPressure == 0 ? "正常" : "告警"}}); + } + jsondata["cooling"] = nodearray; + } + json["data"] = jsondata; return Errcode::OK; } \ No newline at end of file diff --git a/src/protocol/HttpEntity.h b/src/protocol/HttpEntity.h index eb9fa0c..1f8dd44 100644 --- a/src/protocol/HttpEntity.h +++ b/src/protocol/HttpEntity.h @@ -35,6 +35,9 @@ public: Errcode updateStation(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); Errcode deleteStation(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); + Errcode queryStationInfo(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); + Errcode queryStationData(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); + Errcode queryDeviceList(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); Errcode insertDevice(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); Errcode updateDevice(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); @@ -58,5 +61,8 @@ public: Errcode queryStatSystem(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); Errcode queryStatTotal(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); + Errcode queryStatStation(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); Errcode queryStatDayList(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); + + Errcode queryEnvironment(const httplib::Request& req, httplib::Response& resp, NJsonNode& json); }; \ No newline at end of file diff --git a/src/protocol/MqttEntity.cpp b/src/protocol/MqttEntity.cpp index 2af8534..9fefcbe 100644 --- a/src/protocol/MqttEntity.cpp +++ b/src/protocol/MqttEntity.cpp @@ -4,17 +4,31 @@ #define TIMEOUT 10000L -int MqttClient::init(string addr, string client_id, string username, string password, std::vector vecTopic) +int MqttClient::init(string addr, string clientId, string username, string password) { this->addr = addr; - this->vecTopic = vecTopic; + 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", + }; MQTTAsync_connectOptions option = MQTTAsync_connectOptions_initializer; MQTTAsync_message pubmsg = MQTTAsync_message_initializer; int rc {0}; // "tcp://localhost:1883" - rc = MQTTAsync_create(&client, addr.c_str(), client_id.c_str(), MQTTCLIENT_PERSISTENCE_NONE, NULL); + rc = MQTTAsync_create(&client, addr.c_str(), clientId.c_str(), MQTTCLIENT_PERSISTENCE_NONE, NULL); if (rc != MQTTASYNC_SUCCESS) { spdlog::error("[mqtt] MQTTAsync_create error: {}", rc); @@ -42,6 +56,7 @@ int MqttClient::init(string addr, string client_id, string username, string pass if (rc != MQTTASYNC_SUCCESS) { spdlog::error("[mqtt] MQTTAsync_setCallbacks error"); + this->destory(); return rc; } @@ -70,55 +85,43 @@ int MqttClient::init(string addr, string client_id, string username, string pass //MQTTAsync_destroy(&client); } +void MqttClient::destory() +{ + if (client) + { + MQTTAsync_destroy(&client); + client = nullptr; + } +} + struct SubscribInfo { std::function callback; }; -void MqttClient::subscribe(std::vector vecTopics, std::function callback) +void MqttClient::subscribe() { - SubscribInfo* info = new SubscribInfo(); - info->callback = callback; + MQTTAsync_onSuccess* funcSuccess = [](void* context, MQTTAsync_successData* response) + { + spdlog::info("[mqtt] subscribe {} success.", (char*)context); + }; + MQTTAsync_onFailure* funcFailure = [](void* context, MQTTAsync_failureData* response) + { + spdlog::error("[mqtt] subscribe {} failed.", (char*)context); + }; MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer; - options.context = info; - options.onSuccess = [](void* context, MQTTAsync_successData* response) - { - spdlog::info("[mqtt] subscribe success."); - SubscribInfo* info = (SubscribInfo*)context; - info->callback(0); - delete info; - - }; - options.onFailure = [](void* context, MQTTAsync_failureData* response) - { - spdlog::error("[mqtt] subscribe failed."); - SubscribInfo* info = (SubscribInfo*)context; - info->callback(-1); - delete info; - }; - - - int count = 3; - char* topicsTmp[] = { - "topic/aa", - "topic/bb", - "topic/cc" - }; - std::vector qosTmp(count, 1); // 为每个主题指定 QoS - - if (count > 0) + options.onSuccess = funcSuccess; + options.onFailure = funcFailure; + for (auto& topic: vecTopic) { - int rc = MQTTAsync_subscribeMany(client, count, topicsTmp, qosTmp.data(), &options); + options.context = topic.data(); + int rc = MQTTAsync_subscribe(client, topic.data(), qos, &options); if (rc != MQTTASYNC_SUCCESS) { - spdlog::error("[mqtt] subscribe failed, err={}", rc); + spdlog::error("[mqtt] subscribe [{},{}] failed, err={}", topic, qos, rc); } } - else - { - delete info; - } } int MqttClient::publish(string topic, string text) @@ -151,18 +154,45 @@ int MqttClient::publish(string topic, string text) void MqttClient::onConnectionLost(char* cause) { this->isConnected = false; + this->destory(); spdlog::error("MQTT connection lost, cause={}", cause); } +std::string GetSubStr(std::string c, std::string& str) +{ + std::string v; + int pos = str.find_first_of("/"); + if (pos != string::npos) + { + v = str.substr(0, pos); + str = str.substr(pos); + } + return v; +} + int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* msg) { + std::string topicStr = topic; int len = msg->payloadlen; - char* payload = (char*)msg->payload; + std::string payload = (char*)msg->payload; spdlog::info("MQTT message arrived: topic=[{},{}], payload len={}, payload msg={}", topic, msg->qos, len, payload); + // <数据方向>/<数据格式>/<厂家ID>/<指合>/<设备标识,上行可选> + std::string direction = GetSubStr("/", topicStr); + std::string datatype = GetSubStr("/", topicStr); + std::string stationId = GetSubStr("/", topicStr); + std::string command = GetSubStr("/", topicStr); + std::string deviceCode = GetSubStr("/", topicStr); + + if (command == "EMS_YX") {} + else if (command == "EMS_YC") {} + else if (command == "PCU_YX") { this->parsePCU_YX(payload); } + else if (command == "PCU_YC") {} + // 必须释放消息内存! MQTTAsync_freeMessage(&msg); MQTTAsync_free(topic); + return 1; // 1表示消息已经处理 } @@ -175,8 +205,9 @@ void MqttClient::onDeliveryComplete(MQTTAsync_token token) void MqttClient::onConnectSuccess( MQTTAsync_successData* resp) { + spdlog::info("[mqtt] connect to {} success.", addr); this->isConnected = true; - //spdlog::info("[mqtt] connect success: {}", addr); + this->subscribe(); //MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer; //options.context = this; //options.onSuccess = [](void* context, MQTTAsync_successData* response) @@ -203,63 +234,23 @@ void MqttClient::onConnectSuccess( MQTTAsync_successData* resp) } void MqttClient::onConnectFaiure(MQTTAsync_failureData* resp) { + spdlog::error("[mqtt] connect to {} error.", addr); this->isConnected = false; + this->destory(); } -string MQTT::packEquipmentInfo(mqtt::EquipmentInfo& info) + +void MqttClient::parseEMS_YC(std::string& text) +{ + +} +void MqttClient::parsePCU_YX(std::string& text) { - NJsonNode jsonroot; - jsonroot["EquipmentID"] = info.EquipmentID.c_str(); - jsonroot["ManufacturerID"] = info.ManufacturerID.c_str(); - jsonroot["EquipmentModel"] = info.EquipmentModel.c_str(); - jsonroot["ProductionDate"] = info.ProductionDate.c_str(); - jsonroot["OpenForBusinessDate"] = info.OpenForBusinessDate.c_str(); - jsonroot["EquipmentType"] = info.EquipmentType; - return jsonroot.dump(); } -string MQTT::packSwapEquipmentStatusInfo(string node_id) +string MQTT::packEquipmentInfo() { NJsonNode jsonroot; return jsonroot.dump(); } - - -string MQTT::packNotifyStationInfo() -{ - NJsonNode jsonroot; - return jsonroot.dump(); -} - - -string MQTT::packNotifyAlarm() -{ - NJsonNode jsonroot; - return jsonroot.dump(); -} - -string MQTT::packNotifyChargeStatus() -{ - NJsonNode jsonroot; - return jsonroot.dump(); -} - -string MQTT::packNotifySwapStatus() -{ - NJsonNode jsonroot; - return jsonroot.dump(); -} - -string MQTT::packNotifyChargeOrder() -{ - NJsonNode jsonroot; - return jsonroot.dump(); -} - - -string MQTT::packNotifySwapOrder() -{ - NJsonNode jsonroot; - return jsonroot.dump(); -} \ No newline at end of file diff --git a/src/protocol/MqttEntity.h b/src/protocol/MqttEntity.h index 142d37a..f709a06 100644 --- a/src/protocol/MqttEntity.h +++ b/src/protocol/MqttEntity.h @@ -10,10 +10,10 @@ using namespace std; class MqttClient { public: - int init(string addr, string client_id, string username, string password, std::vector vecTopic); - - void subscribe(std::vector topics, std::function callback); + int init(string addr, string clientId, string username, string password); + void destory(); + void subscribe(); int publish(string topic, string text); void onConnectionLost(char* cause); @@ -23,13 +23,15 @@ public: void onConnectSuccess(MQTTAsync_successData* resp); void onConnectFaiure(MQTTAsync_failureData* resp); + void parseEMS_YC(std::string& text); + void parsePCU_YX(std::string& text); public: + std::string clientId; MQTTAsync client = nullptr; std::vector vecTopic; std::string addr; // "tcp://localhost:1883" int qos {1}; - std::string clientId; bool isConnected {false}; bool isSubscribed {false}; }; @@ -52,317 +54,11 @@ public: #define TOPIC_PCS_YC "up/json/预制舱01/PCS_YC" -#define MQTT_TOPIC_NOTIFY_STATION "notification_stationInfo" // 充(换)电站信息变化推送 -#define MQTT_TOPIC_QUERY_STATION "query_stations_info" // 查询充(换)电站信息 -#define MQTT_TOPIC_NOTIFY_ALARM "notification_alarmInfo" // 告警信息推送 -#define MQTT_TOPIC_NOTIFY_CHARGE_STATUS "notification_connectorStatus" //充电设备状态变化推送 -#define MQTT_TOPIC_NOTIFY_SWAP_STATUS "notification_swapStatus" //换电设备状态变化推送 -#define MQTT_TOPIC_QUERY_STATUS "query_station_status" //查询站内设备接口状态 -#define MQTT_TOPIC_NOTIFY_CHARGE_ORDER "notification_orderInfo" //充电电量信息推送 -#define MQTT_TOPIC_QUERY_ORDER "query_order_info" //查询充电电量信息 -#define MQTT_TOPIC_NOTIFY_SWAP_ORDER "notification_swapInfo" //换电记录信息推送 -#define MQTT_TOPIC_QUERY_SWAP_ORDER "query_swap_info" //查询换电电量信息 - -namespace mqtt -{ - // 充(换)电运营商信息 - struct OperatorInfo - { - string OperatorID; // 运营商ID 组织机构代码 是 字符串 9 字符 - string OperatorName; // 运营商名称 机构全称 是 字符串 <= 64 字符 - string OperatorTel1; // 运营商电话1 运营商客服电话 1 是 字符串 <= 32 字符 - string OperatorTel2; // 运营商电话2 运营商客服电话 2 否 字符串 <= 32 字符 - string OperatorRegAddress; // 运营商注册地址 运营商注册地址 否 字符串 <= 64 字符 - string OperatorNote; // 备注 备注信息 否 字符串 <= 255 字符 - }; - - // 充(换)电站信息 - struct StationInfo - { - string StationID; // 充(换)电站 ID 运营商自定义的唯一编码 是 字符串 <= 20 字 符 - string OperatorID; // 运营商 ID 电动汽车充(换)电服务平台的运营商 ID 是 字符串 9 字符 - string EquipmentOwnerID; // 设备所属方 ID 设备所属方组织机构代码,所属方为个人时可不填 否 字符串 9 字符 - - string StationName; // 充(换)电站名称 充(换)电站名称的描述 是 字符串 <= 50 字 - - string CountryCode; // 充(换)电站国家代码 比如 CN 是 字符串 2 字符 - string AreaCode; // 充(换)电站省市辖区编码 填写内容为参照 GB / T2260,以民政部发布最新数据为准 是 字符串 <= 20 字符 - string Address; // 详细地址 是 字符串<= 100字符 - string StationTel; // 站点电话 能够联系场站工作人员进行协助的联系电话 否 字符串<= 30 字符 - string ServiceTel; // 服务电话 平台服务电话,例如 400 电话 是 字符串<= 30字符 - string ServiceType; // *服务类型 1:充电 2:换电 3:充换电 255:其他 是 整型 - string StationType; // 站点类型 1:公共充(换)电站 2:专用充(换)电站 3:居民充电站 255:其他 是 整型 - string StationStatus; // 站点状态 0:未知 1:建设中 5:关闭下线 6:维护中 50:正常使用 是 整型 - string ParkNums; // 车位数量 可停放进行充电的车位总数, 默认:0 未知 是 整型 - float StationLng; // 经度 GCJ - 02 坐标系 是 浮点型 保留小数点后6 位 - float StationLat; // 纬度 GCJ - 02 坐标系 是 浮点型保留小数点后6 位 - string SiteGuide; // 站点引导描述性文字,用于引导车主找到充电车位 否 字符串<= 255字符 - - - int Construction; // 建设场所 - //101:公共服务场所 - //102:公共停车场 - //103:城市交通节点 - //104:加油站 - //105:具备停车条件的充电区域 - //106:高速服务区 - //201:政府机关 - //202:公共机构 - //203:企业事业单位 - //204:公交 - //205:环卫 - //206:物流 - //207:出租车 - //208:港口码头 - //209:重卡换电场所 - //210:矿卡换电场所 - //301:居民(小)区 - //255:其他 - // 是 整型 - string Pictures; // 站点照片 充(换)电设备照片、充(换)电车位照片、停车场入口照片 是 字符串数组 无照片时可传空数组 - string MatchCars; // 服务车型描述 描述该站点可充(换)电服务 的车辆类型:如大巴、物流车、私家乘用车、出租车、重卡型卡车等 否 字符串<= 255字符 - string ParkInfo; // 车位楼层及数量描述车位楼层以及数量信息 否 字符串<= 100字符 - int OpenAllDay; // *全天开放 0:否 1:是 是 整型 - string OpenForBusinessDate; // *投运日期 站点投运日期 yyyy - MM - dd 格式 是 字符串 - string BusineHours; // 营业时间 营业时间描述 否 字符串<=255字符 - - string ElectricityFee; // *电费费率 示例 [{"StartTime":"000000","Price":"1.0000"},{"StartTime":"120000","Price":"1.2000"}] 否 字符串 <= 2000 字符 - string ServiceFee; // *服务费率 示例[{"StartTime":"000000","Price":"1.0000"},{"StartTime":"120000","Price":"1.2000"}] 否 字符串 <= 2000 字符 - - - string ParkOwner; // *停车场产权方 停车场产权人 否 字符串 - string ParkManager; // *停车场管理方 停车场管理人(如:XX 物业) 否 字符串 - int ParkType; // 停车费类型 0:免费 1:不免费 2:限时免费停车 3:充电限时减免 255:参考场地实际收费标准 否 整型 - string ParkFee; // 停车费描述 停车费率描述 否 字符串 <= 255字符 - string Payment; // 支付方式 支付方式: 刷卡、线上、现金其中电子钱包类卡为刷卡,身份鉴权卡、微信 / 支付宝等在线支付、APP 支付为线上否 字符串<= 20 字符 - int SupportOrder; // 是否支持预约 0:不支持预约 1:支持预约。不填默认为 0 否 整型 - string Remark; // 备注 其他备注信息 否 字符串<= 100字符 - string EquipmentInfos; // 充电设备信息列表 该充(换)电站所有充电设备 信息对象数组 是 EquipmentInfos[],参照 4.4 - string SwapEquipmentInfos; // *换电设备信息列表 该充(换)电站所有换电设备。换电站以及充换电站提供此数据,充电站默认空数组。 是 SwapEquipmentInfo[],参照 4.6 换电工位信息 - int BatteryNo; // *备用电池数量换电站内可提供更换最大电池数量。换电站以及充换电站提供此数据,充电站默认填0。 是 整型 - }; - - // 充电设备信息 - struct EquipmentInfo - { - string EquipmentID; - string ManufacturerID; - string EquipmentModel; - string ProductionDate; - string OpenForBusinessDate; - int EquipmentType; - int EquipmentStatus; - vector ConnectorInfos; - float EquipmentLng; - float EquipmentLat; - float Power; - string EquipmentName; - }; - - // 充电设备接口信息 - struct ConnectorInfo - { - string ConnectorID; // 充电设备接口编码 充电设备接口编码,同一运营商内唯一 是 字符串 <= 64 字符 - string ConnectorName; // 充电设备接口名称 否 字符串 <= 30 字符 - int ConnectorType; // 充电设备接口类型 - //1:家用插座(模式 2) - //2:交流接口插座(模式 3,连接方式 B ) - //3:交流接口插头(带枪线,模式 3,连接方式 C) - //4:直流接口枪头(带枪线,模式 4) - //5:无线充电座 - //6:其他 - //7:对换电站电池箱的接口 - //是 整型 - int VoltageUpperLimits; // 额定电压上限 单位:V 是 整型 - int VoltageLowerLimits; // 额定电压下限 单位:V 交流可与额定电压上限相同 是 整型 - int ConstantVoltageUpperLimits; // *恒功率电压上限 单位:V 否 整型 - int ConstantVoltageLowerLimits; // *恒功率电压下限 单位:V 否 整型 - int Current; // 额定电流 单位:A 是 整型 - float Power; // 额定功率 单位:kW 是 浮点型 保留小数点后一位 - string ParkNo; // 车位号 停车场车位编号,或充电架编号 否 字符串 <= 10 字符 - int NationalStandard; // 国家标准 1:2011 2 : 2015 3 : 兼容 2011 和 2015 是 整型 - }; - - // 换电设备信息(SwapEquipmentInfo) - class SwapEquipmentInfo - { - string EquipmentID; // 设备编码 换电设备唯一编码,同一运营商下唯一 是 字符串 <= 64 字符 - string ManufacturerID; // 设备生产商组织机构代码 设备生产商组织机构代码 否 字符串 9 字符 - string EquipmentModel; // 设备型号 由设备生厂商定义的设备型号 否 字符串 <= 20 字符 - string ProductionDate; // 设备生产日期 YYYY - MM - DD 否 字符串 10 字符 - string OpenForBusinessDate; // *投运日期 充电桩投运日期 yyyy - MM - dd 格式 是 字符串 - string OpreateStatus; // 运营状态 0:未知 1:建设中 5:关闭下线 6:维护中 50:正常使用 是 整型 - int EquipmentType; // 换电设备类型 填写内容为参照GB29317 - 2021 4.3节中的描述 1:侧向换电 2:底部换电 3:顶部换电 4:端部换电 5:中置换电 255:其他 是 整型 - string MatchCars; // 服务车型描述 描述该设备可服务的车辆类型以及 型号等 否 字符串<= 1000 字符 - string SupplyBattery; // 提供电池描述 描述该设备提供的电池类型以及型号等 否 字符串<= 100 字符 - }; - - //电池箱信息 - struct BatteryInfo - { - string BatteryNo; // 电池箱编号 运营商自定义唯一编码 是 字符串 <= 32 字 - string BatteryOwnerID; // 电池所属方ID 设备所属方组织机构代码,所属方为个人时可不填 否 字符串 9 字符 - string ManufacturerID; // 设备生产商组织机构代码 设备生产商组织机构代码 否 字符串 9 字符 - string BatteryModel; // 电池型号 由设备生厂商定义的设备型号 否 字符串 <= 20 字符 - string ProductionDate; // 设备生产日期 YYYY - MM - DD 否 字符串 10 字符 - string OpenForBusinessDate; // 投运日期 电池投运日期 yyyy - MM - dd 格式 是 字符串 - int CellNum; // 电池箱所含单体电池个数 电池箱所含单体个数 是 整型 - int SeriesNum; // 单体电池串联总数 串联总数 否 整型 - int ParallelNum; // 单体电池并联总数 并联总数 否 整型 - int BatteryType; // 电池类型 - //1:磷酸铁锂电池 - //2:锰酸锂电池 - //3:钴酸锂电池 - //4:三元材料电池 - //5:聚合物锂离子电池 - //6:钛酸锂电池 - //7:燃料电池 - //255:其它 - //是 整型 - float RatedCapacity; // 电池箱额定容量 单位:Ah,小数点后 1 位 是 浮点型 - float RatedVoltage; // 电池箱额定电压 单位:V,小数点后 1 位 是 浮点型 - }; - - // 充电设备接口状态 - struct ConnectorStatusInfo - { - string ConnectorID; // 充电设备接口编码 充电设备接口编码,同一运营商内唯一 是 字符串<= 64 字符 - string UpdateTime; // 状态更新时间 本次状态变化的时间,格式“yyyy -MM - dd HH : mm:ss” 是 字符串 <= 20 字符 - int Status; // 接口状态 0:离线 1:空闲 2:占用(未充电) 3:占用(充电中) 4:占用(预约锁定) 255:故障 是 整型 - int ParkStatus; // 车位状态 0:未知 10:空闲 50:占用 否 整型 - int LockStatus; // 地锁状态 0:未知 10:已解锁 50:已上锁 否 整型 - int CurrentA; // A 相电流 单位:A,默认:0 含直流(输出) 是 整型 - int CurrentB; // B 相电流 单位:A,默认:0 否 整型 - int CurrentC; // C 相电流 单位:A,默认:0 否 整型 - int VoltageA; // A 相电压 单位:V,默认:0 含直流(输出) 是 整型 - int VoltageB; // B 相电压 单位:V,默认:0 否 整型 - int VoltageC; // C 相电压 单位:V,默认:0 否 整型 - float SOC; // *剩余电量 默认:0 交流充电桩采集不到SOC 值的填 0 是 浮点型 - string Begin_time; // *开始充电时间 格式 为 yyyy-MM-dd HH:mm:ss 是 字符串 - float Current_kwh; // *本次已充电量 单位:kWh 是 浮点型 - float Current_meter; // *当前电表读数 单位:kWh 否 浮点型 - string Vin; // *车架号 否 字符串 <= 20 字符 - //BatteryStatusInfo //*电池状态信息 充电设备有电池情况下需上报 是 BatteryStatusInfo,参照4.9 - }; - - // 电池箱状态 - struct BatteryStatusInfo - { - string BatteryNo; // 电池箱编号 (充电设备有电池情况下需上报) 是 字符串<= 32 字符 - string UpdateTime; // 状态更新时间 本次状态变化的时间,格式“yyyy -MM - dd HH : mm:ss” 是 字符串 <= 20 字符 - float Voltage; // 当前电压 单位:V,小数点后 2 位 (充电设备有电池情况下需上报) 是 浮点型 - float Current; // 当前电流 单位:V,小数点后 2 位 (充电设备有电池情况下需上报) 是 浮点型 - float SOC; // 当前 Soc 当前电池电量百分比,范围:0~100,小数点后 1 位 (充电设备有电池情况下需上报) 是 浮点型 - float SOH; // 当前 Soh 当前电池健康度,范围:0~100,小数点后 1 位(充电设备有电池情况下需上报)是 浮点型 - int BatteryIsFault; // 电池箱是否故障 0:未知 1:是 2:否 (充电设备有电池情况下需上报) 是 整型 - int MaxVoltageBatteryNo; // 最高电压单体电池编号 充电设备有电池情况下需上报 否 整型 - float MaxVoltage; // 最高电压单体电池电压值单位: V,小数点后3位 充电设备有电池情况下需上报 否 浮点型 - int MinVoltageBatteryNo; // 最低电压单体电池编号 充电设备有电池情况下需上报 否 整型 - float MinVoltage; // 最低电压单体电池电压值 单位: V,小数点后 3 位 充电设备有电池情况下需上报 否 浮点型 - float MaxTempBatteryNo; // 最高温度测温点编号 充电设备有电池情况下需上报 否 整型 - int MaxTemp; // 最高温度测温点温度值 单位:℃ 充电设备有电池情况下需上报 否 整型 - int MinTempBatteryNo; // 最低温度测温点编号 充电设备有电池情况下需上报 否 整型 - int MinTemp; // 最低温度测温点温度值 单位:℃ 充电设备有电池情况下需上报 否 整型 - }; - - // 换电设备状态(SwapEquipmentStatusInfo) - struct SwapEquipmentStatusInfo - { - string EquipmentID; // 换电设备编码 换电设备编码,同一运营商内唯一 是 字符串 <= 64 字符 - string UpdateTime; // 状态更新时间 本次状态变化的时间,格式“yyyy - MM - dd HH : mm:ss” 是 字符串 <= 20 字符 - int Status; // 换电设备状态 0:离线 1:空闲 2:工作 255:故障 是 整型 - int SwapMode; // 换电模式 0:手动模式 1:半自动模式 2:全自动模式 3:检修模式 否 整型 - }; - - // 充(换)电站状态(StationStatusInfo) - struct StationStatusInfo - { - string StationID; // 充(换)电站 ID 运营商自定义的唯一编码 是 字符串 <= 20 字符 - string ConnectorStatusInfos; // 充电设备接口状态列表 充(换)电站下所有充电设备接口的状态对象数组 是 ConnectorStatusInfos[], 参照 5.6 - - string SwapEquipmentStatusInfo; // 换电设备状态列 所有充电设备接口的是 SwapEquipmentStatusInfo[]表 状态 ,参照4.10 - }; - - //充电电量信息(OrderInfo) - struct OrderInfo - { - string OperatorID; // 运营商 ID 统一社会信用代码 是 字符串 9 字符 - string ConnectorID; // 充电设备接口编码 充电设备接口编码,同一充(换)电运营平台内唯一 是 字符串 <= 26 字符 - string StartChargeSeq; // 充电业务编号 运营商充电业务编号 是 字符串 <= 32 字符 - int UserChargeType; // 用户发起充电类型 1:充(换)电运营平台注册用户 2 : 监管平台注册用户 3 : 其他 否 整型 - string MobileNumber; // 用户手机号 若用户发起充电类型为APP,用户手机号必填否 字符串 - float Money; // 本次充电消费总金额 单位:元 若通过苏e充APP启动,此字段为必填项。 否 浮点型 - float ElectMoney; // 本次充电电费总金额 单位:元 若通过苏e充APP启动,此字段为必填项。 否 浮点型 - float ServiceMoney; // 本次充电服务费金额 单位:元 若通过苏e充APP启动,此字段为必填项。 否 浮点型 - float Elect; // 本次充电电量 单位 kWh,精度0.001,如果不设置峰谷电价,平电量等于本次充电电量,其他分电量为零。 是 浮点型 - float CuspElect; // *尖阶段电量 单位 kWh,精度0.001 是 浮点型 - float PeakElect; // *峰阶段电量 单位 kWh,精度0.001 是 浮点型 - float FlatElect; // *平阶段电量 单位 kWh,精度0.001, 是 浮点型 - float ValleyElect; // *谷阶段电量 单位 kWh,精度0.001 是 浮点型 - float StartTime; // 本次充电开始时间 格式“yyyy - MM - ddHH : mm:ss” 是 字符串 - float EndTime; // 本次充电结束时间 格式“yyyy - MM - ddHH : mm: ss” 是 字符串 - float PaymentAmount; // 支付金额 支付金额 若通过苏e充APP启动,此字段为必填项。 否 浮点型 保留小数点后 2 位 - float MeterValueStart; // *电表总起值 单位 kWh,精度0.001 是 浮点型 保留小数点后三位 - float MeterValueEnd; // *电表总止值 单位 kWh,精度0.001 是 浮点型 保留小数点后三位 - float Vin; // *本次充电车架号 充电设备有车辆VIN码需上报 否 字符串 <= 64 字符 - float BatteryNo; // *本次充电电池编号 充电设备有电池情况下需上报 否 字符串 <= 64 字符 - float ExchangeChargeSeq;// *换电记录编号 格式“运营商 ID + 唯一编号”,27 字符,如果有对应的换电记录需要填写是 字符串 <= 40 字符 - }; - - // 换电记录信息(SwapInfo) - struct SwapInfo - { - string OperatorID; //运营商 ID 统一社会信用代码 是 字符串 9 字符 - string EquipmentID; // 换电设备编码 换电设备接口编码,同一充(换)电运营平台内唯一 是 字符串 <= 40 字符 - - string ExchangeChargeSeq; // 换电记录编号 格式“运营商 ID + 唯一编号”,27 字 符 是 字符串 - string SwapMode; // 换电模式 0:手动模式 1:半自动模式 2:全自动模式 3:检修模式 否 整型 - string CarNo; // 车牌号 否 字符串 <= 16 字符 - string Vin; // 车辆VIN码 车辆识别码;见GB - T - 27930 - 2015国标PGN512 BMS 和车辆辨识报文(BRM)约定 否 字符串 - string RepDownBatteryNo;// 换下电池箱编号 运营商自定义唯一 编码, 是 字符串 <= 32 字符 - string RepDownBatterySoc;// 换下电池箱SOC 电池电量百分比,范围:0~100, 是 整型 - string RepOnBatteryNo;//换上电池箱编号 运营商自定义唯一编码,是 字符串 <= 32 字符 - int RepOnBatterySoc; //换上电池箱SOC 电池电量百分比,范围:0~100 是 整型 - float TotalPower; //换上电池箱总充入电量 单位:度(kWh) 是 浮点型 保留小数点后两位 - string StartTime; //换电开始时间 格式“yyyy - MM - dd HH : mm:ss” 是 字符串 - string EndTime; //换电结束时间 格式“yyyy - MM - dd HH : mm: ss” 是 字符串 - }; - - // 充(换)电设备告警信息(AlarmInfo) - struct AlarmInfo - { - string EquipmentID; // 设备编码 充电接口唯一编码,对同一运营商,保证唯一 是 字符串 23 字符 - int EquipmentType; //设备类型 1:充电设备 2:换电设备 整型 - string Alert_time; //告警时间 格 式 为 yyyy - MMdd HH : mm:ss 是 字符串 - int Alert_code; //告警代码 告警代码 是 整型 - string Describe; //描述 文字描述,最大长度 256字符。是 字符串 256 字符 - int Status; //状态 告警发生:0;告警 恢复: 1,默认为 0。是 整型 - }; -} - - class MQTT { public: - static string packEquipmentInfo(mqtt::EquipmentInfo& info); + - static string packSwapEquipmentStatusInfo(string node_name); - - // 充(换)电站信息变化推送 - static string packNotifyStationInfo(); - - // 告警信息推送 - static string packNotifyAlarm(); - - // 充电设备状态变化推送, 充电启停或者离线状态改变时推送,充电过程中每分钟一次推送 - static string packNotifyChargeStatus(); - - // 换电设备状态变化推送 - static string packNotifySwapStatus(); - - // 充电电量信息推送(chon), 充电结束后5分钟内推送 - static string packNotifyChargeOrder(); - - // 换电记录信息推送, 换电结束后5分钟内推送 - static string packNotifySwapOrder(); +public: + static string packEquipmentInfo(); }; \ No newline at end of file