调试预制舱通讯协议修改数据解析

This commit is contained in:
lixiaoyuan
2025-09-18 20:12:46 +08:00
parent cec5cdc19a
commit 2ba4ab2781
28 changed files with 363415 additions and 662 deletions

Binary file not shown.

BIN
bin/Release/ESS.pdb Normal file

Binary file not shown.

View File

@@ -1,34 +1,8 @@
{
"debug":0,
"launchdate": "2025-09-01",
"weburl": "http://127.0.0.1:19601/",
"database": {"host": "localhost", "port": 3306, "user": "root", "passwd": "123456", "dbname": "ess"},
"http": {"token":0, "port": 19801, "encryption":0, "encryptKey":""},
"token":"",
"http": {"port": 19801},
"mqtt": {"host":"mqtt://43.136.119.46:6203","username":"jsyhsec","password":"123456"},
"topic": {
"EMS_YX": {"deviceType":101, "polling":0, "enabled": 1},
"EMS_YC": {"deviceType":101, "polling":0, "enabled": 1},
"EMS_YT": {"deviceType":101, "polling":0, "enabled": 1},
"PCS_YX": {"deviceType":102, "polling":1, "enabled": 1},
"PCS_YC": {"deviceType":102, "polling":1, "enabled": 1},
"PCU_YX": {"deviceType":103, "polling":0, "enabled": 1},
"PCU_YC": {"deviceType":103, "polling":0, "enabled": 1},
"BMS_YX": {"deviceType":104, "polling":0, "enabled": 1},
"BMS_YC": {"deviceType":104, "polling":0, "enabled": 1},
"BCU_YC": {"deviceType":105, "polling":1, "enabled": 1},
"BCU_YX": {"deviceType":105, "polling":1, "enabled": 1},
"MEM_YC": {"deviceType":3, "polling":0, "enabled": 1},
"TH_YC": {"deviceType":10, "polling":1, "enabled": 1},
"Fire40_YX": {"deviceType":7, "polling":1, "enabled": 1},
"Cooling_YC": {"deviceType":14, "polling":1, "enabled": 1},
"Cooling_YX": {"deviceType":14, "polling":1, "enabled": 1},
"Gateway_YX": {"deviceType":15, "polling":1, "enabled": 1},
"Gateway_YC": {"deviceType":15, "polling":1, "enabled": 1},
"Charger_YC": {"deviceType":106, "polling":0, "enabled": 1}
},
"view": {"latitude":0,"longitude":0,"altitude":0},
"video": {
"1":{"host":"", "port":9000, "user":"", "passwd":""}
}
"weburl": "http://127.0.0.1:19601/"
}

View File

@@ -866,25 +866,5 @@
{"key": "40021", "datatype": "uint16", "remark": "自定时间段"},
{"key": "40038", "datatype": "uint16", "remark": "其他参数"}
]
},
"Charger_YC":{
"addr":[
{"key": "11", "datatype": "uint16", "remark": "枪1:状态"},
{"key": "12", "datatype": "uint16", "remark": "枪1:需求电压"},
{"key": "13", "datatype": "uint16", "remark": "枪1:需求电流"},
{"key": "14", "datatype": "uint16", "remark": "枪1:需求功率"},
{"key": "15", "datatype": "uint16", "remark": "枪1:输出电压"},
{"key": "16", "datatype": "uint16", "remark": "枪1:输出电流"},
{"key": "17", "datatype": "uint16", "remark": "枪1:输出功率"},
{"key": "18", "datatype": "uint16", "remark": "枪1:功率限值"},
{"key": "21", "datatype": "uint16", "remark": "枪2:状态"},
{"key": "22", "datatype": "uint16", "remark": "枪2:需求电压"},
{"key": "23", "datatype": "uint16", "remark": "枪2:需求电流"},
{"key": "24", "datatype": "uint16", "remark": "枪2:需求功率"},
{"key": "25", "datatype": "uint16", "remark": "枪2:输出电压"},
{"key": "26", "datatype": "uint16", "remark": "枪2:输出电流"},
{"key": "27", "datatype": "uint16", "remark": "枪2:输出功率"},
{"key": "28", "datatype": "uint16", "remark": "枪2:功率限值"}
]
}
}

View File

@@ -96,15 +96,14 @@
"Charger": {
"deviceType":106,
"addrYC":[
["工作状态", "11", "空闲", ""],
["需求电", "12", "0.0", " V", "0.1"],
["需求电流", "13", "0.0", " A", "0.01"],
["需求功率", "14", "0.0", " kW", "0.1"],
["输出电压", "15", "0.0", " V", "0.1"],
["输出电流", "16", "0.0", " A", "0.01"],
["输出功率", "17", "0.0", " kW", "0.1"],
["功率限值", "18", "0.0", " kW", "0.1"],
["需求电压", "31071", "0.0", " V"],
["需求电", "31073", "0.0", " A"],
["需求功率", "31075", "0.0", " kW"],
["功率限值", "31077", "0.0", " kW"],
["输出电压", "31079", "0.0", " V"],
["输出电流", "31081", "0.0", " A"],
["输出功率", "31083", "0.0", " kW"]
],
"addrCurve": ["15", "16", "17"]
"addrCurve": ["31079", "31081", "31083"]
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -16,11 +16,6 @@ void Application::init()
{
// 初始化系统配置,读取配置文件
Config::init("assets/config/app.json");
if (Config::option.debug)
{
spdlog::set_level(spdlog::level::debug); // 设置全局日志等级为 debug
spdlog::debug("[app] spdlog debug enable.");
}
// MQTT 数据结构
REGAddr::load("assets/config/regaddrs.json");
@@ -82,8 +77,8 @@ void Application::runThreadMain()
if (!this->isInit) { continue; }
}
static TimeTick ttMqtt; // 检查 场站的 MQTT 连接
if (ttMqtt.elapse(30))
static TimeTick ttMqtt(1); // 检查 场站的 MQTT 连接
if (ttMqtt.elapse(20))
{
auto& optionMqtt = Config::option.mqtt;
if (!optionMqtt.host.empty())
@@ -91,21 +86,22 @@ void Application::runThreadMain()
for (auto& item : appdata.mapStation)
{
auto& station = item.second;
if (station)
if (station && station->isOpen)
{
if (station->isOpen)
{
// 该函数检查连接状态,若已经连接,则无操作;若未连接,则进行连接操作
item.second->initMqtt();
// 召测
item.second->polling();
}
// 检查设备的在线状态
station->checkDevice();
// 该函数检查连接状态,若已经连接,则无操作;若未连接,则进行连接操作
item.second->initMqtt();
// 召测
item.second->polling();
}
}
}
}
static TimeTick ttData(1); // 检查数据
if (ttData.elapse(20))
{
//appdata.initFromDB();
}
}
}
@@ -114,14 +110,20 @@ void Application::runThreadStat()
int nCachePos = 0;
while (!isQuit)
{
static TimeTick ttStat(1);
if(ttStat.elapse(10))
int64_t tTime = Utils::time();
int64_t tDate = Utils::date();
int64_t delta = tTime-tDate;
int n = delta / 600;
int offset = delta % 600;
bool flagStore = (delta >=0 && delta < 86400 && offset <= 10 && n != nCachePos);
if (flagStore)
{
// 设备历史数据(电压、电流、功率),存储到 history_day
// 统计数据,存储到 stat_station
nCachePos = n;
std::string dt = Utils::dateStr(tDate);
// // 设备历史数据(电压、电流、功率),存储到 history_day
for (auto item: appdata.mapStation)
{
item.second->writeStatistic();
item.second->writeRuntimeData(dt, nCachePos);
}
}
else
@@ -129,6 +131,12 @@ void Application::runThreadStat()
//spdlog::info("保存历史数据倒计时: {}", 600 - offset);
}
// 统计计算,存储到 stat_station
for (auto& station : appdata.mapStation)
{
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}

View File

