#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include "emsctrlProc.h"
#include "define.h"
#include "deviceLayer.h"
#include "jsonct.h"
#include "main.h"
#include <math.h>
#include "ems_ua.h"
#include "../log_module/log_module.h"
#include "pub_fun.h"
#include "../north_mqtt/north_mqtt.h"
#include "lc.h"
#include "../business_log/business_log.h"

int last_turn_off_time = 0;
static volatile double lc_power = 0;
static volatile double lc_repower = 0;

extern ems_cfg_info_t ems_config_tab[];
extern int ems_config_tab_count_g;
extern all_plan g_all_plan[];
extern all_plan north_g_all_plan[][MAX_DAY_YEAR+1];
extern int north_control;
extern key_info_t key_info;

char *state_string[E_MAIN_STATE_MAX]={
    "init",
    "fault",
    "off",
    "idle",
    "charge",
    "discharge",
    "any",
};
void reflush_ems_data(usercfg_variant_t *pcfg)
{

    reflush_other_data_to_usercfg(pcfg);
    for(int i = 0 ;i<ems_config_tab_count_g;i++)
    {
        char *key=NULL;
        key=ems_config_tab[i].nod+strlen(DEV_NO_EMS".");
        if(key!=NULL)ems_syslog(LOG_NOTICE, "reflush key:%s",key);
        switch(ems_config_tab[i].data_type)
        {
            case EMS_POINT_INT:
            {
                dev_set_dev_tag_int(DEV_NO_EMS,key,*((int *)((char *)pcfg + ems_config_tab[i].member_ofs)));
            };
            break;
            case EMS_POINT_FLOAT:
            {
                // 将float按6位精度转换为double
                double data_float = *((float *)((char *)pcfg + ems_config_tab[i].member_ofs));
                double data_double = (int64_t)((data_float * 1000000.0) + 0.5) / 1000000.0;
                dev_set_dev_tag_float(DEV_NO_EMS,key,data_double);
            };
            break;
        } 
        //usleep(10*1000);
    }
    for(int i = 0;i<NUM_TOU_SEG_MAX;i++)//最大96段
    {
        char name[64];
        tou_seg_t *tou = &pcfg->tou[i];
        snprintf(name,sizeof(name),"S%dStHour",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StHour);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dStMin",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StMin);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dEnHour",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnHour);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dEnMin",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnMin);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dPower",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->Power);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dRePower",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->RePower);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dSOCUpperLimit",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SocUp);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dSOCLowerLimit",i+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SocLower);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dStHour",i+1);
    }
}

double get_lc_power(void)
{
    return lc_power;
}
double get_lc_repower(void)
{
    return lc_repower;
}

int reflush_all_plan(void)
{
    time_t t = time(NULL);
    struct tm target_time = {};  
    struct tm *local_time = &target_time;
    localtime_r(&t, local_time);
    for(int j = 0;j<NUM_TOU_SEG_MAX;j++)//最大96段
    {
        char name[64];
        snprintf(name,sizeof(name),"S%dStHour",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dStMin",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dEnHour",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dEnMin",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dPower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dRePower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dSOCUpperLimit",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,-1);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dSOCLowerLimit",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,-1);//usleep(10*1000);
        snprintf(name,sizeof(name),"S%dStHour",j+1);
    }
    memset(g_usercfg_variant.tou, 0, sizeof(g_usercfg_variant.tou));

	// if ((get_cabinet_info()->en_north_mqtt) && ((g_usercfg_variant.ControlMode == MODE_REMOTE))){
    if ((get_cabinet_info()->en_north_mqtt)){
	    for (size_t i = 0; i < MAX_DAY_YEAR; i++)
	    {
            if ((north_control == -1) || (north_control >= NORTH_CHANNEL_CONRTOL_CNT))
            {
                break;
            }
	        if (north_g_all_plan[north_control][i].year == 0)
	        {
	            break;
	        }
	        if ((north_g_all_plan[north_control][i].year == local_time->tm_year+1900)&&(north_g_all_plan[north_control][i].mounth == local_time->tm_mon+1)&&(north_g_all_plan[north_control][i].date == local_time->tm_mday))
	        {
                BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0043, NULL, "[北向]:找到北向当天策略，更新策略");
				ems_syslog(LOG_WARNING, "find north plan, year:%d mounth:%d date:%d", north_g_all_plan[north_control][i].year,north_g_all_plan[north_control][i].mounth, north_g_all_plan[north_control][i].date);
	            for(int j = 0;j<NUM_TOU_SEG_MAX;j++)//最大96段
	            {
	                char name[64];
	                tou_seg_t *tou = &north_g_all_plan[north_control][i].schedule[j];
	                snprintf(name,sizeof(name),"S%dStHour",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StHour);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->StHour);
	                snprintf(name,sizeof(name),"S%dStMin",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StMin);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->StMin);
	                snprintf(name,sizeof(name),"S%dEnHour",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnHour);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->EnHour);
	                snprintf(name,sizeof(name),"S%dEnMin",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnMin);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->EnMin);
	                snprintf(name,sizeof(name),"S%dPower",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->Power);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->Power);
	                snprintf(name,sizeof(name),"S%dRePower",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->RePower);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->RePower);
                    snprintf(name,sizeof(name),"S%dSOCUpperLimit",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SocUp);//usleep(10*1000);
                    ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->SocUp);
                    snprintf(name,sizeof(name),"S%dSOCLowerLimit",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SocLower);//usleep(10*1000);
                    ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->SocLower);
	                snprintf(name,sizeof(name),"S%dStHour",j+1);
	            }
                memcpy(g_usercfg_variant.tou, north_g_all_plan[north_control][i].schedule, sizeof(g_usercfg_variant.tou));
				break;
	        }
            else
            {
                BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0043, NULL, "[北向]:未找到北向当天策略");
            }
	    }
	}

    if(north_control == -1)
    {
        for (size_t i = 0; i < MAX_DAY_YEAR; i++)
	    {
	        if (g_all_plan[i].year == 0)
	        {
	            break;
	        }
	        if ((g_all_plan[i].year == local_time->tm_year+1900)&&(g_all_plan[i].mounth == local_time->tm_mon+1)&&(g_all_plan[i].date == local_time->tm_mday))
	        {
                BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0042, NULL, "[北向]:找到云平台当天策略，更新策略");
	            ems_syslog(LOG_WARNING, "find emms plan, year:%d mounth:%d date:%d", g_all_plan[i].year,g_all_plan[i].mounth, g_all_plan[i].date);
	            for(int j = 0;j<NUM_TOU_SEG_MAX;j++)//最大96段
	            {
	                char name[64];
	                tou_seg_t *tou = &g_all_plan[i].schedule[j];
	                snprintf(name,sizeof(name),"S%dStHour",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StHour);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->StHour);
	                snprintf(name,sizeof(name),"S%dStMin",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StMin);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->StMin);
	                snprintf(name,sizeof(name),"S%dEnHour",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnHour);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->EnHour);
	                snprintf(name,sizeof(name),"S%dEnMin",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnMin);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->EnMin);
	                snprintf(name,sizeof(name),"S%dPower",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->Power);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->Power);
	                snprintf(name,sizeof(name),"S%dRePower",j+1);
	                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->RePower);//usleep(10*1000);
	                ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->RePower);
                    snprintf(name,sizeof(name),"S%dSOCUpperLimit",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SocUp);//usleep(10*1000);
                    ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->SocUp);
                    snprintf(name,sizeof(name),"S%dSOCLowerLimit",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SocLower);//usleep(10*1000);
                    ems_syslog(LOG_NOTICE, "name: %s %d", name, tou->SocLower);
	                snprintf(name,sizeof(name),"S%dStHour",j+1);
	            }
                memcpy(g_usercfg_variant.tou, g_all_plan[i].schedule, sizeof(g_usercfg_variant.tou));
				break;
	        }
            else 
            {
                BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0042, NULL, "[北向]:未找到云平台当天策略");
            }
	    }
    }

	return 0;
}


