Files
energy_storage/src/app/Device.cpp

460 lines
15 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>
std::map<int, std::vector<DeviceParamAddr>> Device::s_mapDeviceAddrParam;
std::map<int, std::vector<std::string>> Device::s_mapDeviceAddrCurve;
static std::vector<DeviceParamAddr>& GetDeviceParamAddrs(int deviceType)
{
static std::vector<DeviceParamAddr> vecAddrs = {};
auto iter = Device::s_mapDeviceAddrParam.find(deviceType);
if (iter != Device::s_mapDeviceAddrParam.end())
{
return iter->second;
}
return vecAddrs;
}
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;
}
void Device::loadParamAddr(std::string filename)
{
try
{
njson json;
if (!JSON::load(filename, json))
{
spdlog::error("[device] json load param addr error, filename={}", filename);
}
for (auto& jsonitem : json.items())
{
std::string key = jsonitem.key();
auto& jsonnodeItem = jsonitem.value();
int type = jsonnodeItem["deviceType"];
auto& vec = s_mapDeviceAddrParam[type];
for (auto& v : jsonnodeItem["addrYC"])
{
std::string name = JSON::get<std::string>(v[0]);
std::string addr = JSON::get<std::string>(v[1]);
std::string defaultVal = JSON::get<std::string>(v[2]);
std::string unit = JSON::get<std::string>(v[3]);
float ratio = Utils::toFloat(JSON::get<string>(v[4]));
vec.push_back(DeviceParamAddr(name, addr, defaultVal, unit, ratio));
}
if (jsonnodeItem.contains("addrCurve"))
{
auto& vec = s_mapDeviceAddrCurve[type];
for (auto& v : jsonnodeItem["addrCurve"])
{
vec.push_back(v.get<std::string>());
}
}
}
}
catch (nlohmann::json::parse_error& e)
{
spdlog::error("[device] parse [{}] error: ", filename, e.what());
}
}
static const int BCU_UNIT_SIZE = 256;
Device::Device()
{
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 = 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::map<int, float>* mapptr = NULL;
if (datatype == 1) { mapptr = &mapCacheVoltage; }
else if (datatype == 2) { mapptr = &mapCacheCurrent; }
else if (datatype == 3) { mapptr = &mapCachePower; }
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; }
}
}
}
bool Device::cache(int npos)
{
if (!CheckCacheType(this->type))
{
return false;
}
if (npos == 0)
{
mapCacheVoltage.clear();
mapCacheCurrent.clear();
mapCachePower.clear();
}
std::string addrV;
std::string addrI;
std::string addrP;
auto iter = s_mapDeviceAddrCurve.find(this->type);
if (iter != 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"));
mapCacheVoltage[npos] = U;
mapCacheCurrent[npos] = I;
mapCachePower[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 = (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;
if (type == 3 ) // 电表
{
running = 1;
}
else if (type == int(EDeviceType::EMS)) // 101 EMS
{
running = 1;
}
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) // 光伏板
{
}
}
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;
}
void Device::getRuntimeParams(std::vector<std::pair<std::string, std::string>>& params)
{
// 3 电表
// 101 EMS
// 102 PCS
// 103 PCU
// 104 BMS
// 105 BCU
// 106 充电桩
// 109 光伏板
auto& vecAddr = s_mapDeviceAddrParam[this->type];
for (auto& item: vecAddr)
{
std::string v = getParam(item.addr, item.defaultVal);
if (type == int(EDeviceType::BCU) )
{
if (item.addr == "0xA003") //"0x11开路0x22待机0x33充电0x44放电"
{
if (v == "17") v = "开路";
else if (v == "34") v = "待机";
else if (v == "51") v = "充电";
else if (v == "68") v = "放电";
}
else if (item.addr == "0xA004") //"0x11跳机 0x22待机0x33放空0x44充满0x55预警0x66正常"
{
if (v == "17") v = "跳机";
else if (v == "34") v = "待机";
else if (v == "51") v = "放空";
else if (v == "68") v = "充满";
else if (v == "85") v = "预警";
else if (v == "102") v = "正常";
}
}
else if (type == int(EDeviceType::BMS))
{
if (item.addr == "0x004A") // 0-待机 1-充电 2-放电
{
if (v == "0") v = "待机";
else if (v == "1") v = "充电";
else if (v == "2") v = "放电";
}
}
else if (type == int(EDeviceType::PCU))
{
if (item.addr == "0x1007") // 电网状态 R uint16 1离网0并网 0x1007
{
if (v == "0") v = "并网";
else if (v == "1") v = "离网";
}
if (item.addr == "0x1006") // 启停状态 R uint16 1开机0关机 0x1008
{
if (v == "1") v = "开机";
else if (v == "0") v = "关机";
}
}
else if (type == int(EDeviceType::PCS))
{
if (item.addr == "0x1009") //充放状态 R uint16 0待机, 1充电, 2放电, 3搁置 0x1009
{
if (v == "0") v = "待机";
else if (v == "1") v = "充电";
else if (v == "2") v = "放电";
else if (v == "3") v = "搁置";
}
else if (item.addr == "0x100A") //电网状态 R uint16 1离网0并网 0x100A
{
if (v == "0") v = "并网";
else if (v == "1") v = "离网";
}
}
//if (this->online) { }
//else { v = "--"; }
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); }
}
}