#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "cJSON.h"
#include <pthread.h>
#include <time.h>
#include "jsonp.h"
#include "emsctrl.h"
#include "emsctrlProc.h"
//#include "mytimer.h"

// #define DEBUG
// #ifdef DEBUG
// #undef dbg_syslog
// #define dbg_syslog(xx, fmt, ...) printf("[%s:%d->%s]" fmt "\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
// #else
// #endif

USER_DEFINE_PROCESS user_define_process = NULL;

PCS_CFG_T g_pcs_cfg_info = {0};
CHARGE_MNG_INFO_T g_charge_mng_info = {0};

STRATEGY_MNG_T g_strategr_mng_info = {0};

DEMAND_CHARGE_INFO_T air_cond_planInfo_before;
DEMAND_CHARGE_INFO_T air_cond_planInfo_after;

#define P_CHARGE_MAX g_pcs_cfg_info.PchaMax
#define P_CHARGE_MIN g_pcs_cfg_info.PchaMin
#define P_DISCHARGE_MAX g_pcs_cfg_info.PDiscMax
#define P_DISCHARGE_MIN g_pcs_cfg_info.PDiscMin



static int guard_count = 0;
static int pcs_count = 0;


static int publish_pcs_data(ipc_session_t *session, char *sn, unsigned char *data, int len, char *desSn)
{
    char topic[TOPIC_MAX_LEN] = {0};
    // ipc/%s/+/device/+/data/set_rglt_raw
    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", sn, "aaa", desSn, "set_rglt_raw");
    // dbg_syslog(LOG_DEBUG, "topic:%s", topic);
    ipc_session_publish(session, topic, data, len);
    return 0;
}

static int publish_call_service(ipc_session_t *session, char *sn, unsigned char *data, int len, char *desSn)
{
    char topic[TOPIC_MAX_LEN] = {0};
    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", sn, "NULL", desSn, TOPIC_EVT_SET_RGLT);
    ipc_session_publish(session, topic, data, len);
    return 0;
}

static int publish_exter_service(ipc_session_t *session, char *sn, unsigned char *data, int len, char *desSn)
{
    char topic[TOPIC_MAX_LEN] = {0};
    snprintf(topic, TOPIC_MAX_LEN, "/ems/%s/service/set", desSn);
    ipc_session_publish(session, topic, data, len);
    return 0;
}

#define PCS_MI 12323

#define PCS_JSON_PACK_START(type)                               \
    CHAR *data_tmp = NULL;                                      \
    cJSON *tag_data = cJSON_CreateObject();                     \
    cJSON_AddStringToObject(tag_data, "sn", var->sn_str);       \
    cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL)); \
    cJSON_AddStringToObject(tag_data, "identifier", type);      \
    cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);

#define PCS_JSON_PACK_END(desSn)                                                           \
    data_tmp = cJSON_Print(tag_data);                                                      \
    publish_pcs_data(var->sessiondev, var->sn_str, data_tmp, strlen(data_tmp), desSn);     \
    publish_call_service(var->sessiondev, var->sn_str, data_tmp, strlen(data_tmp), desSn); \
    free(data_tmp);                                                                        \
    cJSON_Delete(tag_data);

#define GUARD_JSON_PACK_START(type, dev_sn)                     \
	CHAR *data_tmp = NULL;										\
	cJSON *tag_data = cJSON_CreateObject(); 					\
	cJSON_AddStringToObject(tag_data, "sn", dev_sn);		    \
	cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL)); \
	cJSON_AddStringToObject(tag_data, "identifier", type);		\
	cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);

#define GUARD_JSON_PACK_END(desSn)                                                          \
	data_tmp = cJSON_Print(tag_data);														\
	publish_exter_service(var->sessiondev, var->sn_str, data_tmp, strlen(data_tmp), desSn); \
	free(data_tmp); 																		\
	cJSON_Delete(tag_data);

#define EXT_JSON_PACK_END(desSn)                                                            \
    data_tmp = cJSON_Print(tag_data);                                                       \
    publish_exter_service(var->extsession, var->sn_str, data_tmp, strlen(data_tmp), desSn); \
    free(data_tmp);                                                                         \
    cJSON_Delete(tag_data);

#define DI_JSON_PACK_START(type, desSn)                         \
    CHAR *data_tmp = NULL;                                      \
    cJSON *tag_data = cJSON_CreateObject();                     \
    cJSON_AddStringToObject(tag_data, "sn", desSn);             \
    cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL)); \
    cJSON_AddStringToObject(tag_data, "identifier", type);      \
    cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);

#define DI_JSON_PACK_END(desSn)                                                           \
    data_tmp = cJSON_Print(tag_data);                                                       \
    publish_exter_service(var->extsession, var->sn_str, data_tmp, strlen(data_tmp), desSn); \
    free(data_tmp);                                                                         \
    cJSON_Delete(tag_data);

	
void pcs_dev_standby_set(pcs_ctrl_var_t *var)
{
    static time_t time_last = 0;
    time_t time_now = time(NULL);
    if ((g_charge_mng_info.pcs_openState != E_IDLE)||(g_charge_mng_info.ctrlMode != E_CTRL_AUTO)||((g_pcs_cfg_info.type == STRATEGY_TYPE_PEEK)&&((time_now - time_last)>60)))
    {
        time_last = time_now;
        if(g_charge_mng_info.pcs_openState != E_IDLE)  //只有在状态转换的时候上报日志
        report_option(var, "pcs standby");
        g_charge_mng_info.pcs_openState = E_IDLE;
        PCS_JSON_PACK_START("emspcs_standby")
        PCS_JSON_PACK_END(var->pcsSn);
    }
    
}

void pcs_dev_standby_set_by_config(pcs_ctrl_var_t *var) //根据配置模式待机操作
{
    if(g_pcs_cfg_info.supportStandy == 0) 
    pcs_dev_yggl_set(var, 0);
    else
    pcs_dev_standby_set(var);
}
void pcs_dev_yggl_set(pcs_ctrl_var_t *var, WORD power)
{
    PCS_JSON_PACK_START("emspcs_power")
    cJSON_AddNumberToObject(tag_data, "p2", power);
    dbg_syslog(LOG_NOTICE, "set p2 val:%d", power);
    PCS_JSON_PACK_END(var->pcsSn);
}

/*
**控制光伏功率
*/
void pv_dev_yggl_set(pcs_ctrl_var_t *var, WORD power)
{
   
    PCS_JSON_PACK_START("emspcs_power")
    cJSON_AddNumberToObject(tag_data, "pv", power);
    dbg_syslog(LOG_NOTICE, "set pv val:%d", power);
    PCS_JSON_PACK_END(var->pcsSn);
}

void pcs_dev_wggl_set(pcs_ctrl_var_t *var, WORD power)
{
    PCS_JSON_PACK_START("emspcs_wggl")
    cJSON_AddNumberToObject(tag_data, "wggl", power);
    dbg_syslog(LOG_NOTICE, "set wggl val:%d", power);
    PCS_JSON_PACK_END(var->pcsSn);
}


//ipc/21881EFF0043/RS485_6/device/21881EFF0043_PV/data/Set_Rglt {"identifier":"Write_on","sn":"21881EFF0043_PV","mi":2330546,"TAG_5196":1,"timestamp":1681207118}
//ipc/21881EFF0043/RS485_6/device/21881EFF0043_PV/data/Set_Rglt {"identifier":"Write_off","sn":"21881EFF0043_PV","TAG_5197":0,"mi":47927056,"timestamp":1681207054}
void pcs_dev_open(pcs_ctrl_var_t *var)
{
    static time_t time_last = 0;
    time_t time_now = time(NULL);
    if ((g_charge_mng_info.pcs_openState != E_ON)||(g_charge_mng_info.ctrlMode != E_CTRL_AUTO)||((g_pcs_cfg_info.type == STRATEGY_TYPE_PEEK)&&((time_now - time_last)>60)))
    {
        time_last = time_now;
        dbg_syslog(LOG_NOTICE,"pcs_dev_open"); 
        if(g_charge_mng_info.pcs_openState != E_ON)  //只有在状态转换的时候上报日志
        report_option(var, "emspcs_open");
        g_charge_mng_info.pcs_openState = E_ON;
        PCS_JSON_PACK_START("emspcs_open")
        // cJSON_AddNumberToObject(tag_data, "p2", power);
        PCS_JSON_PACK_END(var->pcsSn);
    }
}

void pcs_dev_reset(pcs_ctrl_var_t *var)
{
    report_option(var, "emspcs_reset");
    dbg_syslog(LOG_NOTICE, "pcs_dev_reset");
    PCS_JSON_PACK_START("emspcs_reset")
    PCS_JSON_PACK_END(var->pcsSn);
}

void pcs_dev_close(pcs_ctrl_var_t *var)
{
    static time_t time_last = 0;
    time_t time_now = time(NULL);
    if ((g_charge_mng_info.pcs_openState != E_OFF)||(g_charge_mng_info.ctrlMode != E_CTRL_AUTO)||((g_pcs_cfg_info.type == STRATEGY_TYPE_PEEK)&&((time_now - time_last)>60)))
    {
        time_last = time_now;
        dbg_syslog(LOG_NOTICE,"emspcs_close"); 
        if(g_charge_mng_info.pcs_openState != E_OFF)  //只有在状态转换的时候上报日志
        report_option(var, "emspcs_close");
        g_charge_mng_info.pcs_openState = E_OFF;
        PCS_JSON_PACK_START("emspcs_close")
        // cJSON_AddNumberToObject(tag_data, "p2", power);
        PCS_JSON_PACK_END(var->pcsSn);
    }
}

