1.新增服务端UI界面,显示服务基础信息。2.修改设备显示配置。3.监控页面储能系统显示储能模式,模式设置新增'手动'

This commit is contained in:
lixiaoyuan
2025-09-25 19:20:25 +08:00
parent d7888c2be4
commit 8aba56f47d
39 changed files with 2954 additions and 408 deletions

View File

@@ -195,19 +195,17 @@ bool AppData::initFromDB()
auto station = this->getStation(stationId);
if (station)
{
station->storageIn = fields.get<double>(DMStatStation::STORAGE_ELECT_IN);
station->storageOut = fields.get<double>(DMStatStation::STORAGE_ELECT_OUT);
//station->storageIn = fields.get<double>(DMStatStation::STORAGE_ELECT_IN);
//station->storageOut = fields.get<double>(DMStatStation::STORAGE_ELECT_OUT);
//station->storageNumIn = fields.getFloat(DMStatStation::STORAGE_NUM);
//station->storageNumOut = fields.getFloat(DMStatStation::STORAGE_NUM);
station->storageNumErr = fields.get<int>(DMStatStation::STORAGE_NUM_ERR);
station->solarGen = fields.get<double>(DMStatStation::SOLAR_ELECT_GEN);
station->solarGrid = fields.get<double>(DMStatStation::SOLAR_ELECT_GRID);
station->solarNumErr = fields.get<int>(DMStatStation::SOLAR_NUM_ERR);
station->chargeElect = fields.get<double>(DMStatStation::CHARGE_ELECT);
station->chargeNum = fields.get<int>(DMStatStation::CHARGE_NUM);
station->chargeNumErr = fields.get<int>(DMStatStation::CHARGE_NUM_ERR);
//station->storageNumErr = fields.get<int>(DMStatStation::STORAGE_NUM_ERR);
//station->solarGen = fields.get<double>(DMStatStation::SOLAR_ELECT_GEN);
//station->solarGrid = fields.get<double>(DMStatStation::SOLAR_ELECT_GRID);
//station->solarNumErr = fields.get<int>(DMStatStation::SOLAR_NUM_ERR);
//station->chargeElect = fields.get<double>(DMStatStation::CHARGE_ELECT);
//station->chargeNum = fields.get<int>(DMStatStation::CHARGE_NUM);
//station->chargeNumErr = fields.get<int>(DMStatStation::CHARGE_NUM_ERR);
}
else
{
@@ -216,30 +214,38 @@ bool AppData::initFromDB()
}
}
{ // 初始化场站设备的历史监测数据
{ // 初始化场站设备的历史监测数据(当天)
vector<Fields> result;
DAO::queryRuntimeData(dao, Utils::dateStr(), result);
DAO::queryRuntimeDataHistory(dao, Utils::dateStr(), result);
for (auto& item : result)
{
int stationId = item.get<int>("station_id");
int deviceId = item.get<int>("device_id");
int datatype = item.get<int>("datatype");
auto device = this->getDevice(stationId, deviceId);
if (device)
{
int datatype = item.get<int>("datatype");
std::string value = item.value("value");
njson json;
if (JSON::parse(value, json))
{
std::vector<double> vecVal(json.size());
for (int i=0; i<json.size(); ++i)
{
vecVal[i] = JSON::get<double>(json[i]);
}
device->setCache(datatype, vecVal);
}
std::vector<float> vd;
JSON::parseArray(value, vd);
device->setCache(datatype, vd);
}
}
}
{ // 初始化预测数据源的历史数据(当天)
vector<Fields> result;
DAO::queryPredictHistory(dao, Utils::dateStr(), result);
for (auto& item : result)
{
int stationId = item.get<int>("station_id");
int datatype = item.get<int>("datatype");
auto station = this->getStation(stationId);
if (station)
{
std::string value = item.value("value");
std::vector<float> vd;
JSON::parseArray(value, vd);
station->setCache(datatype, vd);
}
}
}

View File

@@ -98,12 +98,13 @@ void Application::runThreadMain()
}
static TimeTick ttMqttPolling; // 召测
if (!Config::option.mqtt.host.empty() && ttMqttPolling.elapse(10))
int mqttInterval = Config::option.mqtt.interval;
if (!Config::option.mqtt.host.empty() && mqttInterval > 0 && ttMqttPolling.elapse(10))
{
for (auto& item : appdata.mapStation)
{
auto& station = item.second;
if (Utils::time() - station->getPollingTS() > Config::option.mqtt.interval)
if (Utils::time() - station->getPollingTS() > mqttInterval)
{
item.second->polling();
}

View File

@@ -187,22 +187,9 @@ void Device::getCachePower(std::vector<std::string>& vec)
}
}
int64_t GetCurrentTimePos(int step)
void Device::setCache(int datatype, std::vector<float>& vd)
{
auto tp = chrono::system_clock::now();
int64_t tTime = chrono::time_point_cast<chrono::seconds>(tp).time_since_epoch().count();
std::time_t t = chrono::system_clock::to_time_t(tp);
std::tm* tmlocal = localtime(&t);
tmlocal->tm_hour = 0;
tmlocal->tm_min = 0;
tmlocal->tm_sec = 0;
int64_t tDate = chrono::time_point_cast<chrono::seconds>(chrono::system_clock::from_time_t(mktime(tmlocal))).time_since_epoch().count();
return (tTime - tDate) / step;
}
void Device::setCache(int datatype, std::vector<double>& vec)
{
std::map<int, double>* mapptr = NULL;
std::map<int, float>* mapptr = NULL;
if (datatype == 1) { mapptr = &mapCacheVoltage; }
else if (datatype == 2) { mapptr = &mapCacheCurrent; }
else if (datatype == 3) { mapptr = &mapCachePower; }
@@ -211,12 +198,12 @@ void Device::setCache(int datatype, std::vector<double>& vec)
{
const int step = 600;
const int N = 86400/step;
int n = GetCurrentTimePos(step);
int64_t tsSeconds = Utils::timeDaySeconds();
int npos = tsSeconds / step;
for (int i = 0; i<N; ++i)
{
if (i < vec.size()) { (*mapptr)[i] = vec[i]; }
else if (i <= n) { (*mapptr)[i] = 0; }
if (i < vd.size()) { (*mapptr)[i] = vd[i]; }
else if (i <= npos) { (*mapptr)[i] = 0; }
}
}
}
@@ -402,10 +389,10 @@ void Device::getRuntimeParams(std::vector<std::pair<std::string, std::string>>&
if (v == "0") v = "并网";
else if (v == "1") v = "离网";
}
if (item.addr == "0x1008") // 模块状态 R uint16 1开机0机 0x1008
if (item.addr == "0x1006") // 启停状态 R uint16 1开机0机 0x1008
{
if (v == "0") v = "开机";
else if (v == "1") v = "";
if (v == "1") v = "开机";
else if (v == "0") v = "";
}
}
else if (type == int(EDeviceType::PCS))
@@ -466,7 +453,7 @@ void Device::setBCUUnit(std::string k, int pos, int v, int count)
if (k == "0x0056") { bcuUnit[0] = float(v) * 0.1f; }
else if (k == "0x043E") { bcuUnit[1] = float(v) * 0.1f; }
else if (k == "0x0826") { bcuUnit[2] = float(v) * 0.001f; }
else if (k == "0x0C0E") { bcuUnit[3] = float(v); } // * 0.01f
else if (k == "0x0C0E") { bcuUnit[3] = float(v) * 0.01f; } // * 0.01f
else if (k == "0x0FF6") { bcuUnit[4] = float(v); }
}
}

