#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 lc_power_info_t lc_power_info = {0};

extern ems_cfg_info_t ems_config_tab[];
extern int ems_config_tab_count_g;
extern all_plan g_all_plan[];
extern all_TOU_plan g_all_TOU_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<get_tou_max_num();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);
    }


    for(int j = 0;j<get_tou_max_num();j++)//最大96段
    {
        char name[64];
        TOU_local_info_t *tou = &pcfg->TOU_info[j];
        snprintf(name,sizeof(name),"TOUS%dStHour",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StHour);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dStMin",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StMin);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dEnHour",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnHour);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dEnMin",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnMin);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dStratagyType",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->strategy);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dPower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->Power);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dSOCUpperLimit",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SOCUpperLimit);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dSOCLowerLimit",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SOCLowerLimit);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dSurplusToGrid",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SurplusToGrid);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dChargePower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->ChargePower);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dDischargePower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->DischargePower);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dChargeGrid",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->ChargeGrid);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dChargeDG",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->ChargeDG);//usleep(10*1000);
        for (int k = 0; k < tou->userdefNum && k < NUM_TOU_USERDEF_MAX; k++)
        {
            if (tou->userdef[k].id != NULL)
            {
                snprintf(name,sizeof(name),"TOUS%d%s",j+1,tou->userdef[k].id);
                write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->userdef[k].value);//usleep(10*1000);
                ems_syslog(LOG_INFO, "TOU userdef[%d] tag:%s value:%d", k, tou->userdef[k].id,tou->userdef[k].value);                         
            }
        }
    }
}

double get_lc_power(void)
{
    return lc_power_info.active_power;
}
double get_lc_repower(void)
{
    return lc_power_info.reactive_power;
}

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<get_tou_max_num();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<get_tou_max_num();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<get_tou_max_num();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;
}

int reflush_all_TOU_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<get_tou_max_num();j++)//最大96段
    {
        char name[64];
        snprintf(name,sizeof(name),"TOUS%dStHour",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dStMin",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dEnHour",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dEnMin",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dStratagyType",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dPower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dSOCUpperLimit",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,-1);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dSOCLowerLimit",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,-1);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dSurplusToGrid",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dChargePower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dDischargePower",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dChargeGrid",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        snprintf(name,sizeof(name),"TOUS%dChargeDG",j+1);
        write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
        for (size_t i = 0; i < g_usercfg_variant.TOU_info[j].userdefNum; i++)
        {
            snprintf(name,sizeof(name),"TOUS%d%s",j+1,g_usercfg_variant.TOU_info[j].userdef[i].id);
            write_int_to_tag_cache_directly(DEV_NO_EMS,name,0);//usleep(10*1000);
            g_usercfg_variant.TOU_info[j].userdef[i].value = 0;
        }
        memset(&g_usercfg_variant.TOU_info[j],0,offsetof(TOU_local_info_t, userdefNum));
    }
    // north_control = -1;//当前阶段TOU不支持北向需要支持后续扩展
    // if(north_control == -1)
    // {
        for (size_t i = 0; i < MAX_DAY_YEAR; i++)
	    {
	        if (g_all_TOU_plan[i].year == 0)
	        {
	            break;
	        }
	        if ((g_all_TOU_plan[i].year == local_time->tm_year+1900)&&(g_all_TOU_plan[i].mounth == local_time->tm_mon+1)&&(g_all_TOU_plan[i].date == local_time->tm_mday))
	        {
	            ems_syslog(LOG_WARNING, "find TOU plan, year:%d mounth:%d date:%d", g_all_TOU_plan[i].year,g_all_TOU_plan[i].mounth, g_all_TOU_plan[i].date);
	            for(int j = 0;j<get_tou_max_num();j++)//最大96段
	            {
	                char name[64];
	                TOU_info_t *tou = &g_all_TOU_plan[i].schedule[j];
	                snprintf(name,sizeof(name),"TOUS%dStHour",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StHour);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dStMin",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->StMin);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dEnHour",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnHour);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dEnMin",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->EnMin);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dStratagyType",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->strategy);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dPower",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->Power);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dSOCUpperLimit",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SOCUpperLimit);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dSOCLowerLimit",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SOCLowerLimit);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dSurplusToGrid",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->SurplusToGrid);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dChargePower",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->ChargePower);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dDischargePower",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->DischargePower);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dChargeGrid",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->ChargeGrid);//usleep(10*1000);
                    snprintf(name,sizeof(name),"TOUS%dChargeDG",j+1);
                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->ChargeDG);//usleep(10*1000);
                    for (int k = 0; k < tou->userdefNum && k < NUM_TOU_USERDEF_MAX; k++)
                    {
                        if (tou->userdef[k].id != NULL)
                        {
                            for (int l = 0; l < g_usercfg_variant.TOU_info[j].userdefNum; l++)
                            {
                                if (strcmp(tou->userdef[k].id, g_usercfg_variant.TOU_info[j].userdef[l].id)==0)
                                {
                                    snprintf(name,sizeof(name),"TOUS%d%s",j+1,g_usercfg_variant.TOU_info[j].userdef[l].id);
                                    write_int_to_tag_cache_directly(DEV_NO_EMS,name,tou->userdef[k].value);//usleep(10*1000);
                                    g_usercfg_variant.TOU_info[j].userdef[l].value = tou->userdef[k].value;
                                    ems_syslog(LOG_INFO, "TOU userdef[%d] tag:%s value:%d", k, g_usercfg_variant.TOU_info[j].userdef[l].id, g_usercfg_variant.TOU_info[j].userdef[l].value);
                                }
                            }                            
                        }
                    }
                    memcpy(&g_usercfg_variant.TOU_info[j], g_all_TOU_plan[i].schedule,offsetof(TOU_local_info_t, userdefNum));
	            }
				break;
	        }
	    }
    // }

	return 0;
}
extern int g_reflush_all_plan;
extern int g_reflush_all_TOU_plan;