void pv_pcs_dev_open(pcs_ctrl_var_t *var)
{
    if (g_charge_mng_info.pv_pcs_openState == E_ON)
        return;
    g_charge_mng_info.pv_pcs_openState = E_ON;
    report_option(var, "pv emspv_open");
    PCS_JSON_PACK_START("emspv_open")
    // cJSON_AddNumberToObject(tag_data, "p2", power);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void pv_pcs_dev_close(pcs_ctrl_var_t *var)
{
    if (g_charge_mng_info.pv_pcs_openState == E_OFF)
        return;
    g_charge_mng_info.pv_pcs_openState = E_OFF;
    report_option(var, "pv emspv_close");
    PCS_JSON_PACK_START("emspv_close")
    // cJSON_AddNumberToObject(tag_data, "p2", power);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void pv_pcs_dev_yggl_set(pcs_ctrl_var_t *var, WORD power, int pv_flag)
{

    PCS_JSON_PACK_START("emspv_percent")
    cJSON_AddNumberToObject(tag_data, "pv", power);
	cJSON_AddNumberToObject(tag_data, "pv_flag", pv_flag);
    dbg_syslog(LOG_NOTICE, "set pv val:%d", power);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void pf_pcs_dev_open(pcs_ctrl_var_t *var)
{
    if (g_charge_mng_info.pf_pcs_openState == E_ON)
        return;
    g_charge_mng_info.pf_pcs_openState = E_ON;
    report_option(var, "pf emspf_open");
    PCS_JSON_PACK_START("emspf_open")
    // cJSON_AddNumberToObject(tag_data, "p2", power);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void pf_pcs_dev_close(pcs_ctrl_var_t *var)
{
    if (g_charge_mng_info.pf_pcs_openState == E_OFF)
        return;
    g_charge_mng_info.pf_pcs_openState = E_OFF;
    report_option(var, "pf emspf_close");
    PCS_JSON_PACK_START("emspf_close")
    // cJSON_AddNumberToObject(tag_data, "p2", power);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void pcs_demand_set(pcs_ctrl_var_t *var)
{

    PCS_JSON_PACK_START("set_demand")
    cJSON_AddNumberToObject(tag_data, "EDD", g_pcs_cfg_info.EDD);
	cJSON_AddNumberToObject(tag_data, "MD", g_pcs_cfg_info.MD);
	cJSON_AddNumberToObject(tag_data, "DCI", g_pcs_cfg_info.DCI);
	dbg_syslog(LOG_NOTICE, "EDD %d MD %d DCI %d", g_pcs_cfg_info.EDD, g_pcs_cfg_info.MD, g_pcs_cfg_info.DCI);
    PCS_JSON_PACK_END(var->deamndSn);
}

void pcs_single_max_min_set(pcs_ctrl_var_t *var)
{

    PCS_JSON_PACK_START("emspcs_single_maxmin")
    cJSON_AddNumberToObject(tag_data, "SINGLE_MAX", g_pcs_cfg_info.singlemax);
	cJSON_AddNumberToObject(tag_data, "SINGLE_MIN", g_pcs_cfg_info.singlemin);
	dbg_syslog(LOG_NOTICE, "SING_MAX %f SING_MIN %f", g_pcs_cfg_info.singlemax, g_pcs_cfg_info.singlemin);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void charge_station_power_set(pcs_ctrl_var_t *var, WORD power)
{
    PCS_JSON_PACK_START("powerset")
    cJSON_AddNumberToObject(tag_data, "csP", power);
    dbg_syslog(LOG_NOTICE, "set csP val:%d", power);
    PCS_JSON_PACK_END(var->chargeStatinoSn);
}

void pv_pcs_dev_powerenable_set(pcs_ctrl_var_t *var, WORD mode)
{
    if (g_charge_mng_info.pv_penable == mode)
        return;
    g_charge_mng_info.pv_penable = mode;
    PCS_JSON_PACK_START("powerSetEnable")
    cJSON_AddNumberToObject(tag_data, "enable", mode);
    dbg_syslog(LOG_NOTICE, "set enable val:%d", mode);
    PCS_JSON_PACK_END(var->pvpcsSn);
    report_option(var, "pv powerSetEnable %d", mode);
}

static void pcs_remode_set(pcs_ctrl_var_t *var)
{
    PCS_JSON_PACK_START("remote")
    PCS_JSON_PACK_END(var->pcsSn);
}
static void pcs_dev_mode_set(pcs_ctrl_var_t *var)
{
    report_option(var, "mode");
    PCS_JSON_PACK_START("mode")
    PCS_JSON_PACK_END(var->pcsSn);
}

void pcs_dev_connect_set(pcs_ctrl_var_t *var)
{
    report_option(var, "emspcs_connect");
    g_charge_mng_info.connState = E_ON;
    PCS_JSON_PACK_START("emspcs_connect")
    // cJSON_AddNumberToObject(tag_data, "p2", power);
    PCS_JSON_PACK_END(var->pcsSn);
    dbg_syslog(LOG_NOTICE, "pcs_dev_connect");
}

void pcs_dev_disconect_set(pcs_ctrl_var_t *var)
{
    report_option(var, "emspcs_disconnect");
    g_charge_mng_info.connState = E_OFF;
    PCS_JSON_PACK_START("emspcs_disconnect")
    // cJSON_AddNumberToObject(tag_data, "p2", power);
    PCS_JSON_PACK_END(var->pcsSn);
    dbg_syslog(LOG_NOTICE, "pcs_dev_disconect");
}

void do_dev_set(pcs_ctrl_var_t *var, char *identifier, char *tag_do, int value)
{
    DI_JSON_PACK_START(identifier, var->diSn)
    cJSON_AddNumberToObject(tag_data, tag_do, value);
    DI_JSON_PACK_END(var->diSn);
}

void bms_dev_relay_on_set(pcs_ctrl_var_t *var)
{
    report_option(var, "emsbms_relay_on");
    g_charge_mng_info.bmsState = E_ON;
    PCS_JSON_PACK_START("emsbms_relay_on")
    PCS_JSON_PACK_END(var->pcsSn);
    dbg_syslog(LOG_NOTICE, "bmsState->%d", g_charge_mng_info.bmsState);
}

void bms_dev_relay_off_set(pcs_ctrl_var_t *var)
{
    // if (g_charge_mng_info.bmsState == E_OFF)
    //     return;
    report_option(var, "emsbms_relay_off");
    g_charge_mng_info.bmsState = E_OFF;
    PCS_JSON_PACK_START("emsbms_relay_off")
    PCS_JSON_PACK_END(var->pcsSn);
    dbg_syslog(LOG_NOTICE, "bmsState->%d", g_charge_mng_info.bmsState);
}

void energy_assign_on_service_set(pcs_ctrl_var_t *var, WORD action)
{
    PCS_JSON_PACK_START("emspcs_on_service")
    cJSON_AddNumberToObject(tag_data, "action", action);
    dbg_syslog(LOG_NOTICE, "on service:%d", action);
    PCS_JSON_PACK_END(var->pcsSn);
}

static BYTE pcs_demand_timer_close_check(BYTE index)
{
    if (index >= MAX_DEMAND_NUMBER)
        return E_FALSE;

    if (g_pcs_cfg_info.demand_table[index].option == E_CHARGE_IDLE)
        return E_TRUE;

    return E_FALSE;
}


static BYTE pcs_adjpreriod_timer_check()
{
    if (g_charge_mng_info.Adjpreriodcouter >= g_pcs_cfg_info.Adjpreriod * MINUTE_VAL)
    {
        g_charge_mng_info.Adjpreriodcouter -= g_pcs_cfg_info.Adjpreriod * MINUTE_VAL;
        g_charge_mng_info.AdjpreriodFlag = 1;
        return E_TRUE;
    }
    return E_FALSE;
}


void auxi_set(pcs_ctrl_var_t *var, CHAR *pidentifier, CHAR mode)
{
    PCS_JSON_PACK_START(pidentifier);
    cJSON_AddNumberToObject(tag_data, "onoff", mode);
    PCS_JSON_PACK_END(var->auxiSn);
}


void system_protect_to_energy(pcs_ctrl_var_t *var, char *sn,int level)
{
    int i;
    int level_tmp = 0 ;
    if (g_pcs_cfg_info.manual_flag == 2) 
        level_tmp = MAX(level,g_charge_mng_info.total_lev.system);
    else
        level_tmp = g_charge_mng_info.total_lev.system;
    PCS_JSON_PACK_START("protect_level_set");
    cJSON_AddNumberToObject(tag_data, "protect_level", level_tmp);
    cJSON *array = NULL;
    cJSON_AddItemToObject(tag_data, "grps_protect_level", array = cJSON_CreateArray());
    if (var->pcs_grp_num != var->guard_grp_num)//如果一个网关多个pcs，需要每个PCS往下发
    {
        for (i = 0; i < var->pcs_grp_num; i++)
        {
            char buff[100] = {0};
            cJSON *item = NULL;
            int level_tmp_grp = 0;
            if (g_pcs_cfg_info.manual_flag == 2) 
                level_tmp_grp = MAX(level,g_charge_mng_info.grps_lev_eng[i].system);
            else
                level_tmp_grp = g_charge_mng_info.grps_lev_eng[i].system;
            cJSON_AddItemToArray(array, item = cJSON_CreateObject());
            cJSON_AddItemToObject(item, "level", cJSON_CreateNumber(level_tmp_grp)); // 内部嵌套键值
            //cJSON_AddItemToObject(item, "sn", cJSON_CreateNumber(var->grp[i].eng_ass_grp_cfg.belong_gw)); 
            //  兼容写法
            //  snprintf(buff,sizeof(buff),"grp%d_protect_level",i+1);
            //  cJSON_AddNumberToObject(tag_data, "protect_level", g_charge_mng_info.pcs_grp_num[i].system);
        }
    }
    else
    {//一个网关一个动环，因此此时用
        for (i = 0; i < var->guard_grp_num; i++)
        {
            char buff[100] = {0};
            cJSON *item = NULL;
            int level_tmp_grp = 0;
            if (g_pcs_cfg_info.manual_flag == 2) 
                level_tmp_grp = MAX(level,g_charge_mng_info.grps_lev_eng[i].system);
            else
                level_tmp_grp = g_charge_mng_info.grps_lev_eng[i].system;
            cJSON_AddItemToArray(array, item = cJSON_CreateObject());
            cJSON_AddItemToObject(item, "level", cJSON_CreateNumber(level_tmp_grp)); // 内部嵌套键值
            //cJSON_AddItemToObject(item, "sn", cJSON_CreateNumber(var->grp[i].eng_ass_grp_cfg.belong_gw)); 
            //  兼容写法
            //  snprintf(buff,sizeof(buff),"grp%d_protect_level",i+1);
            //  cJSON_AddNumberToObject(tag_data, "protect_level", g_charge_mng_info.grps_lev[i].system);
        }
    }
	dbg_syslog(LOG_NOTICE, "ENERGY PROTECT::::: %s match to %s", sn, var->sn_str);
    PCS_JSON_PACK_END(sn);
}

void system_protect_to_guard(pcs_ctrl_var_t *var, char *sn,int level)
{
    int i;
    GUARD_JSON_PACK_START("protect_level_set", sn);
    cJSON_AddNumberToObject(tag_data, "protect_level", g_charge_mng_info.total_lev.system);
    cJSON *array = NULL;
    cJSON_AddItemToObject(tag_data, "grps_protect_level", array = cJSON_CreateArray());
    for (i = 0; i < var->guard_grp_num; i++)
	{
		if (strstr(sn, var->grp[i].belong_gw))
		{
			cJSON *item = NULL;
            int level_tmp_grp1 = 0;
            if (g_pcs_cfg_info.manual_flag == 2) 
                level_tmp_grp1 = MAX(level,g_charge_mng_info.grps_lev[i].system);
            else
                level_tmp_grp1 = g_charge_mng_info.grps_lev[i].system;
			cJSON_AddItemToArray(array, item = cJSON_CreateObject());
			cJSON_AddItemToObject(item, "level", cJSON_CreateNumber(level_tmp_grp1)); // 内部嵌套键值 
			dbg_syslog(LOG_NOTICE, "GUARD PROTECT::::: %s match to %s", sn, var->grp[i].belong_gw);
			break;
		}
	}
    GUARD_JSON_PACK_END(sn);
}

void system_protect_to_ext(pcs_ctrl_var_t *var, char *sn)
{
    int i;
    PCS_JSON_PACK_START("protect_level_set");
    cJSON_AddNumberToObject(tag_data, "protect_level", g_charge_mng_info.total_lev.system);
    cJSON *array = NULL;
    cJSON_AddItemToObject(tag_data, "grps_protect_level", array = cJSON_CreateArray());
    for (i = 0; i < g_charge_mng_info.grps_num; i++)
    {
        char buff[100] = {0};
        cJSON *item = NULL;
        cJSON_AddItemToArray(array, item = cJSON_CreateObject());
        cJSON_AddItemToObject(item, "level", cJSON_CreateNumber(g_charge_mng_info.grps_lev[i].system)); // 内部嵌套键值
        // 兼容写法
        //  snprintf(buff,sizeof(buff),"grp%d_protect_level",i+1);
        //  cJSON_AddNumberToObject(tag_data, "protect_level", g_charge_mng_info.grps_lev[i].system);
    }
    EXT_JSON_PACK_END(sn);
}
static int sts_check(pcs_ctrl_var_t *var)
{
    if (g_charge_mng_info.runState == E_ON)
    {
        if (g_charge_mng_info.soc < g_pcs_cfg_info.SOCmin)
        {
            pcs_dev_close(var);
        }
    }
}

static void ems_system_fault_proc(pcs_ctrl_var_t *var)
{
    pcs_dev_yggl_set(var, 0);
    pcs_dev_close(var); 
    
}


#define ERRORTIME 30 

static ALARM_STATUS checkPowerLimited(pcs_ctrl_var_t *var)
{
    static time_t time_last = 0;
    if(time_last==0) time_last = time(NULL);
    time_t time_now;
	
    if (g_charge_mng_info.demandState == 1)
    {
        double demandPower = 0;
        if (g_pcs_cfg_info.EDD == 1)
            if(g_pcs_cfg_info.Dylmax > g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100)
				demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;
			else
				demandPower = g_pcs_cfg_info.Dylmax;
		else
	        demandPower = g_pcs_cfg_info.Pmlmax * g_pcs_cfg_info.K1 / 100;
        double pcha = g_charge_mng_info.P1 - demandPower;
        if(pcha>0) 
        {
            time_now = time(NULL);
            if((time_now - time_last)>ERRORTIME)
            return ALARM;
        }
        else 
        time_last = time(NULL);
    }
    return NOALARM;
}

static ALARM_STATUS checkPowerReflux(pcs_ctrl_var_t *var)
{
    static time_t time_last = 0;
    if(time_last==0) time_last = time(NULL);
    time_t time_now;
    if(g_charge_mng_info.P1<0) 
    {
        time_now = time(NULL);
        if((time_now - time_last)>ERRORTIME)
        return ALARM;
    }
    else 
    time_last = time(NULL);
    return NOALARM;
}

static ALARM_STATUS checkSysStoped(pcs_ctrl_var_t *var)
{
    if(var->alarm_status_list[SYSSTOPED]==ALARM)return ALARM;
    else return NOALARM;
}
static ALARM_STATUS checkGridMeter1Offline(pcs_ctrl_var_t *var)
{
    ALARM_STATUS ret = -1;
	time_t curTime = time(NULL);

    if(g_charge_mng_info.P1_1 != 0 && g_charge_mng_info.P1_2 != 0)
    {
        if ((curTime - g_charge_mng_info.update_time.P1_1) >= g_pcs_cfg_info.dev_online_timeout) 
		    ret = ALARM;
		else
		    ret = NOALARM;
		
		if (ret == ALARM) return ret; // 防逆流表离线，直接返回
		
		if ((curTime - g_charge_mng_info.update_time.P1_2) >= g_pcs_cfg_info.dev_online_timeout) 
		    ret = ALARM;
		else
		    ret = NOALARM;
    }
    else 
	    ret = INIT_STA;
	
	return ret;
}

static ALARM_STATUS checkBMSMeter2Offline(pcs_ctrl_var_t *var)
{
    static time_t time_last = 0;
    if(time_last==0) time_last = time(NULL);
    static double p1_last = 0.0f;
    time_t time_now;
    if((g_charge_mng_info.P1!=0)&&(p1_last == g_charge_mng_info.P1)) 
    {
        time_now = time(NULL);
        if((time_now - time_last)>ERRORTIME)
        return ALARM;
    }
    else 
    time_last = time(NULL);
    p1_last = g_charge_mng_info.P1;
    return NOALARM;
}

CHECK_ALARM_LIST check_alarm_list[] = {  //告警信息列表 第一个参数是检验是否触发报警函数返回值ALARM NOALARM  第二触参数发报警的名称  **添加的时候要记得添加相应的宏**
    {checkPowerLimited,"PowerLimited"},
    {checkPowerReflux,"PowerReflux"},
    {checkSysStoped,"SysStoped"},
    {checkGridMeter1Offline,"GridMeter1Offline"},
   // {checkBMSMeter2Offline,"BMSMeter2Offline"},
};


void set_alarm_status(pcs_ctrl_var_t *var,ALARM_TYPE type,ALARM_STATUS status) //给其非周期能检测到的告警信息设置告警  给check_alarm_t函数提供告警判定条件
{
    var->alarm_status_list[type] = status;
}

void pcs_dev_soc_max_min_set(pcs_ctrl_var_t *var, double soc_max, double soc_min)
{
    PCS_JSON_PACK_START("emspcs_soc_maxmin")
    cJSON_AddNumberToObject(tag_data, "SOCMAX", soc_max);
    cJSON_AddNumberToObject(tag_data, "SOCMIN", soc_min);
    dbg_syslog(LOG_DEBUG, "set soc max:%f min:%f", soc_max ,soc_min);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void pcs_dev_modesel_set_ems(pcs_ctrl_var_t *var, int tmp)
{
    PCS_JSON_PACK_START("modesel_set_ems")
    cJSON_AddNumberToObject(tag_data, "ctrlMode", tmp);
    dbg_syslog(LOG_DEBUG, "set ctrlMode:%d -> energyAssignSn",tmp);
    PCS_JSON_PACK_END(var->energyAssignSn);
}

void guardSn_aircond_set(pcs_ctrl_var_t *var, char *sn)
{
    //report_option(var, "emsguard_aircond");
    GUARD_JSON_PACK_START("emsguard_aircond",sn);
    cJSON_AddNumberToObject(tag_data, "aircond_start", var->aircond_set);
    //PCS_JSON_PACK_START("emsguard_aircond")
    GUARD_JSON_PACK_END(sn);
    dbg_syslog(LOG_NOTICE, "sn : %s ->aircond_set : %d",sn,var->aircond_set);
}

static void ems_system_fault_recover_proc(pcs_ctrl_var_t *var)
{
 //   g_charge_mng_info.ctrlMode = g_pcs_cfg_info.runState;
    report_option(var, "系统产生了一个报警恢复！");
}

int get_max_grp_level(pcs_ctrl_var_t *var)
{
    int i = 0;
    int max_grg_level = 0;
    for (int i = 0; i < var->guard_grp_num; i++)
    {
        max_grg_level = MAX(max_grg_level,g_charge_mng_info.grps_lev[i].system);
    }
    return max_grg_level;
}

int get_min_grp_level(pcs_ctrl_var_t *var)
{
    int i = 0;
    int min_grg_level = 3;
    for (int i = 0; i < var->guard_grp_num; i++)
    {
        min_grg_level = MIN(min_grg_level,g_charge_mng_info.grps_lev[i].system);
    }
    return min_grg_level;
}

int get_grp_level(pcs_ctrl_var_t *var)
{
    int level = 0;
    if (g_pcs_cfg_info.manual_flag == 0) // 分组（针对于柜体/动环）全是3级故障，切手动
        level = get_min_grp_level(var);
    else
		level = get_max_grp_level(var);
    return level;
}

#define TAKEACKIONLEVEL 3  //执行关机并手动模式的等级 
char *alarm_string[4] = {"无报警","一级","二级","三级"};
static int ems_system_fault_level(pcs_ctrl_var_t *var)  //对异常等级进行相关操作 返回当前的异常等级
{
    static time_t last = 0;
    time_t now = 0;
    int level = get_grp_level(var);
    time(&now);
	CHAR dev_sn[TOPIC_MAX_LEN] = {0};
	
    if (g_charge_mng_info.lev_changed || (now - last) > 30)
    {
        last = now;
        // g_charge_mng_info.lev_changed = false;
        if (level>=TAKEACKIONLEVEL)
        {
            // ems_system_fault_proc(var);
            // split report from action,added by yut
            if (g_charge_mng_info.lev_changed)
            {
                set_alarm_status(var,SYSSTOPED,ALARM);
                if(g_charge_mng_info.ctrlMode == E_CTRL_MANUAL) 
                report_option(var, "系统产生一个三级异常报警！");
                else
                report_option(var, "系统因为产生一个三级异常报警而停止，需要手动恢复！");
                ems_mode_set(E_CTRL_MANUAL);
                if(g_pcs_cfg_info.alarmClose == 1)
                {
                    pcs_dev_yggl_set(var, 0);
                    pcs_dev_close(var); // 关机
                    if ((g_pcs_cfg_info.PvSwitch == E_ON)||(g_pcs_cfg_info.PVmax>0)) //If pv is on, the pv value should be cleared when you switch to manual mode
                    {
                        clear_pv(var);
                    }
                }
                pcs_config_save();
            }
        }
        else if (g_charge_mng_info.lev_changed)
        {
            //ems_system_fault_recover_proc(var);
            report_option(var, "系统产生了一个报警或恢复,当前报警等级:%s！",alarm_string[level]);
        }
        // ended by yut
        g_charge_mng_info.lev_changed = false; //added by yut
        
        // 分发给设备
        system_protect_to_energy(var, var->energyAssignSn,level);
		for (int i = 0; i < var->guard_grp_num; i++)
		{
			snprintf(dev_sn, TOPIC_MAX_LEN, "%s%s", var->grp[i].belong_gw, "_GUARD");
			system_protect_to_guard(var, dev_sn,level);
		}

        if (var->extsession)
        {
            system_protect_to_ext(var, var->energyAssignSn);
            system_protect_to_ext(var, var->guardSn);
        }
        dbg_syslog(LOG_WARNING, "System protect dispatch success");
    }
    return level;
}

static bool check_auto_count(void) //校验STRATEGY_TYPE_PV_TRACK计数器到了没
{
    bool ret = false;
    if(g_charge_mng_info.Adjpreriodcouter==0)
    {
        ret = true;
    }
    else ret = false;
    g_charge_mng_info.Adjpreriodcouter++;
    if((g_pcs_cfg_info.Adjpreriod<=0) || (g_pcs_cfg_info.Adjpreriod == 15)) 
    {
        g_pcs_cfg_info.Adjpreriod = 5;//如果被配置为0 或者读文件为0 则设置为5秒
        dbg_syslog(LOG_WARNING, "load config Adjpreriod = %d ,then set Adjpreriod = 5s !!!",g_pcs_cfg_info.Adjpreriod);
    }
    if(g_charge_mng_info.Adjpreriodcouter>(g_pcs_cfg_info.Adjpreriod-1)) 
    {
        g_charge_mng_info.Adjpreriodcouter=0;
    } 
    return ret;       
}

static bool check_dlkj_count(void) //校验STRATEGY_TYPE_DLKJ计数器到了没
{
    bool ret = false;
    if(g_charge_mng_info.Adjpreriodcouter==0)
    {
        ret = true;
    }
    else ret = false;
    g_charge_mng_info.Adjpreriodcouter++;
    if(g_charge_mng_info.Adjpreriodcouter>g_pcs_cfg_info.Adjpreriod) // P2 computes every 3s 
    {
        g_charge_mng_info.Adjpreriodcouter=0;
    }    
    return ret;       
}



static void some_alarm_check(pcs_ctrl_var_t *var)
{
    //check_alarm_t alarm_list_function;
    for (ALARM_TYPE i = POWERLIMITED; i < ALARM_TYPE_MAX; i++)
    {
        publish_alarm_up(var,check_alarm_list[i].alarm_info_string,i,check_alarm_list[i].alarm_function_list_t(var));
    }
}

static unsigned int get_seconds_of_today(void) 
{
    time_t t = time(NULL);
    struct tm *local_time = localtime(&t);
    unsigned int today_second = 0;
    today_second = local_time->tm_hour * 3600 + local_time->tm_min * 60 + local_time->tm_sec;
    dbg_syslog(LOG_DEBUG, "today_second: %d", today_second);

    return today_second;
}

extern int To_initialize(CHARGE_MNG_INFO_T *char_mng, PCS_CFG_T *pcfg);

static int pcs_second_period_poll(pcs_ctrl_var_t *var)
{
    unsigned int today_second = 0;
    static int last_type = -1,last_ctrlMode = -1,pcs_open_time = 0;
    static bool pcs_open_set = false;
	static int last_aircond_sta = 0;
    static double last_socmin = -2,last_socmax = -2;
	static float last_singlemax = 0, last_singlemin = 0;
	static char last_EDD = -1;
	static unsigned int last_MD = 0, last_DCI = 0;
    static time_t time_last_soc_update = 0;
    static time_t time_last_aircond_update = 0;
    time_t time_now1 = time(NULL);
    time_t time_now2 = time(NULL);
    CHAR dev_sn[TOPIC_MAX_LEN] = {0};
	time_t time1 = -1;

    if (g_charge_mng_info.ctrlMode == E_CTRL_REMOTER) {
        last_ctrlMode = E_CTRL_REMOTER;
        if (!pcs_open_set) {
            pcs_dev_open(var);
            pcs_open_set = true;
        }

        if (var->proxy.cur_mode == E_POWER_SET_MODE) {
            dbg_syslog(LOG_DEBUG, "cur_mode: %d", var->proxy.cur_mode);
            pcs_dev_yggl_set(var, var->proxy.mode1_power_set);
        }
        else if(var->proxy.cur_mode == E_POWER_PLAN_SET_MODE) {
            if (var->proxy.mode2_power_plan_num <= 0) {
                dbg_syslog(LOG_ERR, "there is no mode2_power_plan_num in proxy mode");
                return -1;
            }

            dbg_syslog(LOG_DEBUG, "cur_mode: %d", var->proxy.cur_mode);
            today_second = get_seconds_of_today();

            bool plan_found = false; 
            for (int i = 0; i < var->proxy.mode2_power_plan_num; i++) {
                if (today_second > var->proxy.mode2_power_plan[i].start_time && today_second <= var->proxy.mode2_power_plan[i].end_time) {
                    pcs_dev_yggl_set(var, var->proxy.mode2_power_plan[i].power);
                    plan_found = true;
                    break;
                }
            }

            if (!plan_found) {
                dbg_syslog(LOG_WARNING, "no suitable plan found for the today_second(%d)", today_second);
                pcs_dev_yggl_set(var, 0);
            }
        }
        else {
            dbg_syslog(LOG_ERR, "invalid cur_mode: %d", var->proxy.cur_mode);
        }
    }
    else
    {
        //dbg_syslog(LOG_INFO, "ctrlMode:%d\r\n", g_charge_mng_info.ctrlMode);
        update_plan_cfg(var); //刷新计划
        some_alarm_check(var); //检查部分需要周期检查的告警
		if(g_charge_mng_info.ctrlMode == E_CTRL_AUTO) 
        {   
            if (g_strategr_mng_info.cont == 0 || g_strategr_mng_info.initflag == 0) //没有新计划
            {
                dbg_syslog(LOG_WARNING, "no plan or init failed!!! cont:%d init:%d,aircond time cannot be calculated!", g_strategr_mng_info.cont, g_strategr_mng_info.initflag);
            }
            else
            {
                ems_update_plan_option_aircond(var);
                last_aircond_sta = var->aircond_set;
                if ((g_charge_mng_info.planInfo.option == E_CHARGE_DOING || g_charge_mng_info.planInfo.option == E_CHAREG_DISCH))
                {
                    var->aircond_set = 1;
                }
                else if ((air_cond_planInfo_after.option == E_CHARGE_DOING || air_cond_planInfo_after.option == E_CHAREG_DISCH))// && var->aircond_set == 0)
                {
                    //当前时间往后延时时间为运行则运行--提前运行
                    var->aircond_set = 1;
                }
                else if ((air_cond_planInfo_before.option == E_CHARGE_IDLE || air_cond_planInfo_before.option == E_CHARGE_STOP))// && var->aircond_set == 1)
                {
                    //当前时间往前延时时间为停止则停止--延后结束
                    var->aircond_set = 0;
                }
                
                if(var->aircond_set == -1 || last_aircond_sta != var->aircond_set || time_now2 - time_last_aircond_update > 60)
                {
                    time_last_aircond_update = time_now2;
                    for (int i = 0; i < var->guard_grp_num; i++)
                    {
                        snprintf(dev_sn, TOPIC_MAX_LEN, "%s%s", var->grp[i].belong_gw, "_GUARD");
                        guardSn_aircond_set(var,dev_sn);
                    }
                }
            }
        }
        if(ems_system_fault_level(var)>=TAKEACKIONLEVEL)
        {
            if(g_pcs_cfg_info.alarmClose == 1)
            {
                pcs_dev_yggl_set(var, 0);
                pcs_dev_close(var); // 关机
                if ((g_pcs_cfg_info.PvSwitch == E_ON)||(g_pcs_cfg_info.PVmax>0)) //If pv is on, the pv value should be cleared when you switch to manual mode
                {
                    clear_pv(var);
                }
            }
            
            return 0; //错误等级大于0直接返回
        }
        
        if(g_charge_mng_info.ctrlMode == E_CTRL_MANUAL) 
        {
            last_ctrlMode = E_CTRL_MANUAL;
            return 0; //手动模式直接返回 后面是自动模式的操作
        }

        if (g_strategr_mng_info.cont == 0 || g_strategr_mng_info.initflag == 0) //没有新计划直接返回
        {
            dbg_syslog(LOG_WARNING, "no plan or init failed!!! cont:%d init:%d", g_strategr_mng_info.cont, g_strategr_mng_info.initflag);
            return 0;
        }

		if (g_charge_mng_info.AgainstState == 1 || g_charge_mng_info.demandState == 1)
		{
	        if (g_charge_mng_info.multi_meter_flag == 0 || checkGridMeter1Offline(var) == ALARM ) //此处判断电网电表离线不上报故障，动环默认检测到电网电表离线上报二级故障
	        {
	            dbg_syslog(LOG_WARNING, "multi_meter module no config or GridMeter is offline, multi_meter_flag:%d status:%d", g_charge_mng_info.multi_meter_flag, checkGridMeter1Offline(var));
				pcs_dev_yggl_set(var, 0);
				pcs_dev_close(var); // 关机
			    return 0;
			}
		}
		
        if (last_socmax != g_pcs_cfg_info.SOCmax || last_socmin != g_pcs_cfg_info.SOCmin || time_now1 - time_last_soc_update > 60)
        {
            time_last_soc_update = time_now1;
            last_socmax = g_pcs_cfg_info.SOCmax;
            last_socmin = g_pcs_cfg_info.SOCmin;
            pcs_dev_soc_max_min_set(var,last_socmax,last_socmin);
        }
		
        if (last_EDD != g_pcs_cfg_info.EDD || last_MD != g_pcs_cfg_info.MD || last_DCI != g_pcs_cfg_info.DCI)
        {
        	dbg_syslog(LOG_NOTICE, "automatically update plans local::: EDD %d, MD %d, DCI %d", g_pcs_cfg_info.EDD, g_pcs_cfg_info.MD, g_pcs_cfg_info.DCI);
            last_EDD = g_pcs_cfg_info.EDD;
			
			if (last_MD != g_pcs_cfg_info.MD)
			{
	            last_MD = g_pcs_cfg_info.MD;
                if (g_pcs_cfg_info.MD > g_pcs_cfg_info.Dylmax) // 月初需量(若大于当前最大需量则第二天生效，若小于<=当前需量则下个月月初生效)
                {
                    time(&time1);
					localtime_r(&time1, &g_charge_mng_info.dynamic_demand.back_tim);
                    g_charge_mng_info.dynamic_demand.triger = 1;
				}
			    dbg_syslog(LOG_NOTICE, "MD %d, Dylmax %d", g_pcs_cfg_info.MD, g_pcs_cfg_info.Dylmax);
			}
			
			if (last_DCI != g_pcs_cfg_info.DCI) // 需量计算间隔
			{
				last_DCI = g_pcs_cfg_info.DCI;
			    To_initialize(&g_charge_mng_info, &g_pcs_cfg_info);
			}

			//pcs_demand_set(var);
			pcs_config_save();
        }
	
	    if (last_singlemax != g_pcs_cfg_info.singlemax || last_singlemin != g_pcs_cfg_info.singlemin)
        {    
     		last_singlemax = g_pcs_cfg_info.singlemax;
			last_singlemin = g_pcs_cfg_info.singlemin;
		    dbg_syslog(LOG_WARNING, "StationControl set single_Vol limit H:%f, L:%f ", g_pcs_cfg_info.singlemax, g_pcs_cfg_info.singlemin);
			pcs_single_max_min_set(var);
        }
		
		dbg_syslog(LOG_INFO, "Current strategy template type:%d", g_pcs_cfg_info.type);
        switch (g_pcs_cfg_info.type)
        {
            case STRATEGY_TYPE_PEEK: //计划模式削峰填谷
                if(check_auto_count())ems_process_main(var);
                break;
            case STRATEGY_TYPE_DLKJ: //需量控制 电网电表需量和负载需量
                if(check_auto_count())ems_demand_ctrl_main(var);
                break;
            case STRATEGY_TYPE_PV_TRACK:   //最大需量和光伏的最大需量
                if((last_type!=STRATEGY_TYPE_PV_TRACK)||(last_ctrlMode==E_CTRL_MANUAL)) //模式切换过 则需要重新开机 防止关机情况开机过慢导致逆流的问题
                {
                    dbg_syslog(LOG_INFO, "type is error:%d", g_pcs_cfg_info.type);
                    g_charge_mng_info.pcs_openState = E_OFF;
                    pcs_dev_standby_set_by_config(var);
                    pcs_dev_open(var);
                    last_ctrlMode = STRATEGY_TYPE_PV_TRACK;
                    pcs_open_time=0;
                }
                if(pcs_open_time>10)
                {
                    if(check_auto_count())
                    {
                        ems_max_demand_ctrl_main(var);
                    }
                }
                else
                {
                    dbg_syslog(LOG_INFO, "need wait pcs_open, time:%d", 10-pcs_open_time);
                }
                pcs_open_time++;
            break;
            default:
            dbg_syslog(LOG_INFO, "type is error:%d", g_pcs_cfg_info.type);
            break;
        }
        last_type = g_pcs_cfg_info.type;
    }

    return 0;
}
//#endif//delete by yut
static BYTE pcs_discharge_track(double p1, BYTE K2, USHORT p3, WORD *updown)
{
    // g_pcs_cfg_info.K2*p3  放电值
    if (p1 > (100 - K2) * p3 / 100 + g_pcs_cfg_info.Adjstep)
    {

        // p1 - (100 - K2)*p3/100 + 5
        *updown += g_pcs_cfg_info.Adjstep;
        // 增加放电功率
        return E_TRUE;
    }
    else if (p1 < (100 - K2) * p3 / 100 - g_pcs_cfg_info.Adjstep)
    {
        // 降低放电功率
        *updown -= g_pcs_cfg_info.Adjstep;
        return E_TRUE;
    }
    return E_FALSE;
}

static BYTE pcs_discharge_demand_check(double p1, USHORT Pmlmax, BYTE k1)
{

    if (p1 > (k1 * Pmlmax) / 100)
    {
        return E_TRUE;
    }
    return E_FALSE;
}

static BYTE pcs_charge_soc_check()
{
    if (g_charge_mng_info.soc >= g_pcs_cfg_info.SOCmax)
        return E_TRUE;
    return E_FALSE;
}

static BYTE pcs_discharge_soc_check()
{
    if (g_charge_mng_info.soc <= g_pcs_cfg_info.SOCmin)
        return E_TRUE;
    return E_FALSE;
}

static int pcs_charge_doing_check(double p1, USHORT Pmlmax, BYTE k1)
{
    if (p1 > Pmlmax * k1 / 100)
    {
        // 快速降低Pcs充电功率；
        return E_TRUE;
    }
    if (p1 < k1 * Pmlmax)
    {
        // 考虑是否需要增加充电功率；
    }
    return E_FALSE;
}

static void pcs_ctrl_subscribe_all(pcs_ctrl_var_t *var)
{
    CHAR topic[TOPIC_MAX_LEN] = {0};

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/%s", var->sn_str, var->vir_sn_str, TOPIC_EVT_SET_RGLT);
   
    dbg_syslog(LOG_NOTICE, "topic:%s", topic);
    ipc_session_subscribe(var->session, topic);
    
}

static void pcs_to_dev_subscribe_all(pcs_ctrl_var_t *var)
{
    CHAR topic[TOPIC_MAX_LEN] = {0};
    int i;
    
    //snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/+", var->sn_str, var->vir_sn_str);
    snprintf(topic, TOPIC_MAX_LEN, "ipc/+/+/device/+/data/service/+");//yut
    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->sessiondev, topic);

    for (i = 0; i < var->exdevnodeinfo.cont; i++)
    {
        snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/%s", var->sn_str, var->exdevnodeinfo.pdevnodecfg[i].devSn,
                 var->exdevnodeinfo.pdevnodecfg[i].identifier);
        dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
        ipc_session_subscribe(var->sessiondev, topic);
    }

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/+", var->sn_str, var->energyAssignSn);
    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->sessiondev, topic);
/*
    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/+", var->sn_str, var->guardSn);
    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->sessiondev, topic);
*/
    for (i = 0; i < var->guard_grp_num; i++)
	{
	    snprintf(topic, TOPIC_MAX_LEN, "/ems/%s%s/service", var->grp[i].belong_gw, "_GUARD");
	    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
	    ipc_session_subscribe(var->sessiondev, topic);
	}

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/+", var->sn_str, var->deamndSn);
    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->sessiondev, topic);

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/+", var->sn_str, var->multiMeterSn);
    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->sessiondev, topic);
	
	snprintf(topic, TOPIC_MAX_LEN, "/ems/%s%s/service", var->grp[0].belong_gw, "_DI"); // 主柜DI
    dbg_syslog(LOG_NOTICE, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->sessiondev, topic);

}

static int pcs_ctrl_state_change(void *obj, int state)
{
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)obj;
    char topic[TOPIC_MAX_LEN] = {0};

    switch (state)
    {
    case MQTT_CONNECTED:
        snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/start", var->sn_str, "ems_ctrl");
        // dy_mqtt_session_publish(var->session, topic, "", 0);
        ipc_session_publish(var->session, topic, "", 0);
        break;
    }
    return E_TRUE;
}

static int pcs_reset(pcs_ctrl_var_t *var, cJSON *node)
{
    pcs_dev_reset(var);
    return E_TRUE;
}

static int init_proxy_summary_file(pcs_ctrl_var_t *var, const char *summary_file)
{
    FILE *fp = NULL;
    char *summary = NULL;
    int result = 0;

    if (var == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_file: %p", var, summary_file);
        return -1;
    }

    cJSON *root = cJSON_CreateObject();
    if (root == NULL) {
        dbg_syslog(LOG_ERR, "create root object failed!");
        return -1;
    }

    cJSON_AddNumberToObject(root, "cur_mode", var->proxy.cur_mode);
    cJSON_AddNumberToObject(root, "mode3_pv_power_set",  var->proxy.mode3_pv_power_set);
    cJSON_AddNumberToObject(root, "mode1_power_set", var->proxy.mode1_power_set);

    cJSON *power_plan = cJSON_CreateArray();
    if (power_plan == NULL) {
        dbg_syslog(LOG_ERR, "create power_plan object failed!");
        result = -1;
        goto cleanup;
    }

    cJSON *default_item = cJSON_CreateIntArray((int[]){0, 86400, 0}, 3);
    cJSON_AddItemToArray(power_plan, default_item);
    cJSON_AddItemToObject(root, "mode2_power_plan", power_plan);
    cJSON_AddNumberToObject(root, "mode2_power_plan_num", var->proxy.mode2_power_plan_num);

    summary = cJSON_Print(root);
    write_file_data(summary_file, summary, strlen(summary));

cleanup:
    if (summary != NULL) {
        free(summary);
    }
    if (root != NULL) {
        cJSON_Delete(root);
    }
    if (power_plan != NULL) {
        cJSON_Delete(power_plan);
    }

    return result;
}

static void print_proxy_load_result(pcs_ctrl_var_t *var)
{
    if (var == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p", var);
        return;
    }

    dbg_syslog(LOG_NOTICE, "-------------------proxy load result-------------------");
    dbg_syslog(LOG_NOTICE, "cur_mode: %d", var->proxy.cur_mode);
    dbg_syslog(LOG_NOTICE, "mode3_pv_power_set: %d", var->proxy.mode3_pv_power_set);
    dbg_syslog(LOG_NOTICE, "mode1_power_set: %d", var->proxy.mode1_power_set);
    dbg_syslog(LOG_NOTICE, "mode2_power_plan_num: %d", var->proxy.mode2_power_plan_num);
    if (var->proxy.mode2_power_plan_num > 0) {
        for (int i = 0; i < var->proxy.mode2_power_plan_num; i++) {
            dbg_syslog(LOG_NOTICE, "mode2_power_plan[%d]: start_time: %d, end_time: %d, power: %d",
                i, 
                var->proxy.mode2_power_plan[i].start_time, 
                var->proxy.mode2_power_plan[i].end_time,
                var->proxy.mode2_power_plan[i].power);
        }
    }
    dbg_syslog(LOG_NOTICE, "--------------------------------------------------------");
}

static int load_proxy_cfg(pcs_ctrl_var_t *var, const char *summary_file)
{
    char *cfg_str = NULL;
    cJSON *cfg  = NULL;
    cJSON* item = NULL;
    cJSON *subitem = NULL;
    int result = 0;

    if (var == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_file: %p", var, summary_file);
        return -1;
    }

    if (access(summary_file, F_OK) != 0) {
        var->proxy.cur_mode = PROXY_DEFAULT_MODE;
        var->proxy.mode1_power_set = PROXY_DEFAULT_POWER;
        var->proxy.mode2_power_plan_num = 1;
        var->proxy.mode2_power_plan = NULL;
        var->proxy.mode3_pv_power_set  = PROXY_DEFAULT_POWER;

        init_proxy_summary_file(var, summary_file);
        print_proxy_load_result(var);
        return 0;
    }

    cfg_str = read_file_data(summary_file);
    if (cfg_str == NULL) {
        dbg_syslog(LOG_ERR, "read summary_file: %s error", summary_file);
        result = -1;
        goto cleanup;
    }

    cfg = cJSON_Parse(cfg_str);
    if (!cfg) {
        dbg_syslog(LOG_ERR, "parse summary_file: %s error", summary_file);
        result = -1;
        goto cleanup;
    }

    // upload mode1 power_set
    int mode1_power_set = 0;
    item = cJSON_GetObjectItem(cfg, "mode1_power_set");
    if (item == NULL) {
        dbg_syslog(LOG_ERR, "get mode1_power_set from summary_file: %s error", summary_file);
        result = -1;
        goto cleanup;
    }
    GET_JSON_VALUE_INT_LOG(cfg, "mode1_power_set", mode1_power_set);
    var->proxy.mode1_power_set = -mode1_power_set;

    // upload mode2 power_plan_set
    var->proxy.mode2_power_plan_num = 0;
    var->proxy.mode2_power_plan = NULL;
    item = cJSON_GetObjectItem(cfg, "mode2_power_plan");
    if (item == NULL || !cJSON_IsArray(item)) {
        dbg_syslog(LOG_ERR, "get mode2_power_plan from summary_file: %s error", summary_file);
        result = -1;
        goto cleanup;
    }

    var->proxy.mode2_power_plan_num = cJSON_GetArraySize(item);
    if (var->proxy.mode2_power_plan_num <= 0) {
        var->proxy.mode2_power_plan = NULL;
    }
    else {
        var->proxy.mode2_power_plan = (mode2_power_plan_t *)calloc(var->proxy.mode2_power_plan_num, sizeof(mode2_power_plan_t));
        if (var->proxy.mode2_power_plan == NULL) {
            dbg_syslog(LOG_ERR, "malloc failed! size: %d", var->proxy.mode2_power_plan_num * sizeof(mode2_power_plan_t));
            result = -1;
            goto cleanup;
        }

        int i = 0;
        cJSON_ArrayForEach(subitem, item) {
            cJSON *start_time = cJSON_GetArrayItem(subitem, 0);
            cJSON *end_time   = cJSON_GetArrayItem(subitem, 1);
            cJSON *power      = cJSON_GetArrayItem(subitem, 2);

            if (!cJSON_IsNumber(start_time) || !cJSON_IsNumber(end_time) || !cJSON_IsNumber(power)) {
                dbg_syslog(LOG_ERR, "invalid data in mode2_power_plan array, expected numbers");
                result = -1;
                goto cleanup;
            }

            var->proxy.mode2_power_plan[i].start_time = start_time->valueint;
            var->proxy.mode2_power_plan[i].end_time   = end_time->valueint;
            var->proxy.mode2_power_plan[i].power      = -power->valueint;
            i++;
        }
    }

    // upload mode3 pv_power_set
    item = cJSON_GetObjectItem(cfg, "mode3_pv_power_set");
    if (item == NULL) {
        dbg_syslog(LOG_ERR, "get mode3_pv_power_set from summary_file: %s error", summary_file);
        result = -1;
        goto cleanup;
    }
    GET_JSON_VALUE_INT_LOG(cfg, "mode3_pv_power_set", var->proxy.mode3_pv_power_set);

    // upload cur_mode
    item = cJSON_GetObjectItem(cfg, "cur_mode");
    if (item == NULL) {
        dbg_syslog(LOG_ERR, "get cur_mode from summary_file: %s error", summary_file);
        result = -1;
        goto cleanup;
    }
    GET_JSON_VALUE_INT_LOG(cfg, "cur_mode", var->proxy.cur_mode);

    print_proxy_load_result(var);

cleanup:
    if (cfg_str != NULL) {
        free(cfg_str);
    }

    if (cfg != NULL) {
        cJSON_Delete(cfg);
    }

    return result;
}

static int store_payload_to_file(cJSON *payload, const char *cfg_file)
{
    char *payload_str = NULL;
    int result = 0;

    if (payload == NULL || cfg_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! payload: %p, cfg_file: %p", payload, cfg_file);
        return -1;
    }

    payload_str = cJSON_Print(payload);
    if (write_file_data(cfg_file, payload_str, strlen(payload_str)) != 0 ) {
        dbg_syslog(LOG_ERR, "write_file_data failed");
        result = -1;
        goto cleanup;
    }

cleanup:
    if (payload_str != NULL) {
        free(payload_str);
        payload_str = NULL;
    }

    return result;
}

static int update_mode_to_summary_file(pcs_ctrl_var_t *var, cJSON *summary_json, const char *summary_file)
{
    char *summary_dest = NULL;
    int result = 0;

    if (var == NULL || summary_json == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_json: %p, summary_file: %p", var, summary_json, summary_file);
        return -1;
    }

    cJSON *cur_mode = cJSON_GetObjectItem(summary_json, "cur_mode");
    if (cur_mode == NULL) {
        syslog(LOG_ERR, "get cur_mode from summary_file: %s error", summary_file);  
        return -1;
    }

    cJSON_SetNumberValue(cur_mode, var->proxy.cur_mode);
    summary_dest = cJSON_Print(summary_json);

    if (write_file_data(summary_file, summary_dest, strlen(summary_dest)) != 0) {
        syslog(LOG_ERR, "write_file_data failed");  
        result = -1;
        goto cleanup;
    }

cleanup:
    if (summary_dest != NULL) {
        free(summary_dest);
        summary_dest = NULL;
    }

    return result;
}

static int update_powerset_to_summary_file(pcs_ctrl_var_t *var, cJSON *summary_json, const char *summary_file)
{
    char *summary_dest = NULL;
    int result = 0;

    if (var == NULL || summary_json == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_json: %p, summary_file: %p", var, summary_json, summary_file);
        return -1;
    }


    cJSON *mode1_power_set = cJSON_GetObjectItem(summary_json, "mode1_power_set");
    if (mode1_power_set == NULL) {
        syslog(LOG_ERR, "get mode1_power_set from summary_file: %s error", summary_file);
        return -1;
    }

    cJSON_SetNumberValue(mode1_power_set, var->proxy.mode1_power_set);
    summary_dest = cJSON_Print(summary_json);

    if (write_file_data(summary_file, summary_dest, strlen(summary_dest)) != 0) {
        syslog(LOG_ERR, "write_file_data failed");  
        result = -1;
        goto cleanup;
    }

cleanup:
    if (summary_dest != NULL) {
        free(summary_dest);
        summary_dest = NULL;
    }

    return result;
}

static int update_power_plan_set_to_summary_file(pcs_ctrl_var_t *var, cJSON *summary_json, const char *summary_file)
{
    int i = 0;
    char *summary_dest = NULL;

    if (var == NULL || summary_json == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_json: %p, summary_file: %p", var, summary_json, summary_file);
        return -1;
    }

    cJSON *mode2_power_plan = cJSON_GetObjectItem(summary_json, "mode2_power_plan");
    if (mode2_power_plan == NULL) {
        syslog(LOG_ERR, "get mode2_power_plan from summary_file: %s error", summary_file);  
        return -1;
    }

    if (!cJSON_IsArray(mode2_power_plan)) {
        syslog(LOG_ERR, "mode2_power_plan is not an array!");
        return -1;
    }

    int old_array_size = cJSON_GetArraySize(mode2_power_plan);
    for (i = 0; i < old_array_size; i++) {
        cJSON_DeleteItemFromArray(mode2_power_plan, 0);
    }

    for (i = 0; i < var->proxy.mode2_power_plan_num; i++) {
        int start_time = var->proxy.mode2_power_plan[i].start_time;
        int end_time   = var->proxy.mode2_power_plan[i].end_time;
        int power      = var->proxy.mode2_power_plan[i].power;

        syslog(LOG_DEBUG, "i: %d", i);
        syslog(LOG_DEBUG, "start_time: %d", start_time);
        syslog(LOG_DEBUG, "end_time  : %d", end_time);
        syslog(LOG_DEBUG, "power:    : %d", power);

        cJSON *item = cJSON_CreateIntArray((int[]){start_time, end_time, power}, 3);
        cJSON_AddItemToArray(mode2_power_plan, item);
    }

    summary_dest = cJSON_Print(summary_json);
    syslog(LOG_INFO, "summary_dest: %s", summary_dest);
    write_file_data(summary_file, summary_dest, strlen(summary_dest));

    if (summary_dest != NULL) {
        free(summary_dest);
        summary_dest = NULL;
    }

    return 0;
}

static int update_pv_powerset_to_summary_file(pcs_ctrl_var_t *var, cJSON *summary_json, const char *summary_file)
{
    char *summary_dest = NULL;
    int result = 0;

    if (var == NULL || summary_json == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_json: %p, summary_file: %p", var, summary_json, summary_file);
        return -1;
    }

    cJSON *mode3_pv_power_set = cJSON_GetObjectItem(summary_json, "mode3_pv_power_set");
    if (mode3_pv_power_set == NULL) {
        syslog(LOG_ERR, "get mode3_pv_power_set from summary_file: %s error", summary_file);
        return -1;
    }

    cJSON_SetNumberValue(mode3_pv_power_set, var->proxy.mode3_pv_power_set);
    summary_dest = cJSON_Print(summary_json);

    if (write_file_data(summary_file, summary_dest, strlen(summary_dest)) != 0) {
        syslog(LOG_ERR, "write_file_data failed");
        result = -1;
        goto cleanup;
    }

cleanup:
    if (summary_dest != NULL) {
        free(summary_dest);
        summary_dest = NULL;
    }

    return result;
}

static int update_summary_file(pcs_ctrl_var_t *var, PROXY_ACTION_E action, const char *summary_file)
{
    int i = 0;
    int result = 0;
    char  *summary_src  = NULL;
    cJSON *summary_json = NULL;

    if (var == NULL || summary_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, summary_file: %p", var, summary_file);
        return -1;
    }

    summary_src = read_file_data(summary_file);
    if (summary_src == NULL) {
        dbg_syslog(LOG_ERR, "read summary_file failed! summary_file: %s", summary_file);
        result = -1;
        goto cleanup;
    }

    summary_json = cJSON_Parse(summary_src);
    if (!summary_json) {
        dbg_syslog(LOG_ERR, "parse summary_src failed! summary_src: %s", summary_src);
        result = -1;
        goto cleanup;
    }

    switch(action) {
        case E_MODE_TYPE_SET:
            if (update_mode_to_summary_file(var, summary_json, summary_file) != 0) {
                dbg_syslog(LOG_ERR, "update_mode_to_summary_file failed!");
                result = -1;
                goto cleanup;
            }
            break;
        case E_POWER_SET:
            if (update_powerset_to_summary_file(var, summary_json, summary_file) != 0) {
                dbg_syslog(LOG_ERR, "update_powerset_to_summary_file failed!");
                result = -1;
                goto cleanup;
            }
            break;
        case E_POWER_PLAN_SET:
            if (update_power_plan_set_to_summary_file(var, summary_json, summary_file) != 0) {
                dbg_syslog(LOG_ERR, "update_power_plan_set_to_summary_file failed!");
                result = -1;
                goto cleanup;
            }
            break;
        case E_PV_POWER_SET:
            if (update_pv_powerset_to_summary_file(var, summary_json, summary_file) != 0) {
                dbg_syslog(LOG_ERR, "update_pv_powerset_to_summary_file failed!");
                result = -1;
                goto cleanup;
            }
            break;
        default:
            dbg_syslog(LOG_ERR, "invalid action: %d", action);
            result = -1;
            break;
    }

cleanup:
    if (summary_src != NULL) {
        free(summary_src);
        summary_src = NULL;
    }

    if (summary_json != NULL) {
        cJSON_Delete(summary_json);
    }

    return result;
}

static int get_power_plan(pcs_ctrl_var_t *var, cJSON *power_plan_array)
{
    int i = 0;
    cJSON *power_plan_item = NULL;

    if (var == NULL || power_plan_array == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, power_plan_array: %p", var, power_plan_array);
        return -1;
    }

    if (var->proxy.mode2_power_plan != NULL) {
        free(var->proxy.mode2_power_plan);
        var->proxy.mode2_power_plan = NULL;
    }

    var->proxy.mode2_power_plan_num = cJSON_GetArraySize(power_plan_array);
    dbg_syslog(LOG_NOTICE, "power plan num: %d", var->proxy.mode2_power_plan_num);
    if (var->proxy.mode2_power_plan_num <= 0) {
        dbg_syslog(LOG_ERR, "invalid power_plan_num: %d", var->proxy.mode2_power_plan_num);
        return -1;
    }

    var->proxy.mode2_power_plan = (mode2_power_plan_t *)calloc(var->proxy.mode2_power_plan_num, sizeof(mode2_power_plan_t));
    if (var->proxy.mode2_power_plan == NULL) {
        dbg_syslog(LOG_ERR, "malloc failed! size: %d", var->proxy.mode2_power_plan_num * sizeof(mode2_power_plan_t));
        return -1;
    }

    for (i = 0; i < var->proxy.mode2_power_plan_num; i++) {
        cJSON* power_plan_item = cJSON_GetArrayItem(power_plan_array, i);
        if (power_plan_item == NULL || 
            !cJSON_IsArray(power_plan_item) ||
            cJSON_GetArraySize(power_plan_item) != 3) 
        {
            dbg_syslog(LOG_ERR, "power_plan_item not found or not an array or array size != 3");
            if (var->proxy.mode2_power_plan != NULL) {
                free(var->proxy.mode2_power_plan);
            }
            return -1;
        }

        for (int j = 0; j < 3; j++) {
            cJSON* value = cJSON_GetArrayItem(power_plan_item, j);
            if (value == NULL || !cJSON_IsNumber(value)) {
                dbg_syslog(LOG_ERR, "value not found or not a number");
                if (var->proxy.mode2_power_plan != NULL) {
                    free(var->proxy.mode2_power_plan);
                }
                return -1;
            }
        }

        cJSON *start_time = cJSON_GetArrayItem(power_plan_item, 0);
        cJSON *end_time   = cJSON_GetArrayItem(power_plan_item, 1);
        cJSON *power      = cJSON_GetArrayItem(power_plan_item, 2);
        var->proxy.mode2_power_plan[i].start_time = start_time->valueint;
        var->proxy.mode2_power_plan[i].end_time   = end_time->valueint;
        var->proxy.mode2_power_plan[i].power      = -power->valuedouble;
    
        dbg_syslog(LOG_DEBUG, "start_time: %d", var->proxy.mode2_power_plan[i].start_time);
        dbg_syslog(LOG_DEBUG, "end_time  : %d", var->proxy.mode2_power_plan[i].end_time);
        dbg_syslog(LOG_DEBUG, "power recv         : %d", power->valuedouble);
        dbg_syslog(LOG_DEBUG, "power after convert: %d", var->proxy.mode2_power_plan[i].power);
    }

    int last_item_index = i - 1;
    if (var->proxy.mode2_power_plan[last_item_index].end_time != 24 * 60 * 60) {
        dbg_syslog(LOG_ERR, "invalid end second of a day(%d)", var->proxy.mode2_power_plan[last_item_index].end_time);
        return -1;
    }

    return 0;
}

static int handle_work_mode_set(pcs_ctrl_var_t *var, cJSON *payload)
{
    cJSON *data = NULL;

    if (var == NULL || payload == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, payload: %p", var, payload);
        return -1;
    }

    data = cJSON_GetObjectItem(payload, "data");
    if (data == NULL || !cJSON_HasObjectItem(data, "action_type")) {
        dbg_syslog(LOG_ERR, "'data' not found or has no 'action_type'");
        return -1;
    }

    GET_JSON_VALUE_INT_LOG(data, "action_type", var->proxy.cur_mode);
    dbg_syslog(LOG_NOTICE, "action_type: %d", var->proxy.cur_mode);

    if (store_payload_to_file(payload, PROXY_MODE_CFG_FILE) != 0) {
        dbg_syslog(LOG_ERR, "store_payload_to_file failed");
        return -1;
    }

    if (update_summary_file(var, E_MODE_TYPE_SET, PROXY_SUMMARY_FILE) != 0) {
        dbg_syslog(LOG_ERR, "update_summary_file failed");
        return -1;
    }

    if (var->proxy.cur_mode == E_POWER_SET_MODE) {
        var->proxy.mode1_power_set = 0;
    }

    if (var->proxy.cur_mode >= E_POWER_SET_MODE && var->proxy.cur_mode <= E_PV_POWER_SET_MODE) {
        g_charge_mng_info.ctrlMode = E_CTRL_REMOTER;
        pcs_config_save();
    }
    else {
        dbg_syslog(LOG_DEBUG, "invalid cur_mode(%d), will not enter proxy mode", var->proxy.cur_mode);
        return -1;
    }

    return 0;
}

static int handle_power_set(pcs_ctrl_var_t *var, cJSON *payload)
{
    cJSON *data = NULL;
    int mode1_power_set = 0;

    if (var == NULL || payload == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, payload: %p", var, payload);
        return -1;
    }

    data = cJSON_GetObjectItem(payload, "data");
    if (data == NULL || !cJSON_HasObjectItem(data, "power_set")) {
        dbg_syslog(LOG_ERR, "'data' is not found or has no 'power_set'");
        return -1;
    }

    GET_JSON_VALUE_INT_LOG(data, "power_set", mode1_power_set);
    dbg_syslog(LOG_NOTICE, "power_set recv: %d", mode1_power_set);

    var->proxy.mode1_power_set = -mode1_power_set;
    dbg_syslog(LOG_NOTICE, "power_set after convert: %d", var->proxy.mode1_power_set);

    if (store_payload_to_file(payload, PROXY_POWER_SET_CFG_FILE) != 0) {
        dbg_syslog(LOG_ERR, "store_payload_to_file failed");
        return -1;
    }

    if (update_summary_file(var, E_POWER_SET, PROXY_SUMMARY_FILE) != 0) {
        dbg_syslog(LOG_ERR, "update_summary_file failed");
        return -1;
    }

    return 0;
}

static int handle_power_plan_set(pcs_ctrl_var_t *var, cJSON *payload)
{
    cJSON *data = NULL;

    if (var == NULL || payload == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, payload: %p", var, payload);
        return -1;
    }

    data = cJSON_GetObjectItem(payload, "data");
    if (data == NULL || !cJSON_IsArray(data)) {
        dbg_syslog(LOG_ERR, "'data' not found or not an array");
        return -1;
    }

    if (store_payload_to_file(payload, PROXY_PLAN_CFG_FILE) != 0) {
        dbg_syslog(LOG_ERR, "store_payload_to_file failed!");
        return -1;
    }

    if (get_power_plan(var, data) != 0) {
        dbg_syslog(LOG_ERR, "get_power_plan failed!");
        return -1;
    }

    if (update_summary_file(var, E_POWER_PLAN_SET, PROXY_SUMMARY_FILE) != 0) {
        dbg_syslog(LOG_ERR, "update_summary_file failed!");
        return -1;
    }

    return 0;
}

static int handle_pv_power_set(pcs_ctrl_var_t *var, cJSON *payload)
{
    cJSON *data = NULL;

    if (var == NULL || payload == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, payload: %p", var, payload);
        return -1;
    }

    data = cJSON_GetObjectItem(payload, "data");
    if (data == NULL || !cJSON_HasObjectItem(data, "pv_power_set")) {
        dbg_syslog(LOG_ERR, "'data' is not found or has no 'pv_power_set'");
        return -1;
    }

    GET_JSON_VALUE_INT_LOG(data, "pv_power_set", var->proxy.mode3_pv_power_set);
    dbg_syslog(LOG_NOTICE, "pv_power_set: %d", var->proxy.mode3_pv_power_set);

    if (store_payload_to_file(payload, PROXY_PV_CFG_FILE) != 0) {
        dbg_syslog(LOG_ERR, "store_payload_to_file failed");
        return -1;
    }

    if (update_summary_file(var, E_PV_POWER_SET, PROXY_SUMMARY_FILE) != 0) {
        dbg_syslog(LOG_ERR, "update_summary_file failed");
        return -1;
    }

    return 0;
}

static int handle_proxy_mode(pcs_ctrl_var_t *var, cJSON *payload)
{
    int action = -1;

    if (var == NULL || payload == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p, payload: %p", var, payload);
        return E_FALSE;
    }

    if (!cJSON_HasObjectItem(payload, "action")) {
        dbg_syslog(LOG_ERR, "'payload' has no 'action'!");
        return E_FALSE;
    }

    GET_JSON_VALUE_INT_LOG(payload, "action", action);

    switch (action) {
        case E_MODE_TYPE_SET:
            if (handle_work_mode_set(var, payload) != 0) {
                return E_FALSE;
            }
            dbg_syslog(LOG_NOTICE, "pcs_dev_open");
            pcs_dev_open(var);
            break;
        case E_POWER_SET:
            if (handle_power_set(var, payload) != 0) {
                return E_FALSE;
            }
            dbg_syslog(LOG_NOTICE, "pcs_dev_open");
            pcs_dev_open(var);
            break;
        case E_POWER_PLAN_SET:
            if (handle_power_plan_set(var, payload) != 0) {
                return E_FALSE;
            }
            dbg_syslog(LOG_NOTICE, "pcs_dev_open");
            pcs_dev_open(var);
            break;
        case E_PV_POWER_SET:
            if (handle_pv_power_set(var, payload) != 0) {   // 设置光伏随动防逆流功率
                return E_FALSE;
            }
            break;
        default:
            dbg_syslog(LOG_ERR, "invalid action: %d", action);
            return E_FALSE;
    }

    return E_TRUE;
}

static int pcs_devs_structure_set(pcs_ctrl_var_t *var, cJSON *payload)
{
    pid_t status;
    char *pcs_devs_struct = NULL;
    char cmd[256] = {0};
    const char *cfg_file = "/app/config/ems/ems_structure.json";
	const char *restart_ems_ctrl = "/etc/init.d/ems_ctrl restart";
    const char *restart_multi_meters = "/etc/init.d/multi_meters restart";
    const char *restart_enegy_assign = "/etc/init.d/energy_assign restart";
    const char *restart_protocol_parser = "/etc/init.d/protocol_parser restart";

    if (var == NULL || payload == NULL)
    {
        dbg_syslog(LOG_ERR, "invalid arguments! var: %p, payload: %p", var, payload);
        return E_FALSE;
    }

    cJSON_DeleteItemFromObject(payload, "mi");
    pcs_devs_struct = cJSON_Print(payload);
    write_file_data(cfg_file, pcs_devs_struct, strlen(pcs_devs_struct));

    if (pcs_devs_struct != NULL) {
        free(pcs_devs_struct);
        pcs_devs_struct = NULL;
    }

    status = system(restart_multi_meters);
    if (WIFEXITED(status))
    {
        if (WEXITSTATUS(status) != 0)
        {
            dbg_syslog(LOG_ERR, "%s failed, errno: %d", restart_multi_meters, WEXITSTATUS(status));
        }
    }

    status = system(restart_enegy_assign);
    if (WIFEXITED(status))
    {
        if (WEXITSTATUS(status) != 0)
        {
            dbg_syslog(LOG_ERR, "%s failed, errno: %d", restart_enegy_assign, WEXITSTATUS(status));
        }
    }

    status = system(restart_protocol_parser);
    if (WIFEXITED(status))
    {
        if (WEXITSTATUS(status) != 0)
        {
            dbg_syslog(LOG_ERR, "%s failed, errno: %d", restart_protocol_parser, WEXITSTATUS(status));
        }
    }

	system(restart_ems_ctrl);
}

static int pcs_open_set(pcs_ctrl_var_t *var, cJSON *node)
{
    int tmp = 0xff;
    int ret = E_FALSE;
    GET_JSON_VALUE_INT(node, "runState", tmp);
    switch (tmp)
    {
    case E_ON:
        if (g_charge_mng_info.total_lev.system > E_ALARM_LEVEL0)
        {
            ret = E_ALARM_LEVLE_ERR;
        }
        else
        {
            pcs_dev_open(var);
            ret = E_TRUE;
        }
        break;
    case E_OFF:
        pcs_dev_close(var);
        ret = E_TRUE;
        break;
    case E_IDLE:
        if (g_charge_mng_info.total_lev.system > E_ALARM_LEVEL0)
        {
            ret = E_ALARM_LEVLE_ERR;
        }
        else
        {
            pcs_dev_standby_set_by_config(var);
            ret = E_TRUE;
        }
        break;
    }
    if (ret == E_TRUE)
    {
        //g_charge_mng_info.runState = tmp; // 开机操作
        dbg_syslog(LOG_NOTICE, "runState->%d", tmp);
    }
    return ret;
}



void mastSwitch_set_linkage(pcs_ctrl_var_t *var, int val)
{
    int i;

    for (i = 0; i < var->mastswitch_lingageInfo.cont; i++)
    {
        if (var->mastswitch_lingageInfo.plingage[i].val != val)
        {
            report_option(var, "mast switch %d", val);
            auxi_set(var, var->mastswitch_lingageInfo.plingage[i].identifier, val);
            var->mastswitch_lingageInfo.plingage[i].val = val;
        }
    }
}
// linkage cut out
static int linkage_set(pcs_ctrl_var_t *var, cJSON *node)
{
    int tmp = -1;
    int ret = E_FALSE;
    int index = 0;
    CHAR identifier[IDENTIFIER_LEN] = {0};
    GET_JSON_VALUE_INT(node, "onOff", tmp);
    GET_JSON_VALUE_INT(node, "linkage", index);
    dbg_syslog(LOG_NOTICE, "onOff%d: linkage:%d", tmp, index);
    if (index == 0 || index > MAX_DO_NUM)
    {
        return E_FALSE;
    }
    sprintf(identifier, "linkage%d", index);
    // dbg_syslog(LOG_INFO, "linkage_set: id:%s", identifier);
    switch (tmp)
    {
    case E_LINGAGE_OFF:
    case E_LINGAGE_ON:
        // fire_w_g_set_linkage(var, tmp);
        auxi_set(var, identifier, tmp);
        ret = E_TRUE;
    default:
        break;
    }
    return ret;
}



static int pv_pcs_open_set(pcs_ctrl_var_t *var, cJSON *node)
{
    int tmp = 0xff;
    int ret = E_FALSE;
    GET_JSON_VALUE_INT(node, "runState", tmp);
    switch (tmp)
    {
    case E_ON:
        // if (g_charge_mng_info.connState == E_OFF)
        // {
        //     ret = E_NOT_CONNET_GRID;
        // }
        // else   //需求离网状态下可以操作开关机
        {
            pv_pcs_dev_open(var);
            ret = E_TRUE;
        }
        break;
    case E_OFF:
        pv_pcs_dev_close(var);
        ret = E_TRUE;
        break;
    }
    if (ret == E_TRUE)
    {
        g_charge_mng_info.PVrunState = tmp; // 开机操作
        dbg_syslog(LOG_NOTICE, "runState->%d", g_charge_mng_info.PVrunState);
    }
    return ret;
}

static int pv_pcs_gl_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = POWER_MAX_VAL;
    int ret = E_TRUE;
    // ret = api_get_json_num_value(node,&tmp,"pcs_yggl");
    // GET_JSON_VALUE_INT(node, "pcs_yggl", tmp);
    GET_JSON_VALUE_INT(node, "pv_pcs_yggl", tmp);
    // dbg_syslog(LOG_INFO, "abs tmp:%d:max: %d min: %d\r\n", abs(tmp), P_DISCHARGE_MAX, P_DISCHARGE_MIN);
    if (tmp >= 0 && tmp < POWER_MAX_VAL)
    {
        if (tmp > P_CHARGE_MAX || tmp < P_CHARGE_MIN)
        {
            ret = E_PCSYGGLERR;
        }
        else
        {
            g_charge_mng_info.pv_pcs_yggl = tmp; // 有功功率配置
            pv_pcs_dev_yggl_set(var, tmp, PV_FLAG);
        }
    }
    else if (tmp < 0)
    {
        if (abs(tmp) > P_DISCHARGE_MAX || abs(tmp) < P_DISCHARGE_MIN)
        {
            ret = E_PCSYGGLERR;
        }
        else
        {
            g_charge_mng_info.pv_pcs_yggl = tmp;
            pv_pcs_dev_yggl_set(var, tmp, PV_FLAG);
        }
    }
    tmp = POWER_MAX_VAL;
    // ret = api_get_json_num_value(node,&tmp,"pcs_wggl"); //？无功功率范围。
    // GET_JSON_VALUE_INT(node, "pcs_wggl", tmp);
    GET_JSON_VALUE_INT(node, "pv_pcs_wggl", tmp);
    // dbg_syslog(LOG_INFO, "abs tmp:%d:max: %d min: %d\r\n", abs(tmp), P_DISCHARGE_MAX, P_DISCHARGE_MIN);
    if (tmp >= 0 && tmp < POWER_MAX_VAL)
    {
        if (tmp > P_CHARGE_MAX || tmp < P_CHARGE_MIN)
        {
            ret = E_PCSWGGLERR;
        }
        else
        {
            g_charge_mng_info.pv_pcs_wggl = tmp; //无功功率配置
            pcs_dev_wggl_set(var, tmp);
        }
    }
    else if (tmp < 0)
    {

        if (abs(tmp) > P_DISCHARGE_MAX || abs(tmp) < P_DISCHARGE_MIN)
        {
            ret = E_PCSWGGLERR;
        }
        else
        {
            g_charge_mng_info.pv_pcs_wggl = tmp;
            pcs_dev_wggl_set(var, tmp);
        }
    }
}

