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

#include "my_public.h"
#include "pv_pcs.h"

#define PV_PCS_FILE "/app/config/ems/pv_pcs.json"

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

#define SERVICEUPCONT var->devNodeInfo.serviceupcont
#define SERVICEDOWNCONT var->devNodeInfo.servicedowncont
#define SERVICE_DOWN var->devNodeInfo.pserviceInfoDOWN
#define SERVICE_UP var->devNodeInfo.pserviceInfoUP

static int load_pv_pcs_cfg(pv_pcs_var_t *var, const char *cfg_file)
{
    CHAR *pdata = NULL;
    cJSON *root = NULL;
    cJSON *nodes = NULL;
    cJSON *node = NULL;
    cJSON *tmp = NULL;
    int node_cnt = 0, i = 0;
    BYTE flag = E_TRUE;

    if (var == NULL || cfg_file == NULL)
    {
        dy_syslog(LOG_ERR, "pcfg:%p cfg_file:%p", var, cfg_file);
        return -1;
    }
    pdata = read_file_data(cfg_file);

    if (pdata == NULL)
    {
        dy_syslog(LOG_ERR, "read cfg file %s error", cfg_file);
        flag = E_FALSE;
        goto out;
    }
    root = cJSON_Parse(pdata);
    if (!root)
    {
        dy_syslog(LOG_ERR, "parse cfg file %s error", cfg_file);
        flag = E_FALSE;
        goto out;
    }
    GET_JSON_VALUE_STRING_LOG(root, "devSn", var->vir_sn_str);
    GET_JSON_VALUE_STRING_LOG(root, "desSn", var->desSn);
    // GET_JSON_VALUE_INT_LOG(root, "runMode", var->runMode);
    GET_JSON_VALUE_INT_LOG(root, "pcsType", var->pcsType);
    nodes = cJSON_GetObjectItemCaseSensitive(root, "node");

    if (!nodes)
    {
        dy_syslog(LOG_ERR, "get node failed");
        flag = E_FALSE;
        goto out;
    }

    node_cnt = cJSON_GetArraySize(nodes);
    if (node_cnt != 0)
    {
        var->devNodeInfo.pdevnodecfg = (DEV_NODE_CFG_T *)malloc(node_cnt * sizeof(DEV_NODE_CFG_T));

        if (var->devNodeInfo.pdevnodecfg == NULL)
        {
            dy_syslog(LOG_ERR, "malloc pdevnodcfg failed,node_cnt:%d", node_cnt);
            flag = E_FALSE;
            goto out;
        }
        memset(var->devNodeInfo.pdevnodecfg, 0, node_cnt * sizeof(DEV_NODE_CFG_T));
        var->devNodeInfo.devcont = node_cnt;
        for (i = 0; i < node_cnt; i++)
        {
            node = cJSON_GetArrayItem(nodes, i);
            GET_JSON_VALUE_STRING_LOG(node, "devSn", var->devNodeInfo.pdevnodecfg[i].devSn);
            GET_JSON_VALUE_STRING_LOG(node, "type", var->devNodeInfo.pdevnodecfg[i].type);
            GET_JSON_VALUE_INT_LOG(node, "maxChar", var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxChargeP);
            GET_JSON_VALUE_INT_LOG(node, "maxDischar", var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxDischarP);
        }
    }
    nodes = cJSON_GetObjectItemCaseSensitive(root, "service_down");
    if (!nodes)
    {
        dy_syslog(LOG_ERR, "get service_down failed");
        flag = E_FALSE;
        goto out;
    }
    node_cnt = cJSON_GetArraySize(nodes);
    if (node_cnt != 0)
    {
        var->devNodeInfo.pserviceInfoDOWN = (SERVICE_INFO_T *)malloc(node_cnt * sizeof(SERVICE_INFO_T));
        if (var->devNodeInfo.pserviceInfoDOWN == NULL)
        {
            dy_syslog(LOG_ERR, "malloc pserviceInfoDOWN failed,node_cnt:%d", node_cnt);
            flag = E_FALSE;
            goto out;
        }
        var->devNodeInfo.servicedowncont = node_cnt;
        for (i = 0; i < node_cnt; i++)
        {
            node = cJSON_GetArrayItem(nodes, i);
            GET_JSON_VALUE_STRING_LOG(node, "identifier", var->devNodeInfo.pserviceInfoDOWN[i].identifier);
            GET_JSON_VALUE_STRING_LOG(node, "name", var->devNodeInfo.pserviceInfoDOWN[i].name);
        }
        // for (i = 0; i < node_cnt; i++)
        // {
        // dy_syslog(LOG_ERR, "i:%d identifier:%s name:%s",i,SERVICE_DOWN[i].identifier,SERVICE_DOWN[i].name);
        // }
    }
    nodes = cJSON_GetObjectItemCaseSensitive(root, "service_up");
    if (!nodes)
    {
        dy_syslog(LOG_ERR, "get service_up failed");
        flag = E_FALSE;
        goto out;
    }
    node_cnt = cJSON_GetArraySize(nodes);
    if (node_cnt != 0)
    {
        var->devNodeInfo.pserviceInfoUP = (SERVICE_INFO_T *)malloc(node_cnt * sizeof(SERVICE_INFO_T));
        if (var->devNodeInfo.pserviceInfoUP == NULL)
        {
            dy_syslog(LOG_ERR, "malloc pserviceInfoDOWN failed,node_cnt:%d", node_cnt);
            flag = E_FALSE;
            goto out;
        }
        var->devNodeInfo.serviceupcont = node_cnt;
        for (i = 0; i < node_cnt; i++)
        {
            node = cJSON_GetArrayItem(nodes, i);
            GET_JSON_VALUE_STRING_LOG(node, "identifier", var->devNodeInfo.pserviceInfoUP[i].identifier);
            GET_JSON_VALUE_STRING_LOG(node, "inidentifier", var->devNodeInfo.pserviceInfoUP[i].inidentifier);
            GET_JSON_VALUE_STRING_LOG(node, "name", var->devNodeInfo.pserviceInfoUP[i].name);
            {
                int j, tagcon = 0;
                cJSON *tagnodes = NULL;
                cJSON *tagnode = NULL;
                tagnodes = cJSON_GetObjectItemCaseSensitive(node, "tagnode");
                if (!tagnode)
                {
                    // todo 是否需要判断加载失败退出
                    tagcon = cJSON_GetArraySize(tagnodes);
                    dy_syslog(LOG_ERR, "tagcon:%d", tagcon);
                    var->devNodeInfo.pserviceInfoUP[i].tagNode.ptagNode = (TAG_NODE_T *)malloc(tagcon * sizeof(TAG_NODE_T));
                    if (var->devNodeInfo.pserviceInfoUP[i].tagNode.ptagNode == NULL)
                    {
                        flag = E_FALSE;
                        goto out;
                    }
                    var->devNodeInfo.pserviceInfoUP[i].tagNode.nodecont = tagcon;
                    for (j = 0; j < tagcon; j++)
                    {
                        tagnode = cJSON_GetArrayItem(tagnodes, j);
                        GET_JSON_VALUE_STRING_LOG(tagnode, "tag", var->devNodeInfo.pserviceInfoUP[i].tagNode.ptagNode[j].tag);
                        GET_JSON_VALUE_STRING_LOG(tagnode, "name", var->devNodeInfo.pserviceInfoUP[i].tagNode.ptagNode[j].name);
                    }
                }
            }
        }
    }

    nodes = cJSON_GetObjectItemCaseSensitive(root, "service_todev");
    if (!nodes)
    {
        dy_syslog(LOG_ERR, "get service_todev failed");
        flag = E_FALSE;
        goto out;
    }
    node_cnt = cJSON_GetArraySize(nodes);
    if (node_cnt != 0)
    {
        var->devNodeInfo.pserviceInfoTodev = (SERVICE_INFO_T *)malloc(node_cnt * sizeof(SERVICE_INFO_T));
        if (var->devNodeInfo.pserviceInfoTodev == NULL)
        {
            dy_syslog(LOG_ERR, "malloc pserviceInfoDOWN failed,node_cnt:%d", node_cnt);
            flag = E_FALSE;
            goto out;
        }
        var->devNodeInfo.servicetodevcont = node_cnt;
        for (i = 0; i < node_cnt; i++)
        {
            node = cJSON_GetArrayItem(nodes, i);
            GET_JSON_VALUE_STRING_LOG(node, "identifier", var->devNodeInfo.pserviceInfoTodev[i].identifier);
            GET_JSON_VALUE_STRING_LOG(node, "name", var->devNodeInfo.pserviceInfoTodev[i].name);
            {
                int j, tagcon = 0;
                cJSON *tagnodes = NULL;
                cJSON *tagnode = NULL;
                tagnodes = cJSON_GetObjectItemCaseSensitive(node, "tagnode");
                if (!tagnode)
                {
                    // todo 是否需要判断加载失败退出
                    tagcon = cJSON_GetArraySize(tagnodes);
                    dy_syslog(LOG_ERR, "tagcon:%d", tagcon);
                    var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode = (TAG_NODE_T *)malloc(tagcon * sizeof(TAG_NODE_T));
                    if (var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode == NULL)
                    {
                        flag = E_FALSE;
                        goto out;
                    }
                    var->devNodeInfo.pserviceInfoTodev[i].tagNode.nodecont = tagcon;
                    for (j = 0; j < tagcon; j++)
                    {
                        tagnode = cJSON_GetArrayItem(tagnodes, j);
                        GET_JSON_VALUE_STRING_LOG(tagnode, "tag", var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[j].tag);
                        GET_JSON_VALUE_STRING_LOG(tagnode, "name", var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[j].name);
                    }
                }
            }
        }
    }
    nodes = cJSON_GetObjectItemCaseSensitive(root, "operate");
    if (!nodes)
    {
        dy_syslog(LOG_ERR, "get operate failed");
        goto out;
    }
    node_cnt = cJSON_GetArraySize(nodes);
    if (node_cnt != 0)
    {
        if (node_cnt > PCS_TYPE_NUM)
        {
            goto out;
        }
        for (i = 0; i < node_cnt; i++)
        {
            node = cJSON_GetArrayItem(nodes, i);
            GET_JSON_VALUE_INT_LOG(node, "onOff", var->pcs_type_operate[i].onOff);
            GET_JSON_VALUE_INT_LOG(node, "open", var->pcs_type_operate[i].open);
            GET_JSON_VALUE_INT_LOG(node, "close", var->pcs_type_operate[i].close);
            GET_JSON_VALUE_INT_LOG(node, "enable", var->pcs_type_operate[i].enable);
            GET_JSON_VALUE_INT_LOG(node, "disable", var->pcs_type_operate[i].disable);
        }
    }
out:
    cJSON_Delete(root);
    if (pdata != NULL)
    {
        free(pdata);
    }
    if (flag == E_FALSE)
    {
        if (var->devNodeInfo.pdevnodecfg != NULL)
        {
            free(var->devNodeInfo.pdevnodecfg);
        }
        if (var->devNodeInfo.pserviceInfoDOWN != NULL)
        {
            free(var->devNodeInfo.pserviceInfoDOWN);
        }
        if (var->devNodeInfo.pserviceInfoTodev != NULL)
        {
            free(var->devNodeInfo.pserviceInfoTodev);
        }
        if (var->devNodeInfo.pserviceInfoUP != NULL)
        {
            free(var->devNodeInfo.pserviceInfoUP);
        }
    }
    return 0;
}