@@ -5,7 +5,6 @@
#include "common/JsonN.h"
#include "common/Spdlogger.h"
#include "AppData.h"
#include "protocol/MqttEntity.h"
AppOption Config::option;
@@ -20,106 +19,49 @@ bool Config::init(std::string filename)
}
spdlog::info("[config] load config file success, filename={}", filename);
JSON::read(jsonroot, "debug", option.debug);
JSON::read(jsonroot, "weburl", option.webSrvUrl);
JSON::read(jsonroot, "launchdate", option.lunchDate);
if (jsonroot.contains("database"))
{
njson& json = jsonroot.at("database");
njson json = jsonroot.at("database");
JSON::read(json, "host", option.database.host);
JSON::read(json, "port", option.database.port);
JSON::read(json, "user", option.database.user);
JSON::read(json, "passwd", option.database.passwd);
JSON::read(json, "dbname", option.database.dbname);
spdlog::info("[config] parse database success. host={}", option.database.host);
}
else
{
spdlog::error("[config] parse database failed: not found.");
spdlog::info("[config] parse database failed: not found.");
}
if (jsonroot.contains("http"))
{
njson& json = jsonroot.at("http");
JSON::read(json, "token", option.http.useToken);
njson json = jsonroot.at("http");
std:string token;
JSON::read(json, "token", token);
option.http.useToken = !token.empty();
JSON::read(json, "port", option.http.port);
JSON::read(json, "encryption", option.http.encryption);
JSON::read(json, "encryptKey", option.http.encryptKey);
}
else
{
spdlog::error("[config] parse http failed: not found.");
spdlog::info("[config] parse http failed: not found.");
}
if (jsonroot.contains("mqtt"))
{
njson& json = jsonroot.at("mqtt");
njson json = jsonroot.at("mqtt");
JSON::read(json, "host", option.mqtt.host);
JSON::read(json, "username", option.mqtt.username);
JSON::read(json, "password", option.mqtt.password);
}
else
{
spdlog::error("[config] parse mqtt failed: not found.");
spdlog::info("[config] parse mqtt failed: not found.");
}
if (jsonroot.contains("view"))
{
njson& json = jsonroot["view"];
JSON::read(json, "latitude", option.view.latitude);
JSON::read(json, "longitude", option.view.longitude);
JSON::read(json, "altitude", option.view.altitude);
}
else
{
spdlog::error("[config] parse view failed: not found.");
}
JSON::read(jsonroot, "weburl", option.webSrvUrl);
JSON::read(jsonroot, "launchdate", option.lunchDate);
if (jsonroot.contains("video"))
{
njson& json = jsonroot["video"];
for (auto& item: json.items())
{
auto& key = item.key();
auto& jsonItem = item.value();
auto& itemVideo = option.mapVideo[key];
JSON::read(jsonItem, "host", itemVideo.host);
JSON::read(jsonItem, "port", itemVideo.port);
JSON::read(jsonItem, "user", itemVideo.user);
JSON::read(jsonItem, "passwd", itemVideo.passwd);
}
}
else
{
spdlog::error("[config] parse video failed: not found.");
}
if (jsonroot.contains("topic"))
{
njson& json = jsonroot["topic"];
for (auto& item: json.items())
{
auto& key = item.key();
auto& jsonItem = item.value();
auto& info = MqttClient::s_mapTopicInfo[key];
info.name = key;
JSON::read(jsonItem, "deviceType", info.deviceType);
JSON::read(jsonItem, "polling", info.polling);
JSON::read(jsonItem, "enabled", info.enabled);
}
}
return true;
}
AppOption::VideoInfo* Config::getVideoInfo(std::string name)
{
auto iter = option.mapVideo.find(name);
if (iter!=option.mapVideo.end())
{
return &(iter->second);
}
return nullptr;
}

View File

@@ -1,27 +1,23 @@
#pragma once
#include <map>
#include <string>
struct DatabaseOption
{
std::string host;
int port;
std::string user;
std::string passwd;
std::string dbname;
};
struct AppOption
{
int debug {0};
std::string webSrvUrl;
std::string lunchDate;
DatabaseOption database;
struct {
std::string host;
int port;
std::string user;
std::string passwd;
std::string dbname;
} database;
struct {
int useToken {1};
bool useToken {true};
int port {0};
int encryption {1};
std::string encryptKey;
} http;
struct {
@@ -30,20 +26,8 @@ struct AppOption
std::string password;
} mqtt;
struct {
float latitude {0};
float longitude {0};
float altitude {0};
} view;
struct VideoInfo {
std::string host;
int port;
std::string user;
std::string passwd;
};
std::map<std::string, VideoInfo> mapVideo;
std::string webSrvUrl;
std::string lunchDate;
};
@@ -52,7 +36,6 @@ class Config
public:
static bool init(std::string filename);
static AppOption::VideoInfo* getVideoInfo(std::string name);
static AppOption option;
};

View File

