948 lines
38 KiB
C
948 lines
38 KiB
C
/*****************************************************************************
|
||
* @copyright 2024-2024, . POWER SUPPLY CO., LTD.
|
||
* @file mw_schedule_save.h
|
||
* @brief 定时落库功能,用于定期将RTDB数据保存到数据库。
|
||
* @author Gary
|
||
* @date 2024/10/17
|
||
* @remark 初修订
|
||
*****************************************************************************/
|
||
#define _POSIX_C_SOURCE 199309L
|
||
#define UPGRADE_START_MESSAGE 1
|
||
#define UPGRADE_END_MESSAGE 0
|
||
#define EMS_CONFIG_START_MESSAGE 1
|
||
#define EMS_CONFIG_END_MESSAGE 0
|
||
#define _XOPEN_SOURCE 700
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdbool.h>
|
||
#include <stdint.h>
|
||
#include <pthread.h>
|
||
#include <semaphore.h>
|
||
#include <sys/time.h>
|
||
#include <time.h>
|
||
#include <unistd.h>
|
||
#include <errno.h>
|
||
#include "bsp_rtdb.h"
|
||
#include "bsp_data_mode.h"
|
||
#include "kit_db.h"
|
||
#include "kit_log.h"
|
||
#include "utextend.h"
|
||
|
||
#include "mw_schedule_handle.h"
|
||
#include "drv_4g.h"
|
||
#include "drv_wifi.h"
|
||
#include "bsp_ntp.h"
|
||
|
||
uint32_t exeCount = 0; // 线程执行次数计数器,用于取余数
|
||
UT_array* timedDataConfigs, * faultsDataConfigs; // 时序数据配置、故障数据配置
|
||
|
||
// 时序数据的ICD结构定义
|
||
static UT_icd timed_data_storage_icd =
|
||
{
|
||
sizeof(timed_data_storage_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 故障数据的ICD结构定义
|
||
static UT_icd faults_data_storage_icd =
|
||
{
|
||
sizeof(faults_data_storage_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
// 功率数据的ICD结构定义
|
||
static UT_icd power_data_storage_icd =
|
||
{
|
||
sizeof(power_data_storage_t),
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
/*****************************************************************************
|
||
* @brief 将 YYYY/DD/MM HH:MM:SS 格式的字符串转换为 timeval 结构体
|
||
* @param[in] timeString: YYYY/DD/MM HH:MM:SS 格式的时间字符串
|
||
* @param[out] tv: 转换后的 timeval 结构体指针
|
||
* @return 0: 成功;1: 失败 (无效的时间字符串格式或转换错误)
|
||
*****************************************************************************/
|
||
static int stringToTimeval(const char *timeString, struct timeval *tv)
|
||
{
|
||
struct tm tm = {0}; // 初始化 tm 结构体
|
||
char *strptime_result;
|
||
time_t t;
|
||
|
||
// 检查字符串长度
|
||
if (strlen(timeString) != 19)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:时间字符串长度错误: %s\n", timeString);
|
||
return 1;
|
||
}
|
||
|
||
// 使用 strptime 解析时间字符串,注意格式字符串要与 timeString 格式完全匹配
|
||
strptime_result = strptime(timeString, "%Y/%m/%d %H:%M:%S", &tm); // 修改为 %m/%d
|
||
if (strptime_result == NULL)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:strptime 解析时间字符串失败: %s\n", timeString);
|
||
return 1;
|
||
}
|
||
|
||
// 将 struct tm 转换为 time_t
|
||
t = mktime(&tm);
|
||
if (t == -1)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:mktime 转换失败: %s\n", timeString);
|
||
return 1;
|
||
}
|
||
|
||
tv->tv_sec = t;
|
||
tv->tv_usec = 0;
|
||
return 0;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 获取RTDB参数
|
||
* @param[in] devType:设备类型
|
||
* @param[in] pointId:点号
|
||
* @param[in] value:值数组指针
|
||
* @param[in] dataType:数组类型
|
||
* @return 无
|
||
*****************************************************************************/
|
||
static void logic_getValue(dev_type_e devType, uint16_t pointId, void* value, data_type_e dataType)
|
||
{
|
||
switch (dataType)
|
||
{
|
||
case Uint8:
|
||
{
|
||
// 对于 uint8_t 类型
|
||
uint8_t* uint8Value = (uint8_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
uint8Value[i] = (uint8_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Int8:
|
||
{
|
||
// 对于 int8_t 类型
|
||
int8_t* int8Value = (int8_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
int8Value[i] = (int8_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Uint16:
|
||
{
|
||
// 对于 uint16_t 类型
|
||
uint16_t* uint16Value = (uint16_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
uint16Value[i] = (uint16_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Int16:
|
||
{
|
||
// 对于 int16_t 类型
|
||
int16_t* int16Value = (int16_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
int16Value[i] = (int16_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Uint32:
|
||
{
|
||
// 对于 uint32_t 类型
|
||
uint32_t* uint32Value = (uint32_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
uint32Value[i] = (uint32_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Int32:
|
||
{
|
||
// 对于 int32_t 类型
|
||
int32_t* int32Value = (int32_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
int32Value[i] = (int32_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Uint64:
|
||
{
|
||
// 对于 uint64_t 类型
|
||
uint64_t* uint64Value = (uint64_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
uint64Value[i] = (uint64_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Int64:
|
||
{
|
||
// 对于 int64_t 类型
|
||
int64_t* int64Value = (int64_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
int64Value[i] = (int64_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Float32:
|
||
{
|
||
// 对于 float_t (Float32) 类型
|
||
float_t* floatValue = (float_t*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
floatValue[i] = (float_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
case Float64:
|
||
{
|
||
// 对于 double (Float64) 类型
|
||
double* doubleValue = (double*)value;
|
||
for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++)
|
||
{
|
||
doubleValue[i] = getRtdbPointValue(Rtdb_ShMem, devType, i, pointId);
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
// 不支持的类型
|
||
return;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 封装的删除功率数据函数
|
||
* @param[in] timestamp: 删除之前数据时间戳
|
||
*****************************************************************************/
|
||
static void deletePowerData(time_t timestamp)
|
||
{
|
||
struct tm tm_time;
|
||
localtime_r(×tamp, &tm_time);
|
||
char time_str[32];
|
||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time);
|
||
// 调用删除数据库函数
|
||
int ret = kit_del_power_data_by_date(time_str);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, date: %s", time_str);
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 封装的删除时序数据函数
|
||
* @param[in] interval: 存储间隔
|
||
* @param[in] timestamp: 删除之前数据时间戳
|
||
*****************************************************************************/
|
||
static void deleteTimedData(int interval, time_t timestamp)
|
||
{
|
||
struct tm tm_time;
|
||
localtime_r(×tamp, &tm_time);
|
||
char time_str[32];
|
||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time);
|
||
// 调用删除数据库函数
|
||
int ret = kit_del_timed_data_by_date(interval, time_str);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, interval: %d, date: %s", interval, time_str);
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 封装的删除故障数据函数
|
||
* @param[in] interval: 存储间隔
|
||
* @param[in] timestamp: 删除之前数据时间戳
|
||
*****************************************************************************/
|
||
static void deleteFaultsData(time_t timestamp)
|
||
{
|
||
struct tm tm_time;
|
||
localtime_r(×tamp, &tm_time);
|
||
char time_str[32];
|
||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time);
|
||
// 调用删除数据库函数
|
||
int ret = kit_del_faults_data_by_date(time_str);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, date: %s", time_str);
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 封装的删除断点数据函数
|
||
* @param[in] timestamp: 删除之前数据时间戳
|
||
*****************************************************************************/
|
||
static void deleteBreakData(time_t timestamp)
|
||
{
|
||
struct tm tm_time;
|
||
localtime_r(×tamp, &tm_time);
|
||
char time_str[32];
|
||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time);
|
||
// 调用删除数据库函数
|
||
int ret = kit_del_break_data_by_date(time_str);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, date: %s", time_str);
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 每天定时删除业务数据间隔
|
||
*****************************************************************************/
|
||
static void delDbBusDataInterval()
|
||
{
|
||
time_t now;
|
||
time(&now);
|
||
struct tm tm_time;
|
||
localtime_r(&now, &tm_time);
|
||
tm_time.tm_hour += 8; // 加8个小时,考虑时区
|
||
|
||
time_t oneDayAgo = now - 24 * 60 * 60; // 1天前
|
||
time_t oneWeekAgo = now - 7 * 24 * 60 * 60; // 7天前
|
||
time_t twoWeekAgo = now - 14 * 24 * 60 * 60; // 14天前
|
||
time_t threeWeekAgo = now - 21 * 24 * 60 * 60; // 21天前
|
||
time_t oneMonthAgo = now - 30 * 24 * 60 * 60; // 30天前
|
||
time_t twoMonthAgo = now - 2 * 30 * 24 * 60 * 60; // 60天前
|
||
time_t threeMonthAgo = now - 3 * 30 * 24 * 60 * 60; // 90天前
|
||
time_t fiveMonthAgo = now - 5 * 30 * 24 * 60 * 60; // 150天前
|
||
time_t sixMonthsAgo = now - 6 * 30 * 24 * 60 * 60; // 180天前
|
||
|
||
// 删除功率数据
|
||
deletePowerData(oneDayAgo);
|
||
// 删除断点续传数据
|
||
deleteBreakData(oneWeekAgo);
|
||
// 删除时序数据
|
||
deleteTimedData(500, oneDayAgo);
|
||
deleteTimedData(1000, oneWeekAgo);
|
||
deleteTimedData(2000, twoWeekAgo);
|
||
deleteTimedData(3000, threeWeekAgo);
|
||
deleteTimedData(4000, threeWeekAgo);
|
||
deleteTimedData(5000, oneMonthAgo);
|
||
deleteTimedData(6000, oneMonthAgo);
|
||
deleteTimedData(7000, oneMonthAgo);
|
||
deleteTimedData(8000, oneMonthAgo);
|
||
deleteTimedData(9000, oneMonthAgo);
|
||
deleteTimedData(10000, twoMonthAgo);
|
||
deleteTimedData(15000, threeMonthAgo);
|
||
deleteTimedData(20000, fiveMonthAgo);
|
||
deleteTimedData(30000, sixMonthsAgo);
|
||
// 删除故障数据
|
||
deleteFaultsData(sixMonthsAgo);
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 定时将RTDB数据保存到数据库
|
||
* @param[in] storageIntervalType:存储间隔类型
|
||
*****************************************************************************/
|
||
static void saveRTDBToDbInterval(storage_interval_type_e storageIntervalType)
|
||
{
|
||
UT_array* timedDatas = NULL;
|
||
|
||
// 为时序数据动态数组分配空间
|
||
utarray_new(timedDatas, &timed_data_storage_icd);
|
||
for (int i = 0; i < utarray_len(timedDataConfigs); ++i)
|
||
{
|
||
timed_data_config_t* p_config = (timed_data_config_t*)utarray_eltptr(timedDataConfigs, i);
|
||
if (p_config != NULL && p_config->storageInterval == storageIntervalType)
|
||
{
|
||
timed_data_storage_t data = { 0 };
|
||
data.devType = p_config->devType; // 设备种类
|
||
data.devDbId = p_config->devDbId; // 设备数据库Id
|
||
data.storageInterval = p_config->storageInterval; // 存储间隔
|
||
data.pointDbId = p_config->pointDbId; // 点位Id
|
||
data.timedValue = getRtdbPointValue(Rtdb_ShMem, data.devType, p_config->devId - 1, p_config->pointId); // 从实时库获取时序数据
|
||
// if (data.timedValue == 0 || data.timedValue == 128)
|
||
// {
|
||
// KITLOG(LOG_WM_EN, ERROR_EN, "getRtdbPointValue 失败");
|
||
// continue;
|
||
// }
|
||
utarray_push_back(timedDatas, &data);
|
||
}
|
||
}
|
||
|
||
// 插入时序数据
|
||
if (utarray_len(timedDatas) > 0 && kit_insert_timed_data(timedDatas) != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "kit_insert_timed_data 失败");
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 定时将故障数据保存到数据库
|
||
*****************************************************************************/
|
||
static void saveFaultsDataInterval()
|
||
{
|
||
UT_array* faultsDatas = NULL;
|
||
|
||
// 为故障数据动态数组分配空间
|
||
utarray_new(faultsDatas, &faults_data_storage_icd);
|
||
for (int i = 0; i < utarray_len(faultsDataConfigs); ++i)
|
||
{
|
||
faults_data_config_t* p_config = (faults_data_config_t*)utarray_eltptr(faultsDataConfigs, i);
|
||
if (p_config != NULL)
|
||
{
|
||
faults_data_storage_t data = { 0 };
|
||
data.faultsValue = getRtdbPointValue(Rtdb_ShMem, data.devType, p_config->devId - 1, p_config->pointId); // 从实时库获取时序数据
|
||
if (data.faultsValue != 1) // 不是故障时,直接跳过
|
||
{
|
||
continue;
|
||
}
|
||
data.devType = p_config->devType; // 设备种类
|
||
data.devDbId = p_config->devDbId; // 设备数据库Id
|
||
data.pointDbId = p_config->pointDbId; // 点位Id
|
||
utarray_push_back(faultsDatas, &data);
|
||
}
|
||
}
|
||
|
||
// 插入时序数据
|
||
if (utarray_len(faultsDatas) > 0 && kit_insert_faults_data(faultsDatas) != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "kit_insert_faults_data 失败");
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 每分钟定时保存功率数据
|
||
*****************************************************************************/
|
||
static void savePowerDataInterval()
|
||
{
|
||
// 定义存储功率数据的变量
|
||
float_t pccTotalActivePwr[MAX_NUM_CABINT], pccTotalReactivePwr[MAX_NUM_CABINT], pccTotalApparentPwr[MAX_NUM_CABINT], pccTotalPwrFactor[MAX_NUM_CABINT],
|
||
bsTotalActivePwr[MAX_NUM_CABINT], bsTotalReactivePwr[MAX_NUM_CABINT], bsTotalApparentPwr[MAX_NUM_CABINT], bsTotalPwrFactor[MAX_NUM_CABINT],
|
||
pcsTotalActivePwr[MAX_NUM_CABINT], pcsTotalReactivePwr[MAX_NUM_CABINT], pcsTotalApparentPwr[MAX_NUM_CABINT], pcsTotalPwrFactor[MAX_NUM_CABINT];
|
||
UT_array* powerDatas;
|
||
|
||
utarray_new(powerDatas, &power_data_storage_icd); // 初始化powerDatas
|
||
// pcc电表
|
||
logic_getValue(kDev_Type_Pccmeter, kPCC_TotalActivePwr, pccTotalActivePwr, Float32); // pcc电表总有功功率
|
||
logic_getValue(kDev_Type_Pccmeter, kPCC_TotalReactivePwr, pccTotalReactivePwr, Float32); // pcc电表总无功功率
|
||
logic_getValue(kDev_Type_Pccmeter, kPCC_TotalApparentPwr, pccTotalApparentPwr, Float32); // pcc电表总视在功率
|
||
logic_getValue(kDev_Type_Pccmeter, kPCC_TotalPwrFactor, pccTotalPwrFactor, Float32); // pcc电表总功率因数
|
||
// bs储能表
|
||
logic_getValue(kDev_Type_Bsmeter, kBs_TotalActivePwr, bsTotalActivePwr, Float32); // bs储能表总有功功率
|
||
logic_getValue(kDev_Type_Bsmeter, kBs_TotalReactivePwr, bsTotalReactivePwr, Float32); // bs储能表总无功功率
|
||
logic_getValue(kDev_Type_Bsmeter, kBs_TotalApparentPwr, bsTotalApparentPwr, Float32); // bs储能表总视在功率
|
||
logic_getValue(kDev_Type_Bsmeter, kBs_TotalPwrFactor, bsTotalPwrFactor, Float32); // bs储能表总功率因数
|
||
// pcs电表
|
||
logic_getValue(kDev_Type_PCS, kPcs_TotalActivePwr, pcsTotalActivePwr, Float32); // PCS总有功功率
|
||
logic_getValue(kDev_Type_PCS, kPcs_TotalReactivePwr, pcsTotalReactivePwr, Float32); // PCS总无功功率
|
||
logic_getValue(kDev_Type_PCS, kPcs_TotalApparentPwr, pcsTotalApparentPwr, Float32); // PCS总视在功率
|
||
logic_getValue(kDev_Type_PCS, kPcs_TotalPwrFactor, pcsTotalPwrFactor, Float32); // PCS总功率因数
|
||
|
||
|
||
// 遍历bs储能表
|
||
for (int i = 0; i < gStDevTypeNum[kDev_Type_Pccmeter]; ++i)
|
||
{
|
||
// pcc电表总有功功率
|
||
power_data_storage_t pccTotalActivePwrData = { 0 };
|
||
pccTotalActivePwrData.devType = kDev_Type_Pccmeter; // 设备种类
|
||
pccTotalActivePwrData.devId = i; // 设备编号
|
||
pccTotalActivePwrData.pointId = kPCC_TotalActivePwr; // 点位编号
|
||
pccTotalActivePwrData.value = pccTotalActivePwr[i]; // 值
|
||
utarray_push_back(powerDatas, &pccTotalActivePwrData);
|
||
|
||
// pcc电表总无功功率
|
||
power_data_storage_t pccTotalReactivePwrData = { 0 };
|
||
pccTotalReactivePwrData.devType = kDev_Type_Pccmeter; // 设备种类
|
||
pccTotalReactivePwrData.devId = i; // 设备编号
|
||
pccTotalReactivePwrData.pointId = kPCC_TotalReactivePwr; // 点位编号
|
||
pccTotalReactivePwrData.value = pccTotalReactivePwr[i]; // 值
|
||
utarray_push_back(powerDatas, &pccTotalReactivePwrData);
|
||
|
||
// pcc电表总视在功率
|
||
power_data_storage_t pccTotalApparentPwrData = { 0 };
|
||
pccTotalApparentPwrData.devType = kDev_Type_Pccmeter; // 设备种类
|
||
pccTotalApparentPwrData.devId = i; // 设备编号
|
||
pccTotalApparentPwrData.pointId = kPCC_TotalApparentPwr; // 点位编号
|
||
pccTotalApparentPwrData.value = pccTotalApparentPwr[i]; // 值
|
||
utarray_push_back(powerDatas, &pccTotalApparentPwrData);
|
||
|
||
// pcc电表总功率因数
|
||
power_data_storage_t pccTotalPwrFactorData = { 0 };
|
||
pccTotalPwrFactorData.devType = kDev_Type_Pccmeter; // 设备种类
|
||
pccTotalPwrFactorData.devId = i; // 设备编号
|
||
pccTotalPwrFactorData.pointId = kPCC_TotalPwrFactor; // 点位编号
|
||
pccTotalPwrFactorData.value = pccTotalPwrFactor[i]; // 值
|
||
utarray_push_back(powerDatas, &pccTotalPwrFactorData);
|
||
}
|
||
|
||
// 遍历bs储能表
|
||
for (int i = 0; i < gStDevTypeNum[kDev_Type_Bsmeter]; ++i)
|
||
{
|
||
// bs储能表总有功功率
|
||
power_data_storage_t bsTotalActivePwrData = { 0 };
|
||
bsTotalActivePwrData.devType = kDev_Type_Bsmeter; // 设备种类
|
||
bsTotalActivePwrData.devId = i; // 设备编号
|
||
bsTotalActivePwrData.pointId = kBs_TotalActivePwr; // 点位编号
|
||
bsTotalActivePwrData.value = bsTotalActivePwr[i]; // 值
|
||
utarray_push_back(powerDatas, &bsTotalActivePwrData);
|
||
|
||
// bs储能表总无功功率
|
||
power_data_storage_t bsTotalReactivePwrData = { 0 };
|
||
bsTotalReactivePwrData.devType = kDev_Type_Bsmeter; // 设备种类
|
||
bsTotalReactivePwrData.devId = i; // 设备编号
|
||
bsTotalReactivePwrData.pointId = kBs_TotalReactivePwr; // 点位编号
|
||
bsTotalReactivePwrData.value = bsTotalReactivePwr[i]; // 值
|
||
utarray_push_back(powerDatas, &bsTotalReactivePwrData);
|
||
|
||
// bs储能表总视在功率
|
||
power_data_storage_t bsTotalApparentPwrData = { 0 };
|
||
bsTotalApparentPwrData.devType = kDev_Type_Bsmeter; // 设备种类
|
||
bsTotalApparentPwrData.devId = i; // 设备编号
|
||
bsTotalApparentPwrData.pointId = kBs_TotalApparentPwr; // 点位编号
|
||
bsTotalApparentPwrData.value = bsTotalApparentPwr[i]; // 值
|
||
utarray_push_back(powerDatas, &bsTotalApparentPwrData);
|
||
|
||
// bs储能表总功率因数
|
||
power_data_storage_t bsTotalPwrFactorData = { 0 };
|
||
bsTotalPwrFactorData.devType = kDev_Type_Bsmeter; // 设备种类
|
||
bsTotalPwrFactorData.devId = i; // 设备编号
|
||
bsTotalPwrFactorData.pointId = kBs_TotalPwrFactor; // 点位编号
|
||
bsTotalPwrFactorData.value = bsTotalPwrFactor[i]; // 值
|
||
utarray_push_back(powerDatas, &bsTotalPwrFactorData);
|
||
}
|
||
|
||
// 遍历pcs
|
||
for (int i = 0; i < gStDevTypeNum[kDev_Type_PCS]; ++i)
|
||
{
|
||
// PCS总有功功率
|
||
power_data_storage_t pcsTotalActivePwrData = { 0 };
|
||
pcsTotalActivePwrData.devType = kDev_Type_PCS; // 设备种类
|
||
pcsTotalActivePwrData.devId = i; // 设备编号
|
||
pcsTotalActivePwrData.pointId = kPcs_TotalActivePwr; // 点位编号
|
||
pcsTotalActivePwrData.value = pcsTotalActivePwr[i]; // 值
|
||
utarray_push_back(powerDatas, &pcsTotalActivePwrData);
|
||
|
||
// PCS总无功功率
|
||
power_data_storage_t pcsTotalReactivePwrData = { 0 };
|
||
pcsTotalReactivePwrData.devType = kDev_Type_PCS; // 设备种类
|
||
pcsTotalReactivePwrData.devId = i; // 设备编号
|
||
pcsTotalReactivePwrData.pointId = kPcs_TotalReactivePwr; // 点位编号
|
||
pcsTotalReactivePwrData.value = pcsTotalReactivePwr[i]; // 值
|
||
utarray_push_back(powerDatas, &pcsTotalReactivePwrData);
|
||
|
||
// PCS总视在功率
|
||
power_data_storage_t pcsTotalApparentPwrData = { 0 };
|
||
pcsTotalApparentPwrData.devType = kDev_Type_PCS; // 设备种类
|
||
pcsTotalApparentPwrData.devId = i; // 设备编号
|
||
pcsTotalApparentPwrData.pointId = kPcs_TotalApparentPwr; // 点位编号
|
||
pcsTotalApparentPwrData.value = pcsTotalApparentPwr[i]; // 值
|
||
utarray_push_back(powerDatas, &pcsTotalApparentPwrData);
|
||
|
||
// PCS总功率因数
|
||
power_data_storage_t pcsTotalPwrFactorData = { 0 };
|
||
pcsTotalPwrFactorData.devType = kDev_Type_PCS; // 设备种类
|
||
pcsTotalPwrFactorData.devId = i; // 设备编号
|
||
pcsTotalPwrFactorData.pointId = kPcs_TotalPwrFactor; // 点位编号
|
||
pcsTotalPwrFactorData.value = pcsTotalPwrFactor[i]; // 值
|
||
utarray_push_back(powerDatas, &pcsTotalPwrFactorData);
|
||
}
|
||
|
||
// 调用保存功率数据库函数
|
||
int ret = kit_insert_power_data(powerDatas);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "批量插入插入功率数据失败");
|
||
}
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @brief 初始化系统4G配置
|
||
* @param[in] fourthg_dev_config:4G相关配置
|
||
* @return 0-成功 1-失败
|
||
*********************************************************************/
|
||
static int sys4GInitHandle(ems_dev_config_t *fourthg_dev_config)
|
||
{
|
||
int ret = 0;
|
||
drv_4g_t fourthgInfo = {0}; // 使用局部变量,函数结束时自动释放内存
|
||
cJSON *json_obj = cJSON_Parse((const char *)fourthg_dev_config->content); // 解析JSON配置字符串
|
||
|
||
if (json_obj == NULL)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr());
|
||
return 1;
|
||
}
|
||
|
||
cJSON *item;
|
||
|
||
// 安全地获取JSON对象中的各个字段
|
||
item = cJSON_GetObjectItem(json_obj, "enable");
|
||
fourthgInfo.enable = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0;
|
||
// 在使能关闭时,直接返回
|
||
if (fourthgInfo.enable == 0)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(json_obj, "cmdContent");
|
||
strncpy((char *)fourthgInfo.cmdContent, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_CMD_4G_LEN);
|
||
fourthgInfo.cmdContent[MAX_CMD_4G_LEN - 1] = '\0'; // 确保字符串以'\0'结尾
|
||
|
||
cJSON_Delete(json_obj); // 释放JSON对象
|
||
|
||
ret = drvOpen4G(&fourthgInfo);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n");
|
||
return 1;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @brief 初始化系统Wifi配置
|
||
* @param[in] wifi_dev_config: wifi配置信息
|
||
* @return 0-成功 1-失败
|
||
*********************************************************************/
|
||
static int sysWifiInitHandle(ems_dev_config_t *wifi_dev_config)
|
||
{
|
||
int ret = 0;
|
||
drv_wifi_t wifiInfo = {0}; // 使用局部变量,函数结束时自动释放内存
|
||
cJSON *json_obj = cJSON_Parse((const char *)wifi_dev_config->content); // 解析JSON配置字符串
|
||
|
||
if (json_obj == NULL)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr());
|
||
return 1;
|
||
}
|
||
|
||
cJSON *item;
|
||
|
||
// 安全地获取JSON对象中的各个字段
|
||
item = cJSON_GetObjectItem(json_obj, "enable");
|
||
wifiInfo.enable = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0;
|
||
// 在使能关闭时,直接返回
|
||
if (wifiInfo.enable == 0)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
item = cJSON_GetObjectItem(json_obj, "wifiName");
|
||
strncpy((char *)wifiInfo.wifiName, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_WIFI_NAME_LEN);
|
||
wifiInfo.wifiName[MAX_WIFI_NAME_LEN - 1] = '\0'; // 确保字符串以'\0'结尾
|
||
|
||
item = cJSON_GetObjectItem(json_obj, "wifiPassword");
|
||
strncpy((char *)wifiInfo.wifiPassword, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_WIFI_PASS_LEN);
|
||
wifiInfo.wifiPassword[MAX_WIFI_PASS_LEN - 1] = '\0'; // 确保字符串以'\0'结尾
|
||
|
||
cJSON_Delete(json_obj); // 释放JSON对象
|
||
|
||
ret = drvOpenWifi(&wifiInfo);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n");
|
||
return 1;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @brief EMS时间处理初始化函数,根据配置信息设置系统时间(NTP或手动)
|
||
* @param[in] rtc_dev_config: 设备配置信息 (包含NTP和手动时间设置参数,通常为JSON格式)
|
||
* @return 0: 成功;1: 失败 (内存分配失败,JSON解析失败,NTP同步失败,或设置系统时间失败)
|
||
*********************************************************************/
|
||
static int systimeInitHandle(ems_dev_config_t *rtc_dev_config)
|
||
{
|
||
int ret = 0;
|
||
ems_dev_rtc_config_t rtcInfo = {0}; // 使用局部变量,函数结束时自动释放内存
|
||
cJSON *json_obj = cJSON_Parse((const char *)rtc_dev_config->content); // 解析JSON配置字符串
|
||
|
||
if (json_obj == NULL)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr());
|
||
return 1;
|
||
}
|
||
|
||
cJSON *item;
|
||
|
||
// 安全地获取JSON对象中的各个字段
|
||
item = cJSON_GetObjectItem(json_obj, "isNtp");
|
||
rtcInfo.isNtp = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0;
|
||
|
||
// 判断是否使用 NTP 自动对时
|
||
if (rtcInfo.isNtp)
|
||
{
|
||
item = cJSON_GetObjectItem(json_obj, "port");
|
||
rtcInfo.port = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0;
|
||
|
||
item = cJSON_GetObjectItem(json_obj, "address");
|
||
strncpy((char *)rtcInfo.address, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_ADDR_LEN);
|
||
rtcInfo.address[MAX_ADDR_LEN - 1] = '\0'; // 确保字符串以'\0'结尾
|
||
ret = sync_ntp_timestamp((char *)rtcInfo.address, rtcInfo.port,(char *)AdvancedSettingTable[kLinux_Password].value); // 调用NTP对时函数
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:NTP同步失败: %s\n", strerror(errno));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
item = cJSON_GetObjectItem(json_obj, "manualTime");
|
||
strncpy((char *)rtcInfo.manualTime, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", sizeof(rtcInfo.manualTime));
|
||
rtcInfo.manualTime[sizeof(rtcInfo.manualTime) - 1] = '\0'; // 确保字符串以'\0'结尾
|
||
|
||
struct timeval tv;
|
||
if (stringToTimeval((const char *)rtcInfo.manualTime, &tv) != 0)
|
||
{
|
||
return 1; // stringToTimeval函数已经打印了错误信息
|
||
}
|
||
time_t seconds = tv.tv_sec;
|
||
ret = setSysTime(seconds, (char *)AdvancedSettingTable[kLinux_Password].value); // 使用bsp_rtc.c中的setSysTime函数设置系统时间
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n");
|
||
return 1;
|
||
}
|
||
}
|
||
cJSON_Delete(json_obj); // 释放JSON对象
|
||
|
||
return ret;
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @brief 修改EMS的基础设置到系统
|
||
* @param[in] void
|
||
* @return 0-成功 1-失败
|
||
*********************************************************************/
|
||
static void changeEmsConfig(void)
|
||
{
|
||
// EMS修改标志位被修改
|
||
if(EMS_CONFIG_START_MESSAGE == readWebSign(kSign_ShMem, kSign_EmsConfig))
|
||
{
|
||
UT_array *emsDevConfigs = {0};
|
||
int ret = 0;
|
||
if (0 != kit_get_config_db_data(&emsDevConfigs))
|
||
{
|
||
return;
|
||
}
|
||
utarray_foreach(emsDevConfigs, ems_dev_config_t *, p_emsDevConfig)
|
||
{
|
||
switch (p_emsDevConfig->type)
|
||
{
|
||
case kEms_Config_Uart:
|
||
// 系统串口不需要初始化
|
||
break;
|
||
case kEms_Config_Net:
|
||
// // 初始化系统的IP、MAC地址、网关等配置
|
||
// ret = netInitHandble(p_emsDevConfig);
|
||
break;
|
||
case kEms_Config_DI:
|
||
break;
|
||
case kEms_Config_DO:
|
||
break;
|
||
case kEms_Config_Rtc:
|
||
// 初始化系统时间将rtc时钟同步到linux系统
|
||
ret = systimeInitHandle(p_emsDevConfig);
|
||
break;
|
||
case kEms_Config_Wifi:
|
||
ret = sysWifiInitHandle(p_emsDevConfig);
|
||
break;
|
||
case kEms_Config_4G:
|
||
ret = sys4GInitHandle(p_emsDevConfig);
|
||
break;
|
||
default:
|
||
printf("Unknown EMS device config type: %d\n", p_emsDevConfig->type);
|
||
ret = 1;
|
||
break;
|
||
}
|
||
if (ret != 0)
|
||
{
|
||
// 初始化失败,释放资源并返回错误
|
||
utarray_free(emsDevConfigs);
|
||
emsDevConfigs = NULL;
|
||
return;
|
||
}
|
||
}
|
||
// 释放数组内存
|
||
utarray_free(emsDevConfigs);
|
||
emsDevConfigs = NULL;
|
||
return;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 安装升级包
|
||
*****************************************************************************/
|
||
static void installUpgradePackage()
|
||
{
|
||
// 读取升级是否需要标志位
|
||
if(UPGRADE_START_MESSAGE == readWebSign(kSign_ShMem, kSign_SysUpdate))
|
||
{
|
||
upgrade_record_t p_upgradeRecord = {0};
|
||
if(0 == kit_get_upgrade_record(&p_upgradeRecord))
|
||
{
|
||
char buffer[1000]; // 接收执行返回值
|
||
char command[MAX_UPGRADE_PATH_LEN + 8]; // 命令字符串
|
||
snprintf(command, MAX_UPGRADE_PATH_LEN + 8, "dpkg -i %s", p_upgradeRecord.path);
|
||
// 使用 kit_popen_exec 执行"dpkg i "
|
||
if (kit_popen_exec(command, buffer, sizeof(buffer)) != 0)
|
||
{
|
||
snprintf((char *)p_upgradeRecord.errMsg, MAX_UPGRADE_ERR_MSG_LEN, "%s", buffer);
|
||
p_upgradeRecord.status = kUpgrade_Err; // 升级失败
|
||
kit_update_upgrade_record(&p_upgradeRecord); // 更新升级记录
|
||
KITLOG(LOG_DRIVER_EN, ERROR_EN, "EMS升级失败\n");
|
||
return;
|
||
}
|
||
// 设置EMS自启动
|
||
if (kit_popen_exec("systemctl enable company-ems-start", buffer, sizeof(buffer)) != 0)
|
||
{
|
||
KITLOG(LOG_DRIVER_EN, ERROR_EN, "EMS自启动设置失败\n");
|
||
return;
|
||
}
|
||
// LINUX重启
|
||
if (kit_popen_exec("reboot", buffer, sizeof(buffer)) != 0)
|
||
{
|
||
KITLOG(LOG_DRIVER_EN, ERROR_EN, "重启失败\n");
|
||
return;
|
||
}
|
||
p_upgradeRecord.status = kUpgrade_Succ; // 升级成功
|
||
kit_update_upgrade_record(&p_upgradeRecord); // 更新升级记录
|
||
// 写入升级结束标志位
|
||
writeWebSign(kSign_ShMem, kSign_SysUpdate, UPGRADE_END_MESSAGE);
|
||
}
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 每1秒钟执行一次的任务
|
||
* @param[in] arg:线程执行参数
|
||
*****************************************************************************/
|
||
static void* oneSecondTaskHandle(void* arg)
|
||
{
|
||
struct timespec start, end;
|
||
struct timespec interval = { .tv_sec = 1, .tv_nsec = 0 };
|
||
struct timespec tv;
|
||
while (1)
|
||
{
|
||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||
if (exeCount % 1 == 0) // 1秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_1s); // 定时落库
|
||
saveFaultsDataInterval(); // 保存故障
|
||
changeEmsConfig(); // 更新EMS基础配置
|
||
installUpgradePackage(); // 安装升级包
|
||
}
|
||
if (exeCount % 2 == 0) // 2秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_2s);
|
||
}
|
||
if (exeCount % 3 == 0) // 3秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_3s);
|
||
}
|
||
if (exeCount % 4 == 0) // 4秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_4s);
|
||
}
|
||
if (exeCount % 5 == 0) // 5秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_5s);
|
||
}
|
||
if (exeCount % 6 == 0) // 6秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_6s);
|
||
}
|
||
if (exeCount % 7 == 0) // 7秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_7s);
|
||
}
|
||
if (exeCount % 8 == 0) // 8秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_8s);
|
||
}
|
||
if (exeCount % 9 == 0) // 9秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_9s);
|
||
}
|
||
if (exeCount % 10 == 0) // 10秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_10s);
|
||
}
|
||
if (exeCount % 15 == 0) // 15秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_15s);
|
||
}
|
||
if (exeCount % 20 == 0) // 20秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_20s);
|
||
}
|
||
if (exeCount % 30 == 0) // 30秒执行一次
|
||
{
|
||
saveRTDBToDbInterval(kStorage_Interval_30s);
|
||
}
|
||
if (exeCount % 60 == 0) // 60秒执行一次
|
||
{
|
||
savePowerDataInterval(); // 每分钟定时保存功率数据
|
||
}
|
||
if (exeCount % 86400 == 0) // 86400秒执行一次(一天)
|
||
{
|
||
delDbBusDataInterval(); // 每天定时删除业务数据间隔
|
||
}
|
||
// 获取循环结束时间并计算执行时间
|
||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||
long elapsed_ns = (end.tv_sec - start.tv_sec) * 1e9 + (end.tv_nsec - start.tv_nsec);
|
||
long sleep_ns = (interval.tv_sec * 1e9 + interval.tv_nsec) - elapsed_ns;
|
||
|
||
// 如果任务执行时间小于1秒,休眠剩余时间
|
||
if (sleep_ns > 0)
|
||
{
|
||
tv.tv_sec = sleep_ns / 1e9;
|
||
tv.tv_nsec = sleep_ns % (long)1e9;
|
||
nanosleep(&tv, NULL);
|
||
}
|
||
|
||
// 执行次数
|
||
exeCount = (exeCount + 1) % MAX_EXE_COUNT;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
* @brief 创建定时存储任务
|
||
* @return 0-成功 1-失败
|
||
*****************************************************************************/
|
||
void creatScheduledStorageTask()
|
||
{
|
||
int ret = 0;
|
||
pthread_t tid_one_sec; // 定义线程描述符
|
||
|
||
// 从数据库里查询到所有时序数据存储的配置
|
||
ret = kit_get_tdata_config(&timedDataConfigs);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "获取时序数据存储的配置失败!");
|
||
return (void)1;
|
||
}
|
||
|
||
// 从数据库获取故障点位配置
|
||
ret = kit_get_faults_config(&faultsDataConfigs);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "获取故障点位配置失败!");
|
||
return (void)1;
|
||
}
|
||
|
||
// 创建每1秒钟执行一次的线程
|
||
ret = pthread_create(&tid_one_sec, NULL, oneSecondTaskHandle, NULL);
|
||
if (ret != 0)
|
||
{
|
||
KITLOG(LOG_WM_EN, ERROR_EN, "创建每1秒钟执行一次的线程失败");
|
||
return (void)1; // 创建失败,返回错误
|
||
}
|
||
|
||
return (void)0;
|
||
} |