static void pv_pcs_subscribe_all(pv_pcs_var_t *var)
{
    CHAR topic[TOPIC_MAX_LEN] = {0};
    int i, j;

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/set_rglt_raw", var->sn_str, var->vir_sn_str);
    dy_syslog(LOG_INFO, "topic:%s\r\n", topic);
    ipc_session_subscribe(var->session, topic);

    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {
        for (j = 0; j < var->devNodeInfo.serviceupcont; j++)
        {
            snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/%s/data/service/%s", var->sn_str, var->devNodeInfo.pdevnodecfg[i].devSn, var->devNodeInfo.pserviceInfoUP[j].identifier);
            dy_syslog(LOG_INFO, "topic:%s\r\n", topic);
            ipc_session_subscribe(var->session, topic);
        }
    }
}

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

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

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

static void pv_pcs_openoff_to_dev_set(pv_pcs_var_t *var, const char *service)
{
    int i, j, n;
    CHAR *data_tmp = NULL;
    int err = 1, num = 0;
    cJSON *tag_data;
    CHAR tagNode[64] = {0};
    CHAR openFlag = 0;
    if (strcmp("open", service) == 0)
    {
        openFlag = 1;
    }
    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {

        if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.state == 0 && openFlag == 1)
        {
            dy_syslog(LOG_INFO, "num:%d openoff is open", i);
            var->devNodeInfo.pdevnodecfg[i].pcsInfo.state = 1;
        }
        else if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.state == 1 && openFlag == 0)
        {
            dy_syslog(LOG_INFO, "num:%d openoff is close", i);
            var->devNodeInfo.pdevnodecfg[i].pcsInfo.state = 0;
        }
        for (j = 0; j < var->devNodeInfo.servicetodevcont; j++)
        {
            if (strcmp(var->devNodeInfo.pserviceInfoTodev[j].name, service) == 0)
            {
                dy_syslog(LOG_INFO, "openoff set id:%s", var->devNodeInfo.pserviceInfoTodev[j].identifier);
                for (n = 0; n < var->devNodeInfo.pserviceInfoTodev[j].tagNode.nodecont; n++)
                {
                    if (strcmp(var->devNodeInfo.pserviceInfoTodev[j].tagNode.ptagNode[n].name, service) == 0)
                    {

                        tag_data = cJSON_CreateObject();
                        // cJSON_AddStringToObject(tag_data, "sn", var->vir_sn_str);
                        cJSON_AddStringToObject(tag_data, "sn", var->devNodeInfo.pdevnodecfg[i].devSn);
                        cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL));
                        cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);
                        cJSON_AddStringToObject(tag_data, "identifier", var->devNodeInfo.pserviceInfoTodev[j].identifier);
                        if (openFlag)
                        {
                            cJSON_AddNumberToObject(tag_data, var->devNodeInfo.pserviceInfoTodev[j].tagNode.ptagNode[n].tag, var->pcs_type_operate[var->pcsType].close); //设置开机关机
                        }
                        else
                        {
                            cJSON_AddNumberToObject(tag_data, var->devNodeInfo.pserviceInfoTodev[j].tagNode.ptagNode[n].tag, var->pcs_type_operate[var->pcsType].open); //设置开机关机
                        }
                        data_tmp = cJSON_Print(tag_data);
                        publish_to_dev_data(var->session, var->sn_str, data_tmp, strlen(data_tmp), var->devNodeInfo.pdevnodecfg[i].devSn, var->devNodeInfo.pdevnodecfg[i].type);
                        free(data_tmp);
                        cJSON_Delete(tag_data);
                    }
                }
            }
        }
        dy_syslog(LOG_INFO, "num:%d %s", j, service);
    }
}