extern int g_reflush_all_plan;



void *all_plan_task(void *arg)
{
    int reflush_today = 0;
    get_all_plan_from_file();
    while (1)
    {
        sleep(1);
        if (get_cabinet_info()->en_mqtt_emms2) //远程模式下才会将云端策略覆盖本地策略
        {
            time_t t = time(NULL);

            struct tm target_time = {};  
            localtime_r(&t, &target_time);
            struct tm *local_time = &target_time;
            
            if (local_time->tm_mday != reflush_today)
            {
                reflush_today = local_time->tm_mday;
                g_reflush_all_plan = 1;
            }
            if (g_reflush_all_plan)
            {
                reflush_all_plan();
                g_reflush_all_plan = 0;
                server_add_new_log(LOG_CODE_REFLUSH_PLAN,"EMS",LOG_MODE_TRIG,1,NULL);
                get_pcs_ctrl_var()->config_save = true;
                get_pcs_ctrl_var()->reflush_flag = 1;
            }
        }
    }
}
void all_plan_init()
{
    lc_power = dev_get_dev_tag_float(DEV_NO_EMS, LOCAL_CTRL_POWER);
    pthread_t pid;
    if (0 == pthread_create(&pid,NULL,all_plan_task,NULL))
    {
        pthread_setname_np(pid, "all_plan_task");
    }
}