static int pv_pcs_penable_set(pcs_ctrl_var_t *var, cJSON *node)
{
    int tmp = 0xff;
    int ret = E_FALSE;
    GET_JSON_VALUE_INT(node, "enable", tmp);
    switch (tmp)
    {
    case E_ON:
    case E_OFF:
        pv_pcs_dev_powerenable_set(var, tmp);
        ret = E_TRUE;
        break;
    }
    if (ret == E_TRUE)
        g_charge_mng_info.PvPEnable = tmp;
    return ret;
}

static int pcs_connect_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    int ret = E_FALSE;
    // ret = api_get_json_num_value(node,&tmp,"connState");
    GET_JSON_VALUE_INT(node, "connState", tmp);
    switch (tmp)
    {
    case E_ON:
       // g_charge_mng_info.connState = tmp; // 并网操作
        // dbg_syslog(LOG_ERR, "connState:->%d", g_charge_mng_info.connState);
        // pcs_dev_close(var);
        if (g_charge_mng_info.di_flag == 1 && (g_charge_mng_info.di12 == 1 && g_charge_mng_info.di14 == 1)){ // 可并网条件
	        pcs_dev_connect_set(var);
            ret = E_TRUE;
        }
        break;
    case E_OFF:
       // g_charge_mng_info.connState = tmp; // 并网操作
        // dbg_syslog(LOG_ERR, "connState:->%d", g_charge_mng_info.connState);
        if (g_charge_mng_info.di_flag == 1 && (g_charge_mng_info.di12 == 0 || g_charge_mng_info.di14 == 0)){ // 可离网条件
            do_dev_set(var, "DO6", "DO_6", 1);
	        pcs_dev_disconect_set(var);
	        ret = E_TRUE;
        }
        break;
    }
    return ret;
}