static void pv_pcs_open_set(pv_pcs_var_t *var)
{
    pv_pcs_openoff_to_dev_set(var, "open");
    dy_syslog(LOG_INFO, "pcs: open");
}

static void pv_pcs_close_set(pv_pcs_var_t *var)
{
    pv_pcs_openoff_to_dev_set(var, "close");
    dy_syslog(LOG_INFO, "pcs:close");
}

#define PCS_MI 12323

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

static void pv_pcs_report_power(pv_pcs_var_t *var, CHAR *identifier)
{
    CHAR *data_tmp = NULL;
    int i;
    double power = 0;
    cJSON *sub = NULL;
    CHAR tagNode[64] = {0};
    cJSON *tag_data = cJSON_CreateObject();

    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {
        power += var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl;
        dy_syslog(LOG_DEBUG, "i:>%d,send power:%f", i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl);
    }

    cJSON_AddStringToObject(tag_data, "sn", var->sn_str);
    cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL));
    cJSON_AddStringToObject(tag_data, "identifier", identifier);
    cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);
    sprintf(tagNode, "{\"pv\":%f}", power);
    cJSON_AddStringToObject(tag_data, "tag_node", tagNode);
    data_tmp = cJSON_Print(tag_data);

    publish_pcs_data(var->session, var->sn_str, data_tmp, strlen(data_tmp), var->desSn, identifier);

    free(data_tmp);
    cJSON_Delete(tag_data);
}