void *all_plan_task(void *arg)
{
    int reflush_today = 0;
    get_all_plan_from_file();
    get_all_TOU_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;
                g_reflush_all_TOU_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;
            }
            if (g_reflush_all_TOU_plan)
            {
                reflush_all_TOU_plan();
                g_reflush_all_TOU_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_info.active_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<get_tou_max_num();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);


            TOU_local_info_t *TOU2 = &pcfg->TOU_info[i];
            snprintf(name,sizeof(name),"%s.TOUS%dStHour",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->StHour = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dStMin",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->StMin = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dEnHour",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->EnHour = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dEnMin",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->EnMin = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dPower",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->Power = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dStratagyType",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->strategy = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dSOCUpperLimit",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->SOCUpperLimit = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dSOCLowerLimit",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->SOCLowerLimit = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dSurplusToGrid",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->SurplusToGrid = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dChargePower",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->ChargePower = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dDischargePower",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->DischargePower = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dChargeGrid",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->ChargeGrid = data_value->value.to_int;break;}
            snprintf(name,sizeof(name),"%s.TOUS%dChargeDG",DEV_NO_EMS,i+1);
            if(strcmp(node_id,name) == 0) {TOU2->ChargeDG = data_value->value.to_int;break;}

            for (int k = 0; k < TOU2->userdefNum && k < NUM_TOU_USERDEF_MAX; k++)
            {
                if (TOU2->userdef[k].id != NULL)
                {
                    snprintf(name,sizeof(name),"%s.TOUS%d%s",DEV_NO_EMS,i+1,TOU2->userdef[k].id);
                    if (strcmp(name,node_id)==0)
                    {
                        TOU2->userdef[k].value =  data_value->value.to_int;
                        ems_syslog(LOG_INFO, "TOU userdef[%d] tag:%s value:%ld", k, TOU2->userdef[k].tag, data_value->value.to_int);
                    }
                }
            }
        }
    }
    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_cur_reactive_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)
    {
        char tag_name[TAG_NAME_LEN*2] = {"LC%s.PCS"};
        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, REACTIVE_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, REACTIVE_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, REACTIVE_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分功率逻辑
#if 0
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;
}
#endif
static int update_ems_valid_info_disable_group(cab_info_t *cab, lc_power_info_t power_info)
{
    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_info.active_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_info.active_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;
}