static int bms_relay_onoff_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    int ret = E_FALSE;
    // ret = api_get_json_num_value(node,&tmp,"connState");
    GET_JSON_VALUE_INT(node, "Onoff", tmp);
    switch (tmp)
    {
    case E_ON:
        if (g_charge_mng_info.total_lev.system > E_ALARM_LEVEL1)
        {
            ret = E_ALARM_LEVLE_ERR;
        }
        else
        {
            // dbg_syslog(LOG_ERR, "bmsState:->%d", tmp);
            bms_dev_relay_on_set(var);
            ret = E_TRUE;
        }
        break;
    case E_OFF:
        // dbg_syslog(LOG_ERR, "bmsState:->%d", tmp);
        bms_dev_relay_off_set(var);
        ret = E_TRUE;
        break;
    }
    return ret;
}

static int pcs_gl_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = POWER_MAX_VAL;
    int ret = E_FALSE;
    
    GET_JSON_VALUE_INT(node, "pcs_yggl", tmp);
    if(tmp < POWER_MAX_VAL)
    {
        dbg_syslog(LOG_INFO, "abs tmp:%d:max: %d min: %d\r\n", abs(tmp), P_DISCHARGE_MAX, P_DISCHARGE_MIN);
        if (tmp >= 0 )//delete && tmp <=POWER_MAX_VAL yut
        {
            if (tmp > P_CHARGE_MAX || tmp < P_CHARGE_MIN)
            {
                ret = E_PCSYGGLERR;
            }
        }
        else if (tmp < 0)
        {
            if (abs(tmp) > P_DISCHARGE_MAX || abs(tmp) < P_DISCHARGE_MIN)
            {
                ret = E_PCSYGGLERR;
            }
        }  
        g_charge_mng_info.pcs_yggl = tmp;
        pcs_dev_yggl_set(var, tmp);
        ret = E_TRUE;
    }          
    
    tmp = POWER_MAX_VAL;
    ret = E_TRUE;
    GET_JSON_VALUE_INT(node, "pcs_wggl", tmp);
    if(tmp < POWER_MAX_VAL)
    {
        dbg_syslog(LOG_INFO, "abs tmp:%d:max: %d min: %d\r\n", abs(tmp), P_DISCHARGE_MAX, P_DISCHARGE_MIN);
        if (tmp >= 0 )//delete && tmp <=POWER_MAX_VAL yut
        {
            if (tmp > P_CHARGE_MAX || tmp < P_CHARGE_MIN)
            {
                ret = E_PCSWGGLERR;
            }
        }
        else if (tmp < 0)
        {
            if (abs(tmp) > P_DISCHARGE_MAX || abs(tmp) < P_DISCHARGE_MIN)
            {
                ret = E_PCSWGGLERR;
            }

        } 
        g_charge_mng_info.pcs_wggl = tmp;
        pcs_dev_wggl_set(var, tmp);
        ret = E_TRUE;
    }
    
    //???手动配置时下发配置值。
    return ret;
}

static int pcs_sys_config_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0;
    int ret = E_FALSE;
    // ret = api_get_json_num_value(node,&tmp,"SOCmax");
    GET_JSON_VALUE_INT(node, "SOCmax", tmp);
    if (tmp > SOC_MAX_VAL)
    {
        g_pcs_cfg_info.SOCmax = SOC_MAX_VAL;
    }
    else
    {
        g_pcs_cfg_info.SOCmax = tmp;
    }
    // ret = api_get_json_num_value(node,&tmp,"SOCmin");
    GET_JSON_VALUE_INT(node, "SOCmin", tmp);

    if (tmp > SOC_MAX_VAL)
    {
        g_pcs_cfg_info.SOCmin = SOC_MAX_VAL;
    }
    else
    {
        g_pcs_cfg_info.SOCmin = tmp;
    }

    // ret = api_get_json_num_value(node,&tmp,"demandState");
    GET_JSON_VALUE_INT(node, "demandState", tmp);
    if (tmp == 0)
    {
        g_charge_mng_info.demandState = 0;
    }
    else
    {
        g_charge_mng_info.demandState = 1;
    }
    // ret = api_get_json_num_value(node,&tmp,"K1");
    GET_JSON_VALUE_INT(node, "K1", tmp);
    if (tmp > SOC_MAX_VAL)
    {
        g_pcs_cfg_info.K1 = SOC_MAX_VAL;
    }
    else if (tmp <= 0)
    {
        return E_FALSE;
    }
    else
    {
        g_pcs_cfg_info.K1 = tmp;
    }
    GET_JSON_VALUE_INT(node, "K2", tmp);
    if (tmp > SOC_MAX_VAL)
    {
        g_pcs_cfg_info.K2 = SOC_MAX_VAL;
    }
    else if (tmp <= 0)
    {
        return E_FALSE;
    }
    else
    {
        g_pcs_cfg_info.K2 = tmp;
    }
    // ret = api_get_json_num_value(node,&tmp,"AgainstState");
    GET_JSON_VALUE_INT(node, "AgainstState", tmp);
    if (tmp == 0)
    {
        g_charge_mng_info.AgainstState = 0;
    }
    else
    {
        g_charge_mng_info.AgainstState = 1;
    }
    // ret = api_get_json_num_value(node,&tmp,"Pset");
    GET_JSON_VALUE_INT(node, "Pset", tmp);
    if (tmp > AGAINST_POWER_MAX)
    {
        g_pcs_cfg_info.Pset = AGAINST_POWER_MAX;
    }
    else if (tmp < 0)
    {
        return E_FALSE;
    }
    else
    {
        g_pcs_cfg_info.Pset = tmp;
    }
    // ret = api_get_json_num_value(node,&tmp,"Perr");
    GET_JSON_VALUE_INT(node, "Perr", tmp);
    if (tmp > AGAINST_POWER_MAX)
    {
        g_pcs_cfg_info.Perr = AGAINST_POWER_MAX;
    }
    else if (tmp < 0)
    {
        return E_FALSE;
    }
    else
    {
        g_pcs_cfg_info.Perr = tmp;
    }
    // ret = api_get_json_num_value(node,&tmp,"Pmlmax");
    GET_JSON_VALUE_INT(node, "Pmlmax", tmp);
    if (tmp > POWER_MAX_VAL)
    {
        g_pcs_cfg_info.Pmlmax = POWER_MAX_VAL;
    }
    else if (tmp < 0)
    {
        return E_FALSE;
    }
    else
    {
        g_pcs_cfg_info.Pmlmax = tmp;
    }

	GET_JSON_VALUE_INT(node, "EDD", tmp);
    if (tmp >= 0)
    {
        g_pcs_cfg_info.EDD = tmp;
    }
    else
    {
        return E_FALSE;
    }
	GET_JSON_VALUE_INT(node, "MD", tmp);
    if (tmp > 0)
    {
        g_pcs_cfg_info.MD = tmp;
    }
    else
    {
        return E_FALSE;
    }
	GET_JSON_VALUE_INT(node, "DCI", tmp);
    if (tmp > 0)
    {
        g_pcs_cfg_info.DCI = tmp;
    }
    else
    {
        return E_FALSE;
    }

    return E_TRUE;
}

#ifdef DEBUG
#define JSON_GET_NUM_PRINT(root, val, key)             \
    tmp = cJSON_GetObjectItemCaseSensitive(root, key); \
    if (cJSON_IsNumber(tmp))                           \
    {                                                  \
        printf("%s:%d\r\n", key, tmp->valueint);       \
        val = tmp->valueint;                           \
    }