static void pv_pcs_power_set_to_dev(pv_pcs_var_t *var, int index)
{
    int i, j, n;
    CHAR *data_tmp = NULL;
    int err = 1, num = 0;
    cJSON *sub = NULL;
    cJSON *tag_data;
    CHAR tagNode[64] = {0};

    for (i = 0; i < var->devNodeInfo.servicetodevcont; i++)
    {
        if (strcmp(var->devNodeInfo.pserviceInfoTodev[i].name, "yggl") == 0)
        {
            dy_syslog(LOG_INFO, "yggl set id:%s", var->devNodeInfo.pserviceInfoTodev[i].identifier);
            for (n = 0; n < var->devNodeInfo.pserviceInfoTodev[i].tagNode.nodecont; n++)
            {
                dy_syslog(LOG_INFO, "name:%s", var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[n].name);
                if (strcmp(var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[n].name, "yggl") == 0)
                {

                    // for (j = 0; j < var->devNodeInfo.devcont; j++)
                    if (index < var->devNodeInfo.devcont)
                    {
                        tag_data = cJSON_CreateObject();
                        // cJSON_AddStringToObject(tag_data, "sn", var->vir_sn_str);
                        cJSON_AddStringToObject(tag_data, "sn", var->devNodeInfo.pdevnodecfg[index].devSn);
                        cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL));
                        cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);
                        cJSON_AddStringToObject(tag_data, "identifier", var->devNodeInfo.pserviceInfoTodev[i].identifier);
                        cJSON_AddNumberToObject(tag_data, var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[n].tag, var->devNodeInfo.pdevnodecfg[index].pcsInfo.yggl);
                        data_tmp = cJSON_Print(tag_data);
                        if (var->devNodeInfo.pdevnodecfg[index].pcsInfo.yggl == 0)
                        {
                            publish_to_dev_data(var->session, var->sn_str, data_tmp, strlen(data_tmp), var->devNodeInfo.pdevnodecfg[index].devSn, var->devNodeInfo.pdevnodecfg[index].type);
                        }
                        else
                        {
                            publish_to_dev_data(var->session, var->sn_str, data_tmp, strlen(data_tmp), var->devNodeInfo.pdevnodecfg[index].devSn, var->devNodeInfo.pdevnodecfg[index].type);
                        }
                        free(data_tmp);
                        cJSON_Delete(tag_data);
                    }
                }
            }
        }
    }
}