int update_ems_user_cfg(usercfg_variant_t *pcfg, const char *node_id, tag_value *data_value)
{
    int find_config = 0;
    for(int i = 0 ;i<ems_config_tab_count_g;i++)
    {
        if(strcmp(node_id,ems_config_tab[i].nod) == 0) 
        {
            switch(ems_config_tab[i].data_type)
            {
                case EMS_POINT_INT:
                {
                    ems_syslog(LOG_NOTICE, "%s [%d] -> [%ld]",node_id,*((int *)((char *)pcfg + ems_config_tab[i].member_ofs)),data_value->value.to_int);
                    *((int *)((char *)pcfg + ems_config_tab[i].member_ofs)) = data_value->value.to_int;
                };
                break;
                case EMS_POINT_FLOAT:
                {
                    ems_syslog(LOG_NOTICE, "%s [%f] -> [%f]",node_id,*((float *)((char *)pcfg + ems_config_tab[i].member_ofs)),data_value->value.to_float);
                    *((float *)((char *)pcfg + ems_config_tab[i].member_ofs)) = data_value->value.to_float;
                };
                break; 
            }
            find_config = 1;
            break;
        }  
    }

    if(find_config == 0)
    {
        for(int i = 0;i<NUM_TOU_SEG_MAX;i++)//最大96段
        {       
            char name[64];
            tou_seg_t *tou = &pcfg->tou[i];
            snprintf(name,sizeof(name),"%s.S%dStHour",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->StHour = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dStMin",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->StMin = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dEnHour",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->EnHour = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dEnMin",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->EnMin = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dPower",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->Power = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dRePower",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->RePower = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dSOCUpperLimit",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->SocUp = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.S%dSOCLowerLimit",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {tou->SocLower = data_value->value.to_int;break;}
            ems_syslog(LOG_NOTICE, "Load TOU Segment[%d] [%d:%d] -> [%d:%d] = [power:%d] [repower:%d] [Socup:%d] [Soclower:%d]",i+1,tou->StHour,tou->StMin,tou->EnHour,tou->EnMin,tou->Power,tou->RePower,tou->SocUp,tou->SocLower);
        }
    }
    return 0;
}

void set_total_pcs_onoff( int val)
{
    callBaseEvent("客户端1",100,"操作了pcs");
    int log_val = 0;
    if (val == 0)
    {
        log_val = 2;
    }
    else
    {
        log_val = 1;
    }
    int cur_rack_sum = get_pcs_ctrl_var()->cabinet_cnt;
    if(cur_rack_sum == 0)
    {
            def_set_pcs_onoff(DEV_NO_PCS,  val);
            server_add_new_log(LOG_CODE_PCS_ONOFF,DEV_NO_PCS,LOG_MODE_TRIG,log_val,NULL);
    }
    else{
        char buff[64];
        snprintf(buff,sizeof(buff),DEV_NO_PCS);
        for(int i = 1; i <= cur_rack_sum ; i++)
        {
            server_add_new_log(LOG_CODE_PCS_ONOFF,buff,LOG_MODE_TRIG,log_val,NULL);
            def_set_pcs_onoff(buff,  val);
            ems_syslog(LOG_NOTICE, "pcs_no:%s, val:%d, cur_rack_sum:%d", buff, val, cur_rack_sum);
            snprintf(buff,sizeof(buff),DEV_NO_PCS"%d",i+1);
        }
    }
}

void set_total_pcs_onoff_reflush_time(int val)
{
    last_turn_off_time = time(NULL);
    set_total_pcs_onoff(val);
}
int get_total_pcs_onoff( int val)
{
    int pcs_state = 0;
    if(g_usercfg_variant.numOfPcs == 0)
    {
        pcs_state = def_get_pcs_onoff(DEV_NO_PCS);
    }
    else{
        for(int i = 0; i < g_usercfg_variant.numOfPcs ; i++)
        {
            char buff[64];
            snprintf(buff,sizeof(buff),DEV_NO_PCS"%d",i+1);
            pcs_state |= def_get_pcs_onoff(buff);
        }
    }
    return pcs_state;
}

void set_total_pcs_connect( int val)
{
    int log_val = 0;
    if (val == 0)
    {
        log_val = 2;
    }
    else
    {
        log_val = 1;
    }
    if(g_usercfg_variant.numOfPcs == 0)
    {
        server_add_new_log(LOG_CODE_PCS_GRID_ONOFF,DEV_NO_PCS,LOG_MODE_TRIG,log_val,NULL);
        dev_set_pcs_connect(DEV_NO_PCS,  val);
    }
    else{
        for(int i = 0; i < g_usercfg_variant.numOfPcs ; i++)
        {
            char buff[64];
            snprintf(buff,sizeof(buff),DEV_NO_PCS"%d",i+1);
            server_add_new_log(LOG_CODE_PCS_GRID_ONOFF,buff,LOG_MODE_TRIG,log_val,NULL);
            dev_set_pcs_connect(buff,  val);
        }
    }
}
void set_total_pcs_mode( int val)
{
    if(g_usercfg_variant.numOfPcs == 0)
    {
        def_set_pcs_mode(DEV_NO_PCS,  val);
    }
    else{
        for(int i = 0; i < g_usercfg_variant.numOfPcs ; i++)
        {
            char buff[64];
            snprintf(buff,sizeof(buff),DEV_NO_PCS"%d",i+1);
            def_set_pcs_mode(buff,  val);
        }
    }
}
#if 0 // 移到别处
int nod_cmp_int(const char *dev_id, const char *var_id, int cmp)
{
    int tmp = dev_get_dev_tag_int(dev_id, var_id);
    if (cmp > tmp)
    {
        return 1;
    }
    else if (cmp < tmp)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}
#endif

double get_cur_power(void)
{
    if (get_pcs_ctrl_var()->enable_group_ctrl)
    {
        double totle_power = 0.0f;
        char dev_no[DEV_NAME_LEN] = {0};
        int cur_rack_sum  = get_pcs_ctrl_var()->cabinet_cnt;
        snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS);
        for (int i = 1; i < cur_rack_sum+1; i++)
        { 
            totle_power+= (double)dev_get_dev_tag_float(dev_no, ACTIVE_POWER);
            snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS "%d", i + 1);
        }
        return totle_power;
    }
    //
    if (cabinet_info.en_lc_ctrl != 0)
    {
        char tag_name[TAG_NAME_LEN + 8] = {0};
        double value = 0.0f, value_tmp = 0.0f;
        int lc_sum = get_pcs_ctrl_var()->lc_list_len;
        lc_it *lc_arr = get_pcs_ctrl_var()->lc_list;
        for (int i = 0; i < lc_sum; i++)
        {
            value_tmp = 0;
            if  (lc_arr[i].type == eLC_TYPE_LC)
            {
                snprintf(tag_name, sizeof(tag_name), "%s.PCS", lc_arr[i].no);
                if (dev_get_dev_tag_float_with_result(tag_name, ACTIVE_POWER, &value_tmp) >= 0 && dev_get_dev_tag_int(tag_name, STATE_ONLINE) == 1)
                {
                    value += value_tmp;
                }
            }
            else
            {
                if ((dev_get_dev_tag_float_with_result(lc_arr[i].no, ACTIVE_POWER, &value_tmp) >= 0) && (dev_get_dev_tag_int(lc_arr[i].no, STATE_ONLINE) == 1))
                {
                    value += value_tmp;
                }
            }
        }
        return value;
    }
    else
    {
        return dev_get_dev_tag_float(DEV_NO_PCS, ACTIVE_POWER);
    }
}