@@ -256,9 +256,6 @@ void Device::storeDB(int npos)
void Device::setParam(std::string k, int v)
{
this->ts = Utils::time();
online = 1;
float ratio = 1.0;
auto iter = mapMyParams.find(k);
if (iter != mapMyParams.end())
@@ -267,62 +264,40 @@ void Device::setParam(std::string k, int v)
//spdlog::info("[device] set param: {} {}={}, ratio={}", iter->second->name, k, v, ratio);
}
if (type == 106) // 充电桩2号枪特殊数据格式
{
if (k=="22") { ratio = 0.1; }
else if (k=="23") { ratio = 0.01; }
else if (k== "24") { ratio = 0.1; }
else if (k== "25") { ratio = 0.1; }
else if (k== "26") { ratio = 0.01; }
else if (k== "27") { ratio = 0.1; }
else if (k== "28") { ratio = 0.1; }
}
int precision = (ratio != 1.0f) ? 1 : 0;
std::string valStr = Utils::toStr(v*ratio, precision);
if (type == 106) // 充电桩状态,特殊数据格式
{
if (k=="11" || k == "21") {
valStr = (valStr == "1" ? "充电" : "空闲");
}
}
mapParams[k] = valStr;
mapParams[k] = Utils::toStr(v*ratio, precision);
if (type == 3 ) // 电表
{
running = 1;
if (k == "") this->err = v;
}
else if (type == 101) // EMS
{
running = 1;
}
else if (type == 102) // PCS
{
if (k == "0x1003") err = v; // 故障状态 R uint16 1故障0正常 0 0x1003
else if (k == "0x1005") online = v; // 设备在线 R uint16 1在线0无效 1 0x1005
else if (k == "0x1009") running = (v==1 || v==2); //充放状态 R uint16 0待机, 1充电, 2放电, 3搁置 0 0x1009
if (k == "0x1003") err = v; // 故障状态 R uint16 1故障0正常 0 0x1003
if (k == "0x1005") online = v; // 设备在线 R uint16 1在线0无效 1 0x1005
if (k == "0x1009") running = (v==1 || v==2); //充放状态 R uint16 0待机, 1充电, 2放电, 3搁置 0 0x1009
}
else if (type == 103) // PCU
{
if (k == "0x1002") err = v; //故障状态 R uint16 1故障0正常 0 0x1002
else if (k == "0x1004") online = v; //设备在线 R uint16 1在线0无效 1 0x1004
else if (k == "0x1006") running = v; //启停状态 R uint16 1开机0关机 1 0x1006
if (k == "0x1002") err = v; //故障状态 R uint16 1故障0正常 0 0x1002
if (k == "0x1004") online = v; //设备在线 R uint16 1在线0无效 1 0x1004
if (k == "0x1006") running = v; //启停状态 R uint16 1开机0关机 1 0x1006
}
else if (type == 104) // BMS
{
if (k == "0x004A") { err = (v==1); } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x004A
else if (k == "0x004B") running = (v==1 || v==2); //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004B
if (k == "0x004A") { err = (v==1); online = 1; } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x004A
if (k == "0x004B") running = (v==1 || v==2); //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004B
}
else if (type == 105) // BCU
{
if (k == "0xA003") { running = (v==0x33 || v==0x44); } //蓄电池充放电状态 R uint16 "0x11开路,0x22待机,0x33充电,0x44放电" 34 0xA003
else if (k == "0xA004") { err = (v==0x55); } //电池组运行状态 R uint16 "0x11跳机,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" 102 0xA004
if (k == "0xA003") running = (v==0x33 || v==0x44); //蓄电池充放电状态 R uint16 "0x11开路,0x22待机,0x33充电,0x44放电" 34 0xA003
if (k == "0xA004") err = (v==0x55); online=1; //电池组运行状态 R uint16 "0x11跳机,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" 102 0xA004
}
else if (type == 106) // 充电桩
{
if (k == "21") {
running = (mapParams["11"] == "充电" || mapParams["21"] == "充电"); // 充电状态: 0空闲1充电
}
}
else if (type == 109) // 光伏板
{
@@ -368,13 +343,12 @@ void Device::getRuntimeParams1(std::vector<std::pair<std::string, std::string>>&
{
if (type == 106)
{
params.push_back({"工作状态", getParam("21", "空闲")});
params.push_back({"需求电", getParam("22", "0.0") + " V"});
params.push_back({"需求电流", getParam("23", "0.0") + " A"});
params.push_back({"需求功率", getParam("24", "0.0") + " kW"});
params.push_back({"输出电压", getParam("25", "0.0") + " V"});
params.push_back({"输出电流", getParam("26", "0.0") + " A"});
params.push_back({"输出功率", getParam("27", "0.0") + " kW"});
params.push_back({"功率限值", getParam("28", "0.0") + " kW"});
params.push_back({"需求电压", getParam("31072", "0.0") + " V"});
params.push_back({"需求电", getParam("31074", "0.0") + " A"});
params.push_back({"需求功率", getParam("31076", "0.0") + " kW"});
params.push_back({"功率限值", getParam("31078", "0.0") + " kW"});
params.push_back({"输出电压", getParam("31080", "0.0") + " V"});
params.push_back({"输出电流", getParam("31082", "0.0") + " A"});
params.push_back({"输出功率", getParam("31084", "0.0") + " kW"});
}
}

View File

@@ -73,8 +73,6 @@ public:
int online = 0;
int running = 0;
int64_t ts {0};
//std::map<std::string, std::string> mapAttrs;
Fields attrs;

View File

@@ -12,6 +12,20 @@
Station::Station() : stationId(0)
{
mqttCli = std::make_shared<MqttClient>();
// 测试,设置默认值
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)
@@ -19,12 +33,12 @@ void Station::setFields(Fields& fields)
this->stationId = fields.get<int>(DMStation::STATION_ID);
this->name = fields.value(DMStation::NAME);
this->capacity = fields.get<double>(DMStation::CAPACITY);
this->workMode = fields.get<int>(DMStation::WORK_MODE);
this->workModeId = fields.get<int>(DMStation::WORK_MODE);
this->code = fields.value(DMStation::CODE);
this->status = fields.get<int>(DMStation::STATUS);
this->operationDate = fields.value(DMStation::OPERATION_DATE);
this->isOpen = fields.get<int>(DMStation::STATUS);
this->launchDate = fields.value("operation_date");
this->policy.setFields(fields);
}
@@ -120,7 +134,7 @@ void Station::getDeviceByCategory(int category, std::vector<std::shared_ptr<Devi
void Station::setWorkMode(int modeId)
{
this->workMode = modeId;
this->workModeId = modeId;
std::string sql = SQL(SQL::TYPE::update).table(DMStation::TABLENAME)
.update(DMStation::WORK_MODE, std::to_string(modeId))
.where(DMStation::STATION_ID + "=" + std::to_string(stationId)).str();
@@ -143,6 +157,71 @@ void Station::setPolicy(int policyId)
}
}
static std::string MapValueToJson(int npos, std::map<int, double>& mapV)
{
njson jsonarray = njson::array();
for (int i = 0; i<=npos; i++)
{
jsonarray.push_back(mapV[i]);
}
return jsonarray.dump();
}
void Station::writeRuntimeData(std::string dt, int npos)
{
auto dao = DaoEntity::create("history_day");
for (auto iter = mapDevice.begin(); iter!=mapDevice.end(); ++iter)
{
auto device = iter->second;
if (device->cache(npos))
{
Fields fields;
fields.set("dt", dt);
fields.set("station_id", this->stationId);
fields.set("device_id", device->deviceId);
fields.set("datatype", 1);
fields.set("value", MapValueToJson(npos, device->mapCacheVoltage));
DAO::insertRuntimeData(dao, fields);
fields.set("datatype", 2);
fields.set("value", MapValueToJson(npos, device->mapCacheCurrent));
DAO::insertRuntimeData(dao, fields);
fields.set("datatype", 3);
fields.set("value", MapValueToJson(npos, device->mapCachePower));
DAO::insertRuntimeData(dao, fields);
spdlog::info("[device] write runtime date to database, deviceId={}", device->deviceId);
}
}
}
void Station::writeStatistic(std::string dt)
{
Fields fields;
fields.set("storage_elect_in", statData.totalElectIn);
fields.set("storage_elect_out", statData.totalElectOut);
//fields.set("storage_num_in", statData.totalElectIn);
//fields.set("storage_num_out", 0);
//fields.set("storage_num_err", 0);
//fields.set("storage_t_in", 0);
//fields.set("storage_t_out", 0);
//fields.set("storage_usage", 0);
//fields.set("solar_elect_gen", 0);
//fields.set("solar_elect_grid", 0);
//fields.set("solar_num_err", 0);
//fields.set("solar_t", 0);
//fields.set("solar_usage", 0);
//fields.set("charge_elect", 0);
//fields.set("charge_num", 0);
//fields.set("charge_num_err", 0);
//fields.set("charge_t", 0);
//fields.set("charge_usage", 0);
fields.set("income_elect", statData.totalIncome);
//fields.set("income_charge", 0);
//fields.set("usage_rate", 0);
}
void Station::initMqtt()
{
if (status!=0 && mqttCli)
@@ -170,7 +249,7 @@ void Station::setGarewayWorkMode()
njson json;
json["ts"] = Utils::time();
json["no"] = 1; // 设备编号
json["40001"] = this->workMode;
json["40001"] = this->workModeId;
if (policy.type == 1)
{
@@ -188,43 +267,19 @@ void Station::setGarewayWorkMode()
mqttCli->publish("Gateway_YT", text);
}
void Station::checkDevice()
{
for (auto& item: mapDevice)
{
auto& device = item.second;
if (device)
{
if (Utils::time() - device->ts > 60*6)
{
device->online = 0;
}
}
}
}
void Station::setRuntimeData(int deviceNo, string addr, int val)
void Station::setRuntimeData(string addr, int val)
{
if (deviceNo == 1)
{
if (addr == "0x000B") { this->voltage = val; } // A相电压 R uint32 1V 0x000B
if (addr == "0x0011") { this->current = val; } // A相电流 R int32 1A 0x0011
if (addr == "0x0011") { this->power = val; } // 三相总有功 R int32 1kW 0x0023
}
else if (deviceNo == 2)
{
statData.ts = Utils::time();
if (addr == "0x002F") { statData.dayElectIn = val; } //日充电电量 R uint32 1kWh 0x002F
else if (addr == "0x0031") { statData.dayElectOut = val; } //日放电电量 R uint32 1kWh 0x0031
else if (addr == "0x0033") { statData.dayIncomeIn = val; } //日充电费用 R uint32 1RMB 0x0033
else if (addr == "0x0035") { statData.dayIncomeOut = val; } //日放电费用 R uint32 1RMB 0x0035
else if (addr == "0x0037") { statData.dayIncome = val; } //日收益 R int32 1RMB 0x0037
else if (addr == "0x004D") { statData.totalElectIn = val; } //总充电电量 R uint32 1kWh 0x004D
else if (addr == "0x004F") { statData.totalElectOut = val; } //总放电电量 R uint32 1kWh 0x004F
else if (addr == "0x0051") { statData.totalIncomeIn = val; } //总充电费用 R uint32 1RMB 0x0051
else if (addr == "0x0053") { statData.totalIncomeOut = val; } //总放电费用 R uint32 1RMB 0x0053
else if (addr == "0x0055") { statData.totalIncome = val; } //总收益 R int32 1RMB 0x0055
}
if (addr == "0x110E") { statData.dayElectIn = val; } //日充电电量 R uint32 1kWh 0 0x110E
else if (addr == "0x1110") { statData.dayElectOut = val; } //日放电电量 R uint32 1kWh 0 0x1110
else if (addr == "0x1112") { statData.dayIncomeIn = val; } //日充电费用 R uint32 1RMB 0 0x1112
else if (addr == "0x1114") { statData.dayIncomeOut = val; } //日放电费用 R uint32 1RMB 0 0x1114
else if (addr == "0x1116") { statData.dayIncome = val; } //日收益 R int32 1RMB 0 0x1116
else if (addr == "0x112C") { statData.totalElectIn = val; } //总充电电量 R uint32 1kWh 6659(0x112D) 0x112C
else if (addr == "0x112E") { statData.totalElectOut = val; } //总放电电量 R uint32 1kWh 4925(0x112F) 0x112E
else if (addr == "0x1130") { statData.totalIncomeIn = val; } //总充电费用 R uint32 1RMB 6605(0x1131) 0x1130
else if (addr == "0x1132") { statData.totalIncomeOut = val; } //总放电费用 R uint32 1RMB 4949(0x1133) 0x1132
else if (addr == "0x1134") { statData.totalIncome = val; } //总收益 R int32 1RMB -1 0x1134
}
void Station::setTHData(int deviceNo, string addr, int val)
@@ -232,16 +287,8 @@ void Station::setTHData(int deviceNo, string addr, int val)
auto& unit = mapTempHumUnit[deviceNo];
if (addr == "0x0001") { ; } //所属通道号 R uint16 1 0x0001
else if (addr == "0x0002") { ; } //所属温湿度号 R uint16 1~10 0x0002
else if (addr == "0x0003") //温度 R int16 0.1℃ 0x0003
{
unit.temp = float(val) * 0.1;
if (deviceNo == 1) temperature = unit.temp;
}
else if (addr == "0x0004") //湿度 R int16 0.1℃ 0x0004
{
unit.hum = float(val) * 0.1;
if (deviceNo == 1) humidity = unit.hum;
}
else if (addr == "0x0003") { unit.temp = float(val) * 0.1; } //温度 R int16 0.1℃ 0x0003
else if (addr == "0x0004") { unit.hum = float(val) * 0.1; } //湿度 R int16 0.1℃ 0x0004
}
void Station::setFire40Data(int deviceNo, string addr, int val)
@@ -281,8 +328,8 @@ void Station::setCoolingData(int deviceNo, string addr, int val)
if (addr == "0x1001") { ; } //所属通道号 R uint16 1 0x1001
else if (addr == "0x1002") { ; }// 所属冷机号 R uint16 1~10 0x1002
else if (addr == "0x1003") { coolingStatus = unit.powerOn = val; }// 开关 R uint16 0关机1开机 0x1003
else if (addr == "0x1004") { unit.mode = val; }// 采样模式 R uint16 0-出水温度 1-电芯温度 0x1004
else if (addr == "0x1003") { unit.powerOn = val; }// 开关 R uint16 0关机1开机 0x1003
else if (addr == "0x1004") { ; }// 采样模式 R uint16 0-出水温度 1-电芯温度 0x1004
else if (addr == "0x1005") { unit.cooling = val; }// 制冷状态 R uint16 0关闭, 1启动 0x1005
else if (addr == "0x1006") { unit.heating = val; }// 制热状态 R uint16 0关闭, 1启动 0x1006
else if (addr == "0x1007") { unit.highTemp = val; }// 高温告警 R uint16 0正常1告警 0x1007
@@ -294,111 +341,3 @@ void Station::setCoolingData(int deviceNo, string addr, int val)
else if (addr == "0x100D") { ; }// 进水压力传感器 R uint16 0正常1告警 0x100D
else if (addr == "0x100E") { ; }// 出水压力传感器 R uint16 0正常1告警 0x100E
}
void Station::setWorkModeFromGateway(int mode)
{
if (mode != this->workMode)
{
//std::string sql = "update station set work_mode='" + std::to_string(mode) + "'";
//auto ret = DaoEntity::execOnce(sql);
//if (ret)
//{
// spdlog::info("[station] wrok_mode is diffent with gateway, update success.[{}]-[{}]", workMode, mode);
// this->workMode = mode;
//}
//else
//{
// spdlog::error("[station] wrok_mode is diffent with gateway, update failed.[{}]-[{}]", workMode, mode);
//}
//this->setGarewayWorkMode();
}
}
static std::string MapValueToJson(int npos, std::map<int, double>& mapV)
{
njson jsonarray = njson::array();
for (int i = 0; i<=npos; i++)
{
jsonarray.push_back(mapV[i]);
}
return jsonarray.dump();
}
void Station::writeStatistic()
{
auto dao = DaoEntity::create("history_day");
std::string dt = Utils::dateStr();
int64_t tTime = Utils::time();
int64_t tDate = Utils::date();
int npos = (tTime-tDate) / 600;
for (auto iter = mapDevice.begin(); iter!=mapDevice.end(); ++iter)
{
auto device = iter->second;
if (device->cache(npos))
{
Fields fields;
fields.set("dt", dt);
fields.set("station_id", this->stationId);
fields.set("device_id", device->deviceId);
fields.set("datatype", 1);
fields.set("value", MapValueToJson(npos, device->mapCacheVoltage));
DAO::insertRuntimeData(dao, fields);
fields.set("datatype", 2);
fields.set("value", MapValueToJson(npos, device->mapCacheCurrent));
DAO::insertRuntimeData(dao, fields);
fields.set("datatype", 3);
fields.set("value", MapValueToJson(npos, device->mapCachePower));
DAO::insertRuntimeData(dao, fields);
//spdlog::info("[device] write runtime date to database, deviceId={}", device->deviceId);
}
}
if (statData.ts != 0)
{
Fields fields;
fields.set("dt", Utils::dateStr(statData.ts));
fields.set("station_id", this->stationId);
fields.set("device_id", 0);
fields.set("elect_in", statData.dayElectIn);
fields.set("elect_out", statData.dayElectOut);
fields.set("income_in", statData.dayIncomeIn);
fields.set("income_out", statData.dayIncomeOut);
fields.set("income", statData.dayIncome);
//fields.set("num_in", "");
//fields.set("num_out", "");
//fields.set("num_err", "");
//fields.set("t_in", "");
//fields.set("t_out", "");
//fields.set("usage_rate", "");
fields.set("elect_in_total", statData.totalElectIn);
fields.set("elect_out_total", statData.totalElectOut);
fields.set("income_in_total", statData.totalIncomeIn);
fields.set("income_out_total", statData.totalIncomeOut);
fields.set("income_total", statData.totalIncome);
dao->setTableName("stat_storage");
std::vector<std::string> vecKeys = {
"elect_in", "elect_out", "num_in", "num_out", "num_err", "t_in", "t_out", "usage_rate", "income_in", "income_out",
"elect_in_total", "elect_out_total", "income_in_total", "income_out_total"
};
dao->duplicateUpdate(fields, vecKeys);
{
Fields fields;
fields.set("dt", Utils::dateStr(statData.ts));
fields.set("station_id", this->stationId);
fields.set("device_id", 0);
fields.set("storage_elect_in", statData.dayElectIn);
fields.set("storage_elect_out", statData.dayElectOut);
fields.set("income_elect", statData.dayIncome);
DAO::insertStatStation(dao, fields);
}
}
}

