1298 lines
44 KiB
C++
1298 lines
44 KiB
C++
|
|
#include "../json/cjson.h"
|
|||
|
|
#include "../json/mms_json_inter.h"
|
|||
|
|
#include "../json/PQSMsg.h"
|
|||
|
|
#include <array>
|
|||
|
|
#include <string>
|
|||
|
|
#include <cstdlib>
|
|||
|
|
#include <ctime>
|
|||
|
|
#include <string>
|
|||
|
|
#include <vector>
|
|||
|
|
#include <map>
|
|||
|
|
|
|||
|
|
#ifndef EMPTY_FLOAT_VALUE
|
|||
|
|
#define EMPTY_FLOAT_VALUE 3.14159f
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
extern QMutex kafka_data_list_mutex;
|
|||
|
|
extern QList<Ckafka_data_t> kafka_data_list;
|
|||
|
|
|
|||
|
|
// statType: 0=95值, 1=平均值, 2=最大值, 3=最小值
|
|||
|
|
static std::string MakeStatKey(int statType, const std::string& base)
|
|||
|
|
{
|
|||
|
|
switch (statType) {
|
|||
|
|
case 0: return "G_" + base;
|
|||
|
|
case 1: return base;
|
|||
|
|
case 2: return "MAX_" + base;
|
|||
|
|
case 3: return "MIN_" + base;
|
|||
|
|
default: return base;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static cJSON* GetObj(cJSON* parent, const char* name)
|
|||
|
|
{
|
|||
|
|
if (parent == NULL || name == NULL) {
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
return cJSON_GetObjectItem(parent, name);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetJsonFloat(cJSON* root,
|
|||
|
|
const char* group,
|
|||
|
|
const char* phase,
|
|||
|
|
const std::string& key)
|
|||
|
|
{
|
|||
|
|
cJSON* value = GetObj(root, "Value");
|
|||
|
|
cJSON* g = GetObj(value, group);
|
|||
|
|
cJSON* p = GetObj(g, phase);
|
|||
|
|
cJSON* item = GetObj(p, key.c_str());
|
|||
|
|
|
|||
|
|
if (item == NULL) {
|
|||
|
|
return 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_Number) {
|
|||
|
|
return static_cast<float>(item->valuedouble);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_String && item->valuestring != NULL) {
|
|||
|
|
return static_cast<float>(atof(item->valuestring));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetValue(cJSON* root,
|
|||
|
|
int statType,
|
|||
|
|
const char* group,
|
|||
|
|
const char* phase,
|
|||
|
|
const std::string& base)
|
|||
|
|
{
|
|||
|
|
return GetJsonFloat(root, group, phase, MakeStatKey(statType, base));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void FillDeviation(float val, float& up, float& low)
|
|||
|
|
{
|
|||
|
|
if (val >= 0.0f) {
|
|||
|
|
up = val;
|
|||
|
|
low = 0.0f;
|
|||
|
|
} else {
|
|||
|
|
up = 0.0f;
|
|||
|
|
low = -val;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static long long GetJsonTimeMs(cJSON* root)
|
|||
|
|
{
|
|||
|
|
cJSON* value = GetObj(root, "Value");
|
|||
|
|
cJSON* item = GetObj(value, "TIME");
|
|||
|
|
|
|||
|
|
if (item == NULL) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_Number) {
|
|||
|
|
return static_cast<long long>(item->valuedouble);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_String && item->valuestring != NULL) {
|
|||
|
|
return atoll(item->valuestring);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static tagTime MakeTagTimeFromMs(long long ms)
|
|||
|
|
{
|
|||
|
|
time_t sec = static_cast<time_t>(ms / 1000);
|
|||
|
|
struct tm tmv;
|
|||
|
|
#ifdef _WIN32
|
|||
|
|
localtime_s(&tmv, &sec);
|
|||
|
|
#else
|
|||
|
|
localtime_r(&sec, &tmv);
|
|||
|
|
#endif
|
|||
|
|
return tagTime(tmv);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// connectionType: 0=星型, 1=角型
|
|||
|
|
std::array<tagPqData_Float, 4> BuildPqFloatDataFromJson(cJSON* jsondata,
|
|||
|
|
int connectionType)
|
|||
|
|
{
|
|||
|
|
std::array<tagPqData_Float, 4> all_data;
|
|||
|
|
|
|||
|
|
const char* PH3[3];
|
|||
|
|
const char* PH4[4];
|
|||
|
|
|
|||
|
|
if (connectionType == 1) {
|
|||
|
|
// 角型
|
|||
|
|
PH3[0] = "AB";
|
|||
|
|
PH3[1] = "BC";
|
|||
|
|
PH3[2] = "CA";
|
|||
|
|
|
|||
|
|
PH4[0] = "AB";
|
|||
|
|
PH4[1] = "BC";
|
|||
|
|
PH4[2] = "CA";
|
|||
|
|
PH4[3] = "T";
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
// 星型
|
|||
|
|
PH3[0] = "A";
|
|||
|
|
PH3[1] = "B";
|
|||
|
|
PH3[2] = "C";
|
|||
|
|
|
|||
|
|
PH4[0] = "A";
|
|||
|
|
PH4[1] = "B";
|
|||
|
|
PH4[2] = "C";
|
|||
|
|
PH4[3] = "T";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
long long timeMs = GetJsonTimeMs(jsondata);
|
|||
|
|
|
|||
|
|
for (int stat = 0; stat < 4; ++stat) {
|
|||
|
|
tagPqData_Float& dst = all_data[stat];
|
|||
|
|
|
|||
|
|
dst.name = 0;
|
|||
|
|
dst.Data_Type = 0;
|
|||
|
|
|
|||
|
|
if (timeMs > 0) {
|
|||
|
|
dst.time = MakeTagTimeFromMs(timeMs);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 1. Rms[0..8]
|
|||
|
|
// 0-2: 相电压有效值 VRMS
|
|||
|
|
// 3-5: 相电流有效值 IRMS
|
|||
|
|
// 6-8: 线电压有效值 VRMS_LVR
|
|||
|
|
// 注意:根据 ZJ.xml/jsondata,只有线电压有效值使用 LVR
|
|||
|
|
if (connectionType == 1) {
|
|||
|
|
// 角型
|
|||
|
|
|
|||
|
|
// 相电压空置
|
|||
|
|
dst.Rms[0] = EMPTY_FLOAT_VALUE;
|
|||
|
|
dst.Rms[1] = EMPTY_FLOAT_VALUE;
|
|||
|
|
dst.Rms[2] = EMPTY_FLOAT_VALUE;
|
|||
|
|
|
|||
|
|
// 电流
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Rms[i + 3] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "IRMS");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 线电压
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Rms[i + 6] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "VRMS_LVR");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
// 星型
|
|||
|
|
|
|||
|
|
// 相电压
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Rms[i] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "VRMS");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 电流
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Rms[i + 3] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "IRMS");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 线电压
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Rms[i + 6] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "VRMS_LVR");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 电压偏差
|
|||
|
|
// 星型:转换函数取 UU/UL[0..2] 作为相电压偏差,线电压偏差空置
|
|||
|
|
// 角型:转换函数前 3 个位置空置,后面取 UU/UL[0..2] 作为线电压偏差
|
|||
|
|
// 因为 jsondata 里没有 DELTA_V_LVR,所以统一填 DELTA_V 到 [0..2]
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
float dev = GetValue(jsondata, stat, "V", PH3[i], "DELTA_V");
|
|||
|
|
FillDeviation(dev, dst.UU_Deviation[i], dst.UL_Deviation[i]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 频率偏差 + 频率
|
|||
|
|
dst.F_Deviation[0] = GetValue(jsondata, stat, "V", "T", "DELTA_FREQ");
|
|||
|
|
dst.F_Deviation[1] = GetValue(jsondata, stat, "V", "T", "FREQ");
|
|||
|
|
|
|||
|
|
// 4. UI_Seq
|
|||
|
|
dst.UI_Seq[0][0] = GetValue(jsondata, stat, "V", "T", "VZSEQ");
|
|||
|
|
dst.UI_Seq[0][1] = GetValue(jsondata, stat, "V", "T", "VNSEQ");
|
|||
|
|
dst.UI_Seq[0][2] = GetValue(jsondata, stat, "V", "T", "VPSEQ");
|
|||
|
|
dst.UI_Seq[0][3] = GetValue(jsondata, stat, "V", "T", "V_UNBAN");
|
|||
|
|
|
|||
|
|
dst.UI_Seq[1][0] = GetValue(jsondata, stat, "I", "T", "IZSEQ");
|
|||
|
|
dst.UI_Seq[1][1] = GetValue(jsondata, stat, "I", "T", "INSEQ");
|
|||
|
|
dst.UI_Seq[1][2] = GetValue(jsondata, stat, "I", "T", "IPSEQ");
|
|||
|
|
dst.UI_Seq[1][3] = GetValue(jsondata, stat, "I", "T", "I_UNBAN");
|
|||
|
|
|
|||
|
|
// 5. 基波有效值 FuHarm[*][0]
|
|||
|
|
// 星型:FuHarm[0..2][0] 被当作 A/B/C 相电压 V1
|
|||
|
|
// 角型:FuHarm[0..2][0] 被当作 AB/BC/CA 线电压 V1
|
|||
|
|
// jsondata 中仍然使用 V1 字段,不额外使用 LVR
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.FuHarm[i][0] = GetValue(jsondata, stat, "V", PH3[i], "V1");
|
|||
|
|
dst.FuHarm[i + 3][0] = GetValue(jsondata, stat, "I", PH3[i], "I1");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 6. 基波相角 FuHarmPhase[*][0]
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.FuHarmPhase[i][0] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "VFUND_ANGLE");
|
|||
|
|
|
|||
|
|
dst.FuHarmPhase[i + 3][0] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "IFUND_ANGLE");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 7. 2-50 次谐波有效值
|
|||
|
|
// 星型转换:先取 FuHarm[0..2][1..49] 作为相电压,再取 FuHarm[3..5] 作为电流,线电压空置
|
|||
|
|
// 角型转换:先空置相电压,再取 FuHarm[3..5] 作为电流,再取 FuHarm[0..2] 作为线电压
|
|||
|
|
// 所以这里统一填 FuHarm[0..2]=V2..V50,FuHarm[3..5]=I2..I50
|
|||
|
|
for (int h = 1; h < HARMNUM; ++h) {
|
|||
|
|
int no = h + 1;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.FuHarm[i][h] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "V" + std::to_string(no));
|
|||
|
|
|
|||
|
|
dst.FuHarm[i + 3][h] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "I" + std::to_string(no));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 8. 2-50 次谐波相角
|
|||
|
|
for (int h = 1; h < HARMNUM; ++h) {
|
|||
|
|
int no = h + 1;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.FuHarmPhase[i][h] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "VA" + std::to_string(no));
|
|||
|
|
|
|||
|
|
dst.FuHarmPhase[i + 3][h] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "IA" + std::to_string(no));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 9. 间谐波有效值 InHarm[*][0..49]
|
|||
|
|
// 星型:InHarm[0..2] 相电压有效,InHarm[3..5] 电流有效,线电压空置
|
|||
|
|
// 角型:先空置相电压,再取 InHarm[3..5] 电流,再取 InHarm[0..2] 线电压
|
|||
|
|
// jsondata 中统一使用 SV_x / SI_x
|
|||
|
|
for (int h = 0; h < HARMNUM; ++h) {
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.InHarm[i][h].Val =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "SV_" + std::to_string(h));
|
|||
|
|
|
|||
|
|
dst.InHarm[i + 3][h].Val =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "SI_" + std::to_string(h));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 10. 总功率 Total_Power[4][3]
|
|||
|
|
// phase: A/B/C/T
|
|||
|
|
// index: 0=P, 1=Q, 2=S
|
|||
|
|
for (int i = 0; i < 4; ++i) {
|
|||
|
|
dst.Total_Power[i][0] = GetValue(jsondata, stat, "PQ", PH4[i], "P");
|
|||
|
|
dst.Total_Power[i][1] = GetValue(jsondata, stat, "PQ", PH4[i], "Q");
|
|||
|
|
dst.Total_Power[i][2] = GetValue(jsondata, stat, "PQ", PH4[i], "S");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 11. 谐波功率 Harm_Power[4][50]
|
|||
|
|
// h=0 对应 P1/Q1/S1,h=1..49 对应 P2..P50/Q2..Q50/S2..S50
|
|||
|
|
for (int i = 0; i < 4; ++i) {
|
|||
|
|
for (int h = 0; h < HARMNUM; ++h) {
|
|||
|
|
int no = h + 1;
|
|||
|
|
|
|||
|
|
dst.Harm_Power[i][h].P =
|
|||
|
|
GetValue(jsondata, stat, "PQ", PH4[i], "P" + std::to_string(no));
|
|||
|
|
|
|||
|
|
dst.Harm_Power[i][h].Q =
|
|||
|
|
GetValue(jsondata, stat, "PQ", PH4[i], "Q" + std::to_string(no));
|
|||
|
|
|
|||
|
|
dst.Harm_Power[i][h].S =
|
|||
|
|
GetValue(jsondata, stat, "PQ", PH4[i], "S" + std::to_string(no));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 12. 谐波含有率 Harm_Contain[6][50]
|
|||
|
|
// 0-2: 电压谐波含有率
|
|||
|
|
// 3-5: 电流谐波含有率
|
|||
|
|
// 转换函数会根据星型/角型决定这些数据输出到相电压区还是线电压区
|
|||
|
|
for (int h = 1; h < HARMNUM; ++h) {
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Harm_Contain[i][h] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "SV_" + std::to_string(h));
|
|||
|
|
|
|||
|
|
dst.Harm_Contain[i + 3][h] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "SI_" + std::to_string(h));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 13. 谐波总畸变率 Harm_Aberrance[6]
|
|||
|
|
// 0-2: 电压 THD
|
|||
|
|
// 3-5: 电流 THD
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.Harm_Aberrance[i] =
|
|||
|
|
GetValue(jsondata, stat, "V", PH3[i], "VTHD");
|
|||
|
|
|
|||
|
|
dst.Harm_Aberrance[i + 3] =
|
|||
|
|
GetValue(jsondata, stat, "I", PH3[i], "ITHD");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 14. 功率因数
|
|||
|
|
for (int i = 0; i < 4; ++i) {
|
|||
|
|
dst.Cos_PF[i] = GetValue(jsondata, stat, "PQ", PH4[i], "PF");
|
|||
|
|
dst.Cos_DF[i] = GetValue(jsondata, stat, "PQ", PH4[i], "DF");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 15. 波动、短闪、长闪
|
|||
|
|
// 目前 jsondata 中没有 LVR 字段,统一填 A/B/C 三相字段
|
|||
|
|
// 星型转换函数输出三相数据,线电压位置空置
|
|||
|
|
// 角型转换函数先空置三相位置,再把这三个值输出到线电压位置
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
dst.U_Fluctuation[i] = GetValue(jsondata, stat, "V", PH3[i], "FLUC");
|
|||
|
|
dst.U_Flicker[i] = GetValue(jsondata, stat, "V", PH3[i], "PST");
|
|||
|
|
dst.UL_Flicker[i] = GetValue(jsondata, stat, "V", PH3[i], "PLT");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return all_data;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
////////////////////////////////////////////////////实时部分
|
|||
|
|
|
|||
|
|
static float GetRtJsonFloat(cJSON* root,
|
|||
|
|
const char* group,
|
|||
|
|
const char* phase,
|
|||
|
|
const std::string& key)
|
|||
|
|
{
|
|||
|
|
cJSON* value = GetObj(root, "Value");
|
|||
|
|
cJSON* g = GetObj(value, group);
|
|||
|
|
cJSON* p = GetObj(g, phase);
|
|||
|
|
cJSON* item = GetObj(p, key.c_str());
|
|||
|
|
|
|||
|
|
if (item == NULL) {
|
|||
|
|
return 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_Number) {
|
|||
|
|
return static_cast<float>(item->valuedouble);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_String && item->valuestring != NULL) {
|
|||
|
|
return static_cast<float>(atof(item->valuestring));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetRtValue(cJSON* root,
|
|||
|
|
const char* group,
|
|||
|
|
const char* phase,
|
|||
|
|
const std::string& key)
|
|||
|
|
{
|
|||
|
|
return GetRtJsonFloat(root, group, phase, key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static long long GetRtJsonTimeMs(cJSON* root)
|
|||
|
|
{
|
|||
|
|
cJSON* value = GetObj(root, "Value");
|
|||
|
|
cJSON* item = GetObj(value, "TIME");
|
|||
|
|
|
|||
|
|
if (item == NULL) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_Number) {
|
|||
|
|
return static_cast<long long>(item->valuedouble);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item && item->type == cJSON_String && item->valuestring != NULL) {
|
|||
|
|
return atoll(item->valuestring);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static tagTime MakeRtTagTimeFromMs(long long ms)
|
|||
|
|
{
|
|||
|
|
time_t sec = static_cast<time_t>(ms / 1000);
|
|||
|
|
struct tm tmv;
|
|||
|
|
#ifdef _WIN32
|
|||
|
|
localtime_s(&tmv, &sec);
|
|||
|
|
#else
|
|||
|
|
localtime_r(&sec, &tmv);
|
|||
|
|
#endif
|
|||
|
|
return tagTime(tmv);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void FillRtDeviation(float val, float& up, float& low)
|
|||
|
|
{
|
|||
|
|
if (val >= 0.0f) {
|
|||
|
|
up = val;
|
|||
|
|
low = 0.0f;
|
|||
|
|
} else {
|
|||
|
|
up = 0.0f;
|
|||
|
|
low = -val;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// wiringType: 0=星型, 1=角型
|
|||
|
|
RealtagPqDate_float BuildRealPqDataFromJson(cJSON* jsondata, int wiringType)
|
|||
|
|
{
|
|||
|
|
RealtagPqDate_float realdata;
|
|||
|
|
|
|||
|
|
const bool isDelta = (wiringType == 1);
|
|||
|
|
|
|||
|
|
const char* PH3[3];
|
|||
|
|
const char* PH4[4];
|
|||
|
|
|
|||
|
|
if (isDelta) {
|
|||
|
|
PH3[0] = "AB";
|
|||
|
|
PH3[1] = "BC";
|
|||
|
|
PH3[2] = "CA";
|
|||
|
|
|
|||
|
|
PH4[0] = "AB";
|
|||
|
|
PH4[1] = "BC";
|
|||
|
|
PH4[2] = "CA";
|
|||
|
|
PH4[3] = "T";
|
|||
|
|
} else {
|
|||
|
|
PH3[0] = "A";
|
|||
|
|
PH3[1] = "B";
|
|||
|
|
PH3[2] = "C";
|
|||
|
|
|
|||
|
|
PH4[0] = "A";
|
|||
|
|
PH4[1] = "B";
|
|||
|
|
PH4[2] = "C";
|
|||
|
|
PH4[3] = "T";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
long long timeMs = GetRtJsonTimeMs(jsondata);
|
|||
|
|
if (timeMs > 0) {
|
|||
|
|
realdata.time = MakeRtTagTimeFromMs(timeMs);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 1. Rms[0..8]
|
|||
|
|
// 实时结构注释:相电压、线电压、电流有效值
|
|||
|
|
if (isDelta) {
|
|||
|
|
// 角型:相电压空置,线电压从 AB/BC/CA 的 VRMS 取,电流也按 AB/BC/CA 取
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
realdata.Rms[i] = EMPTY_FLOAT_VALUE;
|
|||
|
|
realdata.Rms[i + 3] = GetRtValue(jsondata, "V", PH3[i], "VRMS");
|
|||
|
|
realdata.Rms[i + 6] = GetRtValue(jsondata, "I", PH3[i], "IRMS");
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 星型:相电压 A/B/C VRMS,线电压 A/B/C VRMS_LVR,电流 A/B/C IRMS
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
realdata.Rms[i] = GetRtValue(jsondata, "V", PH3[i], "VRMS");
|
|||
|
|
realdata.Rms[i + 3] = GetRtValue(jsondata, "V", PH3[i], "VRMS_LVR");
|
|||
|
|
realdata.Rms[i + 6] = GetRtValue(jsondata, "I", PH3[i], "IRMS");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 电压偏差
|
|||
|
|
// 星型序列化取 9-11 为相电压偏差;角型序列化 12-14 为线电压偏差。
|
|||
|
|
// 两种最终都从 UU/UL[0..2] 取,所以填 [0..2] 即可。
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
float dev = GetRtValue(jsondata, "V", PH3[i], "DELTA_V");
|
|||
|
|
FillRtDeviation(dev, realdata.UU_Deviation[i], realdata.UL_Deviation[i]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. THD[0..5]
|
|||
|
|
// 星型:THD[0..2] 相电压,THD[3..5] 电流
|
|||
|
|
// 角型:THD[0..2] 填线电压;Delta_RtHarmV 也取 0..2
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
realdata.THD[i] = GetRtValue(jsondata, "V", PH3[i], "VTHD");
|
|||
|
|
realdata.THD[i + 3] = GetRtValue(jsondata, "I", PH3[i], "ITHD");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. FREQ[0..1]
|
|||
|
|
realdata.FREQ[0] = GetRtValue(jsondata, "V", "T", "FREQ");
|
|||
|
|
realdata.FREQ[1] = GetRtValue(jsondata, "V", "T", "DELTA_FREQ");
|
|||
|
|
|
|||
|
|
// 5. UI_Seq[2][5]
|
|||
|
|
// 序列化时输出 [0][0,1,2,4] 和 [1][0,1,2,4],所以 [3] 可放零序不平衡备用,[4] 放负序不平衡
|
|||
|
|
realdata.UI_Seq[0][0] = GetRtValue(jsondata, "V", "T", "VZSEQ");
|
|||
|
|
realdata.UI_Seq[0][1] = GetRtValue(jsondata, "V", "T", "VNSEQ");
|
|||
|
|
realdata.UI_Seq[0][2] = GetRtValue(jsondata, "V", "T", "VPSEQ");
|
|||
|
|
realdata.UI_Seq[0][3] = GetRtValue(jsondata, "V", "T", "VZSEQ_UNBAN");
|
|||
|
|
realdata.UI_Seq[0][4] = GetRtValue(jsondata, "V", "T", "V_UNBAN");
|
|||
|
|
|
|||
|
|
realdata.UI_Seq[1][0] = GetRtValue(jsondata, "I", "T", "IZSEQ");
|
|||
|
|
realdata.UI_Seq[1][1] = GetRtValue(jsondata, "I", "T", "INSEQ");
|
|||
|
|
realdata.UI_Seq[1][2] = GetRtValue(jsondata, "I", "T", "IPSEQ");
|
|||
|
|
realdata.UI_Seq[1][3] = GetRtValue(jsondata, "I", "T", "IZSEQ_UNBAN");
|
|||
|
|
realdata.UI_Seq[1][4] = GetRtValue(jsondata, "I", "T", "I_UNBAN");
|
|||
|
|
|
|||
|
|
// 6. TOTAL_POWER[4][3], COS_PF, COS_DF
|
|||
|
|
for (int i = 0; i < 4; ++i) {
|
|||
|
|
realdata.TOTAL_POWER[i][0] = GetRtValue(jsondata, "PQ", PH4[i], "P");
|
|||
|
|
realdata.TOTAL_POWER[i][1] = GetRtValue(jsondata, "PQ", PH4[i], "Q");
|
|||
|
|
realdata.TOTAL_POWER[i][2] = GetRtValue(jsondata, "PQ", PH4[i], "S");
|
|||
|
|
|
|||
|
|
realdata.COS_PF[i] = GetRtValue(jsondata, "PQ", PH4[i], "PF");
|
|||
|
|
realdata.COS_DF[i] = GetRtValue(jsondata, "PQ", PH4[i], "DF");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 7. 基波有效值和基波相角
|
|||
|
|
// HARMV/HARMI/HARMVP/HARMIP 的 [0] 被序列化函数当作基波 V1/I1 和基波角度。
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
realdata.HARMV[i][0] = GetRtValue(jsondata, "V", PH3[i], "V1");
|
|||
|
|
realdata.HARMI[i][0] = GetRtValue(jsondata, "I", PH3[i], "I1");
|
|||
|
|
|
|||
|
|
realdata.HARMVP[i][0] = GetRtValue(jsondata, "V", PH3[i], "VFUND_ANGLE");
|
|||
|
|
|
|||
|
|
// 实时 JSON 中电流基波相角字段是 I_ANGLE
|
|||
|
|
realdata.HARMIP[i][0] = GetRtValue(jsondata, "I", PH3[i], "I_ANGLE");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 8. 2~50 次谐波、电压/电流相角
|
|||
|
|
for (int h = 1; h < HARMNUM; ++h) {
|
|||
|
|
int no = h + 1;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
realdata.HARMV[i][h] =
|
|||
|
|
GetRtValue(jsondata, "V", PH3[i], "V" + std::to_string(no));
|
|||
|
|
|
|||
|
|
realdata.HARMI[i][h] =
|
|||
|
|
GetRtValue(jsondata, "I", PH3[i], "I" + std::to_string(no));
|
|||
|
|
|
|||
|
|
realdata.HARMVP[i][h] =
|
|||
|
|
GetRtValue(jsondata, "V", PH3[i], "VA" + std::to_string(no));
|
|||
|
|
|
|||
|
|
// 如果以后 JSON 有 IA2~IA50,这里会自动取;当前样例没有则为 0
|
|||
|
|
realdata.HARMIP[i][h] =
|
|||
|
|
GetRtValue(jsondata, "I", PH3[i], "IA" + std::to_string(no));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 9. 间谐波电压 INHARMV[3][50]
|
|||
|
|
for (int h = 0; h < HARMNUM; ++h) {
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
realdata.INHARMV[i][h] =
|
|||
|
|
GetRtValue(jsondata, "V", PH3[i], "SV_" + std::to_string(h));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return realdata;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
///////////////////////////////////////////////////////通用方式,根据不同的模板到pqd查找名称建立映射然后到json中取值填入再序列化输出
|
|||
|
|
struct PqdMeta {
|
|||
|
|
int idx;
|
|||
|
|
std::string name;
|
|||
|
|
std::string phase;
|
|||
|
|
int harmStart;
|
|||
|
|
int harmEnd;
|
|||
|
|
|
|||
|
|
PqdMeta() : idx(-1), harmStart(0), harmEnd(0) {}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static int GetInt(cJSON* obj, const char* name, int defVal = 0)
|
|||
|
|
{
|
|||
|
|
cJSON* item = GetObj(obj, name);
|
|||
|
|
if (!item) return defVal;
|
|||
|
|
if (item->type == cJSON_Number) return item->valueint;
|
|||
|
|
if (item->type == cJSON_String && item->valuestring) return atoi(item->valuestring);
|
|||
|
|
return defVal;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::string GetStr(cJSON* obj, const char* name)
|
|||
|
|
{
|
|||
|
|
cJSON* item = GetObj(obj, name);
|
|||
|
|
if (item && item->type == cJSON_String && item->valuestring) {
|
|||
|
|
return item->valuestring;
|
|||
|
|
}
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetJsonFloat(cJSON* root,
|
|||
|
|
const std::string& group,
|
|||
|
|
const std::string& phase,
|
|||
|
|
const std::string& key)
|
|||
|
|
{
|
|||
|
|
cJSON* value = GetObj(root, "Value");
|
|||
|
|
cJSON* g = GetObj(value, group.c_str());
|
|||
|
|
cJSON* p = GetObj(g, phase.c_str());
|
|||
|
|
cJSON* item = GetObj(p, key.c_str());
|
|||
|
|
|
|||
|
|
if (!item) return 0.0f;
|
|||
|
|
|
|||
|
|
if (item->type == cJSON_Number) {
|
|||
|
|
return static_cast<float>(item->valuedouble);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (item->type == cJSON_String && item->valuestring) {
|
|||
|
|
return static_cast<float>(atof(item->valuestring));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::string Base64Encode(const unsigned char* bytes_to_encode, size_t in_len)
|
|||
|
|
{
|
|||
|
|
static const char base64_chars[] =
|
|||
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|||
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|||
|
|
"0123456789+/";
|
|||
|
|
|
|||
|
|
std::string ret;
|
|||
|
|
int i = 0;
|
|||
|
|
int j = 0;
|
|||
|
|
unsigned char char_array_3[3];
|
|||
|
|
unsigned char char_array_4[4];
|
|||
|
|
|
|||
|
|
while (in_len--) {
|
|||
|
|
char_array_3[i++] = *(bytes_to_encode++);
|
|||
|
|
if (i == 3) {
|
|||
|
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
|||
|
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +
|
|||
|
|
((char_array_3[1] & 0xf0) >> 4);
|
|||
|
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) +
|
|||
|
|
((char_array_3[2] & 0xc0) >> 6);
|
|||
|
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
|||
|
|
|
|||
|
|
for (i = 0; i < 4; i++) {
|
|||
|
|
ret += base64_chars[char_array_4[i]];
|
|||
|
|
}
|
|||
|
|
i = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (i) {
|
|||
|
|
for (j = i; j < 3; j++) {
|
|||
|
|
char_array_3[j] = '\0';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
|||
|
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +
|
|||
|
|
((char_array_3[1] & 0xf0) >> 4);
|
|||
|
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) +
|
|||
|
|
((char_array_3[2] & 0xc0) >> 6);
|
|||
|
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
|||
|
|
|
|||
|
|
for (j = 0; j < i + 1; j++) {
|
|||
|
|
ret += base64_chars[char_array_4[j]];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
while (i++ < 3) {
|
|||
|
|
ret += '=';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ret;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::string FloatBufferToBase64(const std::vector<float>& buffer)
|
|||
|
|
{
|
|||
|
|
const unsigned char* data =
|
|||
|
|
reinterpret_cast<const unsigned char*>(buffer.data());
|
|||
|
|
|
|||
|
|
return Base64Encode(data, buffer.size() * sizeof(float));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::map<int, PqdMeta> BuildPqdMetaMap(cJSON* tplRoot)
|
|||
|
|
{
|
|||
|
|
std::map<int, PqdMeta> result;
|
|||
|
|
|
|||
|
|
cJSON* pqdArr = GetObj(tplRoot, "Pqd");
|
|||
|
|
if (!pqdArr || !pqdArr->type == cJSON_Array){
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int size = cJSON_GetArraySize(pqdArr);
|
|||
|
|
for (int i = 0; i < size; ++i) {
|
|||
|
|
cJSON* item = cJSON_GetArrayItem(pqdArr, i);
|
|||
|
|
if (!item) continue;
|
|||
|
|
|
|||
|
|
PqdMeta meta;
|
|||
|
|
meta.idx = GetInt(item, "Idx", -1);
|
|||
|
|
meta.name = GetStr(item, "Name");
|
|||
|
|
meta.phase = GetStr(item, "Phase");
|
|||
|
|
meta.harmStart = GetInt(item, "HarmStart", 0);
|
|||
|
|
meta.harmEnd = GetInt(item, "HarmEnd", 0);
|
|||
|
|
|
|||
|
|
if (meta.idx >= 0) {
|
|||
|
|
result[meta.idx] = meta;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static cJSON* FindDataSet(cJSON* tplRoot, const std::string& dataSetName)
|
|||
|
|
{
|
|||
|
|
cJSON* cldevArr = GetObj(tplRoot, "Cldev");
|
|||
|
|
if (!cldevArr || !cldevArr->type == cJSON_Array){
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int cldevSize = cJSON_GetArraySize(cldevArr);
|
|||
|
|
for (int i = 0; i < cldevSize; ++i) {
|
|||
|
|
cJSON* cldev = cJSON_GetArrayItem(cldevArr, i);
|
|||
|
|
cJSON* dsArr = GetObj(cldev, "DataSet");
|
|||
|
|
if (!dsArr || !dsArr->type == cJSON_Array){
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int dsSize = cJSON_GetArraySize(dsArr);
|
|||
|
|
for (int j = 0; j < dsSize; ++j) {
|
|||
|
|
cJSON* ds = cJSON_GetArrayItem(dsArr, j);
|
|||
|
|
std::string name = GetStr(ds, "Name");
|
|||
|
|
if (name == dataSetName) {
|
|||
|
|
return ds;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::vector<int> GetDataArrayIdxList(cJSON* dataSet)
|
|||
|
|
{
|
|||
|
|
std::vector<int> result;
|
|||
|
|
|
|||
|
|
cJSON* arr = GetObj(dataSet, "DataArray");
|
|||
|
|
if (!arr || !arr->type == cJSON_Array) {
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int size = cJSON_GetArraySize(arr);
|
|||
|
|
for (int i = 0; i < size; ++i) {
|
|||
|
|
cJSON* item = cJSON_GetArrayItem(arr, i);
|
|||
|
|
int idx = GetInt(item, "Idx", -1);
|
|||
|
|
if (idx >= 0) {
|
|||
|
|
result.push_back(idx);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::string StatPrefix(int statType)
|
|||
|
|
{
|
|||
|
|
// 0=95, 1=平均, 2=最大, 3=最小
|
|||
|
|
switch (statType) {
|
|||
|
|
case 0: return "G_";
|
|||
|
|
case 1: return "";
|
|||
|
|
case 2: return "MAX_";
|
|||
|
|
case 3: return "MIN_";
|
|||
|
|
default: return "";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::string MakeJsonKey(const std::string& baseKey,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
if (!isStat) {
|
|||
|
|
return baseKey;
|
|||
|
|
}
|
|||
|
|
return StatPrefix(statType) + baseKey;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetByKey(cJSON* jsondata,
|
|||
|
|
const std::string& group,
|
|||
|
|
const std::string& phase,
|
|||
|
|
const std::string& baseKey,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
return GetJsonFloat(jsondata, group, phase,
|
|||
|
|
MakeJsonKey(baseKey, isStat, statType));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void AppendHarmValues(std::vector<float>& out,
|
|||
|
|
cJSON* jsondata,
|
|||
|
|
const PqdMeta& meta,
|
|||
|
|
const std::string& group,
|
|||
|
|
const std::string& prefix,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
int start = meta.harmStart;
|
|||
|
|
int end = meta.harmEnd;
|
|||
|
|
|
|||
|
|
if (start <= 0 && end <= 0) {
|
|||
|
|
out.push_back(0.0f);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int h = start; h <= end; ++h) {
|
|||
|
|
out.push_back(GetByKey(jsondata, group, meta.phase,
|
|||
|
|
prefix + std::to_string(h),
|
|||
|
|
isStat, statType));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void AppendInHarmValues(std::vector<float>& out,
|
|||
|
|
cJSON* jsondata,
|
|||
|
|
const PqdMeta& meta,
|
|||
|
|
const std::string& group,
|
|||
|
|
const std::string& prefix,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
int count = meta.harmEnd - meta.harmStart + 1;
|
|||
|
|
if (count <= 0) {
|
|||
|
|
count = 50;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i < count; ++i) {
|
|||
|
|
out.push_back(GetByKey(jsondata, group, meta.phase,
|
|||
|
|
prefix + std::to_string(i),
|
|||
|
|
isStat, statType));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static float GetSingleValueByMeta(cJSON* jsondata,
|
|||
|
|
const PqdMeta& meta,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
const std::string& n = meta.name;
|
|||
|
|
const std::string& ph = meta.phase;
|
|||
|
|
|
|||
|
|
if (n == "Pq_Freq") return GetByKey(jsondata, "V", "T", "FREQ", isStat, statType);
|
|||
|
|
if (n == "Pq_FreqDev") return GetByKey(jsondata, "V", "T", "DELTA_FREQ", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_RmsU") return GetByKey(jsondata, "V", ph, "VRMS", isStat, statType);
|
|||
|
|
if (n == "Pq_RmsLU") return GetByKey(jsondata, "V", ph, "VRMS_LVR", isStat, statType);
|
|||
|
|
if (n == "Pq_RmsI") return GetByKey(jsondata, "I", ph, "IRMS", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_RmsFundU") return GetByKey(jsondata, "V", ph, "V1", isStat, statType);
|
|||
|
|
if (n == "Pq_RmsFundLU") return GetByKey(jsondata, "V", ph, "V1", isStat, statType);
|
|||
|
|
if (n == "Pq_RmsFundI") return GetByKey(jsondata, "I", ph, "I1", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_UDev") return GetByKey(jsondata, "V", ph, "DELTA_V", isStat, statType);
|
|||
|
|
if (n == "Pq_LUDev") return GetByKey(jsondata, "V", ph, "DELTA_V", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_FundUAng") return GetByKey(jsondata, "V", ph, "VFUND_ANGLE", isStat, statType);
|
|||
|
|
if (n == "Pq_FundLUAng") return GetByKey(jsondata, "V", ph, "VFUND_ANGLE", isStat, statType);
|
|||
|
|
if (n == "Pq_FundIAng") return GetByKey(jsondata, "I", ph, "I_ANGLE", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_ThdU") return GetByKey(jsondata, "V", ph, "VTHD", isStat, statType);
|
|||
|
|
if (n == "Pq_ThdLU") return GetByKey(jsondata, "V", ph, "VTHD", isStat, statType);
|
|||
|
|
if (n == "Pq_ThdI") return GetByKey(jsondata, "I", ph, "ITHD", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_SeqZeroU") return GetByKey(jsondata, "V", "T", "VZSEQ", isStat, statType);
|
|||
|
|
if (n == "Pq_SeqNegU") return GetByKey(jsondata, "V", "T", "VNSEQ", isStat, statType);
|
|||
|
|
if (n == "Pq_SeqPosU") return GetByKey(jsondata, "V", "T", "VPSEQ", isStat, statType);
|
|||
|
|
if (n == "Pq_UnbalNegU") return GetByKey(jsondata, "V", "T", "V_UNBAN", isStat, statType);
|
|||
|
|
if (n == "Pq_UnbalZeroU") return GetByKey(jsondata, "V", "T", "VZSEQ_UNBAN", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_SeqZeroI") return GetByKey(jsondata, "I", "T", "IZSEQ", isStat, statType);
|
|||
|
|
if (n == "Pq_SeqNegI") return GetByKey(jsondata, "I", "T", "INSEQ", isStat, statType);
|
|||
|
|
if (n == "Pq_SeqPosI") return GetByKey(jsondata, "I", "T", "IPSEQ", isStat, statType);
|
|||
|
|
if (n == "Pq_UnbalNegI") return GetByKey(jsondata, "I", "T", "I_UNBAN", isStat, statType);
|
|||
|
|
if (n == "Pq_UnbalZeroI") return GetByKey(jsondata, "I", "T", "IZSEQ_UNBAN", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_P") return GetByKey(jsondata, "PQ", ph, "P", isStat, statType);
|
|||
|
|
if (n == "Pq_Q") return GetByKey(jsondata, "PQ", ph, "Q", isStat, statType);
|
|||
|
|
if (n == "Pq_S") return GetByKey(jsondata, "PQ", ph, "S", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_TotP") return GetByKey(jsondata, "PQ", "T", "P", isStat, statType);
|
|||
|
|
if (n == "Pq_TotQ") return GetByKey(jsondata, "PQ", "T", "Q", isStat, statType);
|
|||
|
|
if (n == "Pq_TotS") return GetByKey(jsondata, "PQ", "T", "S", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_PF") return GetByKey(jsondata, "PQ", ph, "PF", isStat, statType);
|
|||
|
|
if (n == "Pq_DF") return GetByKey(jsondata, "PQ", ph, "DF", isStat, statType);
|
|||
|
|
if (n == "Pq_TotPF") return GetByKey(jsondata, "PQ", "T", "PF", isStat, statType);
|
|||
|
|
if (n == "Pq_TotDF") return GetByKey(jsondata, "PQ", "T", "DF", isStat, statType);
|
|||
|
|
|
|||
|
|
if (n == "Pq_Fluct") return GetByKey(jsondata, "V", ph, "FLUC", isStat, statType);
|
|||
|
|
if (n == "Pq_LFluct") return GetByKey(jsondata, "V", ph, "FLUC", isStat, statType);
|
|||
|
|
if (n == "Pq_Pst") return GetByKey(jsondata, "V", ph, "PST", isStat, statType);
|
|||
|
|
if (n == "Pq_LPst") return GetByKey(jsondata, "V", ph, "PST", isStat, statType);
|
|||
|
|
if (n == "Pq_Plt") return GetByKey(jsondata, "V", ph, "PLT", isStat, statType);
|
|||
|
|
if (n == "Pq_LPlt") return GetByKey(jsondata, "V", ph, "PLT", isStat, statType);
|
|||
|
|
|
|||
|
|
return 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void AppendValueByMeta(std::vector<float>& out,
|
|||
|
|
cJSON* jsondata,
|
|||
|
|
const PqdMeta& meta,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
const std::string& n = meta.name;
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmU" || n == "Pq_HarmLU") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "V", "V", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmI") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "I", "I", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmUAng" || n == "Pq_HarmLUAng") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "V", "VA", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmIAng") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "I", "IA", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_InHarmUR" || n == "Pq_InHarmLU") {
|
|||
|
|
AppendInHarmValues(out, jsondata, meta, "V", "SV_", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_InHarmIAmp") {
|
|||
|
|
AppendInHarmValues(out, jsondata, meta, "I", "SI_", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmP" || n == "Pq_FundP" || n == "Pq_TotHarmP") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "PQ", "P", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmQ" || n == "Pq_FundQ" || n == "Pq_TotHarmQ") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "PQ", "Q", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (n == "Pq_HarmS" || n == "Pq_FundS" || n == "Pq_TotHarmS") {
|
|||
|
|
AppendHarmValues(out, jsondata, meta, "PQ", "S", isStat, statType);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
out.push_back(GetSingleValueByMeta(jsondata, meta, isStat, statType));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// dataSetName 示例:
|
|||
|
|
// "Ds$Pqd$Rt$01"
|
|||
|
|
// "Ds$Pqd$Rt$HarmV$01"
|
|||
|
|
// "Ds$Pqd$Stat$01"
|
|||
|
|
std::string BuildBase64ByTemplate(cJSON* templateRoot,
|
|||
|
|
cJSON* jsondata,
|
|||
|
|
const std::string& dataSetName,
|
|||
|
|
bool isStat,
|
|||
|
|
int statType)
|
|||
|
|
{
|
|||
|
|
std::map<int, PqdMeta> metaMap = BuildPqdMetaMap(templateRoot);
|
|||
|
|
|
|||
|
|
cJSON* dataSet = FindDataSet(templateRoot, dataSetName);
|
|||
|
|
if (!dataSet) {
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::vector<int> idxList = GetDataArrayIdxList(dataSet);
|
|||
|
|
|
|||
|
|
std::vector<float> floatBuffer;
|
|||
|
|
floatBuffer.reserve(2048);
|
|||
|
|
|
|||
|
|
for (size_t i = 0; i < idxList.size(); ++i) {
|
|||
|
|
int idx = idxList[i];
|
|||
|
|
|
|||
|
|
std::map<int, PqdMeta>::const_iterator it = metaMap.find(idx);
|
|||
|
|
if (it == metaMap.end()) {
|
|||
|
|
floatBuffer.push_back(0.0f);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
AppendValueByMeta(floatBuffer, jsondata, it->second, isStat, statType);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return FloatBufferToBase64(floatBuffer);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/////////////////////////////////////////////////////////////////////////////////////发送函数
|
|||
|
|
///////////////////////////////////////////////////////////////////////////////////////上送数据的json格式
|
|||
|
|
// 单条 DataArray 数据
|
|||
|
|
struct DataArrayItem {
|
|||
|
|
int DataAttr;
|
|||
|
|
time_t DataTimeSec;
|
|||
|
|
time_t DataTimeUSec;
|
|||
|
|
int DataTag;
|
|||
|
|
std::string Data;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Msg 对象
|
|||
|
|
struct MsgObj {
|
|||
|
|
int Cldid;
|
|||
|
|
int DataType;
|
|||
|
|
int DataAttr;
|
|||
|
|
int DsNameIdx;
|
|||
|
|
std::vector<DataArrayItem> DataArray;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 整体
|
|||
|
|
struct FullObj {
|
|||
|
|
std::string mac;
|
|||
|
|
int Mid;
|
|||
|
|
int Did;
|
|||
|
|
int Pri;
|
|||
|
|
int Type;
|
|||
|
|
MsgObj Msg;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// DataArrayItem -> cJSON
|
|||
|
|
static cJSON* DataArrayItemToJson(const DataArrayItem& d)
|
|||
|
|
{
|
|||
|
|
cJSON* j = cJSON_CreateObject();
|
|||
|
|
|
|||
|
|
cJSON_AddNumberToObject(j, "dataAttr", d.DataAttr);
|
|||
|
|
cJSON_AddNumberToObject(j, "dataTimeSec", (double)d.DataTimeSec);
|
|||
|
|
cJSON_AddNumberToObject(j, "dataTimeUSec", (double)d.DataTimeUSec);
|
|||
|
|
cJSON_AddNumberToObject(j, "dataTag", d.DataTag);
|
|||
|
|
cJSON_AddStringToObject(j, "data", d.Data.c_str());
|
|||
|
|
|
|||
|
|
return j;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MsgObj -> cJSON
|
|||
|
|
static cJSON* MsgObjToJson(const MsgObj& m)
|
|||
|
|
{
|
|||
|
|
cJSON* j = cJSON_CreateObject();
|
|||
|
|
|
|||
|
|
cJSON_AddNumberToObject(j, "clDid", m.Cldid);
|
|||
|
|
cJSON_AddNumberToObject(j, "dataType", m.DataType);
|
|||
|
|
cJSON_AddNumberToObject(j, "dataAttr", m.DataAttr);
|
|||
|
|
cJSON_AddNumberToObject(j, "dsNameIdx", m.DsNameIdx);
|
|||
|
|
|
|||
|
|
// dataArray
|
|||
|
|
cJSON* arr = cJSON_CreateArray();
|
|||
|
|
|
|||
|
|
for (size_t i = 0; i < m.DataArray.size(); ++i) {
|
|||
|
|
cJSON_AddItemToArray(
|
|||
|
|
arr,
|
|||
|
|
DataArrayItemToJson(m.DataArray[i]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cJSON_AddItemToObject(j, "dataArray", arr);
|
|||
|
|
|
|||
|
|
return j;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FullObj -> cJSON
|
|||
|
|
static cJSON* FullObjToJson(const FullObj& f)
|
|||
|
|
{
|
|||
|
|
cJSON* j = cJSON_CreateObject();
|
|||
|
|
|
|||
|
|
cJSON_AddStringToObject(j, "id", f.mac.c_str());
|
|||
|
|
|
|||
|
|
cJSON_AddNumberToObject(j, "mid", f.Mid);
|
|||
|
|
cJSON_AddNumberToObject(j, "did", f.Did);
|
|||
|
|
cJSON_AddNumberToObject(j, "pri", f.Pri);
|
|||
|
|
cJSON_AddNumberToObject(j, "type", f.Type);
|
|||
|
|
|
|||
|
|
cJSON_AddItemToObject(j, "msg",
|
|||
|
|
MsgObjToJson(f.Msg));
|
|||
|
|
|
|||
|
|
return j;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string generate_json(
|
|||
|
|
const std::string mac,
|
|||
|
|
int Mid,
|
|||
|
|
int Did,
|
|||
|
|
int Pri,
|
|||
|
|
int Type,
|
|||
|
|
int Cldid,
|
|||
|
|
int DataType,
|
|||
|
|
int DataAttr,
|
|||
|
|
int DsNameIdx,
|
|||
|
|
const std::vector<DataArrayItem>& dataArray
|
|||
|
|
)
|
|||
|
|
{
|
|||
|
|
FullObj fobj;
|
|||
|
|
|
|||
|
|
fobj.mac = mac;
|
|||
|
|
fobj.Mid = Mid;
|
|||
|
|
fobj.Did = Did;
|
|||
|
|
fobj.Pri = Pri;
|
|||
|
|
fobj.Type = Type;
|
|||
|
|
|
|||
|
|
fobj.Msg.Cldid = Cldid;
|
|||
|
|
fobj.Msg.DataType = DataType;
|
|||
|
|
fobj.Msg.DataAttr = DataAttr;
|
|||
|
|
fobj.Msg.DsNameIdx = DsNameIdx;
|
|||
|
|
fobj.Msg.DataArray = dataArray;
|
|||
|
|
|
|||
|
|
// 转 cJSON
|
|||
|
|
cJSON* root = FullObjToJson(fobj);
|
|||
|
|
|
|||
|
|
// 输出 json 字符串
|
|||
|
|
char* jsonStr = cJSON_PrintUnformatted(root);
|
|||
|
|
|
|||
|
|
std::string result;
|
|||
|
|
|
|||
|
|
if (jsonStr != NULL) {
|
|||
|
|
result = jsonStr;
|
|||
|
|
free(jsonStr);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cJSON_Delete(root);
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//时间转换函数
|
|||
|
|
time_t ConvertToTimestamp(const tagTime& time) {
|
|||
|
|
struct tm t = {};
|
|||
|
|
t.tm_year = time.DeviceYear - 1900; // tm_year 从 1900 开始计
|
|||
|
|
t.tm_mon = time.DeviceMonth - 1; // tm_mon 从 0(1月)开始
|
|||
|
|
t.tm_mday = time.DeviceDay;
|
|||
|
|
t.tm_hour = time.DeviceHour;
|
|||
|
|
t.tm_min = time.DeviceMinute;
|
|||
|
|
t.tm_sec = time.DeviceSecond;
|
|||
|
|
|
|||
|
|
// 返回时间戳(本地时间)
|
|||
|
|
return mktime(&t);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////实时数据封装发送
|
|||
|
|
void enqueue_realtime_pq(const RealtagPqDate_float& realdata,
|
|||
|
|
int nPTType,
|
|||
|
|
unsigned char cid,
|
|||
|
|
const std::string& mac,
|
|||
|
|
const std::string& mpid,
|
|||
|
|
int idx)
|
|||
|
|
{
|
|||
|
|
// 先根据 devIdxMap 的配置决定编码分支:
|
|||
|
|
// 2: 基础数据 3: 谐波电压含有率 4: 谐波电流有效值 5: 间谐波电压含有率
|
|||
|
|
std::string base64;
|
|||
|
|
|
|||
|
|
// 这里尝试用 mac 作为 key 获取 idx;如果项目里 devIdxMap 的 key 不是 mac,
|
|||
|
|
// 你可以把这里改成对应的设备 id(devid)。未命中则再尝试用规范化后的 mac。
|
|||
|
|
switch (idx) {
|
|||
|
|
case 2: // 基础数据(根据接线方式选择转换方法 数据全集解析)
|
|||
|
|
base64 = realdata.ConvertToBase64(nPTType);
|
|||
|
|
break;
|
|||
|
|
case 3: // 谐波电压含有率
|
|||
|
|
base64 = realdata.ConvertToBase64_RtHarmV(nPTType);
|
|||
|
|
break;
|
|||
|
|
case 4: // 谐波电流有效值(幅值)
|
|||
|
|
base64 = realdata.ConvertToBase64_RtHarmI();
|
|||
|
|
break;
|
|||
|
|
case 5: // 间谐波电压含有率
|
|||
|
|
base64 = realdata.ConvertToBase64_RtInHarmV();
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
// 未知 idx,回退到基础数据
|
|||
|
|
base64 = realdata.ConvertToBase64(nPTType);
|
|||
|
|
break;
|
|||
|
|
} else {
|
|||
|
|
// 未配置 idx,回退到基础数据
|
|||
|
|
base64 = realdata.ConvertToBase64(nPTType);
|
|||
|
|
}
|
|||
|
|
//std::cout << base64 << std::endl;
|
|||
|
|
|
|||
|
|
//lnk实时数据使用接口发送20250711
|
|||
|
|
time_t data_time = ConvertToTimestamp(realdata.time);
|
|||
|
|
|
|||
|
|
std::vector<DataArrayItem> arr;
|
|||
|
|
arr.push_back({1, //数据属性 -1-无, 0-“Rt”,1-“Max”,2-“Min”,3-“Avg”,4-“Cp95”
|
|||
|
|
data_time, //数据转换出来的时间,数据时标,相对1970年的秒,无效填入“-1”
|
|||
|
|
0, //数据时标,微秒钟,无效填入“-1”
|
|||
|
|
0, //数据标识,1-标识数据异常
|
|||
|
|
base64});
|
|||
|
|
std::string js = generate_json(
|
|||
|
|
mac, //设备唯一标识,规范化后的MAC地址,如“001122334455”,不带分隔符,字母大写
|
|||
|
|
-1, //需应答的报文订阅者收到后需以此ID应答,无需应答填入“-1”
|
|||
|
|
1, //设备唯一标识Ldid,填入0代表Ndid,后续根据商议决定填id还是数字
|
|||
|
|
1, //报文处理的优先级:1 I类紧急请求/响应 2 II类紧急请求/响应 3 普通请求/响应 4 广播报文
|
|||
|
|
0x1302, //设备数据主动上送的数据类型
|
|||
|
|
cid, //逻辑子设备ID,0-逻辑设备本身,无填-1
|
|||
|
|
0x04, //数据类型固定为电能质量数据
|
|||
|
|
1, //数据属性:无“0”、实时“1”、统计“2”等
|
|||
|
|
idx, //数据集序号(以数据集方式上送),无填-1
|
|||
|
|
arr //数据数组
|
|||
|
|
);
|
|||
|
|
//std::cout << js << std::en
|
|||
|
|
Ckafka_data_t data;
|
|||
|
|
data.monitor_id = 1; //上送的实时数据没有测点序号,统一填1
|
|||
|
|
data.strTopic = TOPIC_RTDATA; //实时topic
|
|||
|
|
data.strText = js;
|
|||
|
|
data.mp_id = mpid; //监测点id
|
|||
|
|
|
|||
|
|
kafka_data_list_mutex.lock(); //加锁
|
|||
|
|
kafka_data_list.append(data); //添加 kafka发送链表
|
|||
|
|
kafka_data_list_mutex.unlock(); //解锁
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
////////////////////////////////////////////////////////////////////////////////统计数据打包发送
|
|||
|
|
|
|||
|
|
// 封装:组装统计数据并入队发送
|
|||
|
|
void enqueue_stat_pq(const std::string& max_base64Str,
|
|||
|
|
const std::string& min_base64Str,
|
|||
|
|
const std::string& avg_base64Str,
|
|||
|
|
const std::string& cp95_base64Str,
|
|||
|
|
time_t data_time,
|
|||
|
|
const std::string& mac,
|
|||
|
|
short cid,
|
|||
|
|
const std::string& mpid)
|
|||
|
|
{
|
|||
|
|
std::vector<DataArrayItem> arr;
|
|||
|
|
arr.push_back({1, //数据属性 -1-无, 0-“Rt”,1-“Max”,2-“Min”,3-“Avg”,4-“Cp95”
|
|||
|
|
data_time, //数据转换出来的时间,数据时标,相对1970年的秒,无效填入“-1”
|
|||
|
|
0, //数据时标,微秒钟,无效填入“-1”
|
|||
|
|
0, //数据标识,1-标识数据异常
|
|||
|
|
max_base64Str});
|
|||
|
|
arr.push_back({2, data_time, 0, 0, min_base64Str});
|
|||
|
|
arr.push_back({3, data_time, 0, 0, avg_base64Str});
|
|||
|
|
arr.push_back({4, data_time, 0, 0, cp95_base64Str});
|
|||
|
|
|
|||
|
|
std::string js = generate_json(
|
|||
|
|
normalize_mac(mac),
|
|||
|
|
-1, //需应答的报文订阅者收到后需以此ID应答,无需应答填入“-1”
|
|||
|
|
1, //设备唯一标识Ldid,填入0代表Ndid,后续根据商议决定填id还是数字
|
|||
|
|
1, //报文处理的优先级:1 I类紧急请求/响应 2 II类紧急请求/响应 3 普通请求/响应 4 广播报文
|
|||
|
|
0x1302, //设备数据主动上送的数据类型
|
|||
|
|
cid, //逻辑子设备ID,0-逻辑设备本身,无填-1(原:avg_data.name)
|
|||
|
|
0x04, //数据类型固定为电能质量
|
|||
|
|
2, //数据属性:无“0”、实时“1”、统计“2”等
|
|||
|
|
1, //数据集序号(以数据集方式上送),无填-1
|
|||
|
|
arr //数据数组
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
//std::cout << js << std::endl;
|
|||
|
|
|
|||
|
|
Ckafka_data_t data;
|
|||
|
|
data.monitor_no = cid; //监测点序号(原:avg_data.name)
|
|||
|
|
data.strTopic = TOPIC_STAT;//统计topic
|
|||
|
|
data.strText = js;
|
|||
|
|
data.mp_id = mpid; //监测点id
|
|||
|
|
|
|||
|
|
kafka_data_list_mutex.lock(); //加锁
|
|||
|
|
kafka_data_list.append(data); //添加 kafka发送链表
|
|||
|
|
kafka_data_list_mutex.unlock(); //解锁
|
|||
|
|
|
|||
|
|
std::cout << "Successfully assembled tagPqData for line: "
|
|||
|
|
<< cid << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
//以下仅估计开发时间,不包括代码编译调试和测试
|
|||
|
|
/*后续接入云平台,云平台需要根据61850协议进行台账下发:需要对比云和微服务的台账差异,看是否能统一,各取所需 一天
|
|||
|
|
实时数据请求需要添加参数处理,idx区分数据集 半天
|
|||
|
|
补招逻辑有差异,61850是全补招,云是事件和稳态分开,补招下发按照61850的来 徐扬添加
|
|||
|
|
暂态上送逻辑基本一致,对比接口上送数据即可 半天
|
|||
|
|
云需要添加映射文件接口给61850使用 徐扬添加
|
|||
|
|
台账变更逻辑一样,对比台账看是否能统一 一天
|
|||
|
|
请求响应、装置连接状态、前置心跳、文件上传、文件下载、文件传输、读取文件目录、文件删除、装置重启指令的处理逻辑基本一致需要对比交互json,下发的要根据61850需求来,部分肯定需要修改 五天
|
|||
|
|
日志上传方案基本一致,代码基本一致,但是上送日志内容可能不一样,可以不修改
|
|||
|
|
mq主题云前置有cloudtopic用于装置控制,61850是filetopic,按照61850的来 徐扬添加针对61850的装置控制逻辑
|
|||
|
|
进程控制要按照61850的来,徐扬添加
|
|||
|
|
上传下载接口基本一致
|
|||
|
|
要添加61850到云的指标映射关系 二天
|
|||
|
|
要添加动态云模板的存储(文件/内存) 和解析代码 五天+
|
|||
|
|
要添加61850数据到云数据的转换、复用代码但是代码是写死的一种模板,可以先完成,后续改动态,复用代码编写数据上送和编译测试 5天+
|
|||
|
|
当前基础的转换框架已搭建,需要基于61850当前的运行控制框架添加模板控制,数据转换控制,数据上送控制等,预计5天+
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|