#define JSON_GET_STRING_PRINT(root, val, key)          \
    tmp = cJSON_GetObjectItemCaseSensitive(root, key); \
    if (cJSON_IsString(tmp))                           \
    {                                                  \
        printf("%s:%s\r\n", key, tmp->valuestring);    \
        strcpy(val, tmp->valuestring);                 \
    }

#define JSON_GET_DUP_STRING_PRINT(root, val, key)      \
    tmp = cJSON_GetObjectItemCaseSensitive(root, key); \
    if (cJSON_IsString(tmp))                           \
    {                                                  \
        printf("%s:%s\r\n", key, tmp->valuestring);    \
        val = strdup(tmp->valuestring);                \
    }

#endif

static int pcs_content_parse(CHAR *pcontent)
{
    cJSON *root, *nodes, *node;
    cJSON *tmp = NULL;
    int node_cnt = 0, i = 0, j;
    CHAR timer[TIME_VAL_LEN] = {0};
    dbg_syslog(LOG_INFO, "content:%s", pcontent);
    root = cJSON_Parse(pcontent);
    if (!root)
    {
        dbg_syslog(LOG_ERR, "pcontent error");
        goto out;
    }
    nodes = cJSON_GetObjectItemCaseSensitive(root, TO_STRING(JSON_NAME_PLANINFO));
    if (!nodes)
    {
        dbg_syslog(LOG_ERR, "get %s failed", TO_STRING(JSON_NAME_PLANINFO));
        goto out;
    }
    node_cnt = cJSON_GetArraySize(nodes);
    // if(node_cnt > 0 ){
    //     memset(g_pcs_cfg_info.demand_table,0,sizeof(DEMAND_CHARGE_INFO_T)*MAX_DEMAND_NUMBER);
    // }
    dbg_syslog(LOG_ERR, "node_cnt:%d", node_cnt);
    for (i = 0; i < node_cnt; i++)
    {
        node = cJSON_GetArrayItem(nodes, i);
        // JSON_GET_STRING_PRINT(node,timer,TO_STRING(JSON_NAME_TIME));
        GET_JSON_VALUE_STRING(node, TO_STRING(JSON_NAME_TIME), timer);
        dbg_syslog(LOG_ERR, "timer：%s", timer);
        for (j = 0; j < MAX_DEMAND_NUMBER; j++)
        {
            if (strcmp(timer, g_pcs_cfg_info.demand_table[j].time) == 0)
            {
                // JSON_GET_STRING_PRINT(node,g_pcs_cfg_info.demand_table[i].time,TO_STRING(JSON_NAME_TIME));
                // JSON_GET_NUM_PRINT(node,g_pcs_cfg_info.demand_table[j].power,TO_STRING(JSON_NAME_POWER));
                // JSON_GET_NUM_PRINT(node,g_pcs_cfg_info.demand_table[j].price,TO_STRING(JSON_NAME_PRICE));
                // JSON_GET_NUM_PRINT(node,g_pcs_cfg_info.demand_table[j].option,TO_STRING(JSON_NAME_OPTION));
                GET_JSON_VALUE_INT(node, TO_STRING(JSON_NAME_POWER), g_pcs_cfg_info.demand_table[j].power);
                GET_JSON_VALUE_INT(node, TO_STRING(JSON_NAME_PRICE), g_pcs_cfg_info.demand_table[j].price);
                GET_JSON_VALUE_INT(node, TO_STRING(JSON_NAME_OPTION), g_pcs_cfg_info.demand_table[j].option);
                g_pcs_cfg_info.demand_table[j].flag = 1;
            }
        }
    }
out:
    if (root)
    {
        cJSON_Delete(root);
    }
}

static int pcs_charge_mode_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    CHAR *pcontent = NULL;
    int ret = E_FALSE;
    // ret = api_get_json_num_value(node,&tmp,"chargeMode");
    GET_JSON_VALUE_INT(node, "chargeMode", tmp);

    switch (tmp)
    {
    case E_CHARGE_FIXED:
    case E_CHARGE_PLAN:
    case E_CHARGE_TRACK:
        // 模式切换处理
        ret = E_TRUE;
        break;
    }
    if (ret == E_TRUE)
    {
        // g_charge_mng_info.chargeMode = tmp;

        g_pcs_cfg_info.CLCha = tmp;
    }
    // ret = api_get_json_num_value(node,&tmp,"Pcha");
    // if(ret == E_TRUE){
    GET_JSON_VALUE_INT(node, "Pcha", tmp);
    g_pcs_cfg_info.Pcha = tmp; // 是否需要保存;
    // }

    // ret = api_get_json_num_value(node,&tmp,"PDisc");
    // if(ret == E_TRUE){
    GET_JSON_VALUE_INT(node, "PDisc", tmp);
    g_pcs_cfg_info.PDisc = tmp; // 是否需要保存;
    // }
    // ret = api_get_json_num_value(node,&tmp,"DischaMode");
    // if(ret == E_TRUE){
    GET_JSON_VALUE_INT(node, "DischaMode", tmp);
    // g_charge_mng_info.DischaMode = tmp; //是否需要保存;增加保存命令------>
    g_pcs_cfg_info.CLDischa = tmp;
    // }
    // ret = api_get_json_dup_string_value(node,(void **)&pcontent,"content");
    GET_JSON_VALUE_DY_STRING(node, "content", pcontent);
    // dbg_syslog(LOG_ERR, "pcontent:%p,v:%s",pcontent,pcontent);
    if (pcontent != NULL)
    {
        pcs_content_parse(pcontent);
        free(pcontent);
    }
    return ret;
}

static int pcs_charge_ctrl_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    int ret = E_FALSE;
    // ret = api_get_json_num_value(node,&tmp,"action");
    GET_JSON_VALUE_INT(node, "action", tmp);

    switch (tmp)
    {
    case E_CHARGE_IDLE:
        pcs_dev_disconect_set(var);
        ret = E_TRUE;
        break;
    case E_CHARGE_DOING:
        pcs_dev_connect_set(var);
        ret = E_TRUE;
        break;
    case E_CHAREG_DISCH:
        pcs_dev_connect_set(var);
        ret = E_TRUE;
        break;
    }
    if (ret == E_TRUE)
    {
        g_charge_mng_info.action = tmp; // 配置动作
    }
    return ret;
}

static int energy_assign_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    int ret = E_FALSE;
    // ret = api_get_json_num_value(node,&tmp,"action");
    GET_JSON_VALUE_INT(node, "action", tmp);
    if (tmp != 0xff)
    {
        energy_assign_on_service_set(var, tmp);
        ret = E_TRUE;
    }
    return ret;
}

int ems_mode_set(int mode)
{
    dbg_syslog(LOG_WARNING, "ctrlMode original:%d,expect:%d", g_charge_mng_info.ctrlMode, mode);
    g_charge_mng_info.ctrlMode = mode;
}
void clear_pv(pcs_ctrl_var_t *var) //重置光伏值
{
    pv_pcs_dev_yggl_set(var,0,PV_FLAG);
    g_charge_mng_info.PvCurrent = 0;
}

static int pcs_mode_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    int ret = E_FALSE;
    DEMAND_CHARGE_INFO_T char_info = {};
    // ret = api_get_json_num_value(node,&tmp,"ctrlMode");
    GET_JSON_VALUE_INT(node, "ctrlMode", tmp);
    // dbg_syslog(LOG_ERR, "ctrlMode:%d,ret:%d", tmp, ret);
    switch (tmp)
    {
    case E_CTRL_MANUAL:
    case E_CTRL_AUTO:
    case E_CTRL_AUTO_DLKJ:// yut
    case E_CTRL_REMOTER:
        ret = E_TRUE;
        break;
    }
    if (ret == E_TRUE)
    {
        // if (g_charge_mng_info.ctrlMode != tmp)
        {
            // 模式切换处理。
            if (tmp == E_CTRL_MANUAL)
            {
                // dbg_syslog(LOG_ERR, "pcs_openState:%d", g_charge_mng_info.pcs_openState);
                g_charge_mng_info.ctrlMode = tmp;
                g_charge_mng_info.lastCtrlMode = E_CTRL_MANUAL; //记录下状态 在切换的时候重置状态机
                g_charge_mng_info.action = E_CHARGE_IDLE;
                pcs_dev_yggl_set(var, 0);
                pcs_dev_close(var);
                if ((g_pcs_cfg_info.PvSwitch == E_ON)||(g_pcs_cfg_info.PVmax>0)) //If pv is on, the pv value should be cleared when you switch to manual mode
                {
                    clear_pv(var);
                }
                
            }
            else if (tmp == E_CTRL_AUTO)
            {
                if (g_charge_mng_info.total_lev.system > E_ALARM_LEVEL1)
                {
                    ret = E_ALARM_LEVLE_ERR;
                }
                else
                {
                    set_alarm_status(var,SYSSTOPED,NOALARM);
                    g_charge_mng_info.ctrlMode = tmp;
                    //pcs_dev_connect_set(var);
                    g_charge_mng_info.pcs_openState=E_OFF;//yut forece to send open to energyass
                    pcs_dev_open(var);
                }
            }
            else
            {
                g_charge_mng_info.ctrlMode = tmp;
                //pcs_dev_connect_set(var);
                //pcs_dev_open(var);
            }
            // 手动自动切换处理，切换手动设置为停止状态。
        }
        pcs_dev_modesel_set_ems(var, tmp);
        pcs_config_save();
    }
    dbg_syslog(LOG_NOTICE, "set ctrlMode:%d", g_charge_mng_info.ctrlMode);
    return ret;
}

static int pcs_powert_test_set(pcs_ctrl_var_t *var, cJSON *node)
{
    WORD tmp = 0xff;
    // api_get_json_num_value(node,&tmp,"p1");
    GET_JSON_VALUE_INT(node, "p1", tmp);
    g_charge_mng_info.P1 = tmp;
    // api_get_json_num_value(node,&tmp,"p3");
    GET_JSON_VALUE_INT(node, "p3", tmp);
    g_charge_mng_info.P3 = tmp;
    // api_get_json_num_value(node,&tmp,"soc");
    GET_JSON_VALUE_INT(node, "soc", tmp);
    g_charge_mng_info.soc = tmp;
    // api_get_json_num_value(node,&tmp,"pcserr");
    GET_JSON_VALUE_INT(node, "pcserr", tmp);
    g_charge_mng_info.pcserr = tmp;
    // api_get_json_num_value(node,&tmp,"bmserr");
    GET_JSON_VALUE_INT(node, "bmserr", tmp);
    g_charge_mng_info.bmserr = tmp;
    return E_TRUE;
}

#define TOPIC_START_PACK(devsn, identifier)                      \
    CHAR topic[TOPIC_MAX_LEN] = {0};                             \
    cJSON *root, *sub;                                           \
    CHAR *out;                                                   \
    WORD bus_addr_index = 0;                                     \
    DWORD now = time(NULL);                                      \
    root = cJSON_CreateObject();                                 \
    if (root != NULL)                                            \
    {                                                            \
        cJSON_AddNumberToObject(root, "mi", var->servInfo.mi);   \
        cJSON_AddNumberToObject(root, "timestamp", now);         \
        cJSON_AddStringToObject(root, "identifier", identifier); \
        cJSON_AddStringToObject(root, "sn", devsn);              \
        sub = cJSON_CreateObject();                              \
        cJSON_AddItemToObject(root, "tags", sub);

#define TOPIC_END_PACK(devsn, cmd)                                                                                           \
    out = cJSON_Print(root);                                                                                                 \
    cJSON_Delete(root);                                                                                                      \
    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data_filtered/service/%s", var->sn_str, "NULL", devsn, cmd); \
    ipc_session_publish(var->session, topic, out, strlen(out));                                                              \
    free(out);                                                                                                               \
    }
static int publish_log_report_up(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, "log_info");
    cJSON_AddNumberToObject(sub, "P1", g_charge_mng_info.P1);
    cJSON_AddNumberToObject(sub, "runstate", g_charge_mng_info.action);
    if(g_charge_mng_info.action==1)
    {
        cJSON_AddNumberToObject(sub, "P2", g_charge_mng_info.currentCharPower);
    }
    if(g_charge_mng_info.action==2)
    {
        cJSON_AddNumberToObject(sub, "P2", g_charge_mng_info.currentDischaPower);
    }
    cJSON_AddNumberToObject(sub, "P3", g_charge_mng_info.P3);   
    TOPIC_END_PACK(var->vir_sn_str, "log_info");
}
static int publish_report_up(pcs_ctrl_var_t *var, CHAR *pInfo)
{
    TOPIC_START_PACK(var->vir_sn_str, "report_info");
    cJSON_AddStringToObject(sub, "info", pInfo);
    cJSON_AddNumberToObject(sub, "result", 0);
    TOPIC_END_PACK(var->vir_sn_str, "report_info");
}

static int publish_dynamic_demand(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, "demand_info");
    cJSON_AddNumberToObject(sub, "TAG_X001", g_pcs_cfg_info.Dylmax);
    TOPIC_END_PACK(var->vir_sn_str, "demand_info");
}

int report_option(pcs_ctrl_var_t *var, CHAR *pInfo, ...)
{
    va_list arg_list;
    CHAR arg_buffer[LOG_BUFFER_SIZE] = {0};
    if (var == NULL || pInfo == NULL)
    {
        dbg_syslog(LOG_INFO, "topic:var:%p,pInfo:%p", var, pInfo);
        return -1;
    }
    dbg_syslog(LOG_WARNING, "%s",pInfo);
    va_start(arg_list, pInfo);
    memset(arg_buffer, 0, LOG_BUFFER_SIZE);
    vsnprintf(arg_buffer, LOG_BUFFER_SIZE - 1, pInfo, arg_list);
    va_end(arg_list);
    publish_report_up(var, arg_buffer);
    return 0;
}

void publish_alarm_up(pcs_ctrl_var_t *var,char * dev_alarm_string, ALARM_TYPE type,ALARM_STATUS status)  //上报弹窗报警
{
    static ALARM_STATUS alarm_status_last[ALARM_TYPE_MAX] = {INIT_STA};
    if(status == alarm_status_last[type])return;
    alarm_status_last[type] = status;
    dbg_syslog(LOG_WARNING, "ALARM:%s value:%d",dev_alarm_string,status);
    TOPIC_START_PACK(var->vir_sn_str, "alarmList");
    cJSON_AddNumberToObject(sub, dev_alarm_string, status);
    TOPIC_END_PACK(var->vir_sn_str, "alarmList");
}


static void pcs_set_replay(pcs_ctrl_var_t *var, int ret)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "result", ret);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
    // ipc/21881200003A/+/device/+/data/Set_Rglt
}


static int ems_some_state_save()
{
    if (g_pcs_cfg_info.savestate == 0)return E_TRUE;
    cJSON *root, *subs, *sub;
    int i;
    char *string = NULL;
    root = cJSON_CreateObject();
    if (root == NULL)
    {
        dbg_syslog(LOG_ERR, "cJSON_CreateObject root NULL");
        return E_MALLOC_ERR;
    }
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_RUNSTATE ), g_charge_mng_info.runState);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_CONNSTATE), g_charge_mng_info.connState);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_YGGL     ), g_charge_mng_info.pcs_yggl);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_WGGL     ), g_charge_mng_info.pcs_wggl);

    string = cJSON_Print(root);
    if (string != NULL)
    {
        write_file_data(EMS_SOME_STATE_CFG_FILE, string, strlen(string));
        free(string);
    }

end:
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
}

static int pcs_config_save()
{
    cJSON *root, *subs, *sub;
    int i;
    char *string = NULL;
    root = cJSON_CreateObject();
    if (root == NULL)
    {
        dbg_syslog(LOG_ERR, "cJSON_CreateObject root NULL");
        return E_MALLOC_ERR;
    }
    g_pcs_cfg_info.runState = g_charge_mng_info.ctrlMode;
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_CLHA), g_pcs_cfg_info.CLCha);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_CLDISCHA), g_pcs_cfg_info.CLDischa);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PMLMAX), g_pcs_cfg_info.Pmlmax);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_DYLMAX), g_pcs_cfg_info.Dylmax);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_EDD), g_pcs_cfg_info.EDD);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_MD), g_pcs_cfg_info.MD);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_DCI), g_pcs_cfg_info.DCI);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_K1), g_pcs_cfg_info.K1);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_K2), g_pcs_cfg_info.K2);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SOCMAX), g_pcs_cfg_info.SOCmax);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SOCMIN), g_pcs_cfg_info.SOCmin);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PSET), g_pcs_cfg_info.Pset);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PERR), g_pcs_cfg_info.Perr);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PVMAX), g_pcs_cfg_info.PVmax);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PCSMAX), g_pcs_cfg_info.PCSmax);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PCHA), g_pcs_cfg_info.Pcha);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PCHAMAX), g_pcs_cfg_info.PchaMax);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PCHAMIN), g_pcs_cfg_info.PchaMin);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PDISC), g_pcs_cfg_info.PDisc);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PDISCMAX), g_pcs_cfg_info.PDiscMax);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PDISCMIN), g_pcs_cfg_info.PDiscMin);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_ADJSTEP), g_pcs_cfg_info.Adjstep);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_ADJPRERIOD), g_pcs_cfg_info.Adjpreriod);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SLIPTIME), g_pcs_cfg_info.Sliptime);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_LOADGRIDMETERSHARE), g_pcs_cfg_info.loadgridmetershare);
    cJSON_AddStringToObject(root, TO_STRING(JSON_NAME_UPGRADE_PLAN_ONEDAY), g_pcs_cfg_info.DayUPgradeTime);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SOCDRT), g_pcs_cfg_info.SOCdrt);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_RUN_STATE), g_pcs_cfg_info.runState);

    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_KM), g_pcs_cfg_info.KM);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SAVESTATE), g_pcs_cfg_info.savestate);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PVSWITCH), g_pcs_cfg_info.PvSwitch);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SOCTHRESHOLD), g_pcs_cfg_info.socThreshold);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_FORBIDDEN), g_pcs_cfg_info.forbidden);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_MAXSUPPLEMENT_P), g_pcs_cfg_info.MAXSupplementP);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_P1_MARGIN), g_pcs_cfg_info.p1Margin);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_PV_MAX_POWER), g_pcs_cfg_info.pvMaxPower);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_AIRCOND_SET_TIMEOUT_BEFORE), g_pcs_cfg_info.aircond_set_timeout_before);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_AIRCOND_SET_TIMEOUT_AFTER), g_pcs_cfg_info.aircond_set_timeout_after);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SINGLEMAX), g_pcs_cfg_info.singlemax);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_SINGLEMIN), g_pcs_cfg_info.singlemin);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_DEV_ONLINE_TIMEOUT), g_pcs_cfg_info.dev_online_timeout);
    cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_MANUAL_FLAG), g_pcs_cfg_info.manual_flag);
	cJSON_AddNumberToObject(root, TO_STRING(JSON_NAME_DEV_METER_FLAG), g_pcs_cfg_info.meter_flag);
	
    subs = cJSON_CreateArray();
    if (subs == NULL)
    {
        goto end;
    }
    cJSON_AddItemToObject(root, TO_STRING(JSON_NAME_PLANINFO), subs);
    for (i = 0; i < MAX_DEMAND_NUMBER; i++)
    {
        sub = cJSON_CreateObject();
        cJSON_AddStringToObject(sub, TO_STRING(JSON_NAME_TIME), g_pcs_cfg_info.demand_table[i].time);
        cJSON_AddNumberToObject(sub, TO_STRING(JSON_NAME_POWER), g_pcs_cfg_info.demand_table[i].power);
        cJSON_AddNumberToObject(sub, TO_STRING(JSON_NAME_PRICE), g_pcs_cfg_info.demand_table[i].price);
        cJSON_AddNumberToObject(sub, TO_STRING(JSON_NAME_PRICE), g_pcs_cfg_info.demand_table[i].option);
        cJSON_AddItemToArray(subs, sub);
    }
    string = cJSON_Print(root);
    if (string != NULL)
    {
        write_file_data(EMS_CFG_SAVE_FILE, string, strlen(string));
        free(string);
    }

end:
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
}

extern int upgrade_pcs_plan_cfg(STRATEGY_MNG_T *pstrategymng, cJSON *root);

static int pcs_upgrade_plan_set(pcs_ctrl_var_t *var, cJSON *node)
{
    CHAR *pcontent = NULL;
    cJSON *root = NULL;
    GET_JSON_VALUE_DY_STRING(node, "content", pcontent);
    if (pcontent == NULL)
    {
        return E_PLANINFO_ERR;
    }
    node = cJSON_Parse(pcontent);
    if (!node)
    {
        dbg_syslog(LOG_ERR, "pcontent error");

        return E_PLANINFO_ERR;
    }
    if (0 == upgrade_pcs_plan_cfg(&g_strategr_mng_info, node))
    {
        char *string = NULL;
        string = cJSON_Print(node);
        if (string != NULL)
        {
            write_file_data(EMS_CFG_PLAN_FILE, string, strlen(string));
            free(string);
        }
        g_strategr_mng_info.initflag = 0;
        update_plan_cfg(var);
        return E_TRUE;
    }
    else
    {
        return E_PLANINFO_ERR;
    }
}

static int pcs_set_process(void *obj, mqtt_message_t *mqtt_msg, cJSON *node)
{
    // mqtt_msg->payload
    // cJSON *node = NULL;
    int ret = E_FALSE;
    int found = 1;
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)obj;

    if (0 == strcmp(var->servInfo.identifier, PROXY_SET)) {
        ret = handle_proxy_mode(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, STRUCTURE_SET))
    {
        ret = pcs_devs_structure_set(var, node);
    }
    // dbg_syslog(LOG_INFO, "pcs_set:%s", var->servInfo.identifier);
    else if (0 == strcmp(var->servInfo.identifier, PCS_OPEN_CMD_SET))   //开关机控制
    {
        if (g_charge_mng_info.ctrlMode != E_CTRL_AUTO)
        {
            ret = pcs_open_set(var, node);
            ems_some_state_save();
        }
        else
        {

            ret = E_RUNSTATE_ERR;
        }
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_CONNECT_CMD_SET))  //并离网操作
    {
        if (g_charge_mng_info.ctrlMode != E_CTRL_AUTO)
        {
            ret = pcs_connect_set(var, node);
            ems_some_state_save();
        }
        else
        {
            ret = E_RUNSTATE_ERR;
        }
    }
#ifdef KB_EMS_CTRL
    else if (0 == strcmp(var->servInfo.identifier, BMS_RELAY_ONOFF))  //bms继电器控制
    {
        if (g_charge_mng_info.ctrlMode != E_CTRL_AUTO)
        {
            ret = bms_relay_onoff_set(var, node);
        }
        else
        {
            ret = E_RUNSTATE_ERR;
        }
    }