View File

@@ -109,18 +109,17 @@ public:
void setWorkMode(int modeId);
void setPolicy(int policyId);
void writeRuntimeData(std::string dt, int npos);
void writeStatistic(std::string dt);
void initMqtt();
void polling();
void setGarewayWorkMode();
void checkDevice();
void setRuntimeData(int deviceNo, string addr, int val);
void setRuntimeData(string addr, int val);
void setTHData(int deviceNo, string addr, int val);
void setFire40Data(int deviceNo, string addr, int val);
void setCoolingData(int deviceNo, string addr, int val);
void setWorkModeFromGateway(int mode);
void writeStatistic();
public:
int stationId {};
@@ -130,13 +129,14 @@ public:
int status {0};
std::string operationDate;
SysPolicy policy;
std::string launchDate {};
bool isConnected {false};
int workMode {}; // 运行模式
int workModeId {}; // 运行模式
int runPolicyId {}; // 运行策略
///////////////////////////////////////////////////////////////////////////////////////////////
/// === 系统统计 ===
// 累计发电量单位kWh
@@ -185,12 +185,6 @@ public:
double temperature {};
// 湿度
double humidity {};
int aircStatus {0};
int coolingStatus {0};
double voltage {0};
double current {0};
double power {0};
double powerFactor {0};
///////////////////////////////////////////////////////////////////////////////////////////////
/// === 设备信息 ===
@@ -213,25 +207,25 @@ public:
struct {
int64_t ts {0};
int64_t ts;
float totalElectIn {0.0}; //总充电电量 R uint32 1kWh 6659(0x112D) 0x112C
float totalElectOut {0.0}; //总放电电量 R uint32 1kWh 4925(0x112F) 0x112E
float totalIncomeIn {0.0}; //总充电费用 R uint32 1RMB 6605(0x1131) 0x1130
float totalIncomeOut {0.0}; //总放电费用 R uint32 1RMB 4949(0x1133) 0x1132
float totalIncome {0.0}; //总收益 R int32 1RMB -1 0x1134
double totalElectIn; //总充电电量 R uint32 1kWh 6659(0x112D) 0x112C
double totalElectOut; //总放电电量 R uint32 1kWh 4925(0x112F) 0x112E
double totalIncomeIn; //总充电费用 R uint32 1RMB 6605(0x1131) 0x1130
double totalIncomeOut; //总放电费用 R uint32 1RMB 4949(0x1133) 0x1132
double totalIncome; //总收益 R int32 1RMB -1 0x1134
//储能充放电时段hh R uint16 时 336 0x01 0x121C
//储能充放电时段mm R uint16 分 0 0x01 0x121D
//储能充放电时段ss R uint16 秒 0 0x01 0x121E
float totalDurationIn {0.0};
float totalDurationOut {0.0};
double totalDurationIn;
double totalDurationOut;
float dayElectIn {0.0}; // 日充电电量 R uint32 1kWh 0 0x110E
float dayElectOut {0.0}; // 日放电电量 R uint32 1kWh 0 0x1110
float dayIncomeIn {0.0}; // 日充电费用 R uint32 1RMB 0 0x1112
float dayIncomeOut {0.0}; // 日放电费用 R uint32 1RMB 0 0x1114
float dayIncome {0.0}; // 日收益 R int32 1RMB 0 0x1116
double dayElectIn; // 日充电电量 R uint32 1kWh 0 0x110E
double dayElectOut; // 日放电电量 R uint32 1kWh 0 0x1110
double dayIncomeIn; // 日充电费用 R uint32 1RMB 0 0x1112
double dayIncomeOut; // 日放电费用 R uint32 1RMB 0 0x1114
double dayIncome; // 日收益 R int32 1RMB 0 0x1116
} statData;