static void pv_pcs_power_set(double power, pv_pcs_var_t *var)
{
    int i, j, num = 0;
    // todo 判断设备正常情况。
    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {
        if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.errState == 0)
        {
            num++;
        }
    }
    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {
        if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.errState == 0)
        {
            dy_syslog(LOG_INFO, "index: %d ->yggl: %d power:%f", i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl, power * POWER_UNIT_VAL / num);
            if (var->pcsType == 0)
            {
                if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl != power * POWER_UNIT_VAL / num)
                {
                    var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = power * POWER_UNIT_VAL / num;
                    if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl > 0)
                    {
                        if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl > var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxChargeP * POWER_UNIT_VAL)
                        {

                            var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxChargeP * POWER_UNIT_VAL;
                        }
                    }
                    else if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl < 0)
                    {

                        if (-var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl > var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxDischarP * POWER_UNIT_VAL)
                        {

                            var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = -var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxDischarP * POWER_UNIT_VAL;
                        }
                    }
                    dy_syslog(LOG_INFO, "i:%d set power:%d", i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl);

                    pv_pcs_power_set_to_dev(var, i); //变更设置
                }
            }
            else
            {
                if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl != power * POWER_UNIT_VAL / num)
                {
                    var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = power * POWER_UNIT_VAL / num;
                    if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl < 0)
                    {
                        if (-var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl > var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxChargeP * POWER_UNIT_VAL)
                        {

                            var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = -var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxChargeP * POWER_UNIT_VAL;
                        }
                    }
                    else if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl > 0)
                    {

                        if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl > var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxDischarP * POWER_UNIT_VAL)
                        {

                            var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = var->devNodeInfo.pdevnodecfg[i].pcsInfo.maxDischarP * POWER_UNIT_VAL;
                        }
                    }
                    dy_syslog(LOG_INFO, "i:%d set power:%d", i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl);

                    // 三相功率
                    // pcs_power3x_set_to_dev(var, i);
                }
            }

            dy_syslog(LOG_INFO, "i:%d power:%d", i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl);
        }
        else
        {
            if (var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl != 0)
            {
                var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl = 0;
                dy_syslog(LOG_INFO, "err i:%d set power:%d", i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.yggl);
                if (var->pcsType == 0)
                {
                    pv_pcs_power_set_to_dev(var, i);
                }
                else
                {
                    // 三相功率
                    // pcs_power3x_set_to_dev(var, i);
                }
            }
        }
    }
}