#endif
    else if (0 == strcmp(var->servInfo.identifier, PCS_GL_CMD_SET))   //pcs功率设置
    {
        if (g_charge_mng_info.ctrlMode != E_CTRL_AUTO)
        {
            ret = pcs_gl_set(var, node);
            ems_some_state_save();
        }
        else
        {
            ret = E_RUNSTATE_ERR;
        }
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_CHARGE_MODE_CMD_SET)) //当前的充放电模式和计划模式的计划列表（不知道用途）
    {
        ret = pcs_charge_mode_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_SYS_CONFIG_CMD_SET))  //策略参数
    {
        ret = pcs_sys_config_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_MODE_SEL_SET))  //手动 自动模式设置
    {
        ret = pcs_mode_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_CONFIG_SAVE))  //保存一次配置文件
    {
        ret = pcs_config_save();
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_STRATEGY_TEMPLATE))  //计划设置
    {
        // pthread_rwlock_unlock(&var->topic_lock);
        ret = pcs_upgrade_plan_set(var, node);
        // pthread_rwlock_wrlock(&var->topic_lock);
    }
    else if (0 == strcmp(var->servInfo.identifier, LINKAGE_SET))
    {
        // dbg_syslog(LOG_INFO, "pcs_set:%s", var->servInfo.identifier);
        ret = linkage_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PV_PCS_OPEN_CMD_SET)) //光伏开关机控制
    {
        ret = pv_pcs_open_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PV_PCS_GL_CMD_SET)) //写光伏功率
    {
        ret = pv_pcs_gl_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PV_PCS_PENABLE_CMS_SET)) //光伏控制使能（和快卜的光伏开关不太一样  这个实际控制光伏开关  快卜的那部分是软件是否使能）
    {
        ret = pv_pcs_penable_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, TOPIC_PCS_RUN_MODE_SET))
    {
    
    }
    else if (0 == strcmp(var->servInfo.identifier, ENGERGY_ASSIGN_SERVICE_SET))  //没用
    {
        ret = energy_assign_set(var, node);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_RESET))  //pcs复位
    {
        ret = pcs_reset(var, node);
    }
    else
    {
        found = 0;
        ret = E_IDEENTIFIER_ERR;
    }
    if (0 == strcmp(var->servInfo.identifier, PCS_POWER_TEST_SET))
    {
        ret = pcs_powert_test_set(var, node);
    }

    // pthread_rwlock_unlock(&var->topic_lock);
    if (found == 1)
        pcs_set_replay(var, ret);
    return found;
}

static void pcs_open_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    dbg_syslog(LOG_INFO, "runState:->%d", g_charge_mng_info.runState);
    cJSON_AddNumberToObject(sub, "runState", g_charge_mng_info.runState);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pcs_open_get_report(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, PCS_OPEN_CMD_GET);
    dbg_syslog(LOG_INFO, "report runState:->%d", g_charge_mng_info.runState);
    cJSON_AddNumberToObject(sub, "runState", g_charge_mng_info.runState);
    TOPIC_END_PACK(var->vir_sn_str, PCS_OPEN_CMD_GET);
}


static void pcs_connect_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "connState", g_charge_mng_info.connState);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
    dbg_syslog(LOG_INFO, "connState:->%d", g_charge_mng_info.connState);
}

static void pcs_connect_get_report(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, PCS_CONNECT_CMD_GET);
    cJSON_AddNumberToObject(sub, "connState", g_charge_mng_info.connState);
    TOPIC_END_PACK(var->vir_sn_str, PCS_CONNECT_CMD_GET);
    dbg_syslog(LOG_INFO, "connState:->%d", g_charge_mng_info.connState);
}

static void pcs_gl_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "pcs_yggl", g_charge_mng_info.pcs_yggl);
    cJSON_AddNumberToObject(sub, "pcs_wggl", g_charge_mng_info.pcs_wggl);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pcs_sys_config_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "SOCmax", g_pcs_cfg_info.SOCmax);
    cJSON_AddNumberToObject(sub, "SOCmin", g_pcs_cfg_info.SOCmin);
    cJSON_AddNumberToObject(sub, "demandState", g_charge_mng_info.demandState);
    cJSON_AddNumberToObject(sub, "K1", g_pcs_cfg_info.K1);
    cJSON_AddNumberToObject(sub, "K2", g_pcs_cfg_info.K2);
    cJSON_AddNumberToObject(sub, "AgainstState", g_charge_mng_info.AgainstState);
    cJSON_AddNumberToObject(sub, "Pset", g_pcs_cfg_info.Pset);
    cJSON_AddNumberToObject(sub, "Perr", g_pcs_cfg_info.Perr);
    cJSON_AddNumberToObject(sub, "Pmlmax", g_pcs_cfg_info.Pmlmax);
	cJSON_AddNumberToObject(sub, "Dylmax", g_pcs_cfg_info.Dylmax);
	cJSON_AddNumberToObject(sub, "EDD", g_pcs_cfg_info.EDD);
	cJSON_AddNumberToObject(sub, "MD", g_pcs_cfg_info.MD);
	cJSON_AddNumberToObject(sub, "DCI", g_pcs_cfg_info.DCI);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static CHAR *pcs_get_Plan_info()
{
    int i;
    cJSON *root, *sub, *info;
    CHAR *out;
    root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "root null----->");
        return NULL;
    }
    sub = cJSON_CreateArray();
    if (sub == NULL)
    {
        dbg_syslog(LOG_ERR, "sub null----->");
        return NULL;
    }
    cJSON_AddItemToObject(root, "PlanInfo", sub);
    for (i = 0; i < MAX_DEMAND_NUMBER; i++)
    {
        // if (g_pcs_cfg_info.demand_table[i].flag)
        // {
        info = cJSON_CreateObject();

        if (sub == NULL)
        {
            dbg_syslog(LOG_ERR, "info null----->");
            break;
        }
        cJSON_AddItemToArray(sub, info);
        cJSON_AddStringToObject(info, "time", g_pcs_cfg_info.demand_table[i].time);
        cJSON_AddNumberToObject(info, "power", g_pcs_cfg_info.demand_table[i].power);
        cJSON_AddNumberToObject(info, "price", g_pcs_cfg_info.demand_table[i].price);
        cJSON_AddNumberToObject(info, "option", g_pcs_cfg_info.demand_table[i].option);
        // }
    }
    out = cJSON_Print(root);
    cJSON_Delete(root);
    return out;
}

static void pcs_charge_mode_get(pcs_ctrl_var_t *var)
{
    CHAR *PlanInfo = NULL;
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "chargeMode", g_pcs_cfg_info.CLCha);
    cJSON_AddNumberToObject(sub, "Pcha", g_pcs_cfg_info.Pcha);
    cJSON_AddNumberToObject(sub, "PDisc", g_pcs_cfg_info.PDisc);
    cJSON_AddNumberToObject(sub, "DischaMode", g_pcs_cfg_info.CLDischa);
    PlanInfo = pcs_get_Plan_info();
    if (NULL == PlanInfo)
    {
        cJSON_AddStringToObject(sub, "content", "[]");
    }
    else
    {
        cJSON_AddStringToObject(sub, "content", PlanInfo);
        // printf("%s", PlanInfo);
        free(PlanInfo);
    }
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pcs_charge_ctrl_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "action", g_charge_mng_info.action);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pcs_mode_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "ctrlMode", g_charge_mng_info.ctrlMode);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pv_pcs_open_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    dbg_syslog(LOG_INFO, "runState:->%d", g_charge_mng_info.PVrunState);
    cJSON_AddNumberToObject(sub, "runState", g_charge_mng_info.PVrunState);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pv_pcs_penable_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "enable", g_charge_mng_info.PvPEnable);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static void pv_pcs_gl_get(pcs_ctrl_var_t *var)
{
    TOPIC_START_PACK(var->vir_sn_str, var->servInfo.identifier);
    cJSON_AddNumberToObject(sub, "pcs_yggl", g_charge_mng_info.pv_pcs_yggl);
    cJSON_AddNumberToObject(sub, "pcs_wggl", g_charge_mng_info.pv_pcs_wggl);
    TOPIC_END_PACK(var->vir_sn_str, var->servInfo.identifier);
}

static int pcs_get_process(void *obj, mqtt_message_t *mqtt_msg, cJSON *node)
{
    // cJSON *node = NULL;
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)obj;
    // node = api_get_json_node(mqtt_msg->payload);
    // node = cJSON_Parse(mqtt_msg->payload);
    if (!node)
    {
        return E_FALSE;
    }
    if (0 == strcmp(var->servInfo.identifier, PCS_OPEN_CMD_GET))
    {
        pcs_open_get(var);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_CONNECT_CMD_GET))
    {
        pcs_connect_get(var);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_GL_CMD_GET))
    {

        pcs_gl_get(var);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_SYS_CONFIG_CMD_GET))
    {
        pcs_sys_config_get(var);
    }
    else if (0 == strcmp(var->servInfo.identifier, PCS_CHARGE_MODE_CMD_GET))
    {
        pcs_charge_mode_get(var);
    }
    // else if (0 == strcmp(var->servInfo.identifier, PCS_CHARGE_CTRL_CMD_GET))
    // {
    //     pcs_charge_ctrl_get(var);
    // }
    else if (0 == strcmp(var->servInfo.identifier, PCS_MODE_SEL_GET))
    {
        pcs_mode_get(var);
    }
    else if (0 == strcmp(var->servInfo.identifier, PV_PCS_OPEN_CMD_GET))
    {

        pv_pcs_open_get(var);
    }
    else if (0 == strcmp(var->servInfo.identifier, PV_PCS_GL_CMD_GET))
    {
        pv_pcs_gl_get(var); 
    }
    else if (0 == strcmp(var->servInfo.identifier, PV_PCS_PENABLE_CMS_GET))
    {
        pv_pcs_penable_get(var); 
    }
    else if (0 == strcmp(var->servInfo.identifier, TOPIC_PCS_RUN_MODE_GET))
    {
    }
    else
    {
        pcs_set_replay(var, E_IDEENTIFIER_ERR);
    }
    // pthread_rwlock_unlock(&var->topic_lock);
    // cJSON_Delete(node);
    return E_TRUE;
}

static int pcs_ctrl_mqtt_handle_recv_msg(void *obj, ipc_msg_t *mqtt_msg)
{ 
    int i, j;
    int tmp = 0;
    double tmp1 = -1;
    cJSON *node = NULL;
    cJSON *sub = NULL;
    CHAR *tagNode = NULL;
	cJSON *tags = NULL;
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)obj;
    // dbg_syslog(LOG_INFO, "%s", mqtt_msg->topic);
    if (strstr(mqtt_msg->topic, "data/service") || strstr(mqtt_msg->topic, "_GUARD/service") || strstr(mqtt_msg->topic, "_DI/service"))
    {
        // node = api_get_json_node(mqtt_msg->payload);
        // goto out;
        node = cJSON_Parse(mqtt_msg->payload);
        if (!node)
        {
            dbg_syslog(LOG_ERR, "get node: %s error", mqtt_msg->topic);
            return 0;
        }
        GET_JSON_VALUE_INT(node, "mi", var->devservInfo.mi);
        GET_JSON_VALUE_INT(node, "timestamp", var->devservInfo.timestamp);
        memset(var->devservInfo.identifier,0,sizeof(var->devservInfo.identifier));
        GET_JSON_VALUE_STRING(node, "identifier", var->devservInfo.identifier);
        GET_JSON_VALUE_STRING(node, "sn", var->devservInfo.devSn);
		
		tags = cJSON_GetObjectItem(node, "tags");
		if(tags)
		{
			if (strcmp(var->devservInfo.identifier, "fault_level_report") == 0)
			{
				cJSON *grps_level_item = cJSON_GetObjectItem(tags, "grps_fault_level");
				
				if (strstr(var->devservInfo.devSn, "_GUARD"))	//错误等级 来自于guard模块
				{
					for (i = 0; grps_level_item && i < var->guard_grp_num; i++)
					{
						if (strstr(var->devservInfo.devSn, var->grp[i].belong_gw))
						{
							GET_JSON_VALUE_INT(tags, "fault_level", g_charge_mng_info.total_lev.guard);
							cJSON *item = cJSON_GetArrayItem(grps_level_item, 0);
							GET_JSON_VALUE_INT(item, "level", g_charge_mng_info.grps_lev[i].guard);
						#if 1
							dbg_syslog(LOG_NOTICE, "GUARD[%d]:%s", i, var->devservInfo.devSn);
							dbg_syslog(LOG_NOTICE, "total_fault_level:%d", g_charge_mng_info.total_lev.guard);
							dbg_syslog(LOG_NOTICE, "group_fault_level:%d", g_charge_mng_info.grps_lev[i].guard);
						#endif
							break;
						}
					}
				}
			
				// 计算系统报警，取各个系统最大值
				int level = 0;
				level = MAX(g_charge_mng_info.total_lev.eng_ass, g_charge_mng_info.total_lev.guard);
				if (g_charge_mng_info.total_lev.system != level)
				{
					g_charge_mng_info.lev_changed = true;
					g_charge_mng_info.total_lev.system = level;
				}
				for (i = 0; grps_level_item && i < var->guard_grp_num; i++)
				{
					level = MAX(g_charge_mng_info.grps_lev[i].eng_ass, g_charge_mng_info.grps_lev[i].guard);
					if (g_charge_mng_info.grps_lev[i].system != level)
					{
						g_charge_mng_info.lev_changed = true;
						g_charge_mng_info.grps_lev[i].system = level;
					}
				}
		   }
            else if(strcmp(var->devservInfo.identifier, "aircond_set_timeout_by_min")==0)
            {
                int timeout = -1;
                int timeout_after = -1;
                GET_JSON_VALUE_INT(sub, "aircond_set_timeout_before", timeout);
                GET_JSON_VALUE_INT(sub, "aircond_set_timeout_after", timeout_after);
                if (timeout >= 0 && timeout_after >= 0)
                {
                    g_pcs_cfg_info.aircond_set_timeout_before = timeout;
                    g_pcs_cfg_info.aircond_set_timeout_after = timeout_after;
                }
                dbg_syslog(LOG_NOTICE, "aircond_set_timeout:%d  after:%d", g_pcs_cfg_info.aircond_set_timeout_before,g_pcs_cfg_info.aircond_set_timeout_after);
                pcs_config_save();
            }
			else if(strcmp(var->devservInfo.identifier, "report_info") == 0)
			{
				cJSON *gw_sn_item = cJSON_GetObjectItem(node, "gw_sn");
				if (gw_sn_item != NULL) {
					cJSON_ReplaceItemInObject(node, "gw_sn", cJSON_CreateString(var->sn_str));
				}
				cJSON *sn_item = cJSON_GetObjectItem(node, "sn");
				if (sn_item != NULL) {
					cJSON_ReplaceItemInObject(node, "sn", cJSON_CreateString(var->vir_sn_str));
				}

				char *json_str = cJSON_Print(node);
				CHAR topic[TOPIC_MAX_LEN] = {0};
				snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data_filtered/service/%s", var->sn_str, "NULL", var->vir_sn_str, var->devservInfo.identifier);
				ipc_session_publish(var->session, topic, json_str, strlen(json_str));	
				
				free(json_str); 
			}
			else if(strcmp(var->devservInfo.identifier, "DIRead") == 0)
			{
                int di12 = -1;
                int di14 = -1;
                GET_JSON_VALUE_INT(sub, "DI12", di12);
                GET_JSON_VALUE_INT(sub, "DI14", di14);
                if (di12 >= 0 && di14 >= 0)
                {
                    g_charge_mng_info.di12 = di12;
                    g_charge_mng_info.di14 = di14;
                }
				g_charge_mng_info.di_flag = 1;
			}
	    }
		
        GET_JSON_VALUE_DY_STRING(node, "tag_node", tagNode);
        if (tagNode)
        {
            sub = cJSON_Parse(tagNode);
            if (sub)
            {
                if (strcmp(var->devservInfo.identifier, "fault_level_report") == 0)
                {
                    cJSON *grps_level_item = cJSON_GetObjectItem(sub, "grps_fault_level");

                    if (strcmp(var->devservInfo.devSn, var->energyAssignSn) == 0)  //错误等级 来自于energyAssignSn  
                    {
                        GET_JSON_VALUE_INT(sub, "fault_level", g_charge_mng_info.total_lev.eng_ass);
                        if (var->pcs_grp_num != var->guard_grp_num)
                        {
                            int eng_ass_pcs_max_level[GRP_NUM_MAX] = {0};
                            for (i = 0; grps_level_item && i < var->pcs_grp_num; i++)
                            {
                                cJSON *item = cJSON_GetArrayItem(grps_level_item, i);
                                GET_JSON_VALUE_INT(item, "level", g_charge_mng_info.grps_lev_eng[i].eng_ass);
                                eng_ass_pcs_max_level[g_charge_mng_info.grps_lev_eng[i].eng_ass_pcs_grp] = MAX(eng_ass_pcs_max_level[g_charge_mng_info.grps_lev_eng[i].eng_ass_pcs_grp],g_charge_mng_info.grps_lev_eng[i].eng_ass);
                            }
                            for (i = 0; grps_level_item && i < var->guard_grp_num; i++)
                            {
                                g_charge_mng_info.grps_lev[i].eng_ass = eng_ass_pcs_max_level[i];
                            }
                        }
                        else
                        {
                            for (i = 0; grps_level_item && i < var->guard_grp_num; i++)
                            {
                                cJSON *item = cJSON_GetArrayItem(grps_level_item, i);
                                GET_JSON_VALUE_INT(item, "level", g_charge_mng_info.grps_lev[i].eng_ass);
                            }
                        }
                    }

                    // 计算系统报警，取各个系统最大值
                    int level = 0;
                    level = MAX(g_charge_mng_info.total_lev.eng_ass, g_charge_mng_info.total_lev.guard);
                    if (g_charge_mng_info.total_lev.system != level)
                    {
                        g_charge_mng_info.lev_changed = true;
                        g_charge_mng_info.total_lev.system = level;
                    }
                    for (i = 0; grps_level_item && i < var->guard_grp_num; i++)
                    {
                        level = MAX(g_charge_mng_info.grps_lev[i].eng_ass, g_charge_mng_info.grps_lev[i].guard);
                        if (g_charge_mng_info.grps_lev[i].system != level)
                        {
                            g_charge_mng_info.lev_changed = true;
                            g_charge_mng_info.grps_lev[i].system = level;
                        }
                        for (j = 0; grps_level_item && j < var->pcs_grp_num; j++)
                        {
                            if ((i == g_charge_mng_info.grps_lev_eng[j].eng_ass_pcs_grp) && (g_charge_mng_info.grps_lev_eng[j].system != level))
                            {
                                g_charge_mng_info.grps_lev_eng[j].system = level;//原始组的system更新，方便后面下发
                            }
                        }
                    }

                }
                else if(strcmp(var->devservInfo.identifier, "system_status")==0)
                {
                    int soc = -1;
                    tmp1 = -1;
                    GET_JSON_VALUE_INT(sub, "bms_soc", soc);
                    float soc_f = soc;
                    if (soc >= 0)
                    {
                        g_charge_mng_info.soc = soc_f / 10 ;
                    }

                    //dbg_syslog(LOG_INFO, "g_charge_mng_info.soc:%f,%d ",g_charge_mng_info.soc,soc);
                    int tmp_t = -1;
                    GET_JSON_VALUE_INT(sub, "fully_charged",tmp_t);
                    if(tmp_t>0)
                     g_charge_mng_info.chFull = tmp_t;
                    //dbg_syslog(LOG_INFO, "g_charge_mng_info.chFull:%d ,%d ",g_charge_mng_info.chFull,tmp_t);

                    tmp_t = -1;
                    GET_JSON_VALUE_INT(sub, "empty_discharge",tmp_t);
                    if(tmp_t>0)
                    g_charge_mng_info.dischNull = tmp_t;
                    //dbg_syslog(LOG_INFO, "g_charge_mng_info.dischNul:%d ,%d ",g_charge_mng_info.dischNull,tmp_t);   

                    //GET_JSON_VALUE_DOUBLE(sub, "pv_power", g_charge_mng_info.Pv);
                    //dbg_syslog(LOG_INFO, "g_charge_mng_info.Pv:%f ",g_charge_mng_info.Pv);   
                    //time(&g_charge_mng_info.update_time.Pv);
                }
				else if(strcmp(var->devservInfo.identifier, "dynamic_demand_report")==0)
                {
                    USHORT demand = -1;
                    GET_JSON_VALUE_INT(sub, "up_demand", demand);
                    if (demand >= 0)
                        g_pcs_cfg_info.Dylmax = demand;
				    dbg_syslog(LOG_INFO, "receive dynamic demand value:%d", g_pcs_cfg_info.Dylmax);
					pcs_config_save();
                }
                else if(strcmp(var->devservInfo.identifier, "aircond_set_timeout_by_min")==0)
                {
                    int timeout = -1;
                    int timeout_after = -1;
                    GET_JSON_VALUE_INT(sub, "aircond_set_timeout_before", timeout);
                    GET_JSON_VALUE_INT(sub, "aircond_set_timeout_after", timeout_after);
                    if (timeout >= 0 && timeout_after >= 0)
                    {
                        g_pcs_cfg_info.aircond_set_timeout_before = timeout;
                        g_pcs_cfg_info.aircond_set_timeout_after = timeout_after;
                    }
                    dbg_syslog(LOG_NOTICE, "aircond_set_timeout:%d  after:%d", g_pcs_cfg_info.aircond_set_timeout_before,g_pcs_cfg_info.aircond_set_timeout_after);
                    pcs_config_save();
                }
				else if((strcmp(var->devservInfo.identifier, "report_info") == 0) || (strcmp(var->devservInfo.identifier, "alarmList") == 0))
				{
					cJSON *sn_item = cJSON_GetObjectItem(node, "sn");
					if (sn_item != NULL) {
						cJSON_ReplaceItemInObject(node, "sn", cJSON_CreateString(var->vir_sn_str));
					}
					
					char *json_str = cJSON_Print(node);
					CHAR topic[TOPIC_MAX_LEN] = {0};
					snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data_filtered/service/%s", var->sn_str, "NULL", var->vir_sn_str, var->devservInfo.identifier);
					ipc_session_publish(var->session, topic, json_str, strlen(json_str));	
					
					free(json_str); 
				}
                else
                {
                    for (i = 0; i < var->devnodeinfo.cont; i++)
                    {
                        if (strcmp(var->devservInfo.identifier, var->devnodeinfo.pdevnodecfg[i].identifier) == 0)
                        {
                            if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "soc") == 0)
                            {
                                // api_get_json_num_value(sub,&tmp,"soc");
                                int soc = -1;
                                tmp1 = -1;
                                GET_JSON_VALUE_DOUBLE(sub, "soc", tmp1);
                                GET_JSON_VALUE_INT(sub, "bms_soc", soc);
                                if (tmp1 >= 0)
                                {
                                    g_charge_mng_info.soc = tmp1 / 10;
                                }
                                else if (soc >= 0)
                                {
                                    g_charge_mng_info.soc = soc / 10;
                                }
                                // dbg_syslog(LOG_INFO, "soc:%f ", g_charge_mng_info.soc);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "p1") == 0)
                            {
                                pthread_mutex_lock(&g_charge_mng_info.dynamic_demand.demand_lock);
                                // api_get_json_num_value(sub,&tmp,"p1");
                                // GET_JSON_VALUE_INT(sub, "p1", tmp);
                                GET_JSON_VALUE_DOUBLE(sub, "p1", tmp1);
                                g_charge_mng_info.P1 = tmp1;
                                time(&g_charge_mng_info.update_time.P1);
								g_charge_mng_info.multi_meter_flag = 1;
								dbg_syslog(LOG_INFO, "ems_ctrl mqtt receive p1:%f", g_charge_mng_info.P1);
                                // dbg_syslog(LOG_INFO, "p1:%f ", g_charge_mng_info.P1);
								pthread_cond_signal(&g_charge_mng_info.dynamic_demand.demand_cond);
								pthread_mutex_unlock(&g_charge_mng_info.dynamic_demand.demand_lock);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "p3") == 0)
                            {
                                // api_get_json_num_value(sub,&tmp,"p3");
                                // GET_JSON_VALUE_INT(sub, "p3", tmp);
                                GET_JSON_VALUE_DOUBLE(sub, "p3", tmp1);
                                if (g_pcs_cfg_info.loadgridmetershare == 1)
                                {
                                    tmp1 = tmp1 - g_pcs_cfg_info.Pset; // 负载和电网共用电表。
                                    if (tmp1 < 0)
                                    {
                                        tmp1 = g_pcs_cfg_info.Perr;
                                    }
                                }
                                g_charge_mng_info.P3 = tmp1;
                                time(&g_charge_mng_info.update_time.P3);
                                // dbg_syslog(LOG_INFO, "p3:%f ", tmp1);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "pcsalarm") == 0)
                            {
                                // api_get_json_num_value(sub,&tmp,"pcsalarm");
                                GET_JSON_VALUE_INT(sub, "pcsalarm", tmp);
                                g_charge_mng_info.pcserr = tmp;
                                g_charge_mng_info.pcserrflag = 1;
                                // dbg_syslog(LOG_INFO, "pcsalarm:%d ", tmp);
                                // ems_alarm_process(var);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "bmsalarm") == 0)
                            {
                                // api_get_json_num_value(sub,&tmp,"bmsalarm");
                                GET_JSON_VALUE_INT(sub, "bmsalarm", tmp);
                                g_charge_mng_info.bmserr = tmp;
                                g_charge_mng_info.bmserrflag = 1;
                                // dbg_syslog(LOG_INFO, "bmsalarm:%d ", tmp);
                                // ems_alarm_process(var);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "auxi") == 0)
                            {

                                GET_JSON_VALUE_INT(sub, "fire", g_charge_mng_info.fireAlarm);
                                GET_JSON_VALUE_INT(sub, "smog", g_charge_mng_info.smogAlarm);
                                GET_JSON_VALUE_INT(sub, "warterIm", g_charge_mng_info.waterImAlarm);
                                tmp = -1;
                                GET_JSON_VALUE_INT(sub, "pcsalarm", tmp);
                                if (tmp != -1)
                                {
                                    g_charge_mng_info.pcserr = tmp;
                                }
                                GET_JSON_VALUE_INT(sub, "surgein", g_charge_mng_info.ioinfo.surge_io_in_line);
                                GET_JSON_VALUE_INT(sub, "surgestation", g_charge_mng_info.ioinfo.surge_io_in_station);
                                GET_JSON_VALUE_INT(sub, "door", g_charge_mng_info.ioinfo.door_io_state);
                                GET_JSON_VALUE_INT(sub, "loadio", g_charge_mng_info.ioinfo.load_io_state);
                                GET_JSON_VALUE_INT(sub, "gridio", g_charge_mng_info.ioinfo.grid_io_state);
                                GET_JSON_VALUE_INT(sub, "transio", g_charge_mng_info.ioinfo.trans_io_state);
                                GET_JSON_VALUE_INT(sub, "tiaoji", g_charge_mng_info.ioinfo.tiaoji_io_state);
                                GET_JSON_VALUE_INT(sub, "temp", g_charge_mng_info.ioinfo.temp_io_state);
                                GET_JSON_VALUE_INT(sub, "gas", g_charge_mng_info.ioinfo.gas_io_state);
                                GET_JSON_VALUE_INT(sub, "emerstop", g_charge_mng_info.ioinfo.emer_stop_io_state);
                                g_charge_mng_info.ioinfo.fire_io_state = g_charge_mng_info.fireAlarm;
                                g_charge_mng_info.ioinfo.smog_io_state = g_charge_mng_info.smogAlarm;
                                g_charge_mng_info.ioinfo.connectok = 1;
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "AVflag") == 0)
                            {
                                GET_JSON_VALUE_INT(sub, "AVflag", g_charge_mng_info.gridOffFlag);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "mastswitch") == 0)
                            {
                                GET_JSON_VALUE_INT(sub, "mastswitch", g_charge_mng_info.mastSwitch);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "pv") == 0)
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "pv", g_charge_mng_info.Pv);
                                time(&g_charge_mng_info.update_time.Pv);
								//dbg_syslog(LOG_INFO, " pv:%f", g_charge_mng_info.Pv);
                            }
							else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "pf") == 0)
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "pf", g_charge_mng_info.Pf);
                                time(&g_charge_mng_info.update_time.Pf);
								//dbg_syslog(LOG_INFO, " pf:%f", g_charge_mng_info.Pf);
                            }
							else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "p2") == 0)
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "p2", g_charge_mng_info.P2);
                                time(&g_charge_mng_info.update_time.P2);
								//dbg_syslog(LOG_INFO, " p2:%f", g_charge_mng_info.P2);
                            }
							else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "p1_1") == 0) // 总有功功率
                            {
                                pthread_mutex_lock(&g_charge_mng_info.dynamic_demand.demand_lock);
                                GET_JSON_VALUE_DOUBLE(sub, "p1_1", g_charge_mng_info.P1_1);
                                time(&g_charge_mng_info.update_time.P1_1);
								//dbg_syslog(LOG_INFO, " p1_1:%f", g_charge_mng_info.P1_1);
								g_charge_mng_info.multi_meter_flag = 1;
								pthread_cond_signal(&g_charge_mng_info.dynamic_demand.demand_cond);
								pthread_mutex_unlock(&g_charge_mng_info.dynamic_demand.demand_lock);
                            }
							else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "p1_2") == 0) // 总视在功率
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "p1_2", g_charge_mng_info.P1_2);
                                time(&g_charge_mng_info.update_time.P1_2);
								//dbg_syslog(LOG_INFO, " p1_2:%f", g_charge_mng_info.P1_2);
								g_charge_mng_info.multi_meter_flag = 1;								
                            }
							else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "p1_3") == 0) // 总功率因数
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "p1_3", g_charge_mng_info.P1_3);
								//dbg_syslog(LOG_INFO, " p1_3:%f", g_charge_mng_info.P1_3);
								g_charge_mng_info.multi_meter_flag = 1;							
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "chstationP") == 0)
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "realpower", g_charge_mng_info.CharStaP);
                                GET_JSON_VALUE_DOUBLE(sub, "expectpower", g_charge_mng_info.CharStaExpP);
                            }
                            else if (strcmp(var->devnodeinfo.pdevnodecfg[i].name, "GV") == 0)
                            {
                                GET_JSON_VALUE_DOUBLE(sub, "GV", g_charge_mng_info.VG1);
                            }
                        }
                    }
                    for (i = 0; i < var->exdevnodeinfo.cont; i++)
                    {
                        if ((strcmp(var->devservInfo.devSn, var->exdevnodeinfo.pdevnodecfg[i].devSn) == 0) &&
                            (strcmp(var->devservInfo.identifier, var->exdevnodeinfo.pdevnodecfg[i].identifier) == 0))
                        {
                            for (j = 0; j < var->exdevnodeinfo.pdevnodecfg[i].tagNode.nodecont; j++)
                            {
                                if (strcmp(var->exdevnodeinfo.pdevnodecfg[i].tagNode.ptagNode[j].name, "temp") == 0)
                                {
                                    GET_JSON_VALUE_DOUBLE(sub, var->exdevnodeinfo.pdevnodecfg[i].tagNode.ptagNode[j].tag, tmp1);
                                    g_charge_mng_info.tempVal = tmp1;
                                    // dbg_syslog(LOG_INFO, "temp val:%f ", g_charge_mng_info.tempVal);
                                }
                                else if (strcmp(var->exdevnodeinfo.pdevnodecfg[i].tagNode.ptagNode[j].name, "pvgl") == 0)
                                {
                                    //GET_JSON_VALUE_DOUBLE(sub, var->exdevnodeinfo.pdevnodecfg[i].tagNode.ptagNode[j].tag, tmp1);
                                    //g_charge_mng_info.Pv = tmp1;
                                }
                            }
                        }
                    }
                }
                cJSON_Delete(sub);
            }
            free(tagNode);
        }
    }
    else if(strstr(mqtt_msg->topic, TOPIC_EVT_SET_RGLT))
    {
        node = cJSON_Parse(mqtt_msg->payload);
        if (!node)
        {
            dbg_syslog(LOG_ERR, "get node: %s error", mqtt_msg->topic);
            return 0;
        }
        GET_JSON_VALUE_INT(node, "mi", var->servInfo.mi);
        GET_JSON_VALUE_INT(node, "timestamp", var->servInfo.timestamp);
        GET_JSON_VALUE_STRING(node, "identifier", var->servInfo.identifier);
        GET_JSON_VALUE_STRING(node, "sn", var->servInfo.devSn);
        
        dbg_syslog(LOG_INFO, "mi:%d,timestamp:%d id:%s sn:%s\r\n", var->servInfo.mi, var->servInfo.timestamp, var->servInfo.identifier, var->servInfo.devSn);
        pthread_rwlock_wrlock(&var->topic_lock);
        if (0 == pcs_set_process(obj, mqtt_msg, node))
        {
            pcs_get_process(obj, mqtt_msg, node);
        }
        pthread_rwlock_unlock(&var->topic_lock);//combine with set_rglt
    }