View File

@@ -47,7 +47,7 @@ public:
void getCachePower(std::vector<std::string>& vec);
// int datatype: 1: 电压2电流3功率
void setCache(int datatype, std::vector<double>& vec);
void setCache(int datatype, std::vector<float>& vec);
bool cache(int npos);
void storeDB(int npos);
@@ -87,9 +87,9 @@ public:
std::shared_ptr<CommEntity> commEntity;
int64_t tsDataDate {};
std::map<int, double> mapCacheVoltage;
std::map<int, double> mapCacheCurrent;
std::map<int, double> mapCachePower;
std::map<int, float> mapCacheVoltage;
std::map<int, float> mapCacheCurrent;
std::map<int, float> mapCachePower;
std::map<std::string, std::string> mapParams;
std::map<std::string, DeviceParamAddr*> mapMyParams;

View File

@@ -203,6 +203,19 @@ void Station::setGarewayWorkMode()
mqttCli->publish("Gateway_YT", text);
}
string Station::getGatewayMode()
{
// 0手动1峰谷套利2增网配容3应急供电4并网保电5自定时段
if (workModeGateway == 0) { return "手动"; }
else if (workModeGateway == 1) { return "峰谷套利"; }
else if (workModeGateway == 2) { return "增网配容"; }
else if (workModeGateway == 3) { return "应急供电"; }
else if (workModeGateway == 4) { return "并网保电"; }
else if (workModeGateway == 5) { return "自定时段"; }
else { return "--"; };
}
void Station::checkDevice()
{
for (auto& item: mapDevice)
@@ -331,6 +344,7 @@ void Station::readCoolingData(int deviceNo, string addr, int val)
void Station::readGatewayMode(int mode)
{
this->workModeGateway = mode;
if (mode != this->workMode)
{
//this->setGarewayWorkMode();
@@ -363,20 +377,61 @@ void Station::readGatewayStatus(int cdzStatus, int emuStatus)
}
}
static std::string MapValueToJson(int npos, std::map<int, double>& mapV)
static std::string MapValueToJson(int npos, std::map<int, float>& mapV)
{
njson jsonarray = njson::array();
for (int i = 0; i<=npos; i++)
{
jsonarray.push_back(mapV[i]);
jsonarray.push_back(int(mapV[i]));
}
return jsonarray.dump();
}
void Station::setCache(int datatype, std::vector<float>& vd)
{
std::map<int, float>* mapptr = NULL;
if (datatype == 1) { mapptr = &mapCacheElectIn; }
else if (datatype == 2) { mapptr = &mapCacheElectOut; }
else if (datatype == 3) { mapptr = &mapCacheElectCharger; }
if (mapptr)
{
const int step = 600;
const int N = 86400/step;
int64_t tsSeconds = Utils::timeDaySeconds();
int npos = tsSeconds / step;
for (int i = 0; i<N; ++i)
{
if (i < vd.size()) { (*mapptr)[i] = vd[i]; }
else if (i <= npos) { (*mapptr)[i] = 0; }
}
}
}
void Station::cache()
{
int64_t tDaySeconds = Utils::timeDaySeconds();
int npos = tDaySeconds / 600;
int offset = tDaySeconds % 600;
bool save = false;
if (offset >= (600-180) && npos + 1 < 144)
{
npos += 1;
save = true;
}
else if (offset <= 180 && posCache < npos)
{
save = true;
posCache = npos;
}
if (save)
{
mapCacheElectIn[npos] = Utils::random(100, 800); // dayElectIn
mapCacheElectOut[npos] = Utils::random(100, 800); // dayElectOut
mapCacheElectCharger[npos] = Utils::random(100, 800); // 暂无数据源
}
}
void Station::writeStatistic()
{
auto dao = DaoEntity::create("history_day");
std::string dt = Utils::dateStr();
int64_t tTime = Utils::time();
int64_t tDate = Utils::date();
@@ -386,7 +441,7 @@ void Station::writeStatistic()
for (auto iter = mapDevice.begin(); iter!=mapDevice.end(); ++iter)
{
auto device = iter->second;
if (device->cache(npos) && device->type == int(EDeviceType::BMS))
if (device->cache(npos))
{
Fields fields;
fields.set("dt", dt);
@@ -407,7 +462,7 @@ void Station::writeStatistic()
}
}
if (statData.ts != 0)
if (statData.ts > 0)
{
Fields fields;
fields.set("dt", Utils::dateStr(statData.ts));
@@ -437,15 +492,14 @@ void Station::writeStatistic()
};
dao->duplicateUpdate(fields, vecKeys);
{
{ // stat_day
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);
DAO::insertStatDay(dao, fields);
}
{
Fields fields;
@@ -458,4 +512,25 @@ void Station::writeStatistic()
}
}
{
// 预测数据源记录
dao->setTableName("predict_day");
Fields fields;
fields.set("dt", dt);
fields.set("station_id", stationId);
fields.set("datatype", 1); // 1储能充电2储能放电3充电桩充电4发电
fields.set("value", MapValueToJson(npos, mapCacheElectIn));
dao->duplicateUpdate(fields, {"value"});
fields.set("datatype", 2); // 1储能充电2储能放电3充电桩充电4发电
fields.set("value", MapValueToJson(npos, mapCacheElectOut));
dao->duplicateUpdate(fields, {"value"});
fields.set("datatype", 3); // 1储能充电2储能放电3充电桩充电4发电
fields.set("value", MapValueToJson(npos, mapCacheElectCharger));
dao->duplicateUpdate(fields, {"value"});
}
}