#if 0
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;
}
#endif
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;
}

#if 0
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;
}
#endif


static int update_cab_expt_power_info_disable_group(cab_info_t *cab, lc_power_info_t power_info)
{
    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;
    }
    
    double original_active_power = power_info.active_power;
    subpower = power_info.active_power;

    power_info.active_power = 0;

    if (cab->cab[0].status == 0)
    {
        // BMS 功率限制
        cab->cab[0].exp_powert = bms_limit_power_disable_group(subpower);
        power_info.active_power += cab->cab[0].exp_powert;
        cab->cab[0].exp_repowert = power_info.reactive_power;
        
        //
        if (original_active_power != 0)
        {
            //
            double ratio = cab->cab[0].exp_powert / original_active_power;
            cab->cab[0].phase_a_exp_powert = power_info.phase_a_power * ratio;
            cab->cab[0].phase_b_exp_powert = power_info.phase_b_power * ratio;
            cab->cab[0].phase_c_exp_powert = power_info.phase_c_power * ratio;
        }
        else
        {
            //
             cab->cab[0].phase_a_exp_powert = 0;
             cab->cab[0].phase_b_exp_powert = 0;
             cab->cab[0].phase_c_exp_powert = 0;
        }
        
        // 更新总结构体中的三相功率（这里只有一个柜子有效，直接赋值）
        cab->phase_a_exp_powert = cab->cab[0].phase_a_exp_powert;
        cab->phase_b_exp_powert = cab->cab[0].phase_b_exp_powert;
        cab->phase_c_exp_powert = cab->cab[0].phase_c_exp_powert;
        
        ems_syslog(LOG_NOTICE, "Cab[0] Phases: A=%.2f, B=%.2f, C=%.2f", 
            cab->cab[0].phase_a_exp_powert, cab->cab[0].phase_b_exp_powert, cab->cab[0].phase_c_exp_powert);
        // -----------------------
    }
    else
    {
        cab->cab[0].exp_powert = 0;
        cab->cab[0].exp_repowert = 0;
        cab->cab[0].phase_a_exp_powert = 0;
        cab->cab[0].phase_b_exp_powert = 0;
        cab->cab[0].phase_c_exp_powert = 0;
        
        cab->phase_a_exp_powert = 0;
        cab->phase_b_exp_powert = 0;
        cab->phase_c_exp_powert = 0;
    }

    if (IS_CHARGE(subpower))
    {
        if ((power_info.active_power - subpower) > 1.0)
        {
            ems_syslog(LOG_ERR, "BMS对期望功率进行了限制。LC输入功率:%.2f, BMS限制后的期望功率:%.2f", subpower, power_info.active_power);
        }
    }
    else if (IS_DISCHARGE(subpower))
    {
        if ((subpower - power_info.active_power) > 1.0)
        {
            ems_syslog(LOG_ERR, "BMS对期望功率进行了限制。LC输入功率:%.2f, BMS限制后的期望功率:%.2f", subpower, power_info.active_power);
        }
    }
    cab->exp_powert = power_info.active_power;
    cab->exp_repowert = power_info.reactive_power;
    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:                                 // 保护
            if (g_usercfg_variant.EnableSinglePhaseReverse == 1)
            {
                // 启用分相控制，下发三相有功
                pe_set_value(dev_no, "set_power_A", cab->cab[index].phase_a_exp_powert);
                pe_set_value(dev_no, "set_power_B", cab->cab[index].phase_b_exp_powert);
                pe_set_value(dev_no, "set_power_C", cab->cab[index].phase_c_exp_powert);
                // 无功照常下发（假设无功不分相，或者由总无功控制）
                def_set_pcs_repower(dev_no, exp_repowert); 
            }
            else
            {
                // 原有逻辑：下发总有功
                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))
        {
            if (g_usercfg_variant.EnableSinglePhaseReverse == 1)
            {
                double phase_a = 0, phase_b = 0, phase_c = 0;
                dev_get_function_double(dev_no, "get_power_A", &phase_a);
                dev_get_function_double(dev_no, "get_power_B", &phase_b);
                dev_get_function_double(dev_no, "get_power_C", &phase_c);
                
                PcsActivePower = phase_a + phase_b + phase_c;
                PcsReactivePower = def_get_pcs_repower(dev_no);
            }
            else
            {
                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()
{
    lc_power_info_t power_info = get_lc_power_info();
    power_info.active_power = ems_limit_power(power_info.active_power);

    if (power_info.active_power == 0) {
        power_info.phase_a_power = power_info.phase_b_power = power_info.phase_c_power = 0;
    } else {
        double total = fabs(power_info.phase_a_power) + fabs(power_info.phase_b_power) + fabs(power_info.phase_c_power);
        //
        double ratio_a = total > 0 ? (power_info.phase_a_power / total) : (1.0 / 3.0);
        double ratio_b = total > 0 ? (power_info.phase_b_power / total) : (1.0 / 3.0);
        double ratio_c = total > 0 ? (power_info.phase_c_power / total) : (1.0 / 3.0);

        power_info.phase_a_power = power_info.active_power * ratio_a;
        power_info.phase_b_power = power_info.active_power * ratio_b;
        power_info.phase_c_power = power_info.active_power * ratio_c;
    }

    if(get_cabinet_info()->is_slave != 0 && g_usercfg_variant.EnableSinglePhaseReverse == 1 && power_info.active_power != 0)
    {
        double phase_a_power = dev_get_dev_tag_float(DEV_NO_EMS, SET_PHASE_A_POWER);
        double phase_b_power = dev_get_dev_tag_float(DEV_NO_EMS, SET_PHASE_B_POWER);
        double phase_c_power = dev_get_dev_tag_float(DEV_NO_EMS, SET_PHASE_C_POWER);
        double total_phase_power = phase_a_power + phase_b_power + phase_c_power;
        double phase_a_power_coef = phase_a_power / total_phase_power;
        double phase_b_power_coef = phase_b_power / total_phase_power;
        double phase_c_power_coef = phase_c_power / total_phase_power;

        power_info.phase_a_power = power_info.active_power * phase_a_power_coef;
        power_info.phase_b_power = power_info.active_power * phase_b_power_coef;
        power_info.phase_c_power = power_info.active_power * phase_c_power_coef;
    }

    ems_syslog(LOG_NOTICE,
               "Updated power distribution: Total Active Power = %.2f, Phase A "
               "= %.2f, Phase B = %.2f, Phase C = %.2f",
               power_info.active_power, power_info.phase_a_power,
               power_info.phase_b_power, power_info.phase_c_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, power_info);
        update_cab_expt_power_info_disable_group(cab_info, power_info);
    }
    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_syslog(LOG_INFO, "[ZC] 查找设备: 主类型='%s', 子类型='%s', 最大数量=%d", type_main, child_type, max_cnt);
    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;
            }
            proto_syslog(LOG_DEBUG, "[ZC] 检查设备[%d][%d]: 类型='%s', 子类型='%s', 设备号='%s'",
                         i, j, dev->dev_type, dev->dev_child_type, dev->no);
            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);
                    proto_syslog(LOG_INFO, "[ZC] 找到匹配设备[%d]: 设备号='%s'", cnt, dev->no);
                    cnt++;
                }
                else{
                    proto_syslog(LOG_ERR, "PCS_meter num > 10 ");
                }
            }
        }
    }
    proto_syslog(LOG_INFO, "[ZC] 查找设备完成: 主类型='%s', 子类型='%s', 匹配数量=%d", type_main, child_type, cnt);
    return cnt;
}