out:
    if (node)
    {
        cJSON_Delete(node);
    }
    return 0;
}

static int ems_alarm_process(pcs_ctrl_var_t *var)
{
    DEMAND_CHARGE_INFO_T char_info = {0};
    if (g_charge_mng_info.ctrlMode != E_CTRL_AUTO)
        return 0;
    pthread_rwlock_wrlock(&var->topic_lock);
    if (g_charge_mng_info.bmserr == 1 || g_charge_mng_info.pcserr == 1)
    {
        if (g_charge_mng_info.connState == E_ON)
        {
            pcs_dev_close(var);
            pcs_dev_disconect_set(var);

            // g_charge_mng_info.connState = E_OFF;
        }
        pcs_charge_switch_process(var, E_CHARGE_IDLE, char_info);
    }
    else
    {
        if (g_charge_mng_info.connState == E_OFF)
        {
            pcs_dev_connect_set(var);
            pcs_dev_open(var);
            // g_charge_mng_info.connState = E_ON;
        }
    }
    pthread_rwlock_unlock(&var->topic_lock);
    return 0;
}



// combine to ctrl_mqtt_recv_msg


int pcs_ctrl_mqtt_client_init(pcs_ctrl_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, MAX_CLIENT_ID_LEN, "INT_pcs_ctrl_%s", var->sn_str);
    
    var->session = ipc_session_new(clientId, (void *)var, IPC_DEFAULT);
    if (var->session == NULL)
        return -1;
    

    ipc_session_set_callbacks(var->session, pcs_ctrl_mqtt_handle_recv_msg, pcs_ctrl_state_change);
    pcs_ctrl_subscribe_all(var);
    ipc_session_start(var->session);
    return 0;
}

int pcs_to_dev_mqtt_client_init(pcs_ctrl_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, MAX_CLIENT_ID_LEN, "INT_pcs_to_dev_%s", var->sn_str);
    var->sessiondev = ipc_session_new(clientId, (void *)var, IPC_DEFAULT);
    // var->sessiondev = ipc_session_new(clientId, (void *)var, IPC_NNG);
    if (var->sessiondev == NULL)
        return -1;
    
    ipc_session_set_callbacks(var->sessiondev, pcs_ctrl_mqtt_handle_recv_msg, NULL);
    pcs_to_dev_subscribe_all(var);
    ipc_session_start(var->sessiondev);
    return 0;
}
extern int load_some_state_cfg(CHARGE_MNG_INFO_T *pcfg, const char *cfg_file, int savestate);
extern int load_pcs_cfg(PCS_CFG_T *pcfg, const char *cfg_file);
extern int load_devInfo_cfg(pcs_ctrl_var_t *var, const char *cfg_file);
extern int load_pcs_plan_cfg(STRATEGY_MNG_T *pstrategymng, const char *cfg_file);
static void pcs_init_plan_name()
{
    int i;
    CHAR timer[TIME_VAL_LEN] = {0};

    for (i = 0; i < MAX_DEMAND_NUMBER / DIVIDE_OF_HOUR; i++)
    {
        sprintf(g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR].time, "P%02d%02d", i, 0);
        sprintf(g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR + 1].time, "P%02d%02d", i, 15);
        sprintf(g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR + 2].time, "P%02d%02d", i, 30);
        sprintf(g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR + 3].time, "P%02d%02d", i, 45);
        dbg_syslog(LOG_INFO, "i:%d timer:%s~%s~%s~%s", i, g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR].time,
                  g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR + 1].time,
                  g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR + 2].time,
                  g_pcs_cfg_info.demand_table[i * DIVIDE_OF_HOUR + 3].time);
    }
    for (i = 0; i < MAX_DEMAND_NUMBER / 4; i++)
    {
        sprintf(g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR].time, "P%02d%02d", i, 0);
        sprintf(g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR + 1].time, "P%02d%02d", i, 15);
        sprintf(g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR + 2].time, "P%02d%02d", i, 30);
        sprintf(g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR + 3].time, "P%02d%02d", i, 45);
        dbg_syslog(LOG_INFO, "i:%dremoter timer:%s~%s~%s~%s", i, g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR].time,
                  g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR + 1].time,
                  g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR + 2].time,
                  g_pcs_cfg_info.remoterdemand_table[i * DIVIDE_OF_HOUR + 3].time);
    }
}
extern void ems_timer_upgrade(pcs_ctrl_var_t *var);
// #define UPDATE_PLAN_TIME "P0000"

static void update_plan_cfg(pcs_ctrl_var_t *var)
{
    int i;
    int index = -1, pri = 0;
    time_t time1 = 0;
    BYTE day = 0xff;
    CHAR timer[TIME_VAL_LEN] = {0};
    time1 = time(NULL); // UTC时间平台下发时间关注？？？？？
    get_date_p(time1, &day);
    if (g_strategr_mng_info.cont == 0)
    {
        dbg_syslog(LOG_WARNING, "cont 0");
        return;
    }

    if (g_strategr_mng_info.initflag == 1)
    {
        get_time_p(timer);
        // dbg_syslog(LOG_INFO, "dayflag:%d upgradeTime:%s timer:%s", g_strategr_mng_info.dayflag, g_pcs_cfg_info.DayUPgradeTime, timer);
        if (strcmp(g_pcs_cfg_info.DayUPgradeTime, timer) != 0)
        {
            g_strategr_mng_info.dayflag = 0;
            // dbg_syslog(LOG_INFO, "timer:%s", timer);
            return;
        }
        dbg_syslog(LOG_DEBUG, "dayflag:%d", g_strategr_mng_info.dayflag);
        if (g_strategr_mng_info.dayflag == 1)
        {
            return;
        }
        report_option(var, "upgrade one day:upgradeTime:%s timer:%s", g_pcs_cfg_info.DayUPgradeTime, timer);
    }
    dbg_syslog(LOG_DEBUG, "cont:%d", g_strategr_mng_info.cont);

    // g_strategr_mng_info.initflag = 0;
    g_strategr_mng_info.dayflag = 1;
    for (i = 0; i < g_strategr_mng_info.cont; i++)
    {
        dbg_syslog(LOG_DEBUG, "priority:%d time1:%ld startDate:%ld endDate:%ld", g_strategr_mng_info.pStrategyTable[i].priority, time1,
                  g_strategr_mng_info.pStrategyTable[i].startDate, g_strategr_mng_info.pStrategyTable[i].endDate);
        if (g_strategr_mng_info.pStrategyTable[i].repeat == E_REPEAT_WEEK)
        {
            if ((time1 >= g_strategr_mng_info.pStrategyTable[i].startDate) && (time1 < g_strategr_mng_info.pStrategyTable[i].endDate))
            {
                if (pri < g_strategr_mng_info.pStrategyTable[i].priority)
                {
                    if (g_strategr_mng_info.pStrategyTable[i].weekly.weekNum[day] == 1)
                    {
                        index = i;
                        pri = g_strategr_mng_info.pStrategyTable[i].priority; // todo 判断周期模式;
                    }
                }
            }
        }
    }
    // dbg_syslog(LOG_INFO, "pri:%d", pri);
    for (i = 0; i < g_strategr_mng_info.cont; i++)
    {
        dbg_syslog(LOG_DEBUG, "priority:%d time1:%ld startDate:%ld endDate:%ld", g_strategr_mng_info.pStrategyTable[i].priority, time1,
                  g_strategr_mng_info.pStrategyTable[i].startDate, g_strategr_mng_info.pStrategyTable[i].endDate);
        if (g_strategr_mng_info.pStrategyTable[i].repeat == E_REPEAT_DAY)
        {
            if ((time1 >= g_strategr_mng_info.pStrategyTable[i].startDate) && (time1 < g_strategr_mng_info.pStrategyTable[i].endDate))
            {
                if (pri < g_strategr_mng_info.pStrategyTable[i].priority)
                {
                    index = i;
                    pri = g_strategr_mng_info.pStrategyTable[i].priority; // todo 判断周期模式;
                }
            }
        }
    }
    // dbg_syslog(LOG_INFO, "pri:%d", pri);
    for (i = 0; i < g_strategr_mng_info.cont; i++)
    {
        dbg_syslog(LOG_DEBUG, "priority:%d time1:%ld startDate:%ld endDate:%ld", g_strategr_mng_info.pStrategyTable[i].priority, time1,
                  g_strategr_mng_info.pStrategyTable[i].startDate, g_strategr_mng_info.pStrategyTable[i].endDate);
        if (g_strategr_mng_info.pStrategyTable[i].repeat == E_REPEAT_KEEP)
        {
            if (pri < g_strategr_mng_info.pStrategyTable[i].priority)
            {
                index = i;
                pri = g_strategr_mng_info.pStrategyTable[i].priority; // todo 判断周期模式;
            }
        }
    }
    // dbg_syslog(LOG_INFO, "pri:%d", pri);
    if (index == -1)
    {
        dbg_syslog(LOG_WARNING, "not found");
        return;
    }
    // 读写锁
    //  pthread_rwlock_wrlock(&var->topic_lock);
    g_charge_mng_info.demandState = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.demandState;//yut
    g_charge_mng_info.AgainstState = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.AgainstState;
	g_charge_mng_info.lgState = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.lgState;
    g_pcs_cfg_info.K1 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.K1;
    g_pcs_cfg_info.K2 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.K2;
    g_pcs_cfg_info.Pcha = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.Pcha;
    g_pcs_cfg_info.PDisc = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PDisc;
    g_pcs_cfg_info.Perr = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.Perr;
    g_pcs_cfg_info.Pmlmax = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.Pmlmax;
	g_pcs_cfg_info.EDD = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.EDD;
    g_pcs_cfg_info.MD = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.MD;
    g_pcs_cfg_info.DCI = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.DCI;
	if (g_pcs_cfg_info.DCI == 0) g_pcs_cfg_info.DCI = 15; // 站控不配置需量计算时间间隔时，默认15分钟
	dbg_syslog(LOG_NOTICE, "DCI: %d", g_pcs_cfg_info.DCI);
    g_pcs_cfg_info.CLDischa = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.CLDischa;
    g_pcs_cfg_info.CLCha = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.CLCha;
    g_pcs_cfg_info.Pset = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.Pset;
    g_pcs_cfg_info.PVmax = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PVmax;
    g_pcs_cfg_info.SOCmax = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.SOCmax;
    g_pcs_cfg_info.SOCmin = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.SOCmin;
    g_pcs_cfg_info.PCSmax = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PCSmax;
    g_pcs_cfg_info.type = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.type;
    g_pcs_cfg_info.dischargeThreshold = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.dischargeThreshold;
    g_pcs_cfg_info.chargeEndPower = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.chargeEndPower;
    g_pcs_cfg_info.chargeStartPower = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.chargeStartPower;
    g_pcs_cfg_info.dischareeEndThresholdVal = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.dischareeEndThresholdVal;
    g_pcs_cfg_info.dischargeEndThreshold = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.dischargeEndThreshold;
	dbg_syslog(LOG_NOTICE, "chargeStartPower:%d, chargeEndPower:%d, dischargeThreshold:%d, dischargeEndThreshold:%d, dischargeEndThreshold:%d", g_pcs_cfg_info.chargeStartPower, g_pcs_cfg_info.chargeEndPower, g_pcs_cfg_info.dischargeThreshold, g_pcs_cfg_info.dischargeEndThreshold, g_pcs_cfg_info.dischargeEndThreshold);
    g_pcs_cfg_info.tempThreshold = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.tempThreshold;
    g_pcs_cfg_info.loadTrackingLimit = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.loadTrackingLimit;
    g_pcs_cfg_info.GridRateVol = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.GridRateVol;
    g_pcs_cfg_info.PmlRecoverMax = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PmlRecoverMax;
    g_pcs_cfg_info.G1 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.G1;
    g_pcs_cfg_info.G1T = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.G1T;
    g_pcs_cfg_info.DK2 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.DK2;
    g_pcs_cfg_info.K1T = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.K1T;
    g_pcs_cfg_info.DK1T = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.DK1T;
    g_pcs_cfg_info.RK1 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.RK1;
    g_pcs_cfg_info.RK1T = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.RK1T;
    g_pcs_cfg_info.G2T = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.G2T;
    g_pcs_cfg_info.GST1 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.GST1;
    g_pcs_cfg_info.GST2 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.GST2;
    g_pcs_cfg_info.PFT1 = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PFT1;
    g_pcs_cfg_info.pf = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.pf;

    if(g_pcs_cfg_info.type == STRATEGY_TYPE_PV_TRACK) //光伏的需要设置 其他的暂时读取开机配置文件的值
    {
            g_pcs_cfg_info.Adjpreriod=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.Adjpreriod; 
    }
    if (g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PchaMax != 0)
    {
        g_pcs_cfg_info.PchaMax=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PchaMax;
    }
    if (g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PDiscMax != 0)
    {
        g_pcs_cfg_info.PDiscMax=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PDiscMax;
    }
    dbg_syslog(LOG_NOTICE, "upgrade plan PchaMax:%d PDiscMax %d", g_pcs_cfg_info.PchaMax, g_pcs_cfg_info.PDiscMax);
    g_pcs_cfg_info.PvSwitch=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PvSwitch;
    g_pcs_cfg_info.socThreshold=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.socThreshold;
    g_pcs_cfg_info.forbidden=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.forbidden;
    g_pcs_cfg_info.MAXSupplementP=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.MAXSupplementP ;
    g_pcs_cfg_info.p1Margin=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.p1Margin;
    g_pcs_cfg_info.pvMaxPower=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.pvMaxPower;
    //if (g_strategr_mng_info.pStrategyTable[index].strategryTemplate.aircond_set_timeout_before != 0)
    {
        g_pcs_cfg_info.aircond_set_timeout_before=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.aircond_set_timeout_before;
    }
    //if (g_strategr_mng_info.pStrategyTable[index].strategryTemplate.aircond_set_timeout_after != 0)
    {
        g_pcs_cfg_info.aircond_set_timeout_after=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.aircond_set_timeout_after;
    }
    dbg_syslog(LOG_NOTICE, "upgrade plan aircond_set_timeout_before:%d aircond_set_timeout_after %d", g_pcs_cfg_info.aircond_set_timeout_before, g_pcs_cfg_info.aircond_set_timeout_after);
	g_pcs_cfg_info.singlemax=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.singlemax;
	g_pcs_cfg_info.singlemin=g_strategr_mng_info.pStrategyTable[index].strategryTemplate.singlemin;

    // g_pcs_cfg_info.demand_table = g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PlanInfo;
    memcpy(g_pcs_cfg_info.demand_table, g_strategr_mng_info.pStrategyTable[index].strategryTemplate.PlanInfo, sizeof(DEMAND_CHARGE_INFO_T) * MAX_DEMAND_NUMBER);
    // pthread_rwlock_unlock(&var->topic_lock);
    g_strategr_mng_info.update = 1;
    g_strategr_mng_info.initflag = 1;
    //ems_timer_upgrade(var);
    report_option(var, "upgrade plan weekday:%d pri:%d ", day, pri);
    dbg_syslog(LOG_NOTICE, "upgrade plan weekday:%d pri %d", day, pri);
    return;
}
#define GRID_VOL_DEFAULT 220
void run_mode_load()
{
    g_charge_mng_info.ctrlMode = g_pcs_cfg_info.runState;
    g_charge_mng_info.VG1 = GRID_VOL_DEFAULT;
}