double get_rea_power(void)
{
    if (get_pcs_ctrl_var()->enable_group_ctrl)
    {
        double totle_power = 0.0f;
        char dev_no[DEV_NAME_LEN] = {0};
        int cur_rack_sum  = get_pcs_ctrl_var()->cabinet_cnt;
        snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS);
        for (int i = 1; i < cur_rack_sum+1; i++)
        {
            totle_power+= (double)dev_get_dev_tag_float(dev_no, REACTIVE_POWER);
            snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS "%d", i + 1);
        }
        return totle_power;
    }
    //
    if (cabinet_info.en_lc_ctrl != 0)
    {
        return dev_get_dev_tag_float(DEV_NO_EMS, REACTIVE_POWER);
    }
    else
    {
        return dev_get_dev_tag_float(DEV_NO_PCS, REACTIVE_POWER);
    }
}

#if 1 //LC分功率逻辑
static int update_cab_valid_info(cab_info_t *cab, double power)
{
    int available_sum = 0;
    int cur_rack_sum = cab->cfg_sum = get_pcs_ctrl_var()->cabinet_cnt;
    //
    char tag_name[TAG_NAME_LEN] = {0};

    if (IS_CHARGE(power))
    {
        for (int i = 0; i < cur_rack_sum; i++)
        {
            cab->cab[i].status = 1;
            snprintf(tag_name, sizeof(tag_name), CAB_SYSTEM_STATUS "%d", i + 1);
            if (nod_cmp_int(DEV_NO_EMS, tag_name, 0) != 0)
            {
                ems_syslog(LOG_ERR, "柜%d 系统状态异常导致其期望功率为0", i + 1);
                continue;
            }
            //
            snprintf(tag_name, sizeof(tag_name), CAB_PROHIBITE_CHARGE "%d", i + 1);
            if (nod_cmp_int(DEV_NO_EMS, tag_name, 0) != 0)
            {
                ems_syslog(LOG_ERR, "柜%d 禁充导致其期望功率为0", i + 1);
                continue;
            }
            //
            snprintf(tag_name, sizeof(tag_name), CAB_DOD_LIMITED "%d", i + 1);
            if (nod_cmp_int(DEV_NO_EMS, tag_name, 0) > 0)
            {
                ems_syslog(LOG_ERR, "柜%d DOD保护导致其期望功率为0", i + 1);
                continue;
            }
            cab->cab[i].status = 0;
            available_sum++;
        }
    }
    else if (IS_DISCHARGE(power))
    {
        for (int i = 0; i < cur_rack_sum; i++)
        {
            cab->cab[i].status = 1;
            snprintf(tag_name, sizeof(tag_name), CAB_SYSTEM_STATUS "%d", i + 1);
            if (nod_cmp_int(DEV_NO_EMS, tag_name, 0) != 0)
            {
                ems_syslog(LOG_ERR, "柜%d 系统状态异常导致其期望功率为0", i + 1);
                continue;
            }
            //
            snprintf(tag_name, sizeof(tag_name), CAB_PROHIBITE_DISCHARGE "%d", i + 1);
            if (nod_cmp_int(DEV_NO_EMS, tag_name, 0) != 0)
            {
                ems_syslog(LOG_ERR, "柜%d 禁放导致其期望功率为0", i + 1);
                continue;
            }
            snprintf(tag_name, sizeof(tag_name), CAB_DOD_LIMITED "%d", i + 1);
            if (nod_cmp_int(DEV_NO_EMS, tag_name, 0) > 0)
            {
                ems_syslog(LOG_ERR, "柜%d DOD保护导致其期望功率为0", i + 1);
                continue;
            }
            cab->cab[i].status = 0;
            available_sum++;
        }
    }
    else
    {
        for (int i = 0; i < cur_rack_sum; i++)
        {
            cab->cab[i].status = 0;
            available_sum++;
        }
    }
    cab->valid_sum = available_sum;

    return available_sum;
}

static int update_ems_valid_info_disable_group(cab_info_t *cab, double power, double repower)
{
    int available_sum = 0;
    int cur_rack_sum = cab->cfg_sum = get_pcs_ctrl_var()->cabinet_cnt;
    if (cur_rack_sum > 1)
    {
        ems_syslog(LOG_ERR, "cabinet cnt error");
    }
    static int chadischapro = 0; // 0正常  1上限（禁充）  2下限（禁放）单柜（不使能主从模式）策略DOD充放保护标记在此定义
    if (key_info.index != key_info.last_index || (get_pcs_ctrl_var()->reflush_flag == 1)) {
        get_pcs_ctrl_var()->reflush_flag = 0;
        key_info.last_index = key_info.index;
        chadischapro = 0;
        ems_syslog(LOG_WARNING, "策略时间段切换，强制清除策略DOD禁充、禁放标记...");
    }

    //
    if (IS_CHARGE(power))
    {
        for (int i = 0; i < cur_rack_sum; i++)
        {
            cab->cab[i].status = 1;
            if (nod_cmp_int(DEV_NO_EMS, SYSTEM_STATUS, 0) != 0)
            {
                ems_syslog(LOG_ERR, "系统状态异常，导致期望功率为0；请检查系统状态字确认系统状态异常原因");
                continue;
            }
            //
            if (nod_cmp_int(DEV_NO_EMS, PROHIBITE_CHARGE, 0) != 0)
            {
                ems_syslog(LOG_ERR, "禁充保护，导致期望功率为0；请检查BMS的当前SOC或BMS过压告警");
                continue;
            }
            // 策略DOD
            if (g_usercfg_variant.ControlMode == EMS_AUTO_MODE && g_usercfg_variant.StratagyType == STRATAGY_TYPE_PERIOD_CTRL){ // --自动模式+削峰填谷，策略中的DOD保护才会生效
                // 单柜，cur_rack_sum = 1
                double soc_cur = dev_get_dev_tag_float(DEV_NO_EMS, CURRENT_SOC);
                if (logic_dod_protect(&key_info, &chadischapro, soc_cur) == 1){
                    ems_syslog(LOG_ERR, "策略DOD禁充保护，导致期望功率为0；请检查BMS的当前SOC");
                    continue;                
                }
            }
            cab->cab[i].status = 0;
            available_sum++;
        }
    }
    else if (IS_DISCHARGE(power))
    {
        for (int i = 0; i < cur_rack_sum; i++)
        {
            cab->cab[i].status = 1;
            if (nod_cmp_int(DEV_NO_EMS, SYSTEM_STATUS, 0) != 0)
            {
                ems_syslog(LOG_ERR, "系统状态异常，导致期望功率为0；请检查系统状态字确认系统状态异常原因");
                continue;
            }
            //
            if (nod_cmp_int(DEV_NO_EMS, PROHIBITE_DISCHARGE, 0) != 0)
            {
                ems_syslog(LOG_ERR, "禁放保护，导致期望功率为0；请检查BMS的当前SOC或BMS欠压告警");
                continue;
            }
            // 策略DOD
            if (g_usercfg_variant.ControlMode == EMS_AUTO_MODE && g_usercfg_variant.StratagyType == STRATAGY_TYPE_PERIOD_CTRL){
                // 单柜，cur_rack_sum = 1
                double soc_cur = dev_get_dev_tag_float(DEV_NO_EMS, CURRENT_SOC);
                if (logic_dod_protect(&key_info, &chadischapro, soc_cur) == 2){
                    ems_syslog(LOG_ERR, "策略DOD禁放保护，导致期望功率为0；请检查BMS的当前SOC");
                    continue;                
                } 
            }           
            cab->cab[i].status = 0;
            available_sum++;
        }
    }
    else
    {
        for (int i = 0; i < cur_rack_sum; i++)
        {
            cab->cab[i].status = 0;
            available_sum++;
        }
    }
    cab->valid_sum = available_sum;

    return available_sum;
}


