Files
energy_storage/src/app/Device.cpp
2026-05-25 15:07:33 +08:00

380 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Device.h"
#include "common/Spdlogger.h"
#include "common/Utils.h"
#include "protocol/CommEntity.h"
#include "common/JsonN.h"
#include "app/DataStruct.h"
#include <unordered_set>
#include "Application.h"
#include "Station.h"
static std::unordered_set<int> g_setCacheDeviceType = {3, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110};
static bool CheckCacheType(int type)
{
return g_setCacheDeviceType.find(type) != g_setCacheDeviceType.end();
}
std::shared_ptr<Device> Device::create(Fields& fields)
{
auto device = std::make_shared<Device>();
device->setFields(fields);
return device;
}
static const int BCU_UNIT_SIZE = 256;
Device::Device()
{
cacheU = vector<float>(144, 0);
cacheI = vector<float>(144, 0);
cacheP = vector<float>(144, 0);
vecBCUUnit = std::vector<std::vector<float>>(BCU_UNIT_SIZE, std::vector<float>(5, 0.0f));
}
void Device::setFields(Fields& fields)
{
fields.get("station_id", this->stationId);
fields.get("device_id", this->deviceId);
fields.get("type", this->type);
fields.get("name", this->name);
fields.get("code", this->code);
fields.get("is_open", this->isOpen);
fields.get("attrs", this->attrsJson);
fields.get("category", this->category);
fields.get("sort_no", this->sortNo);
// 解析属性的JSON字符串转换成键值对
njson jsonroot;
bool ret = JSON::parse(this->attrsJson, jsonroot);
if (!ret) // 解析错误
{
spdlog::error("[device] device attr json parse error, device_id={}", this->deviceId);
}
else
{
this->attrs.clear();
for (auto& [key, val] : jsonroot.items()) {
std::string valType = val.type_name();
if (valType == "string") {
this->attrs.set(key, val.get<std::string>());
}
else if (valType == "number") {
this->attrs.set(key, val.get<int>());
}
else {
spdlog::error("[device] device attr unknown type: key={}, valtype={}", key, valType);
}
}
}
auto& vecAddrs = REGAddr::GetDeviceParamAddrs(this->type);
for (auto& item: vecAddrs)
{
this->mapMyParams[item.addr] = &item;
}
}
int Device::startComm()
{
if (!isOpen)
{
if (commEntity && commEntity->alive)
{
commEntity->close();
}
return 0;
}
//// 从属性列表中获取通讯方式和通讯地址、端口
//std::string commType = attrs.value("commType");
//
//// 如果entity的通讯协议类型当前配置不一致需要关闭连接删除通讯后创建新的通讯
//if (commEntity && commEntity->type != commType)
//{
// commEntity->close();
// commEntity = nullptr;
//}
//// 创建新的通讯
//if (!commEntity)
//{
// commEntity = CommEntity::create(attrs);
// if (!commEntity) { return -1; }
//}
//commEntity->start();
return 0;
}
//void Device::getCacheVoltage(std::vector<std::string>& vec)
//{
// vec.resize(mapCacheVoltage.size());
// int i = 0;
// for (auto iter = mapCacheVoltage.begin(); iter != mapCacheVoltage.end(); ++iter)
// {
// vec[i] = Utils::toStr(iter->second);
// i++;
// }
//}
//void Device::getCacheCurrent(std::vector<std::string>& vec)
//{
// vec.resize(mapCacheCurrent.size());
// int i = 0;
// for (auto iter = mapCacheCurrent.begin(); iter != mapCacheCurrent.end(); ++iter)
// {
// vec[i] = Utils::toStr(iter->second);
// i++;
// }
//}
//void Device::getCachePower(std::vector<std::string>& vec)
//{
// vec.resize(mapCachePower.size());
// int i = 0;
// for (auto iter = mapCachePower.begin(); iter != mapCachePower.end(); ++iter)
// {
// vec[i] = Utils::toStr(iter->second);
// i++;
// }
//}
void Device::setCache(int datatype, std::vector<float>& vd)
{
std::vector<float>* vecptr = NULL;
if (datatype == 1) { vecptr = &cacheU; }
else if (datatype == 2) { vecptr = &cacheI; }
else if (datatype == 3) { vecptr = &cacheP; }
if (vecptr)
{
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< vecptr->size(); ++i)
{
if (i < vd.size()) { (*vecptr)[i] = vd[i]; }
else if (i <= npos) { (*vecptr)[i] = 0; }
}
}
}
bool Device::cache(int npos)
{
if (!CheckCacheType(this->type))
{
return false;
}
if (npos == 0)
{
std::fill(cacheU.begin(), cacheU.end(), 0);
std::fill(cacheI.begin(), cacheI.end(), 0);
std::fill(cacheP.begin(), cacheP.end(), 0);
}
std::string addrV;
std::string addrI;
std::string addrP;
auto iter = REGAddr::s_mapDeviceAddrCurve.find(this->type);
if (iter != REGAddr::s_mapDeviceAddrCurve.end())
{
auto& vecAddr = iter->second;
auto size = vecAddr.size();
if (size >= 1) { addrV = vecAddr[0]; }
if (size >= 2) { addrI = vecAddr[1]; }
if (size >= 3) { addrP = vecAddr[2]; }
}
// 根据设备类型从参数(寄存器地址)中读取实时数据进行保存
int U = Utils::toInt(this->getParam(addrV, "0"));
int I = Utils::toInt(this->getParam(addrI, "0"));
int P = addrP.empty() ? U*I*0.001 : Utils::toInt(this->getParam(addrP, "0"));
cacheU[npos] = U;
cacheI[npos] = I;
cacheP[npos] = P;
return true;
}
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())
{
ratio = iter->second->ratio;
//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 = 0;
if (ratio == 0.1f) { precision = 1; }
else if (ratio == 0.01f) { precision = 2; }
else if (ratio == 0.001f) { precision = 3; }
std::string valStr = Utils::toStr(v*ratio, precision);
if (type == 106) // 充电桩状态,特殊数据格式
{
if (k=="11" || k == "21") {
valStr = (valStr == "1" ? "充电" : "空闲");
}
}
mapParams[k] = valStr;
if (type == int(EDeviceType::E_METER)) // 电表
{
running = 1;
}
else if (type == int(EDeviceType::EMS)) // 101 EMS
{
running = 1;
// EMS 没有总的故障状态标识,需要对多有的故障状态位进行判断
err = (mapParams["0x2001"] != "0") || (mapParams["0x2002"] != "0") ||
(mapParams["0x2006"] != "0") || (mapParams["0x2007"] != "0") ||
(mapParams["0x200B"] != "0") || (mapParams["0x200C"] != "0") ||
(mapParams["0x200E"] != "0") || (mapParams["0x200F"] != "0") ||
(mapParams["0x2010"] != "0") || (mapParams["0x2011"] != "0") ||
(mapParams["0x2013"] != "0") || (mapParams["0x2014"] != "0") ||
(mapParams["0x2018"] != "0") || (mapParams["0x2019"] != "0") ||
(mapParams["0x201A"] != "0") || (mapParams["0x201B"] != "0") ||
(mapParams["0x201C"] != "0") || (mapParams["0x201D"] != "0") ||
(mapParams["0x201E"] != "0") || (mapParams["0x201F"] != "0") ||
(mapParams["0x2020"] != "0") || (mapParams["0x2021"] != "0") ||
(mapParams["0x2022"] != "0");
}
else if (type == int(EDeviceType::PCS)) // 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
}
else if (type == int(EDeviceType::PCU)) // 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
}
else if (type == int(EDeviceType::BMS)) // 104 BMS
{
if (k == "0x0049")
{
err = (v==1);
} //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x0049
else if (k == "0x004A") { running = (v==1 || v==2); } //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004A
}
else if (type == int(EDeviceType::BCU)) // 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
}
else if (type == int(EDeviceType::CHARGER)) // 106 充电桩
{
if (k == "21") {
running = (mapParams["11"] == "充电" || mapParams["21"] == "充电"); // 充电状态: 0空闲1充电
}
}
else if (type == 109) // 光伏板
{
}
if (err )
{
auto station = Application::data().getStation(stationId);
station->err = 1;
}
}
std::string Device::getParam(std::string k, std::string defaultVal)
{
if (k.empty())
{
return defaultVal;
}
auto iter = mapParams.find(k);
if (iter != mapParams.end())
{
return iter->second;
}
return defaultVal;
}
static map<int, map<string, string>> g_mapAddrValStr =
{
};
void Device::getRuntimeParams(std::vector<std::pair<std::string, std::string>>& params)
{
if (type == int(EDeviceType::E_METER_TD))
{
}
auto& vecAddr = REGAddr::s_mapDeviceAddrParam[this->type];
for (auto& item : vecAddr)
{
std::string v = getParam(item.addr, item.defaultVal);
auto& mapValStr = REGAddr::g_mapRegAddrValStr[type][item.addr];
auto iter = mapValStr.find(v);
if (iter != mapValStr.end())
{
v = iter->second;
}
params.push_back({ item.name, v + item.unit });
}
}
void Device::getRuntimeParams1(std::vector<std::pair<std::string, std::string>>& params)
{
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"});
}
}
void Device::setBCUUnit(std::string k, int pos, int v, int count)
{
//单体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
if (pos < BCU_UNIT_SIZE)
{
auto& bcuUnit = vecBCUUnit[pos];
if (pos == 0)
{
bcuCount = count;
for (int i = count; i<BCU_UNIT_SIZE; ++i)
{
std::fill(vecBCUUnit[i].begin(), vecBCUUnit[i].end(), 0.0f);
}
}
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; } // * 0.01f
else if (k == "0x0FF6") { bcuUnit[4] = float(v); }
}
}