static void pv_pcs_power_enable(pv_pcs_var_t *var, CHAR *service)
{
    int i, j, n;
    CHAR *data_tmp = NULL;
    int err = 1, num = 0;
    cJSON *sub = NULL;
    cJSON *tag_data;
    CHAR tagNode[64] = {0};

    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {
        for (j = 0; j < var->devNodeInfo.servicetodevcont; j++)
        {
            if (strcmp(var->devNodeInfo.pserviceInfoTodev[j].name, service) == 0)
            {
                dy_syslog(LOG_INFO, "powerenable set id:%s", var->devNodeInfo.pserviceInfoTodev[j].identifier);
                for (n = 0; n < var->devNodeInfo.pserviceInfoTodev[j].tagNode.nodecont; n++)
                {
                    if (strcmp(var->devNodeInfo.pserviceInfoTodev[j].tagNode.ptagNode[n].name, service) == 0)
                    {

                        tag_data = cJSON_CreateObject();
                        // cJSON_AddStringToObject(tag_data, "sn", var->vir_sn_str);
                        cJSON_AddStringToObject(tag_data, "sn", var->devNodeInfo.pdevnodecfg[i].devSn);
                        cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL));
                        cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);
                        cJSON_AddStringToObject(tag_data, "identifier", var->devNodeInfo.pserviceInfoTodev[j].identifier);
                        cJSON_AddNumberToObject(tag_data, var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[n].tag, var->pcs_type_operate[var->pcsType].enable);
                        data_tmp = cJSON_Print(tag_data);
                        publish_to_dev_data(var->session, var->sn_str, data_tmp, strlen(data_tmp), var->devNodeInfo.pdevnodecfg[i].devSn, var->devNodeInfo.pdevnodecfg[i].type);
                        free(data_tmp);
                        cJSON_Delete(tag_data);
                    }
                }
            }
        }
        dy_syslog(LOG_INFO, "num:%d %s", j, service);
    }
}

static void pv_pcs_power_disable(pv_pcs_var_t *var,CHAR *service)
{
    int i, j, n;
    CHAR *data_tmp = NULL;
    int err = 1, num = 0;
    cJSON *sub = NULL;
    cJSON *tag_data;
    CHAR tagNode[64] = {0};

    for (i = 0; i < var->devNodeInfo.devcont; i++)
    {
        for (j = 0; j < var->devNodeInfo.servicetodevcont; j++)
        {
            if (strcmp(var->devNodeInfo.pserviceInfoTodev[j].name, service) == 0)
            {
                dy_syslog(LOG_INFO, "powerenable set id:%s", var->devNodeInfo.pserviceInfoTodev[j].identifier);
                for (n = 0; n < var->devNodeInfo.pserviceInfoTodev[j].tagNode.nodecont; n++)
                {
                    if (strcmp(var->devNodeInfo.pserviceInfoTodev[j].tagNode.ptagNode[n].name, service) == 0)
                    {

                        tag_data = cJSON_CreateObject();
                        // cJSON_AddStringToObject(tag_data, "sn", var->vir_sn_str);
                        cJSON_AddStringToObject(tag_data, "sn", var->devNodeInfo.pdevnodecfg[i].devSn);
                        cJSON_AddNumberToObject(tag_data, "timestamp", time(NULL));
                        cJSON_AddNumberToObject(tag_data, "mi", PCS_MI);
                        cJSON_AddStringToObject(tag_data, "identifier", var->devNodeInfo.pserviceInfoTodev[j].identifier);
                        cJSON_AddNumberToObject(tag_data, var->devNodeInfo.pserviceInfoTodev[i].tagNode.ptagNode[n].tag, var->pcs_type_operate[var->pcsType].disable);
                        data_tmp = cJSON_Print(tag_data);
                        publish_to_dev_data(var->session, var->sn_str, data_tmp, strlen(data_tmp), var->devNodeInfo.pdevnodecfg[i].devSn, var->devNodeInfo.pdevnodecfg[i].type);
                        free(data_tmp);
                        cJSON_Delete(tag_data);
                    }
                }
            }
        }
        dy_syslog(LOG_INFO, "num:%d %s", j, service);
    }
}