View File

@@ -115,6 +115,8 @@ public:
void setGarewayWorkMode();
void checkDevice();
string getGatewayMode();
void readAlert(std::shared_ptr<Device> device, std::string addr, int v, std::string text);
void readRuntimeData(int deviceNo, string addr, int val);
void readTHData(int deviceNo, string addr, int val);
@@ -123,6 +125,10 @@ public:
void readGatewayMode(int mode);
void readGatewayStatus(int cdzStatus, int emuStatus);
void setCache(int datatype, std::vector<float>& vd);
void cache();
int posCache {0};
void writeStatistic();
int posDayStat {0};
@@ -138,6 +144,7 @@ public:
bool isConnected {false};
int workMode {}; // 运行模式
int workModeGateway { -1 }; // 运行模式
int runPolicyId {}; // 运行策略
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -158,23 +165,19 @@ public:
///////////////////////////////////////////////////////////////////////////////////////////////
/// === 日统计 ===
double storageIn {}; // 储能充电电量
double storageOut {}; // 储能放电电量
int storageNumIn {}; // 储能电次数
int storageNumOut {}; // 储能放电次数
int storageNumErr {}; // 储能故障次数
double solarGen {}; // 光伏发电电量
double solarGrid {}; // 光伏入网电量
int solarNumErr {}; // 光伏故障次数
double chargeElect {}; // 充电设备充电电量
int chargeNum {}; // 充电设备充电次数
int chargeNumErr {}; // 充电设备故障次数
double incomeElect {}; // 发电收益金额
double incomeCharge {}; // 充电收益金额
//double storageIn {}; // 储能充电电量
//double storageOut {}; // 储能放电电量
//int storageNumIn {}; // 储能充电次数
//int storageNumOut {}; // 储能电次数
//int storageNumErr {}; // 储能故障次数
//double solarGen {}; // 光伏发电电量
//double solarGrid {}; // 光伏入网电量
//int solarNumErr {}; // 光伏故障次数
//double chargeElect {}; // 充电设备充电电量
//int chargeNum {}; // 充电设备充电次数
//int chargeNumErr {}; // 充电设备故障次数
//double incomeElect {}; // 发电收益金额
//double incomeCharge {}; // 充电收益金额
///////////////////////////////////////////////////////////////////////////////////////////////
/// === 环境 ===
@@ -200,7 +203,6 @@ public:
std::unordered_map<int, std::shared_ptr<Device>> mapDevice;
std::map<int, std::map<std::string, std::shared_ptr<Device>>> mapDeviceGroup;
// 温湿度信息
std::map<int, TempHumUnit> mapTempHumUnit;
// 消防4.0信息
@@ -269,4 +271,14 @@ public:
int emuStatus {-1};
std::map<std::string, int64_t> mapAlertCache;
///////////////////////////////////////////////////////////////////////////////////////////////
/// 说明从电表中读取对应数据每间隔600秒10分钟缓存一个点位存储到数据库用于绘制一天的电曲线
// 储能充电量缓存key位置索引0->144val电量
std::map<int, float> mapCacheElectIn;
// 储能放电量缓存key位置索引0->144val电量
std::map<int, float> mapCacheElectOut;
// 充电桩充电量缓存key位置索引0->144val电量
std::map<int, float> mapCacheElectCharger;
};