View File

@@ -21,7 +21,7 @@ void Spdlogger::init(spdlog::level::level_enum log_level, std::string filename)
// 创建控制台接收器
auto consoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
//consoleSink->set_level(log_level); // 设置控制台日志等级
consoleSink->set_level(spdlog::level::info); // 设置控制台日志等级
//consoleSink->set_pattern("[%T] [%^%l%$] %v"); // 设置日志格式
// 创建文件接收器
@@ -31,7 +31,7 @@ void Spdlogger::init(spdlog::level::level_enum log_level, std::string filename)
// 每日文件sink可选每天生成新文件
auto dailySink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/ess.log", 0, 0);
//dailySink->set_level(log_level);
dailySink->set_level(spdlog::level::debug);
//dailySink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
// 创建一个多重接收器的 logger
@@ -40,8 +40,8 @@ void Spdlogger::init(spdlog::level::level_enum log_level, std::string filename)
// 设置全局 logger
spdlog::set_default_logger(logger);
spdlog::set_level(log_level); // 设置全局日志等级为 debug
spdlog::flush_on(log_level); // 开启日志刷新
spdlog::set_level(spdlog::level::debug); // 设置全局日志等级为 debug
spdlog::flush_on(spdlog::level::info); // 开启日志刷新
}
void Spdlogger::drop()

View File

@@ -644,7 +644,6 @@ Errcode DAO::insertStatStation(std::shared_ptr<DaoEntity> dao, Fields& fields)
{
// 根据主键dt、station_id、category写入或更新数据
if (!dao) { dao = DaoEntity::create("stat_station"); }
else { dao->setTableName("stat_station"); }
std::vector<std::string> vecKeys = {
"storage_elect_in",
"storage_elect_out",

View File

@@ -129,18 +129,21 @@ int DaoEntity::duplicateUpdate(Fields& fields, const vector<string>& keys)
string val;
for (auto& item : fields.map())
{
if (!key.empty()) { key += ","; val += ","; }
if (!key.empty())
{
key += ","; val += ",";
}
key += (item.first);
val += ("'" + item.second + "'");
}
string str;
for (auto& k : keys)
{
if (fields.contains(k))
if (!str.empty())
{
if (!str.empty()) { str += ","; }
str += (k + "='" + fields.value(k) + "'");
str += ",";
}
str += (k + "='" + fields.value(k) + "'");
}
string sql = "INSERT INTO " + tableName + "(" + key + ") VALUES (" + val + ") ON duplicate KEY UPDATE " + str;
return this->db->exec(sql);

View File

@@ -124,15 +124,14 @@ int main(int argc, char** argv)
// 设置控制台输入为 UTF-8 编码(如果需要输入中文)
SetConsoleCP(CP_UTF8);
// 初始化日志
Spdlogger::init(spdlog::level::info, "");
Spdlogger::init(spdlog::level::debug, "");
spdlog::info("[main] start ... ======================================================================");
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--ignore-gpu-blacklist --enable-gpu-rasterization --enable-native-gpu-memory-buffers --num-raster-threads=4");
// 运行后台服务
Application::instance().init();
while (1) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); };
// 启动 PV 服务主线程

View File