static int pc_pcs_mqtt_handle_recv_msg(void *obj, ipc_msg_t *mqtt_msg)
{
    cJSON *node = NULL;
    cJSON *sub = NULL;
    CHAR *tagNode = NULL;
    int i, n, j = 0;
    double tmp1 = 0;
    int tmp = 0;
    pv_pcs_var_t *var = (pv_pcs_var_t *)obj;
    dy_syslog(LOG_INFO, "topic:%s", mqtt_msg->topic);
    if (strstr(mqtt_msg->topic, "data/service"))
    {
        node = cJSON_Parse(mqtt_msg->payload);
        if (!node)
        {
            return E_FALSE;
        }
        GET_JSON_VALUE_INT_LOG(node, "mi", var->servInfo.mi);
        GET_JSON_VALUE_INT_LOG(node, "timestamp", var->servInfo.timestamp);
        GET_JSON_VALUE_STRING_LOG(node, "identifier", var->servInfo.identifier);
        GET_JSON_VALUE_STRING_LOG(node, "sn", var->servInfo.devSn);
        dy_syslog(LOG_INFO, "SERVICEUPCONT:%d\r\n", SERVICEUPCONT);
        // sub = cJSON_GetObjectItemCaseSensitive(node, "tags");

        GET_JSON_VALUE_DY_STRING_LOG(node, "tag_node", tagNode);
        if (tagNode != NULL)
        {
            sub = cJSON_Parse(tagNode);
            if (sub)
            {
                for (i = 0; i < SERVICEUPCONT; i++)
                {
                    //  dy_syslog(LOG_INFO, "i:%d identifier:%s name:%s",i,SERVICE_UP[i].identifier,SERVICE_UP[i].name);
                    if (strcmp(SERVICE_UP[i].identifier, var->servInfo.identifier) == 0)
                    {
                        for (j = 0; j < var->devNodeInfo.devcont; j++)
                        {
                            if (strcmp(var->devNodeInfo.pdevnodecfg[j].devSn, var->servInfo.devSn) == 0)
                            {
                                if (SERVICE_UP[i].tagNode.nodecont > 0)
                                {
                                    for (n = 0; n < SERVICE_UP[i].tagNode.nodecont; n++)
                                    {
                                        tmp1 = -1;
                                        GET_JSON_VALUE_DOUBLE_LOG(sub, SERVICE_UP[i].tagNode.ptagNode[n].tag, tmp1);
                                        if (tmp1 != -1)
                                        {
                                            dy_syslog(LOG_INFO, "tag name:%s", SERVICE_UP[i].tagNode.ptagNode[n].name);
                                            if (strcmp(SERVICE_UP[i].tagNode.ptagNode[n].name, "fault") == 0)
                                            {
                                                var->devNodeInfo.pdevnodecfg[j].pcsInfo.errState = tmp1;
                                            }
                                            else if (strcmp(SERVICE_UP[i].tagNode.ptagNode[n].name, "stop") == 0)
                                            {
                                                dy_syslog(LOG_INFO, "tmp1:%d i:%d state:%d", tmp1, i, var->devNodeInfo.pdevnodecfg[i].pcsInfo.state);
                                                // if(tmp ==1){
                                                //     if(var->devNodeInfo.pdevnodecfg[i].pcsInfo.state ==1){
                                                //         pcs_open_set(var);
                                                //     }
                                                // }else{
                                                //     if(var->devNodeInfo.pdevnodecfg[i].pcsInfo.state !=1){
                                                //         pcs_close_set(var);
                                                //     }
                                                // }
                                            }
                                            else if (strcmp(SERVICE_UP[i].tagNode.ptagNode[n].name, "pvgl") == 0)
                                            {

                                                var->devNodeInfo.pdevnodecfg[j].pcsInfo.yggl = tmp1;
                                                pv_pcs_report_power(var, SERVICE_UP[i].inidentifier);
                                            }
                                        }
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
                cJSON_Delete(sub);
            }
            free(tagNode);
        }
    }
    else if (strstr(mqtt_msg->topic, "data/set_rglt_raw"))
    {
        node = cJSON_Parse(mqtt_msg->payload);
        if (!node)
        {
            return E_FALSE;
        }
        GET_JSON_VALUE_INT_LOG(node, "mi", var->servInfo.mi);
        GET_JSON_VALUE_INT_LOG(node, "timestamp", var->servInfo.timestamp);
        GET_JSON_VALUE_STRING_LOG(node, "identifier", var->servInfo.identifier);
        GET_JSON_VALUE_STRING_LOG(node, "sn", var->servInfo.devSn);
        dy_syslog(LOG_INFO, "SERVICEDOWNCONT:%d\r\n", SERVICEDOWNCONT);

        for (i = 0; i < SERVICEDOWNCONT; i++)
        {
            dy_syslog(LOG_INFO, "i:%d identifier:%s name:%s", i, SERVICE_DOWN[i].identifier, SERVICE_DOWN[i].name);
            if (strcmp(SERVICE_DOWN[i].identifier, var->servInfo.identifier) == 0)
            {
                if (strcmp(SERVICE_DOWN[i].name, "on") == 0)
                {
                    pv_pcs_open_set(var);
                }
                else if (strcmp(SERVICE_DOWN[i].name, "off") == 0)
                {
                    pv_pcs_close_set(var);
                }
                else if (strcmp(SERVICE_DOWN[i].name, "p2") == 0)
                {
                    GET_JSON_VALUE_DOUBLE_LOG(node, "p2", tmp1);
                    pv_pcs_power_set(tmp1, var);
                }
                else if (strcmp(SERVICE_DOWN[i].name, "powerenable") == 0)
                {
                    GET_JSON_VALUE_DOUBLE_LOG(node, "enable", tmp);
                    if (tmp)
                    {
                        pv_pcs_power_enable(var,"powerenable");
                    }
                    else
                    {
                        pv_pcs_power_disable(var,"powerenable");
                    }
                }
            }
        }
    }

    if (node)
    {
        cJSON_Delete(node);
    }
    return 0;
}

static int pv_pcs_mqtt_client_init(pv_pcs_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};
    snprintf(clientId, MAX_CLIENT_ID_LEN, "INT_pv_pcs_dev_%s", var->sn_str);
    var->session = ipc_session_new(clientId, (void *)var, IPC_DEFAULT);

    if (var->session == NULL)
        return -1;

    ipc_session_set_callbacks(var->session, pc_pcs_mqtt_handle_recv_msg, pv_pcs_state_change);
    pv_pcs_subscribe_all(var);
    ipc_session_start(var->session);
    sleep(5);
    return E_TRUE;
}

static void pv_pcs_dev_init(void *obj)
{
    int ret;
    pv_pcs_var_t *var = (pv_pcs_var_t *)obj;
    ret = load_pv_pcs_cfg(var, PV_PCS_FILE);
    if (ret != 0)
    {
        dy_syslog(LOG_INFO, "load_pcs_dev_cfg fail:file name->%s", PV_PCS_FILE);
    }
    get_board_sn(var->sn_str); //所有表信息;meter  sn
    dy_syslog(LOG_INFO, "board SN:%s", var->sn_str);

    pv_pcs_mqtt_client_init(var);
}

static void pv_pcs_dev_entry(void *obj)
{
    int ret = -1, maxfd;
    fd_set rset;
    struct timeval timeout;

    while (1)
    {
        SELECT_INIT();
        // SELECT_ADD_FD(var->second_period_timer);
        timeout.tv_usec = 0;
        timeout.tv_sec = 5;
        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            dy_syslog(LOG_INFO, "errno %d\n", errno);

            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                dy_syslog(LOG_INFO, "errno---");
                break;
            }
        }
    }
}

void main()
{
    pv_pcs_var_t pv_pcs_dev = {0};
    pv_pcs_dev_init(&pv_pcs_dev);
    pv_pcs_dev_entry(&pv_pcs_dev);
}