static void charge_mng_info_init()
{
    time(&g_charge_mng_info.update_time.P1);
	time(&g_charge_mng_info.update_time.P2);
    time(&g_charge_mng_info.update_time.P3);
    time(&g_charge_mng_info.update_time.Pv);
	time(&g_charge_mng_info.update_time.Pf);
}

static void print_cfg_load_result(pcs_ctrl_var_t *var)
{
    int i = 0;
    if (var == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument!");
        return;
    }

    dbg_syslog(LOG_NOTICE, "----------------guardSn-----------------");
    dbg_syslog(LOG_NOTICE, "guardCnt: %d", var->guard_grp_num);
    for (i = 0; i < var->guard_grp_num; i++) {
        dbg_syslog(LOG_NOTICE, "belong_gw[%d].guard_SN: %s_%s", i, var->grp[i].belong_gw, "GUARD");
    }
    dbg_syslog(LOG_NOTICE, "------------------------------------------------");
}

char last_belong_gw[32] = "";

static int add_data_struct(pcs_ctrl_var_t *var, cJSON *node, guard_grp_t *cfg)
{ 
    int i;
	char *belong_gw = NULL; 
    cJSON *type = cJSON_GetObjectItem(node, "type");
    dbg_syslog(LOG_NOTICE, "type:%s",type->valuestring);
    if( strcmp(type->valuestring, "pcs") == 0)
    {
        GET_JSON_VALUE_DY_STRING(node, "belong_gw", belong_gw);
        pcs_count++;
		if (strcmp(last_belong_gw, belong_gw) != 0)
		{
			strncpy(last_belong_gw, belong_gw, sizeof(last_belong_gw));
			dbg_syslog(LOG_NOTICE, "last_belong_gw:%s", last_belong_gw);
			GET_JSON_VALUE_DY_STRING(node, "dev_sn", cfg->pcs_sn);
			GET_JSON_VALUE_DY_STRING(node, "belong_gw", cfg->belong_gw);
			guard_count++;
            g_charge_mng_info.grps_lev_eng[pcs_count-1].eng_ass_pcs_grp = guard_count - 1;
		}else
        {
            g_charge_mng_info.grps_lev_eng[pcs_count-1].eng_ass_pcs_grp = guard_count - 1;
			return -1;
        }
    }
	#if 0
    else if( strcmp(type->valuestring,"meter") == 0)
    {
        GET_JSON_VALUE_DY_STRING(node, "dev_sn", cfg->meter_sn);
        GET_JSON_VALUE_DY_STRING(node, "belong_gw", cfg->belong_gw);
        hash_intptr_addptr(&var->sub_gw_sn_map, cfg->meter_sn, strlen(cfg->meter_sn), cfg->belong_gw);
    }
	#endif
    else if( strcmp(type->valuestring,"cluster") == 0)
    {
        GET_JSON_VALUE_DY_STRING(node, "dev_sn", cfg->bms_sn[cfg->bms_dev_num]);
        GET_JSON_VALUE_DY_STRING(node, "belong_gw", cfg->bms_belong_gw[cfg->bms_dev_num]);
        (cfg->bms_dev_num)++;
    }
	return 0;
}

void ems_load_config_from_ems_structure(pcs_ctrl_var_t *var, char *cfg_file)
{
    char *pdata = NULL;
    cJSON *storage = NULL;
    cJSON *node = NULL;
    cJSON *child_dev = NULL;
    cJSON *child_devs = NULL;
    cJSON *root = NULL;
    cJSON *nodes = NULL;
    char type[32] = {'\0'};

    if (var == NULL || cfg_file == NULL) {
        dbg_syslog(LOG_ERR, "invalid argument! var: %p cfg_file: %p", var, cfg_file);
        goto out;
    }

    dbg_syslog(LOG_NOTICE, "cfg_file: %s", cfg_file);
    pdata = read_file_data(cfg_file);
    if (pdata == NULL) {
        dbg_syslog(LOG_ERR, "read cfg file %s error", cfg_file);
        goto out;
    }

    root = cJSON_Parse(pdata);
    if (!root) {
        dbg_syslog(LOG_ERR, "parse pdata %s error", pdata);
        goto out;
    }

    storage = cJSON_GetObjectItemCaseSensitive(root, "storage");
    if (!storage) {
        dbg_syslog(LOG_ERR, "get object storage error");
        goto out;
    }

    int dev_cnt = cJSON_GetArraySize(storage);
    int pcs_idx = 0;
    for (int i = 0; i < dev_cnt; i++) {
        cJSON *dev = cJSON_GetArrayItem(storage, i);
        if (dev == NULL) {
            dbg_syslog(LOG_ERR, "cJSON_GetArrayItem() failed!");
            goto out;
        }

        GET_JSON_VALUE_STRING_LOG(dev, "type", type);
        if (strcmp(type, "pcs") != 0) {
            continue;
        }        
        if (add_data_struct(var, dev, &var->grp[pcs_idx]) == -1)
	        continue;
		
        pcs_idx = pcs_idx + 1;
    }
    var->guard_grp_num = guard_count;
    var->pcs_grp_num = pcs_count;

    print_cfg_load_result(var);
out:
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
    if (pdata != NULL)
    {
        free(pdata);
    }
}

void ems_load_config(pcs_ctrl_var_t *var, char *cfg_file)
{
    char *pdata = NULL;
    cJSON *node = NULL;
    cJSON *child_node = NULL;
    cJSON *child_nodes = NULL;
    cJSON *root = NULL;
    cJSON *nodes = NULL;
    pdata = read_file_data(cfg_file);

    if (pdata == NULL)
    {
        dbg_syslog(LOG_ERR, "read cfg file %s error", cfg_file);
        goto out;
    }

    root = cJSON_Parse(pdata);
    if (!root)
    {
        dbg_syslog(LOG_ERR, "parse pdata %s error", pdata);
        goto out;
    }

    nodes = cJSON_GetObjectItemCaseSensitive(root, "groups");
    if (!nodes)
    {
        dbg_syslog(LOG_ERR, "get groups node failed");
        goto out;
    }

	int pcs_idx = 0;
    int node_cnt = cJSON_GetArraySize(nodes);
    if (node_cnt != 0)
    {
        for (int i = 0; i < node_cnt; i++)
        {
            node = cJSON_GetArrayItem(nodes, i);

			if (add_data_struct(var, node, &var->grp[pcs_idx]) == -1)
				continue;
			pcs_idx = pcs_idx + 1;
        }
    }
    var->guard_grp_num = guard_count;
    var->pcs_grp_num = pcs_count;
    print_cfg_load_result(var);
out:
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
    if (pdata != NULL)
    {
        free(pdata);
    }
}

static void *carry_power_value(void *param)
{
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)param;
	unsigned int timeout = 10*1000; // 超时时间 10s
	time_t time1 = -1;
	double usr_p1 = 0;

    while (1)
    {
	    pthread_mutex_lock(&g_charge_mng_info.dynamic_demand.demand_lock);

		// what to do?
		
	    lnxall_condvar_timedwait(&g_charge_mng_info.dynamic_demand.demand_cond, &g_charge_mng_info.dynamic_demand.demand_lock, timeout);

		//dbg_syslog(LOG_INFO, "carry_power_value p1:%f", g_charge_mng_info.P1);
		
		BYTE index = g_charge_mng_info.dynamic_demand.ping_pong;
		power_t *power_buf = &g_charge_mng_info.dynamic_demand.pingpangbuff[index];
		time(&time1);
		if ((time1 >= g_charge_mng_info.dynamic_demand.action_tim) && (time1 <= g_charge_mng_info.dynamic_demand.step_tim))
		{
		    if (power_buf->num < POWER_NUM_MAX)
		    {
		        usr_p1 = 1 ? g_charge_mng_info.P1_1 : g_charge_mng_info.P1; // 有功功率
				power_buf->p[power_buf->num] = (float)usr_p1;
				power_buf->num++;
				dbg_syslog(LOG_INFO, "within the time frame-> index: %d, num: %d, p1 Active power: %f", index, power_buf->num, usr_p1);
		    }
		}
		
	    pthread_mutex_unlock(&g_charge_mng_info.dynamic_demand.demand_lock);
    }
    return 0;
}

/* 需量：在电网中，需量是一个指定时间间隔内的平均功率，指定的时间间隔就是需量周期，我们国家通常采用 15 分钟做为需量周期，采用“滑差”的方式测量需量。
         通常一个月为一个结算周期，取结算周期内的最大需量进行需量电费的计算 */
static void *calculate_demand_report(void *param)
{
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)param;
	int i = 0;
	float average = 0, sum = 0;
    int *p_num = &(g_charge_mng_info.dynamic_demand.power_data.num);
	float *p_data = g_charge_mng_info.dynamic_demand.power_data.data;
		
	time_t time1 = -1;
	struct tm tNow;
    bool touch_flag = false; 

    while (1)
    {
        time(&time1);
		localtime_r(&time1, &tNow); // localtime_r 修改；
		
		if (time1 >= g_charge_mng_info.dynamic_demand.step_tim)
		{
            g_charge_mng_info.dynamic_demand.action_tim = time1;
			g_charge_mng_info.dynamic_demand.step_tim = time1 + 60;
		    g_charge_mng_info.dynamic_demand.ping_pong = !g_charge_mng_info.dynamic_demand.ping_pong;
		    touch_flag = true;
		}
		if (touch_flag)
		{
			BYTE index = g_charge_mng_info.dynamic_demand.ping_pong;
			power_t *power_buf = &g_charge_mng_info.dynamic_demand.pingpangbuff[!index];

			for (i = 0; i < power_buf->num; i++) {
				sum += power_buf->p[i];
			}
            if ((sum != 0) && (power_buf->num != 0)) average = (float)sum/power_buf->num; // 求1分钟区间 p1平均值
			dbg_syslog(LOG_INFO, "one minutes section, match to :%02d:%02d:%02d number: %d, average_value: %f", tNow.tm_hour, tNow.tm_min, tNow.tm_sec, power_buf->num, average);

			p_data[*p_num] = average;
			*p_num += 1;
            if (*p_num >= g_pcs_cfg_info.DCI) *p_num = g_pcs_cfg_info.DCI - 1;
			
			sum = 0;
            power_buf->num = 0;
			memset(power_buf->p, 0, sizeof(power_buf->p));
			
			touch_flag = false;
		}

		if (time1 >= g_charge_mng_info.dynamic_demand.dci_tim)
        {
            g_charge_mng_info.dynamic_demand.dci_tim = time1 + 60; // 采用“滑差”的方式测量需量

			for (i = 0; i < g_pcs_cfg_info.DCI; i++) {
				sum += p_data[i];
			}
			if ((sum != 0) && (g_pcs_cfg_info.DCI != 0)) average = (float)sum/g_pcs_cfg_info.DCI; // 求DCI区间 p1平均值
			dbg_syslog(LOG_INFO, "DCI section, match to :%02d:%02d:%02d, average_value: %f, Dylmax : %d", tNow.tm_hour, tNow.tm_min, tNow.tm_sec, average, g_pcs_cfg_info.Dylmax);

			sum = 0;
			memmove(p_data, p_data + 1, (DCI_NUM_MAX - 1) * sizeof(float)); // << 数组元素 左移1
			
			if (average > g_pcs_cfg_info.Dylmax)
			{
				g_pcs_cfg_info.Dylmax = (USHORT)average;
				pcs_config_save();
			}

			if (g_pcs_cfg_info.EDD == 1) publish_dynamic_demand(var);
		}
		
	    usleep(200 * 1000);
    }
    return 0;
}

static void dynamic_demand_other(void *param)
{
    pcs_ctrl_var_t *var = (pcs_ctrl_var_t *)param;

	time_t time1 = -1;
	struct tm tNow;

    time(&time1);
	localtime_r(&time1, &tNow); // localtime_r 修改；

	// 下发月初需量大于当前最大需量，则第二天生效
    if (g_charge_mng_info.dynamic_demand.triger == 1)
    {
        if (tNow.tm_mday != g_charge_mng_info.dynamic_demand.back_tim.tm_mday)
        {
			g_pcs_cfg_info.Dylmax = g_pcs_cfg_info.MD;
            pcs_config_save();
			g_charge_mng_info.dynamic_demand.triger = 0;
        }
	}

	// 每个月月初开始都按照设置的月初需量控制
    if ((tNow.tm_mday == 1) && (tNow.tm_hour == 0) && (tNow.tm_min == 0) && ((tNow.tm_sec >= 0) && (tNow.tm_sec <= 2)))
    {
        g_pcs_cfg_info.Dylmax = g_pcs_cfg_info.MD;
		pcs_config_save();
	}
}

void pcs_init(pcs_ctrl_var_t *var)
{
	pthread_t thread_carry;
	pthread_t thread_calculate;
    // jsonTest();
    get_board_sn(var->sn_str); // 所有表信息;meter sn
   // mytimer_init((void *)var);
    // timer_test(var); 定时器测试。
    charge_mng_info_init();
    pthread_rwlock_init(&var->topic_lock, NULL);
	pthread_mutex_init(&g_charge_mng_info.dynamic_demand.demand_lock, NULL);
    lnxall_condvar_init(&g_charge_mng_info.dynamic_demand.demand_cond);
    pcs_init_plan_name();
    load_pcs_cfg(&g_pcs_cfg_info, EMS_CFG_FILE);
    load_pcs_cfg(&g_pcs_cfg_info, EMS_CFG_SAVE_FILE);
    load_some_state_cfg(&g_charge_mng_info, EMS_SOME_STATE_CFG_FILE,g_pcs_cfg_info.savestate);
    load_pcs_plan_cfg(&g_strategr_mng_info, EMS_CFG_PLAN_FILE);
    //add brief default configuration
    load_devInfo_cfg(var, EMS_DEV_NODE_FILE);
    run_mode_load();
    load_proxy_cfg(var, PROXY_SUMMARY_FILE);
	if (access(EMS_STRUCTURE_CFG_FILE, F_OK) == 0) {
        ems_load_config_from_ems_structure(var, EMS_STRUCTURE_CFG_FILE);
    }
    else {
        ems_load_config(var, EMS_CFG_ENER_FILE);
    }

    // update_plan_cfg(var);
    dbg_syslog(LOG_NOTICE, "board SN:%s", var->sn_str);
    // one client left
    pcs_ctrl_mqtt_client_init(var);
    pcs_to_dev_mqtt_client_init(var);
    //pcs_exdev_mqtt_client_init(var);
    var->second_period_timer = my_timer_create();
    if (var->second_period_timer > 0)
    {
        my_timer_set(var->second_period_timer, 1, SECOND_TIME);
    }
    //sleep(5);
    update_plan_cfg(var);
	To_initialize(&g_charge_mng_info, &g_pcs_cfg_info);
	pthread_create(&thread_carry, NULL, carry_power_value, (void *)var);
	pthread_create(&thread_calculate, NULL, calculate_demand_report, (void *)var);
}

#define PLAN_INFO g_pcs_cfg_info.demand_table

static void pcs_charge_switch_process(pcs_ctrl_var_t *var, BYTE type, DEMAND_CHARGE_INFO_T char_info)
{
    // dbg_syslog(LOG_INFO, "charge switch :%d\r\n", type);
    // pcs_dev_disconect_set(var);
    pcs_dev_yggl_set(var, 0);

    switch (type)
    {
    case E_CHARGE_IDLE:
        if (g_charge_mng_info.action != E_CHARGE_IDLE)
        {
            report_option(var, "switch idle");
            g_charge_mng_info.action = E_CHARGE_IDLE; //
            // 关闭pcs 并网，关闭充放电
        }
        if (g_charge_mng_info.pcs_openState == 1)
            pcs_dev_close(var);
        break;
    case E_CHARGE_DOING:
        if (g_charge_mng_info.action != E_CHARGE_DOING)
        {
            report_option(var, "switch to charging");
        }
        if (g_charge_mng_info.pcs_openState == 0)
            pcs_dev_open(var);        
        g_charge_mng_info.action = E_CHARGE_DOING;
        // dbg_syslog(LOG_INFO, "chargeMode :%d\r\n", g_charge_mng_info.chargeMode);
        switch (g_charge_mng_info.chargeMode)
        {
        case E_CHARGE_FIXED:
            g_charge_mng_info.currentCharPower = g_pcs_cfg_info.Pcha;
            break;
        case E_CHARGE_PLAN:
            if (char_info.power == 0)
            {
                g_charge_mng_info.currentCharPower = g_pcs_cfg_info.Pcha;
            }
            else
            {
                g_charge_mng_info.currentCharPower = char_info.power;
            }

            break;
        }        
        break;
    case E_CHAREG_DISCH:
        if (g_charge_mng_info.action != E_CHAREG_DISCH)
        {
            report_option(var, "switch to discharging");
        }
        if (g_charge_mng_info.pcs_openState == 0)
            pcs_dev_open(var);        
        g_charge_mng_info.action = E_CHAREG_DISCH;
        // dbg_syslog(LOG_INFO, "chargeMode :%d K2：%d P3:%f\r\n", g_charge_mng_info.DischaMode, g_pcs_cfg_info.K2, g_charge_mng_info.P3);

        switch (g_charge_mng_info.DischaMode)
        {
        case E_CHARGE_FIXED:
            g_charge_mng_info.currentDischaPower = g_pcs_cfg_info.PDisc;
            break;
        case E_CHARGE_PLAN:
            if (char_info.power == 0)
            {
                g_charge_mng_info.currentDischaPower = g_pcs_cfg_info.PDisc;
            }
            else
            {
                g_charge_mng_info.currentDischaPower = char_info.power;
            }
            break;
        case E_CHARGE_TRACK:
            g_charge_mng_info.currentDischaPower = g_charge_mng_info.P3 * g_pcs_cfg_info.K2 / 100;
            // pcs_discharge_track(g_charge_mng_info.P1,g_pcs_cfg_info.K2,g_charge_mng_info.P3,&setPower);
            break;
        }
        
        break;
    }
    // dbg_syslog(LOG_INFO, "charge_switch:%d", g_charge_mng_info.action);
}

int pcs_charge_plan_process(CHAR *ptimer, DEMAND_CHARGE_INFO_T *chInfo)
{
    int i;
    for (i = 0; i < MAX_DEMAND_NUMBER; i++)
    {
        
        if (strcmp(PLAN_INFO[i].time, ptimer) == 0)
        {
            
            *chInfo = PLAN_INFO[i];
            return E_TRUE;
        }
    }
    return E_FALSE;
}

void pcs_entry(pcs_ctrl_var_t *var)
{
    int ret = -1, maxfd, iot_rep_count = 0;
    fd_set rset;
    struct timeval timeout;
    g_charge_mng_info.switchCounter = 0 ;
    while (1)
    {
        SELECT_INIT();
        SELECT_ADD_FD(var->second_period_timer);
        timeout.tv_usec = 0;
        timeout.tv_sec = 5;
        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            dbg_syslog(LOG_INFO, "errno %d\n", errno);

            if (errno == EINTR)
            {
                
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            if (var->second_period_timer > 0 && FD_ISSET(var->second_period_timer, &rset))
            {
                FD_CLR(var->second_period_timer, &rset);
                // dbg_syslog(LOG_INFO, "---------->");
                EMS_TIMER_CONFIRM(var->second_period_timer);
                if (user_define_process == NULL)
                {
                    pcs_second_period_poll(var);
                    
                    if(iot_rep_count>=10)
                    {
                        dbg_syslog(LOG_INFO, "report to IoT---------->");
                         //report_option(var, "runingMode: %d powerOfCharge %d powerOfDischarge %d",
                          //g_charge_mng_info.action,g_charge_mng_info.currentCharPower,
                         // g_charge_mng_info.currentDischaPower);
                         publish_log_report_up(var);
                         
                        iot_rep_count=0;
                    }
                    else
                    {    
                        iot_rep_count++;
                    }

					dynamic_demand_other(var);
                }
                else
                {
                    user_define_process(var);
                }
            }
        }
    }
}

void main()
{
    pcs_ctrl_var_t pcs_ctrl_var = {0};
    lnxall_loglevel_set(LNXALL_LOGDEBUG, 1);
    pcs_init(&pcs_ctrl_var);
    pcs_entry(&pcs_ctrl_var);
}