static double bms_limit_power(double power, int index)
{
    double limit = 0;
    char limit_tag[TAG_NAME_LEN] = {0};
    if (g_usercfg_variant.en_bms_power_limit != 0)
    {
        if (IS_CHARGE(power))
        {
            snprintf(limit_tag, sizeof(limit_tag), MAX_CHARGE_POWER "%d", index + 1);
            limit = 0 - dev_get_dev_tag_float(DEV_NO_EMS, limit_tag);
            if (power < limit)
            {
                power = limit;
            }
        }
        else
        {
            snprintf(limit_tag, sizeof(limit_tag), MAX_DISCHA_POWER "%d", index + 1);
            limit = dev_get_dev_tag_float(DEV_NO_EMS, limit_tag);
            if (power > limit)
            {
                power = limit;
            }
        }
    }
    return power;
}

static double bms_limit_power_disable_group(double power)
{
    double limit = 0;

    if (g_usercfg_variant.en_bms_power_limit != 0)
    {
        if (IS_CHARGE(power))
        {
            limit = 0 - dev_get_dev_tag_float(DEV_NO_EMS, MAX_CHARGE_POWER);
            if (power < limit)
            {
                power = limit;
            }
        }
        else
        {
            limit = dev_get_dev_tag_float(DEV_NO_EMS, MAX_DISCHA_POWER);
            if (power > limit)
            {
                power = limit;
            }
        }
    }
    return power;
}


static int update_cab_expt_power_info(cab_info_t *cab, double val)
{
    double subpower = 0;
    int cur_valid_rack_sum = cab->valid_sum;
    char sub_expect_power[TAG_NAME_LEN] = {0};
    ems_syslog(LOG_NOTICE, "cur valid rack sum:%d", cur_valid_rack_sum);
    if (cur_valid_rack_sum < 1)
    {
        ems_syslog(LOG_ERR, "当前没有可以充放电的柜子,可充放柜子数:%d", cur_valid_rack_sum);
        subpower = 0;
    }
    else
    {
        // 每个柜子的功率
        subpower = val / (double)cur_valid_rack_sum;
    }

    val = 0;
    for (int i = 0; i < cab->cfg_sum; i++)
    {
        if (cab->cab[i].status == 0)
        {
            cab->cab[i].exp_powert = bms_limit_power(subpower, i);
            val += cab->cab[i].exp_powert;
            
        }
        else
        {
            cab->cab[i].exp_powert = 0;
        }

        if (IS_CHARGE(subpower))
        {
            if ((cab->cab[i].exp_powert - subpower) > 1.0)
            {
                ems_syslog(LOG_ERR, "BMS对期望功率进行了限制。LC输入功率:%.2f, BMS限制后的期望功率:%.2f", subpower, cab->cab[i].exp_powert);
            }
        }
        else if (IS_DISCHARGE(subpower))
        {
            if ((subpower - cab->cab[i].exp_powert) > 1.0)
            {
                ems_syslog(LOG_ERR, "BMS对期望功率进行了限制。LC输入功率:%.2f, BMS限制后的期望功率:%.2f", subpower, cab->cab[i].exp_powert);
            }
        }
        snprintf(sub_expect_power, sizeof(sub_expect_power), EXPECT_ACT_POWER "%d", i + 1);
        dev_set_dev_tag_float(DEV_NO_EMS, sub_expect_power, cab->cab[i].exp_powert);
    }
    cab->exp_powert = val;
    dev_set_dev_tag_float(DEV_NO_EMS, EXPECT_ACT_POWER, cab->exp_powert);
    return 0;
}