@@ -128,8 +128,6 @@ public:
static std::map<std::string, HandlerOptions> g_mapHttpHandlerGet =
{
{"/queryBaseinfo", HandlerOptions(&HttpEntity::logqueryBaseinfoin, {})},
{"/login", HandlerOptions(&HttpEntity::login, {DMUser::ACCOUNT, DMUser::PASSWD})},
{"/queryUserList", HandlerOptions(&HttpEntity::queryUserList, {})},
{"/deleteUser", HandlerOptions(&HttpEntity::deleteUser, { DMUser::USER_ID})},
@@ -282,7 +280,6 @@ void HttpEntity::runHandler(std::string name, const HandlerOptions& handler, con
jsonresp["errmsg"] = ErrcodeStr(errcode) + (errmsg.empty() ? "" : (":"+errmsg));
resp.set_content(jsonresp.dump(), "text/plain; charset=utf-8");
resp.status = 200;
spdlog::info("[http] request: {}, response: {}.", name, int(errcode));
}
void HttpEntity::registGet(std::string name, void (HttpEntity::* func)(const httplib::Request& req, httplib::Response& resp))
@@ -290,18 +287,6 @@ void HttpEntity::registGet(std::string name, void (HttpEntity::* func)(const htt
this->httpsvr.Get(name, std::bind(func, this, std::placeholders::_1, std::placeholders::_2));
}
Errcode HttpEntity::logqueryBaseinfoin(const httplib::Request& req, njson& json, std::string& errmsg)
{
json["data"] = {
{"encryption", Config::option.http.encryption},
{"encryptKey", Config::option.http.encryptKey},
{"latitude", Config::option.view.latitude},
{"longitude", Config::option.view.longitude},
{"altitude", Config::option.view.altitude}
};
return Errcode::OK;
}
Errcode HttpEntity::login(const httplib::Request& req, njson& json, std::string& errmsg)
{
std::string userId;
@@ -617,13 +602,12 @@ Errcode HttpEntity::insertStation(const httplib::Request& req, njson& json, std:
Errcode HttpEntity::updateStation(const httplib::Request& req, njson& json, std::string& errmsg)
{
Fields params;
GetRequestParam(req, {"station_id", "name", "address", "lon", "lat", "tel", "capacity", "status", "work_mode", "policy_id", "operation_date"}, params);
GetRequestParam(req, {"station_id", "name", "address", "lon", "lat", "tel", "capacity", "status", "work_mode", "policy_id"}, params);
std::string stationId = params.value("station_id");
params.check("capacity", "", "0.0");
params.check("lon", "", "0.0");
params.check("lat", "", "0.0");
params.check("status", "", "1");
params.check("policy_id", "", "NULL");
Errcode err = DAO::updateStationById(params);
if (err == Errcode::OK)
{
@@ -637,11 +621,16 @@ Errcode HttpEntity::updateStation(const httplib::Request& req, njson& json, std:
}
else
{
auto station = Application::data().getStation(Utils::toInt(stationId));
if (result.size() > 0 && station)
if (result.size() > 0)
{
station->setFields(result[0]);
auto station = Application::data().getStation(Utils::toInt(stationId));
if (station)
{
station->setFields(result[0]);
station->setGarewayWorkMode();
}
}
}
}
return err;
@@ -692,15 +681,6 @@ Errcode HttpEntity::queryStationOverview(const httplib::Request& req, njson& jso
njson jsonCharge = njson::parse(R"({"category":2, "count":0, "power":0.0})");
njson jsonSolar = njson::parse(R"({"category":3, "count":0, "power":0.0})");
njson jsonSecurity = njson::parse(R"({"category":4, "count":0, "power":0.0})");
auto videoInfo = Config::getVideoInfo(stationId);
if (videoInfo)
{
jsonSecurity["host"] = videoInfo->host;
jsonSecurity["port"] = videoInfo->port;
jsonSecurity["user"] = videoInfo->user;
jsonSecurity["passwd"] = videoInfo->passwd;
}
for (auto& fields : result)
{
int category = fields.get<int>("category");
@@ -763,21 +743,16 @@ Errcode HttpEntity::queryStationInfo(const httplib::Request& req, njson& json, s
}
Errcode HttpEntity::queryStationData(const httplib::Request& req, njson& json, std::string& errmsg)
{
std::string stationId = req.get_param_value("station_id");
auto station = Application::data().getStation(Utils::toInt(stationId));
// 温度, 电压、电流、功率、功率因数、
njson jsondata;
if (station)
{
// 温度, 电压、电流、功率、功率因数、
jsondata["voltage"] = station->voltage;
jsondata["current"] = station->current;
jsondata["power"] = station->power;
jsondata["powerFactor"] = station->powerFactor;
jsondata["envTemp"] = station->temperature;
jsondata["envhum"] = station->humidity;
jsondata["aircStatus"] = station->aircStatus;
jsondata["coolingStatus"] = station->coolingStatus;
}
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;
@@ -1131,9 +1106,9 @@ static std::string VerifyStatSqlCondition(Fields& params)
return sqlCondition;
}
static std::string GetRequestStatParams(const httplib::Request& req, Fields& params)
static std::string GetRequestStatParams(const httplib::Request& req)
{
Fields params;
GetRequestParam(req, {"station_id", "category", "start_date", "end_date"}, params);
VerifyRequstParamsStatDate(params);
return VerifyStatSqlCondition(params);
@@ -1141,8 +1116,7 @@ static std::string GetRequestStatParams(const httplib::Request& req, Fields& par
Errcode HttpEntity::queryStatTotal(const httplib::Request& req, njson& json, std::string& errmsg)
{
Fields params;
std::string sqlCondition = GetRequestStatParams(req, params);
std::string sqlCondition = GetRequestStatParams(req);
std::string sql = R"(SELECT SUM(ss.storage_elect_in) storage_elect_in,
SUM(storage_elect_in) storage_elect_in,
SUM(storage_elect_out) storage_elect_out,
@@ -1161,22 +1135,12 @@ Errcode HttpEntity::queryStatTotal(const httplib::Request& req, njson& json, std
SUM(income_charge) income_charge
FROM stat_station ss)" + sqlCondition + ";";
std::string stationId = params.value("station_id");
njson jsondata;
auto station = Application::data().getStation(Utils::toInt(stationId));
if (station)
{
jsondata["launch_date"] = station->launchDate;
}
std::vector<Fields> result;
DaoEntity::execOnce(sql, result);
if (result.size() > 0)
{
auto& fields = result[0];
njson jsondata;
// jsondata["launch_date"] = "2025-09-01"; //场站上线日期
// jsondata["station_id"] = station_id;
jsondata["storage_elect_in"] = fields.value("storage_elect_in"); //储能充电电量kWh精度0.001
@@ -1236,8 +1200,7 @@ Errcode HttpEntity::queryStatDetailList(const httplib::Request& req, njson& json
std::vector<Fields> result;
auto err = DAO::queryStatStationList(pageinfo, params, result);
//json["data"] = FieldsToJsonArray(result);
HttpHelper::setPagination(pageinfo, result, json);
json["data"] = FieldsToJsonArray(result);
return err;
}
@@ -1323,38 +1286,40 @@ Errcode HttpEntity::queryEnvironment(const httplib::Request& req, njson& json, s
auto& unit = iter->second;
njson node;
node["pos"] = "#" + std::to_string(iter->first);
node["temp"] = Utils::toStr(unit.temp);
node["hum"] = Utils::toStr(unit.hum);
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;
njson nodearray = njson::array();
for (auto& item: mapAircUnit)
if (unit)
{
auto& unit = item.second;
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) + "%"}});
break;
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<int, std::string> mapFireStatusDef = { {0, "正常"}, {1,"预警"}, {2,"火警"} };
std::map<int, string> mapStatusDef = {{0, "无效"}, {1, "掉线"}, {2, "正常"}, {3, "启动"}};
auto& mapFire40Unit = station->mapFire40Unit;
njson nodearray = njson::array();
for (auto iter = mapFire40Unit.begin(); iter!=mapFire40Unit.end(); ++iter)
@@ -1373,19 +1338,20 @@ Errcode HttpEntity::queryEnvironment(const httplib::Request& req, njson& json, s
}
{ // 冷机
auto& mapCoolingUnit = station->mapCoolingUnit;
CoolingUnit unitTmp;
CoolingUnit* unit = (mapCoolingUnit.size() > 0) ? &(mapCoolingUnit[0]) : &unitTmp;
njson nodearray = njson::array();
for (auto& item: mapCoolingUnit)
if (unit)
{
auto& unit = item.second;
njson 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 ? "正常" : "告警"}});
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;
}

View File

@@ -29,7 +29,6 @@ public:
//void onGet(const httplib::Request& req, httplib::Response& resp);
Errcode logqueryBaseinfoin(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode login(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode queryUserList(const httplib::Request& req, njson& json, std::string& errmsg);

View File

@@ -9,20 +9,6 @@
#define TIMEOUT 10000L
bool MqttClient::load(std::string filename)
{
njson jsonroot;
bool ret = JSON::load(filename, jsonroot);
if (!ret)
{
spdlog::error("[mqtt] load config file failed, filename={}", filename);
return false;
}
return true;
}
std::map<std::string, TopicInfo> MqttClient::s_mapTopicInfo;
int MqttClient::init(string addr, string clientId, string username, string password)
{
@@ -39,7 +25,7 @@ int MqttClient::init(string addr, string clientId, string username, string passw
this->clientId = clientId;
//this->mapTopicInfo["EMS_YX"] = TopicInfo("EMS_YX", 101);
//this->mapTopicInfo["EMS_YC"] = TopicInfo("EMS_YC", 101);
this->mapTopicInfo["EMS_YC"] = TopicInfo("EMS_YC", 101);
//this->mapTopicInfo["EMS_YT"] = TopicInfo("EMS_YT", 101);
//this->mapTopicInfo["PCS_YX"] = TopicInfo("PCS_YX", 102, 1);
//this->mapTopicInfo["PCS_YC"] = TopicInfo("PCS_YC", 102, 1);
@@ -49,14 +35,14 @@ int MqttClient::init(string addr, string clientId, string username, string passw
//this->mapTopicInfo["BMS_YC"] = TopicInfo("BMS_YC", 104);
//this->mapTopicInfo["BCU_YX"] = TopicInfo("BCU_YX", 105, 1);
//this->mapTopicInfo["BCU_YC"] = TopicInfo("BCU_YC", 105, 1);
//this->mapTopicInfo["MEM_YC"] = TopicInfo("MEM_YC", 3); // 不召测
//this->mapTopicInfo["MEM_YC"] = TopicInfo("MEM_YC", 3, 1);
//this->mapTopicInfo["TH_YC"] = TopicInfo("TH_YC", 10, 1);
//this->mapTopicInfo["Fire40_YX"] = TopicInfo("Fire40_YX", 7, 1);
//this->mapTopicInfo["Cooling_YC"] = TopicInfo("Cooling_YC", 14, 1);
//this->mapTopicInfo["Cooling_YX"] = TopicInfo("Cooling_YX", 14, 1);
this->mapTopicInfo["Cooling_YC"] = TopicInfo("Cooling_YC", 14, 1);
this->mapTopicInfo["Cooling_YX"] = TopicInfo("Cooling_YX", 14, 1);
//this->mapTopicInfo["Gateway_YX"] = TopicInfo("Gateway_YX", 15, 1);
//this->mapTopicInfo["Gateway_YC"] = TopicInfo("Gateway_YC", 15, 1);
//this->mapTopicInfo["Charger_YC"] = TopicInfo("Charger_YC", 106);
//this->mapTopicInfo["Charger_YC"] = TopicInfo("Charger_YC", 106, 1);
MQTTAsync_connectOptions option = MQTTAsync_connectOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
@@ -149,21 +135,18 @@ void MqttClient::subscribe()
MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer;
options.onSuccess = funcSuccess;
options.onFailure = funcFailure;
for (auto& item: MqttClient::s_mapTopicInfo)
for (auto& item: mapTopicInfo)
{
if (item.second.enabled)
std::string topic = "up/json/" + clientId + "/" + item.first;
options.context = (void*)&item.first;
int rc = MQTTAsync_subscribe(client, topic.data(), qos, &options);
if (rc != MQTTASYNC_SUCCESS)
{
std::string topic = "up/json/" + clientId + "/" + item.first;
options.context = (void*)&item.first;
int rc = MQTTAsync_subscribe(client, topic.data(), qos, &options);
if (rc != MQTTASYNC_SUCCESS)
{
spdlog::error("[mqtt] subscribe [{},{}] failed, err={}", topic, qos, rc);
}
else
{
spdlog::info("[mqtt] subscribe [{},{}] ", topic, qos);
}
spdlog::error("[mqtt] subscribe [{},{}] failed, err={}", topic, qos, rc);
}
else
{
spdlog::info("[mqtt] subscribe [{},{}] ", topic, qos);
}
}
}
@@ -216,10 +199,10 @@ int MqttClient::polling()
return 0;
}
for (auto& item: MqttClient::s_mapTopicInfo)
for (auto& item: mapTopicInfo)
{
auto& topicInfo = item.second;
if (topicInfo.polling && topicInfo.enabled)
if (topicInfo.polling)
{
std::vector<std::shared_ptr<Device>> vecDevice;
station->getDeviceByType(topicInfo.deviceType, vecDevice);
@@ -285,6 +268,96 @@ void MqttClient::onConnectFaiure(MQTTAsync_failureData* resp)
this->destory();
}
void MqttClient::ParseArrivedMessage(njson& json, string clientId, string command, std::shared_ptr<Station> station)
{
std::string stationNo = clientId;
auto mapRegPtr = REGAddr::getRegMap(command);
if (!mapRegPtr)
{
spdlog::error("[mqtt] get register add info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
return;
}
auto iterTopic = mapTopicInfo.find(command);
if (iterTopic == mapTopicInfo.end())
{
spdlog::error("[mqtt] get topic info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
return;
}
TopicInfo& topicInfo = iterTopic->second;
int deviceNo = -1;
JSON::read(json, "no", deviceNo);
auto device = station->getDeviceByType(topicInfo.deviceType, Utils::toStr(deviceNo));
if (!device)
{
return;
}
for (auto& item: json.items())
{
std::string key = item.key();
if (key != "ts" && key != "no")
{
auto data = json.at(key);
if (data.is_array())
{
std::string addrText;
auto iter = mapRegPtr->find(key);
for (int i = 0; i<data.size(); ++i)
{
if (iter != mapRegPtr->end())
{
auto addr = iter->first;
int val = data[i];
device->setParam(addr, val);
spdlog::info("[mqtt] read [{}]={},{}", addr, val, iter->second.remark);
if (command == "EMS_YC" && addr == "0x110C")
{
int a = 30;
a = 100;
}
if (command == "EMS_YC")
{
station->setRuntimeData(addr, val);
}
else if (command == "Fire40_YX")
{
station->setFire40Data(deviceNo, addr, val);
}
else if (command == "TH_YC")
{
station->setTHData(deviceNo, addr, val);
}
else if (command == "Cooling_YX" || command == "Cooling_YC")
{
station->setCoolingData(deviceNo, addr, val);
}
else if (command == "Gateway_YX")
{
//if (key == "CDZ") "CDZ": 1, //充电桩 1在线0离线
//else if (key == "EMU") //储能 1在线0离线
}
++iter;
}
}
}
else if (data.is_number())
{
device->setParam(key, data.get<int>());
}
else if (data.is_string())
{
device->setParam(key, Utils::toInt(data.get<std::string>()));
}
}
}
}
int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* msg)
{
std::string topicStr = topic;
@@ -339,7 +412,7 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m
}
else
{
ParseArrivedMessage(json, command, station);
ParseArrivedMessage(json, clientId, command, station);
}
// 必须释放消息内存!
@@ -349,119 +422,117 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m
}
void MqttClient::ParseArrivedMessage(njson& json, string command, std::shared_ptr<Station> station)
string MQTT::pack(std::string name)
{
std::string stationNo = clientId;
njson json;
json["ts"] = Utils::time();
json["no"] = 1;
auto iterTopic = MqttClient::s_mapTopicInfo.find(command);
if (iterTopic == MqttClient::s_mapTopicInfo.end())
if (name == "EMS_YC")
{
spdlog::error("[mqtt] get topic info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
return;
}
TopicInfo& topicInfo = iterTopic->second;
//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
int deviceNo = -1;
JSON::read(json, "no", deviceNo);
auto device = station->getDeviceByType(topicInfo.deviceType, Utils::toStr(deviceNo));
if (!device)
//储能系统SOC R uint16 0.1 0x107A
//储能系统SOH R uint16 0.1 0x107B
json["addr"] = {"0x107A", "0x107B", "0x107E", "0x1080", "0x1082", "0x1084", "0x1086", "0x1088"};
}
else if (name == "PCS_YC")
{
spdlog::error("[mqtt] get device info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
return;
}
//总充电量 R uint32 1kWh 0x0003
//总放电量 R uint32 1kWh 0x0005
auto mapRegPtr = REGAddr::getRegMap(command);
if (!mapRegPtr)
//A相电压 R int16 1V 0x0010
//B相电压 R int16 1V 0x0011
//C相电压 R int16 1V 0x0012
//A相电流 R int16 1A 0x0019
//B相电流 R int16 1A 0x001A
//C相电流 R int16 1A 0x001B
//三相总有功功率 R int16 1kW 0x0025
//三相总无功功率 R int16 1kVar 0x0026
//三相总视在功率 R int16 1kVA 0x0027
//三相总功率因数 R int16 1 0x0028
//充电功率 R int16 1kW 0x002C
//放电功率 R int16 1kW 0x002D
json["addr"] = {"0x0003", "0x0005", "0x0010", "0x0011", "0x0012", "0x0019", "0x001A", "0x001B", "0x0025", "0x0026", "0x0027", "0x0028", "0x002C", "0x002D"};
}
else if (name == "PCU_YC")
{
spdlog::error("[mqtt] get register add info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
return;
//PCS侧线A相电压 R int16 1v 0x0013
//PCS侧线B相电压 R int16 1v 0x0014
//PCS侧线C相电压 R int16 1v 0x0015
//PCS侧功率因数A R int16 1 0x0019
//PCS侧功率因数B R int16 1 0x001A
//PCS侧功率因数C R int16 1 0x001B
//PCS侧相电流A R int16 1A 0x001C
//PCS侧相电流B R int16 1A 0x001D
//PCS侧相电流C R int16 1A 0x001E
//PCS侧三相总有功功率 R int16 1kW 0x0028
//PCS侧三相总无功功率 R int16 1kVar 0x0029
//PCS侧三相总视在功率 R int16 1kVA 0x002A
//PCS侧三相总功率因数 R int16 1 0x002B
json["addr"] = {"0x0013", "0x0014", "0x0015", "0x1080", "0x1082", "0x1084", "0x1086", "0x1088"};
}
for (auto& item: json.items())
else if (name == "BMS_YC")
{
std::string key = item.key();
if (key == "ts" || key == "no")
{
continue;
}
//SOC R uint16 0.1 0x0001
//SOH R uint16 0.1 0x0002
//电压 R uint32 0.1V 0x0003
//电流 R int32 0.1A 0x0005
//可充电量 R uint32 1kWh 0x0007
//可放电量 R uint32 1kWh 0x0009
//可充电状态 R uint16 1可充电0不可充电 0x0047
//可放电状态 R uint16 1可放电0不可放电 0x0048
//运行状态 R uint16 运行状态 0-正常 1-告警 2-保护 0x0049
//充放电状态 R uint16 0-待机 1-充电 2-放电 0x004A
auto data = json[key];
if (data.is_array())
{
if (command == "Charger_YC")
{
if (key == "1") key = "11";
else if (key == "2") key = "21";
}
std::string addrText;
auto iter = mapRegPtr->find(key);
if (iter != mapRegPtr->end())
{
for (int i = 0; i<data.size(); ++i)
{
auto addr = iter->first;
int val = data[i];
device->setParam(addr, val);
spdlog::debug("[mqtt] read [{}]={}, {}", addr, val, iter->second.remark);
if (command == "MEM_YC") { station->setRuntimeData(deviceNo, addr, val); }
else if (command == "Fire40_YX") { station->setFire40Data(deviceNo, addr, val); }
else if (command == "TH_YC") { station->setTHData(deviceNo, addr, val); }
else if (command == "Cooling_YX" || command == "Cooling_YC") { station->setCoolingData(deviceNo, addr, val); }
else if (command == "Gateway_YX")
{
//if (key == "CDZ") "CDZ": 1, //充电桩 1在线0离线
//else if (key == "EMU") //储能 1在线0离线
}
++iter;
}
}
}
else if (data.is_number())
{
device->setParam(key, data.get<int>());
}
else if (data.is_string())
{
device->setParam(key, Utils::toInt(data.get<std::string>()));
}
}
}
std::vector<std::string> KEY_CHARGER_1 = {"31071", "31073", "31075", "31077", "31079", "31081", "31083"};
std::vector<std::string> KEY_CHARGER_2 = {"31072", "31074", "31076", "31078", "31080", "31082", "31084"};
void MqttClient::ParseMessageCharge(njson& json, string command, std::shared_ptr<Station> station, std::shared_ptr<Device> device)
{
if (json.contains("1"))
{
auto& jsondata = json["1"];
if (jsondata.is_array())
{
for (int i = 0; i<jsondata.size(); i++)
{
if (i<KEY_CHARGER_1.size())
{
auto& addr = KEY_CHARGER_1[i];
auto val = jsondata[i].get<int>();
device->setParam(addr, val);
spdlog::info("[mqtt] read: 枪1 [{}]={}", addr, val);
}
}
}
}
if (json.contains("2"))
{
auto& jsondata = json["2"];
if (jsondata.is_array())
{
for (int i = 0; i<jsondata.size(); i++)
{
if (i<KEY_CHARGER_2.size())
{
auto& addr = KEY_CHARGER_2[i];
auto val = jsondata[i].get<int>();
device->setParam(addr, val);
spdlog::info("[mqtt] read: 枪2 [{}]={}", addr, val);
}
}
}
json["addr"] = {"0x0001", "0x0002", "0x0003", "0x0005", "0x0007", "0x0009", "0x0047", "0x0048", "0x0049", "0x004A"};
}
else if (name == "BCU_YC")
{
//电表类型 R uint16 "0储能站总表 1逆变前侧电表 2逆变后侧电表 3配电柜电表 4并网口电表" 0x0008
//A相电压 R uint32 1V 0x000B
//B相电压 R uint32 1V 0x000D
//C相电压 R uint32 1V 0x000F
//A相电流 R int32 1A 0x0011
//B相电流 R int32 1A 0x0013
//C相电流 R int32 1A 0x0015
//尖段电价 R uint32 1RMB 0x0027
//峰段电价 R uint32 1RMB 0x0029
//平段电价 R uint32 1RMB 0x002B
//谷段电价 R uint32 1RMB 0x002D
//日充电电量 R uint32 1kWh 0x002F
//日放电电量 R uint32 1kWh 0x0031
//日充电费用 R uint32 1RMB 0x0033
//日放电费用 R uint32 1RMB 0x0035
//日收益 R int32 1RMB 0x0037
//总充电电量 R uint32 1kWh 0x004D
//总放电电量 R uint32 1kWh 0x004F
//总充电费用 R uint32 1RMB 0x0051
//总放电费用 R uint32 1RMB 0x0053
//总收益 R int32 1RMB 0x0055
}
else if (name == "TH_YC")
{
//所属通道号 R uint16 1 0x0001
//所属温湿度号 R uint16 1~10 0x0002
//温度 R int16 0.1℃ 0x0003
//湿度 R int16 0.1℃ 0x0004
}
return json.dump();
}

View File

@@ -7,14 +7,13 @@
#include "common/JsonN.h"
class Station;
class Device;
struct TopicInfo
{
std::string name;
int deviceType {0};
int polling {0}; // 召测
int enabled {1};
TopicInfo() {};
TopicInfo(std::string name, int deviceType, int polling=0)
:name(name), deviceType(deviceType), polling(polling)
@@ -26,8 +25,6 @@ using namespace std;
class MqttClient
{
public:
static bool load(std::string filename);
int init(string addr, string clientId, string username, string password);
void destory();
@@ -42,8 +39,7 @@ public:
void onConnectFaiure(MQTTAsync_failureData* resp);
int onMessageArrived(char* topic, int len, MQTTAsync_message* msg);
void ParseArrivedMessage(njson& json, string command, std::shared_ptr<Station> station);
void ParseMessageCharge(njson& json, string command, std::shared_ptr<Station> station, std::shared_ptr<Device> device);
void ParseArrivedMessage(njson& json, string clientId, string command, std::shared_ptr<Station> station);
public:
// MQTT clientId (使用station 的 code)
@@ -55,7 +51,7 @@ public:
bool isConnected {false};
bool isSubscribed {false};
static std::map<std::string, TopicInfo> s_mapTopicInfo;
std::map<std::string, TopicInfo> mapTopicInfo;
};
@@ -75,3 +71,12 @@ public:
#define TOPIC_PCS_YC "up/json/预制舱01/PCS_YC"
#define TOPIC_PCS_YC "up/json/预制舱01/PCS_YC"
class MQTT
{
public:
public:
static string pack(std::string name);
};