void update_total_energy(void)
{
    char dev_no[DEV_NAME_LEN * 2] = {0};
    int mt_cnt = 0;
    int use_grid_meter = 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};

    ems_syslog(LOG_NOTICE, "开始更新总能量，优先从关口表获取数据");

    // 优先从 GRID_METER（关口表）获取数据
    mt_cnt = get_same_child_type_devs_cnt_if_zc(DEV_NO_METER, "GRID", dev_no_list, sizeof(dev_no_list) / sizeof(dev_no_list[0]));
    ems_syslog(LOG_INFO, "找到 %d 个关口表设备", mt_cnt);
    if (mt_cnt == 0) {
        ems_syslog(LOG_WARNING, "未找到 GRID_METER 类型的关口表设备");
    }
    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))
        {
            double fwd = dev_get_dev_tag_float(dev_no, MT_FORWARD_ENERGY);
            double rev = dev_get_dev_tag_float(dev_no, MT_REVERSE_ENERGY);
            double act = dev_get_dev_tag_float(dev_no, MT_ACTIVE_POWER);
            double rea = dev_get_dev_tag_float(dev_no, MT_REACTIVE_POWER);
            ems_syslog(LOG_INFO, "关口表设备[%d]在线: 设备号='%s', 正向能量=%.2f, 反向能量=%.2f, 有功功率=%.2f, 无功功率=%.2f",
                       i, dev_no, fwd, rev, act, rea);
            forward_energy += fwd;
            reverse_energy += rev;
            active_power += act;
            reactive_power += rea;
            use_grid_meter = 1;
        }
        else
        {
            ems_syslog(LOG_WARNING, "关口表设备[%d]离线: 设备号='%s'", i, dev_no);
        }
    }

    // 如果没有关口表或关口表不在线，从 PCS 电表获取数据
    if (!use_grid_meter)
    {
        ems_syslog(LOG_NOTICE, "未使用关口表，切换到PCS电表获取数据");
        memset(dev_no_list, 0, sizeof(dev_no_list));
        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]));
        ems_syslog(LOG_INFO, "找到 %d 个PCS电表设备", mt_cnt);
        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))
            {
                double fwd = dev_get_dev_tag_float(dev_no, MT_FORWARD_ENERGY);
                double rev = dev_get_dev_tag_float(dev_no, MT_REVERSE_ENERGY);
                double act = dev_get_dev_tag_float(dev_no, MT_ACTIVE_POWER);
                double rea = dev_get_dev_tag_float(dev_no, MT_REACTIVE_POWER);
                ems_syslog(LOG_INFO, "PCS电表设备[%d]在线: 设备号='%s', 正向能量=%.2f, 反向能量=%.2f, 有功功率=%.2f, 无功功率=%.2f",
                           i, dev_no, fwd, rev, act, rea);
                forward_energy += fwd;
                reverse_energy += rev;
                active_power += act;
                reactive_power += rea;
            }
            else
            {
                ems_syslog(LOG_WARNING, "PCS电表设备[%d]离线: 设备号='%s'", i, dev_no);
            }
        }
    }

    ems_syslog(LOG_NOTICE, "设置总能量: 正向=%.2f, 反向=%.2f, 有功=%.2f, 无功=%.2f",
               forward_energy, reverse_energy, active_power, 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) // 自动模式, 周期策略按计划时段判断, 其他策略暂不依赖tou
    {
        tval = AC_STOP;
        if (pcfg->StratagyType != STRATAGY_TYPE_PERIOD_CTRL)
        {
            if (IS_IDLE(powernow))
            {
                if (time(NULL) - last_idel_time > delay_time) 
                {
                    tval = AC_STOP;
                }
            }
            else
            {
                last_idel_time = time(NULL);
            }
        }
        else
        {
            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 < get_tou_max_num(); 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(lc_power_info_t power_info)
{
    set_lc_power(power_info);
}

lc_power_info_t get_lc_power_info(void)
{
    lc_power_info_t power_info;
    power_info.active_power = lc_power_info.active_power;
    power_info.reactive_power = lc_power_info.reactive_power;
    power_info.phase_a_power = lc_power_info.phase_a_power;
    power_info.phase_b_power = lc_power_info.phase_b_power;
    power_info.phase_c_power = lc_power_info.phase_c_power;
    return power_info;
}

double get_ems_lc_power(void)
{
    return lc_power_info.active_power;
}

double get_ems_lc_repower(void)
{
    return lc_power_info.reactive_power;
}

double get_ems_phase_a_power(void)
{
    return lc_power_info.phase_a_power;
}

double get_ems_phase_b_power(void)
{
    return lc_power_info.phase_b_power;
}

double get_ems_phase_c_power(void)
{
    return lc_power_info.phase_c_power;
}

void set_lc_power(lc_power_info_t power_info)
{
    lc_power_info.active_power = power_info.active_power;
    lc_power_info.reactive_power = power_info.reactive_power;
    lc_power_info.phase_a_power = power_info.phase_a_power;
    lc_power_info.phase_b_power = power_info.phase_b_power;
    lc_power_info.phase_c_power = power_info.phase_c_power;


    ems_syslog(LOG_NOTICE, "Set lc power: active=%f, reactive=%f",
                power_info.active_power, power_info.reactive_power);
    dev_set_dev_tag_float(DEV_NO_EMS, LOCAL_CTRL_POWER, lc_power_info.active_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
}

int check_pf_adjust_condition(double current_power_factor, double target_power_factor, double power_factor_deviation)
{
    if (target_power_factor < 0 || target_power_factor > 1.0) {
        ems_syslog(LOG_ERR, "目标功率因数无效：%f，必须在 0 到 1 之间", target_power_factor);
        return -1;
    }

    if (power_factor_deviation < 0 || power_factor_deviation > 1.0) {
        ems_syslog(LOG_ERR, "功率因数偏差无效：%f，必须在 0 到 1 之间", power_factor_deviation);
        return -1;
    }
    
    if (target_power_factor + power_factor_deviation > 1.0) {
        ems_syslog(LOG_ERR, "目标功率因数 + 偏差超出范围：%f + %f = %f > 1.0", 
                   target_power_factor, power_factor_deviation, target_power_factor + power_factor_deviation);
        return -1;
    }
    
    if (target_power_factor - power_factor_deviation < 0) {
        ems_syslog(LOG_ERR, "目标功率因数 - 偏差超出范围：%f - %f = %f < 0", 
                   target_power_factor, power_factor_deviation, target_power_factor - power_factor_deviation);
        return -1;
    }
    
    double pf_diff = fabs(current_power_factor - target_power_factor);
    
    if (pf_diff <= power_factor_deviation)
    {
        ems_syslog(LOG_ERR, "功率因数在允许范围内，无需调整。当前 PF:%.4f, 目标 PF:%.4f, 偏差:%.4f", 
                   current_power_factor, target_power_factor, pf_diff);
        return 0;  // 在允许范围内，无需调整
    }
    else
    {
        ems_syslog(LOG_ERR, "功率因数超出允许范围，需要调整。当前 PF:%.4f, 目标 PF:%.4f, 允许偏差:%.4f, 实际偏差:%.4f", 
                   current_power_factor, target_power_factor, power_factor_deviation, pf_diff);
        return 1;  // 超出允许范围，需要调整
    }
}

double exec_dynamic_reactive_compensation(double current_active_power,
                                          double current_reactive_power,
                                          double cur_repower,
                                          double current_power_factor,
                                          double target_power_factor,
                                          double rated_power) {
  // 检查输入是否为 NaN，如果是则使用当前无功功率代替
  if (isnan(cur_repower)) {
    ems_syslog(LOG_WARNING, "cur_repower 为 NaN，使用当前无功功率代替");
    cur_repower = current_reactive_power;
  }
  // 当前视在功率
//   double current_apparent_power =
//       sqrt(current_active_power * current_active_power +
//            current_reactive_power * current_reactive_power);

  // 目标视在功率
  double target_apparent_power = current_active_power / target_power_factor;

  // 检查目标视在功率是否超过额定功率
  double actual_apparent_power = target_apparent_power;
  double limited = 0; // 标记是否被限制

  if (target_apparent_power > rated_power) {
    actual_apparent_power = rated_power;
    limited = 1;
  }

  // 目标无功功率（使用限制后的视在功率计算）
  double diff = actual_apparent_power * actual_apparent_power -
                current_active_power * current_active_power;
  if (diff < 0) {
    // 额定功率不足，无法补偿无功，返回当前无功
    ems_syslog(LOG_WARNING, "额定功率%.2f kVA小于当前有功功率%.2f kW，无法进行无功补偿",
               actual_apparent_power, current_active_power);
    return cur_repower;
  }
  double target_reactive_power = sqrt(diff);

  if (current_reactive_power < 0) {
    target_reactive_power = -target_reactive_power;
  }

  double compensation_power = target_reactive_power - current_reactive_power;

  double set_reactpower = cur_repower + compensation_power;

  if (limited) {
    // 计算实际能达到的功率因数
    double actual_power_factor = current_active_power / actual_apparent_power;
    ems_syslog(
        LOG_NOTICE,
        "动态功率因数调整计算结果（受额定功率限制）：当前有功功率=%.2f kW, "
        "当前无功功率=%.2f kVar, 当前功率因数=%.4f, 目标功率因数=%.4f, "
        "额定功率=%.2f kVA, 目标视在功率=%.2f kVA（被限制为%.2f kVA）, "
        "实际可达功率因数=%.4f, 补偿无功功率=%.2f kVar, "
        "设置给PCS的无功功率=%.2f kVar",
        current_active_power, current_reactive_power, current_power_factor,
        target_power_factor, rated_power, target_apparent_power,
        actual_apparent_power, actual_power_factor, compensation_power,
        set_reactpower);
  } else {
    ems_syslog(
        LOG_NOTICE,
        "动态功率因数调整计算结果：当前有功功率=%.2f kW, "
        "当前无功功率=%.2f kVar, 当前功率因数=%.4f, 目标功率因数=%.4f, "
        "计算得到的补偿无功功率=%.2f kVar, 设置给PCS的无功功率=%.2f kVar",
        current_active_power, current_reactive_power, current_power_factor,
        target_power_factor, compensation_power, set_reactpower);
  }

  return set_reactpower;
}

int Dynamic_Power_Factor_Correction(double *cur_repower ,time_t *pfcor_last_time){
    double current_active_power   = dev_get_dev_tag_float(DEV_NO_GRID_MT, ACTIVE_POWER);
    double current_reactive_power = dev_get_dev_tag_float(DEV_NO_GRID_MT, REACTIVE_POWER);
    // double current_apparent_power = dev_get_dev_tag_float(DEV_NO_GRID_MT, "ApparentPower");
    double current_power_factor   = dev_get_dev_tag_float(DEV_NO_GRID_MT, "PowerFactor");
    double target_power_factor    = g_usercfg_variant.PowerFactorTargetValue;
    double power_factor_deviation = g_usercfg_variant.PowerFactorDeviation;
    time_t adjust_interval        = time(NULL) - *pfcor_last_time;
    double rated_power            = get_cabinet_info()->rated_power;
    //test测试代码，手动计算当前电功率因数
    //current_power_factor = current_active_power / current_apparent_power;
    //

    int check_result = check_pf_adjust_condition(current_power_factor, target_power_factor, power_factor_deviation);
    if (check_result < 0) {
        // 参数无效
        return -2;
    }
    
    if (check_result > 0) // 需要调整
    {
        if (adjust_interval >= g_usercfg_variant.PowerFactorAdjustmentPeriod)
        {
            *cur_repower = exec_dynamic_reactive_compensation(
                current_active_power,
                current_reactive_power,
                *cur_repower,
                current_power_factor,
                target_power_factor,
                rated_power);
            *pfcor_last_time = time(NULL); //更新调整时间
        }
        else {
            ems_syslog(LOG_DEBUG, "功率因数调整间隔未到，无需调整。当前时间: %ld, 上次调整时间: %ld, 已过时间: %ld秒, 需要间隔: %d秒", 
                       time(NULL), *pfcor_last_time, adjust_interval, g_usercfg_variant.PowerFactorAdjustmentPeriod);
            return -1;
        }
    }
    else {
        return -1; // 不需要调整
    }

    return 1; 
}

double get_cur_phase_power_by_name(const char *phase_power_name)
{
    if (phase_power_name == NULL)
    {
        return 0.0f;
    }

    if (cabinet_info.en_lc_ctrl != 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 (dev_get_dev_tag_float_with_result(lc_arr[i].no, phase_power_name, &value_tmp) >= 0)
            {
                value += value_tmp;
            }
        }

        return value;
    }
    else
    {
        double power = 0;
        power = dev_get_dev_tag_float(DEV_NO_EMS, phase_power_name);
        return power;
    }
}