static int update_cab_expt_power_info_disable_group(cab_info_t *cab, double power, double repower)
{
    double subpower = 0;
    int cur_valid_rack_sum = cab->valid_sum;
    ems_syslog(LOG_NOTICE, "cur valid rack sum:%d", cur_valid_rack_sum);
    if (cur_valid_rack_sum != 1)
    {
        ems_syslog(LOG_ERR, "cur valid rack sum:%d", cur_valid_rack_sum);
        subpower = 0;
    }
    subpower = power;

    power = 0;
    if (cab->cab[0].status == 0)
    {
        cab->cab[0].exp_powert = bms_limit_power_disable_group(subpower);
        power += cab->cab[0].exp_powert;
        cab->cab[0].exp_repowert = repower;
    }
    else
    {
        cab->cab[0].exp_powert = 0;
        cab->cab[0].exp_repowert = 0;
    }

    if (IS_CHARGE(subpower))
    {
        if ((power - subpower) > 1.0)
        {
            ems_syslog(LOG_ERR, "BMS对期望功率进行了限制。LC输入功率:%.2f, BMS限制后的期望功率:%.2f", subpower, power);
        }
    }
    else if (IS_DISCHARGE(subpower))
    {
        if ((subpower - power) > 1.0)
        {
            ems_syslog(LOG_ERR, "BMS对期望功率进行了限制。LC输入功率:%.2f, BMS限制后的期望功率:%.2f", subpower, power);
        }
    }
    cab->exp_powert = power;
    cab->exp_repowert = repower;
    dev_set_dev_tag_float(DEV_NO_EMS, EXPECT_ACT_POWER, cab->exp_powert);
    return 0;
}

static time_t *manual_pcs_auto_turn_off_time;
static int cab_num = 0;
int check_DD_mode_pcs_autp_turn_off()
{
    if(g_usercfg_variant.ControlMode != EMS_MANUAL_MODE || manual_pcs_auto_turn_off_time == NULL || dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN) == 0)
    {
        return -1;
    }
    char dev_no[DEV_NAME_LEN] = {0};
    snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS);
    int time_interval = dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN_OFF_TIME);
    for(int i = 0; i < cab_num; i++)
    {
        if (last_turn_off_time < manual_pcs_auto_turn_off_time[i]) //没有手动控制开关
        {
            if ((time(NULL) - manual_pcs_auto_turn_off_time[i] >= time_interval) && (0 != def_get_pcs_onoff(dev_no)))
            {
                def_set_pcs_onoff(dev_no, 0); // 关机
                manual_pcs_auto_turn_off_time[i] = 0;
            }

        }
        snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS "%d", i + 1);
    }
    return 0;
}

static int update_cab_expt_power_sync(cab_info_t *cab)
{
    int index = 0;
    char dev_no[DEV_NAME_LEN] = {0};
    double exp_powert = 0, exp_repowert = 0;

    cab_num = cab->cfg_sum;
    if(manual_pcs_auto_turn_off_time == NULL)
    {
        manual_pcs_auto_turn_off_time = calloc(cab_num, sizeof(time_t));
        if (!manual_pcs_auto_turn_off_time) {
            ems_syslog(LOG_ERR, "Failed to allocate memory for manual_pcs_auto_turn_off_time");
        }
    }
    
    // 写入功率
    snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS);

    do
    {
        exp_powert = cab->cab[index].exp_powert;
        exp_repowert = cab->cab[index].exp_repowert;
        //
        if (dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN)) // 使能自动关机
        {
            if (IS_IDLE(exp_powert))
            {
                if (cab->cab[index].start_0_power_time == 0)
                {
                    cab->cab[index].start_0_power_time = time(NULL);
                    manual_pcs_auto_turn_off_time[index] = time(NULL);
                }
                else
                {
                    if (last_turn_off_time < cab->cab[index].start_0_power_time) //没有手动控制开关
                    {
                        int time_interval = dev_get_dev_tag_int(DEV_NO_EMS, PCS_AUTO_TURN_OFF_TIME);
                        if ((time(NULL) - cab->cab[index].start_0_power_time >= time_interval) && (0 != def_get_pcs_onoff(dev_no)))
                        {
                            def_set_pcs_onoff(dev_no, 0); // 关机
                        }
                    }
                }
            }
            else
            {
                cab->cab[index].start_0_power_time = 0;
                manual_pcs_auto_turn_off_time[index] = 0;
                if (0 == def_get_pcs_onoff(dev_no)) // 没有开机
                {
                    def_set_pcs_onoff(dev_no, 1); // 开机
                }
            }
        }
        else
        {
            manual_pcs_auto_turn_off_time[index] = 0;
            cab->cab[index].start_0_power_time = 0;
            if ((!IS_IDLE(exp_powert)) && (0 == def_get_pcs_onoff(dev_no))) // 没有开机
            {
                def_set_pcs_onoff(dev_no, 1); // 开机
            }
        }
        //
        switch (cab->cab[index].status)
        {
        case 0:                                 // 正常
        case 1:                                 // 保护
            def_set_pcs_power(dev_no, exp_powert);      // 设置有功
            def_set_pcs_repower(dev_no, exp_repowert);  // 设置无功
            break;
        default:
            ems_syslog(LOG_ERR, "柜[%d]的系统状态错误, 系统状态=%d", index, cab->cab[index].status);
            break;
        }
        //
        index++;
        snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS "%d", index + 1);
    } while (index < cab->cfg_sum);
    return 0;
}

static int update_cab_power_sync_ems(cab_info_t *cab)
{
    int index = 0;
    char dev_no[DEV_NAME_LEN] = {0};
    double PcsActivePower = 0;
    double PcsReactivePower = 0;
    double LastActivePower = 0;
    double LastReactivePower = 0;

    snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS);
    do
    {
        ems_syslog(LOG_INFO, "dev_no = %s", dev_no);
        if(dev_get_dev_tag_float(dev_no, STATE_ONLINE))
        {
            PcsActivePower = def_get_pcs_power(dev_no);
            PcsReactivePower = def_get_pcs_repower(dev_no);
        }
        else
        {
            PcsActivePower = 0;
            PcsReactivePower = 0;
        }
        index++;
        LastActivePower += PcsActivePower;
        LastReactivePower += PcsReactivePower;

        snprintf(dev_no, sizeof(dev_no), DEV_NO_PCS "%d", index + 1);
    } while (index < cab->cfg_sum);

    dev_set_dev_tag_float(DEV_NO_EMS, PCS_ACTIVEPOWER, LastActivePower);
    dev_set_dev_tag_float(DEV_NO_EMS, PCS_REACTIVEPOWER, LastReactivePower);

    return 0;
}


cab_info_t cab_info[MAX_RACK_SUM_SUPPORT];
int update_cab_info()
{
    double power = get_lc_power();
    double repower = get_lc_repower();
    double active_power = ems_limit_power( power);
    // update_installed_power();
    if (get_pcs_ctrl_var()->enable_group_ctrl) // 分组已废弃
    {
        update_cab_valid_info(cab_info, active_power);
        update_cab_expt_power_info(cab_info, active_power);
    }
    else
    {
        update_ems_valid_info_disable_group(cab_info, active_power, repower);
        update_cab_expt_power_info_disable_group(cab_info, active_power, repower);
    }
    update_cab_expt_power_sync(cab_info);
    update_cab_power_sync_ems(cab_info);

    return 0;
}

void update_total_power_sync(void)
{
    update_cab_power_sync_ems(cab_info);
}


#endif


int get_same_child_type_devs_cnt_if_zc(char *type_main, char *child_type, char dev_no_list[][DEV_NAME_LEN], int max_cnt)
{
    int cnt = 0;
    if(!type_main || !child_type)
    {
        proto_syslog(LOG_ERR, "Invalid param ,need a specific type");
        return -1;
    }
    proto_forward_t *dev_var = get_proto_forward_var();
    for (int i = 0; i < dev_var->channels_size; i++)
    {
        for (int j = 0; j < dev_var->channels[i]->devs_size; j++)
        {
            device_t *dev = dev_var->channels[i]->devs[j];
            if (dev == NULL)
            {
                proto_syslog(LOG_ERR, "device[%d] is null", i);
                continue;
            }
            if (strcmp(dev->dev_type,type_main) == 0 && strcmp(dev->dev_child_type, child_type) == 0)
            {
                if (cnt < max_cnt) {
                    snprintf(dev_no_list[cnt], sizeof(dev_no_list[0]), "%s", dev->no);
                    cnt++;
                }
                else{
                    proto_syslog(LOG_ERR, "PCS_meter num > 10 ");
                }
            }
        }
    }
    return cnt;
}

void update_total_energy(void)
{
    char dev_no[DEV_NAME_LEN * 2] = {0};
    int mt_cnt = 0;

    double forward_energy = 0;
    double reverse_energy = 0;
    double active_power = 0;
    double reactive_power = 0;
    char dev_no_list[10][DEV_NAME_LEN] = {0};

    mt_cnt = get_same_child_type_devs_cnt_if_zc(DEV_NO_METER, "PCS", dev_no_list, sizeof(dev_no_list) / sizeof(dev_no_list[0]));
    for (int i = 0; i < mt_cnt; i++)
    {
        snprintf(dev_no, sizeof(dev_no), "%s", dev_no_list[i]);

        if (dev_get_dev_tag_float(dev_no, STATE_ONLINE))
        {
            forward_energy += dev_get_dev_tag_float(dev_no, MT_FORWARD_ENERGY);
            reverse_energy += dev_get_dev_tag_float(dev_no, MT_REVERSE_ENERGY);
            active_power += dev_get_dev_tag_float(dev_no, MT_ACTIVE_POWER);
            reactive_power += dev_get_dev_tag_float(dev_no, MT_REACTIVE_POWER);
        }
    }

    dev_set_dev_tag_float(DEV_NO_EMS, TOTAL_FORWARD_ENERGY, forward_energy);
    dev_set_dev_tag_float(DEV_NO_EMS, TOTAL_REVERSE_ENERGY, reverse_energy);
    dev_set_dev_tag_float(DEV_NO_EMS, TOTAL_ACTIVE_POWER, active_power);
    dev_set_dev_tag_float(DEV_NO_EMS, TOTAL_REACTIVE_POWER, reactive_power);
}

void set_total_pv_power(double val)
{
    dev_set_dev_tag_float(DEV_NO_EMS, PV_CUR_PERCENT,val);
    int index = 0;
    int cur_pv_sum = get_pcs_ctrl_var()->pv_pcs_num;
    char dev_no[DEV_NAME_LEN] = {0};
    // 写入功率
    snprintf(dev_no, sizeof(dev_no), DEV_NO_PV);
    do
    {
        dev_set_dev_tag_float(dev_no, PV_PERCENT_LIMIT,val);
        index++;
        snprintf(dev_no, sizeof(dev_no), DEV_NO_PV "%d", index + 1);
    } while (index < cur_pv_sum);
}
// double get_total_pv_power()
// {
//     dev_set_dev_tag_float(DEV_NO_EMS, PV_CUR_PERCENT,val);
//     int index = 0;
//     int cur_pv_sum = get_pcs_ctrl_var()->pv_pcs_num;
//     char dev_no[DEV_NAME_LEN] = {0};
//     // 写入功率
//     snprintf(dev_no, sizeof(dev_no), DEV_NO_PV);
//     do
//     {
//         dev_set_dev_tag_float(dev_no, PV_PERCENT_LIMIT,val);
//         index++;
//         snprintf(dev_no, sizeof(dev_no), DEV_NO_PV "%d", index + 1);
//     } while (index < cur_pv_sum);
// }


// void check_limit_power(void)
// {
//     float power = dev_get_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER);
//     float expect_power = dev_get_dev_tag_float(DEV_NO_EMS, EXPECT_ACT_POWER);
//     ems_syslog(LOG_DEBUG, "abs(expect_total_power):%f, power %f, limit %f", fabsf(expect_power), power, (fabsf(expect_power) - power));
//     if((fabsf(expect_power - power)) > 0.001)
//     {
//         if(dev_get_dev_tag_int(DEV_NO_EMS, POWER_LIMITED) == 0)
//         {
//             dev_set_dev_tag_int(DEV_NO_EMS, POWER_LIMITED, 1);
//         }
//     }
//     else
//     {   
//         if(dev_get_dev_tag_int(DEV_NO_EMS, POWER_LIMITED) == 1)
//         {
//             dev_set_dev_tag_int(DEV_NO_EMS, POWER_LIMITED, 0);
//         }
//     }
// }

// void check_peflux_power(void)
// {
//     double power = dev_get_dev_tag_float(DEV_NO_GRID_MT, METER_POWER);
//     if(power < 0.0f)
//     {
//         if(dev_get_dev_tag_int(DEV_NO_EMS, POWER_REFLUX) == 0)
//         {
//             dev_set_dev_tag_int(DEV_NO_EMS, POWER_REFLUX, 1);
//         }
//     }
//     else
//     {   
//         if(dev_get_dev_tag_int(DEV_NO_EMS, POWER_REFLUX) == 1)
//         {
//             dev_set_dev_tag_int(DEV_NO_EMS, POWER_REFLUX, 0);
//         }
//     }
// }



void emsctrl_proc_init(pcs_ctrl_var_t *var) 
{
    int ret = 0;
    ems_syslog(LOG_NOTICE, "SysStatus CHECK...");
    ret = device_layer_selftest(var);
    if(ret == 0)
    {
        ems_syslog(LOG_NOTICE, "SysStatus NORM!");
        dev_set_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS,  EMS_SYSTEM_NORM);
    }   
    else
    {
        ems_syslog(LOG_NOTICE, "SysStatus EXCEPT!");
        dev_set_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS,  EMS_SYSTEM_EXCEPT);
    }
}

// 检查空调是否需要开启
void check_aircond_startstop(float powernow)
{
    usercfg_variant_t* pcfg = &g_usercfg_variant;

    int tval = AC_START;
    int today_second = (int) get_seconds_of_today();
    int ahead_time = dev_get_dev_tag_int(DEV_NO_EMS, AIR_COND_AHEAD_TIME) * 60;
    int delay_time = dev_get_dev_tag_int(DEV_NO_EMS, AIR_COND_DELAY_TIME) * 60;

    static time_t last_idel_time = 0;
    if (pcfg->ControlMode == 0) // 手动模式 功率为0时开始计时, delay_time后停机
    {
        if (IS_IDLE(powernow))
        {
            if (time(NULL) - last_idel_time > delay_time) 
            {
                tval = AC_STOP;
            }
        }
        else
        {
            last_idel_time = time(NULL);
        }
    }
    else if (pcfg->ControlMode == 1) // 策略模式,按照策略时间
    {
        tval = AC_STOP;
        if (ahead_time < 0 || delay_time < 0)
        {
            ems_syslog(LOG_ERR, "Error, invalid AIR_COND_XXX_TIME: %d, %d", ahead_time, delay_time);
            if (ahead_time < 0) ahead_time = 0;
            if (delay_time < 0) delay_time = 0;           
        }

        for (int i = 0; i < NUM_TOU_SEG_MAX; i++) 
        {
            tou_seg_t* tou = &pcfg->tou[i];

            int start_time = tou->StHour * 3600 + tou->StMin * 60;
            int end_time   = tou->EnHour * 3600 + tou->EnMin * 60;

            if (start_time == end_time) continue;
            
            if (today_second >= start_time - ahead_time && today_second <= end_time + delay_time)
            {
                tval = AC_START;
                last_idel_time = time(NULL); // 防止切换手动时空调立刻关机
                break;
            }
        }
    }

    dev_set_dev_tag_int(DEV_NO_EMS, AIR_COND_STARTSTOP_CTRL, tval);
    if (!(get_cabinet_info()->en_lc)) // 对等模式设置空调，主从模式由从机控制空调
    {
        ac_set_mode_api(tval);     // 1:开机; 0:停机  
    }
}


void check_lc_and_set(double power, double repower)
{
    set_lc_power(power, repower);
}

double get_ems_lc_power(void)
{
    return lc_power;
}

double get_ems_lc_repower(void)
{
    return lc_repower;
}


void set_lc_power(double power, double repower)
{
    lc_power = power;
    lc_repower = repower;
    ems_syslog(LOG_NOTICE, "Set lc power:%f repower:%f", lc_power, lc_repower);
    dev_set_dev_tag_float(DEV_NO_EMS, LOCAL_CTRL_POWER, lc_power); 

    void *lc_power_update(void *arg);
    lc_power_update(NULL);
#if 0
    if (dev_get_dev_tag_int(DEV_NO_EMS,SYSTEM_STATUS)==EMS_SYSTEM_EXCEPT)
    {
        ems_syslog(LOG_ERR, "EMS system status protected");
        goto Protect;
    }
    if(IS_CHARGE(power))
    {
        if(dev_get_dev_tag_int(DEV_NO_EMS, PROHIBITE_CHARGE) != 0)
        {
            ems_syslog(LOG_ERR, "Set power be refused, BMS prohibite charging,check whether or not exit alarm in BMS");
            goto Protect;
        }
    }
    else if(IS_DISCHARGE(power))
    {
        if(dev_get_dev_tag_int(DEV_NO_EMS, PROHIBITE_DISCHARGE) != 0)
        {
            ems_syslog(LOG_ERR, "Set power be refused, BMS prohibite discharging,check whether or not exit alarm in BMS");
            goto Protect;
        }
    }
    set_total_pcs_power(power);
    return;

    Protect:
        ems_syslog(LOG_ERR, "Protect:Set power be refused!");
        set_total_pcs_power(0);
#endif
}
