#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include "cloud_emmsv2_common.h"
#include "dy_utils/cJSON.h"
#include "dy_utils/dy_common.h"
#include "mqtt_session.h"
#include "dy_utils/protocol.h"

static void cloud_emmsv2_gendevclass(cJSON *root)
{   
    char *data = NULL;
    int lens;

    /*cJSON *info = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "info", info);
    cJSON *devclass = cJSON_CreateArray();
    cJSON_AddItemToObject(info,"dev_class", devclass);*/

    data = read_file_data_and_lens("/app/config/devclass.json", &lens);
    if (data == NULL)
    {
        dbg_syslog(LOG_ERR, "read devclass.json failed");
        return;
    }

    cJSON *devinfo = cJSON_Parse(data);
    if (!devinfo)
    {
        dbg_syslog(LOG_ERR, "parse devclass json file failed");
        return;
    }
    cJSON_AddItemToObject(root, "info", devinfo);
/*
    cJSON *node = cJSON_CreateObject();
    cJSON_AddStringToObject(node, "type", "METER");
    cJSON *devarray = cJSON_CreateArray();
    cJSON *devnode = cJSON_CreateObject();
    cJSON_AddStringToObject(devnode, "no", "PCS_METER");
    cJSON_AddStringToObject(devnode, "type", "PCS");
    cJSON_AddStringToObject(devnode, "name", "储能表");
    cJSON_AddStringToObject(devnode, "addr", "305195410001");
    cJSON_AddStringToObject(devnode, "template", "METER_COMMON_DLT645.json");
    cJSON_AddStringToObject(devnode, "vendor", "宁波三星");
    cJSON_AddStringToObject(devnode, "model", "METER-SANXING-DTZY188");
    cJSON_AddItemToArray(devarray, devnode);
*/
}

//将
static void parse_stra(char *strastr, unsigned short *segpower, unsigned char *segmode, short *segwggl)
{
    char *tok;
    tok = strtok(strastr, "|");
    if (!tok)
    {
        dbg_syslog(LOG_ERR, "strastr format error");
    }

    for(int i = 0; i < MAX_TIME_SEG; i++)
    {
        tok = strtok(0, "|");
        segpower[i] = atoi(tok);
        tok = strtok(0, "|");
        segmode[i] = atoi(tok);
        tok = strtok(0, "|");
        segwggl[i] = atoi(tok);
    }
}

//将devname表的数据生成json结构体，并添加msg数组里
void append_devmsg(cloud_emmsv2_var_t *var, cJSON *msgs, char *devname)
{
    cJSON *devdata = cJSON_CreateObject();
    cJSON_AddStringToObject(devdata, "no", devname);
    cJSON *devtag = cJSON_CreateObject();
    cJSON_AddItemToObject(devdata, "tags", devtag);

    char cmd[CMD_SHORT_LENGTH] = {0};
    snprintf(cmd, CMD_SHORT_LENGTH, "zrange %s 0 -1", devname);
    redisReply *reply_data = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply_data || (reply_data->type != REDIS_REPLY_ARRAY) || (reply_data->elements <= 0))
    {
        dbg_syslog(LOG_ERR, "getall devs failed");
        cJSON_Delete(devdata);
        return;
    }
    for (int i = 0; i < reply_data->elements; i++)
    {
        char *tok = strtok(reply_data->element[i]->str, "|");
        char *tok2 = strtok(0, "|");
        dbg_syslog(LOG_ERR, "tok %s tok2 %s", tok, tok2);
        if (strstr(tok2, "."))
        {
            cJSON_AddNumberToObject(devtag, tok, atof(tok2));
        }
        else
        {
            cJSON_AddNumberToObject(devtag, tok, atoi(tok2));
        }

    }
    freeReplyObject(reply_data);

    cJSON_AddItemToArray(msgs, devdata);
}

//读取数据库，生成设备遥测数据
void cloud_emmsv2_subdevmsg(cloud_emmsv2_var_t *var, cJSON *root)
{
    char cmd[CMD_SHORT_LENGTH] = {0};
    cJSON *msgs = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "messages", msgs);

    snprintf(cmd, CMD_SHORT_LENGTH, "hgetall devs");    //访问devs表，遍历所有设备
    redisReply *reply_devs = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply_devs || (reply_devs->type != REDIS_REPLY_ARRAY) || (reply_devs->elements <= 0))
    {
        dbg_syslog(LOG_ERR, "getall devs failed");
        return;
    }
    for (int i = 0; i < reply_devs->elements; i+=2)
    {
        snprintf(cmd, CMD_MAX_LENGTH, "zrange %s 0 -1", reply_devs->element[i]->str);   //设备上报到emms云平台的数据存放在以设备SN命名的有序集中
        redisReply *reply_data = (redisReply *)redisCommand(var->context, cmd);
        if (NULL == reply_data || (reply_data->type != REDIS_REPLY_ARRAY) || (reply_data->elements <= 0))
        {
            dbg_syslog(LOG_ERR, "get dev %s data failed", reply_devs->element[i]->str);
            continue;
        }
        cJSON *curdevdata = cJSON_CreateObject();
        cJSON_AddItemToArray(msgs, curdevdata);
        cJSON_AddStringToObject(curdevdata, "no", reply_devs->element[i]->str);
        cJSON *tags = cJSON_CreateObject();
        cJSON_AddItemToObject(curdevdata, "tags", tags);
        for (int j = 0; j < reply_data->elements; j++)
        {
            char *tok = strtok(reply_data->element[j]->str, "|");
            char *tok2 = strtok(0, "|");
            if (strstr(tok2, "."))
            {
                cJSON_AddNumberToObject(tags, tok, atof(tok2));
            }
            else
            {
                cJSON_AddNumberToObject(tags, tok, atoi(tok2));
            }
        }
        freeReplyObject(reply_data);

        if (strstr(reply_devs->element[i]->str, "Rack"))    //生成电芯数据的数组
        {
            uint allvolt[512] = {0};
            double alltemp[256] = {0};
            int maxvolt = 0, maxtemp = 0; 
            snprintf(cmd, CMD_MAX_LENGTH, "zrange %s_CELL 0 -1", reply_devs->element[i]->str);
            reply_data = (redisReply *)redisCommand(var->context, cmd);
            if (NULL == reply_data || (reply_data->type != REDIS_REPLY_ARRAY) || (reply_data->elements <= 0))
            {
                dbg_syslog(LOG_ERR, "get dev %s data failed", reply_devs->element[i]->str);
                continue;
            }
            cJSON *celltemp = cJSON_CreateArray();
            cJSON *cellvolt = cJSON_CreateArray();
            cJSON_AddItemToObject(tags, "CellTemp", celltemp);
            cJSON_AddItemToObject(tags, "CellVol", cellvolt);

            for(int k = 0; k < reply_data->elements; k++)
            {
                char *tok = strtok(reply_data->element[k]->str, "|");
                char *tok2 = strtok(0, "|");
                if (strstr(tok, "CV"))
                {
                    uint index = atoi(tok + 2);
                    if (index > maxvolt)
                    {
                        maxvolt = index;
                    }
                    allvolt[index] = (uint)(atof(tok2) * 1000);
                }
                if (strstr(tok, "CT"))
                {
                    uint index = atoi(tok + 2);
                    if (index > maxtemp)
                    {
                        maxtemp = index;
                    }
                    /*for (int m = 0; m < strlen(tok2); m++)
                    {
                        if (tok2[m]=='.' && (m+1 < strlen(tok2)))
                        {
                            tok2[m]=tok2[m+1];
                            tok2[m+1]='.';
                            break;
                        }
                    }*/
                    alltemp[index] = atof(tok2);
                }
            }
            for (int p = 1; p <= maxvolt; p++)
            {
                cJSON *cvolt = cJSON_CreateNumber(allvolt[p]);
                cJSON_AddItemToArray(cellvolt, cvolt);
            }
            for (int q = 1; q <= maxtemp; q++)
            {
                cJSON *ctemp = cJSON_CreateNumber(alltemp[q]);
                cJSON_AddItemToArray(celltemp, ctemp);
            }

            freeReplyObject(reply_data);
        }
    }
    freeReplyObject(reply_devs);
}

void cloud_emmsv2_dashboardmsg(cloud_emmsv2_var_t *var, cJSON *root)
{
    char cmd[CMD_SHORT_LENGTH] = {0};
    cJSON *msgs = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "messages", msgs);

    append_devmsg(var, msgs, "repoparam");
    snprintf(cmd, CMD_SHORT_LENGTH, "hgetall devs");
    redisReply *reply = (redisReply *)redisCommand(var->context, cmd);
    if ((NULL == reply) || (reply->type != REDIS_REPLY_ARRAY) || (reply->elements <= 0))
    {
        dbg_syslog(LOG_ERR, "getall devs failed");
        freeReplyObject(reply);
        return;
    }
    for(int i = 0; i < reply->elements; i+=2)
    {
        if (strstr(reply->element[i]->str, "meter") || strstr(reply->element[i]->str, "PCS") ||strstr(reply->element[i]->str, "Rack") || strstr(reply->element[i]->str, "PV"))
        {    
            dbg_syslog(LOG_ERR, "append dev %s ", reply->element[i]->str);
            append_devmsg(var, msgs, reply->element[i]->str);
        }
    }
    freeReplyObject(reply);
}

void cloud_emmsv2_pubalarm(cloud_emmsv2_var_t *var, cJSON *msgs)
{
    char topic[TOPIC_MAX_LEN];

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_ALARM);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));
    cJSON *msgArray = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "messages", msgArray);
    cJSON *dummsg = cJSON_Duplicate(msgs, 1);
    cJSON_AddItemToArray(msgArray, dummsg);

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_ALARM);

    dbg_syslog(LOG_ERR, "to publish %s %s", topic, data_tmp);
    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

//向ems_ctrl发送某天的策略。入参tm_score为日期转换成的realstra表中的分数，如20240201
void cloud_emmsv2_pubstra(cloud_emmsv2_var_t *var, uint tm_score)
{
    char topic[TOPIC_MAX_LEN * 2] = {0};
    unsigned short segpower[MAX_TIME_SEG] = {0};
    unsigned char segmode[MAX_TIME_SEG] = {0};
    short segwggl[MAX_TIME_SEG] = {0};
    char cmd[CMD_MAX_LENGTH] = {0};
    char timestr[8] = {0};
    cJSON *rt_data = cJSON_CreateObject();
    cJSON *content = cJSON_CreateArray();
    cJSON_AddItemToObject(rt_data, "content", content);
    cJSON *dailystra = cJSON_CreateObject();
    cJSON_AddItemToArray(content, dailystra);
    cJSON *planinfo = cJSON_CreateArray();
    cJSON_AddItemToObject(dailystra, "PlanInfo", planinfo);

    snprintf(cmd, CMD_MAX_LENGTH, "zrangebyscore "REDIS_STRA_BASE" %u %u", tm_score, tm_score);
    redisReply *reply_stra = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply_stra)
    {
        dbg_syslog(LOG_ERR, "execcmd %s failed", cmd);
    }
    else if (reply_stra->type == REDIS_REPLY_NIL)
    {
        dbg_syslog(LOG_ERR, "No strategy of specific date %u", tm_score);
    }
    else if (reply_stra->type == REDIS_REPLY_STRING)
    {
        parse_stra(reply_stra->str, segpower, segmode, segwggl);
    }
    else if (reply_stra->type == REDIS_REPLY_ARRAY && reply_stra->elements > 0)
    {
        parse_stra(reply_stra->element[0]->str, segpower, segmode, segwggl);
    }
    freeReplyObject(reply_stra);
    
    for (int i = 0; i < MAX_TIME_SEG; i++)
    {
        cJSON *timeseg = cJSON_CreateObject();
        cJSON_AddNumberToObject(timeseg, "option", segmode[i]);
        cJSON_AddNumberToObject(timeseg, "power", segpower[i]);
        cJSON_AddNumberToObject(timeseg, "Wggl", segwggl[i]);
        snprintf(timestr, 8, "P%02d%02d", i / 4, (((i % 4)<<4)-(i % 4)));
        cJSON_AddStringToObject(timeseg, "time", timestr);
        cJSON_AddItemToArray(planinfo, timeseg);
    }

    snprintf(cmd, CMD_MAX_LENGTH, "hgetall "REDIS_PROPARAM_BASE);
    redisReply *reply_pro = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply_pro)
    {
        dbg_syslog(LOG_ERR, "execcmd %s failed", cmd);
    }
    else if (reply_pro->type == REDIS_REPLY_NIL)
    {
        dbg_syslog(LOG_ERR, "No protected param");
    }
    else
    {
        for(int k = 0; k < reply_pro->elements; k+=2)
        {
            tagmap_entry_t *curtag;
            double paramVal = atof(reply_pro->element[k+1]->str);  
            HASH_FIND_STR(var->tagmaps, reply_pro->element[k]->str, curtag);
            if (curtag != NULL)
            {
                cJSON_AddNumberToObject(dailystra, curtag->emsctrltag, paramVal);
            }
            else
            {
                cJSON_AddNumberToObject(dailystra, reply_pro->element[k]->str, paramVal);
            }
        }
    }
    freeReplyObject(reply_pro);
    cJSON_AddNumberToObject(dailystra, "repeat", 1);
    cJSON_AddNumberToObject(dailystra, "priority", 1);
    cJSON_AddNumberToObject(dailystra, "pvMax", 0);
    cJSON_AddNumberToObject(dailystra, "type", 1);
    cJSON_AddStringToObject(dailystra, "weekly", "");

    cJSON_AddStringToObject(rt_data, "identifier", "strategyTemplate");
    cJSON_AddNumberToObject(rt_data, "mi",var->mi++);
    cJSON_AddNumberToObject(rt_data, "timestamp", time(NULL));
    cJSON_AddStringToObject(rt_data, "sn", var->emsctrl_sn_str);
    cJSON_AddNumberToObject(rt_data, "emmsv2", 1);

    char *data_tmp = cJSON_PrintUnformatted(rt_data);
    snprintf(topic, TOPIC_MAX_LEN * 2, "ipc/%s/NULL/device/%s/data/Set_Rglt", var->sn_str, var->emsctrl_sn_str);

    ipc_session_publish(var->session, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(rt_data);
}

static int cloud_emmsv2_subscribe_all(cloud_emmsv2_var_t *var)
{
    mqtt_session_t *mqtt_session = var->session_cloud;
    char topic[128];

    snprintf(topic, sizeof(topic), "%s/%s/%s/+", PLATFORM, LCPOSTRSP, var->sn_str);
    mqtt_session_subscribe(mqtt_session, topic);

    snprintf(topic, sizeof(topic), "%s/%s/%s/+", PLATFORM, EMMSGET, var->sn_str);
    mqtt_session_subscribe(mqtt_session, topic);

    snprintf(topic, sizeof(topic), "%s/%s/%s/+", PLATFORM, EMMSSET, var->sn_str);
    mqtt_session_subscribe(mqtt_session, topic);

    return 0;
}

//进程与云平台之间的状态切换
static int cloud_emmsv2_state_change(void *obj, int state)
{
    cloud_emmsv2_var_t *var = (cloud_emmsv2_var_t *)obj;

    switch (state)
    {
    case MQTT_CONNECTING:
        post_net_led(LED_TWINKLE);
        var->comm_status = COMM_STATUS_CONNECTING;
        break;
    case MQTT_CONNECTED:
        post_net_led(LED_LIGHT_ON);
        var->comm_status = COMM_STATUS_CONNECTED;
        if (!var->status_timer)
        {
            //开启心跳超时检查定时器
            var->status_timer = my_timer_create();
            if (var->status_timer <= 0)
            {
                dbg_syslog(LOG_INFO, "[ERR] create status check timer fail, %d", var->status_timer);
            }

            if (var->status_timer > 0)
            {
                my_timer_set(var->status_timer, 2, 2000);
            }
        }
        break;
    case MQTT_DISCONNECTED:
        post_net_led(LED_LIGHT_OFF);
        var->comm_status = COMM_STATUS_IDLE;
        break;
    default:
        dbg_syslog(LOG_ERR, "wrong mqtt state:%d", state);
    }
    return 0;
}

//推送设备列表到云平台
void cloud_emmsv2_pubdevinfo(cloud_emmsv2_var_t *var)
{
    char topic[TOPIC_MAX_LEN];

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_DEVI);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));

    cloud_emmsv2_gendevclass(root);

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_DEVI);

    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

static int get_alarm_count(cloud_emmsv2_var_t *var)
{
    int retval = 0;
    char cmd[CMD_MAX_LENGTH];
    snprintf(cmd, CMD_MAX_LENGTH, "hlen "REDIS_REAL_ALARM_TABLE);
    redisReply *reply = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply)
    {
        dbg_syslog(LOG_ERR, "execcmd %s error", cmd);
        return 0;
    }
    retval = (int)reply->integer;
    freeReplyObject(reply);
    return retval;
}

void timer_heart_beat(cloud_emmsv2_var_t *var)
{
    char topic[TOPIC_MAX_LEN];

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_HB);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));

    cJSON *info = cJSON_CreateObject();
    cJSON_AddNumberToObject(info, "alarmCnt", get_alarm_count(var));
    cJSON_AddItemToObject(root, "info", info);

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_HB);

    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

void timer_emsctrl_report(cloud_emmsv2_var_t *var)
{
    char topic[TOPIC_MAX_LEN] = {0};
    char cmd[CMD_MAX_LENGTH] = {0};

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_TELM);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));

    cJSON *tags = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "tags", tags);
    /* iterate all emsctrl telemetry, insert into tags */

    snprintf(cmd, CMD_MAX_LENGTH, "hgetall "REDIS_REPOPARAM_BASE);
    dbg_syslog(LOG_ERR, "emsctrl report cmd %s", cmd);
    redisReply *reply = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply)
    {
        dbg_syslog(LOG_ERR, "get report param failed");
    }
    else
    {
        dbg_syslog(LOG_ERR, "reply %d elements %lu", reply->type, reply->elements);
        for (int i = 0; i < reply->elements; i+=2)
        {
            cJSON_AddNumberToObject(tags, reply->element[i]->str, atof(reply->element[i+1]->str));
        }
    }

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_TELM);

    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

void timer_subdev_report(cloud_emmsv2_var_t *var)
{
    char topic[TOPIC_MAX_LEN];

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_SUBTELM);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));

    //cJSON *messages = cJSON_CreateArray();
    //cJSON_AddItemToObject(root, "messages", messages);
    /* iterate subdev,  generate a node includes all tags of subdev, append to messages */
    cloud_emmsv2_subdevmsg(var, root);

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_SUBTELM);

    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

void timer_dashboard_report(cloud_emmsv2_var_t *var)
{
    char topic[TOPIC_MAX_LEN];

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_DASHBOARDDATA);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));

    cloud_emmsv2_dashboardmsg(var, root);

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_DASHBOARDDATA);

    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

void gateway_login_msg(cloud_emmsv2_var_t *var)
{
    char topic[TOPIC_MAX_LEN];

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        dbg_syslog(LOG_ERR, "create json object error");
        return;
    }
    cJSON_AddStringToObject(root, "funcId", FUNC_LOGIN);
    cJSON_AddStringToObject(root, "lcSN", var->sn_str);
    cJSON_AddNumberToObject(root, "seq", var->seq++);
    cJSON_AddNumberToObject(root, "time", time(NULL));

    cJSON *logininfo = cJSON_CreateObject();
    cJSON_AddStringToObject(logininfo, "protocolVer", var->protocolVer);
    cJSON_AddNumberToObject(logininfo, "mode", var->mode);
    cJSON_AddStringToObject(logininfo, "id", var->lcid);
    cJSON_AddStringToObject(logininfo, "station", var->lcsta);
    cJSON_AddNumberToObject(logininfo, "capacity", var->capacity);
    cJSON_AddNumberToObject(logininfo, "power", var->power);
    cJSON_AddStringToObject(logininfo, "time", var->loadtime);
    cJSON_AddStringToObject(logininfo, "local", var->loc);
    cJSON_AddStringToObject(logininfo, "station_name", var->staname);
    cJSON_AddStringToObject(logininfo, "vendor", var->vendor);
    cJSON_AddStringToObject(logininfo, "softVersion", var->softver);
    cJSON_AddStringToObject(logininfo, "tenant_id", var->tenant_id);
    cJSON_AddStringToObject(logininfo, "model", var->model);
    cJSON_AddItemToObject(root, "info", logininfo);

    char *data_tmp = cJSON_PrintUnformatted(root);
    snprintf(topic, TOPIC_MAX_LEN, "%s/%s/%s/%s", PLATFORM, LCPOST, var->sn_str, FUNC_LOGIN);

    sleep(10);  // 等待10s再发login以等待其他服务启动
    mqtt_session_publish(var->session_cloud, topic, data_tmp, strlen(data_tmp));
    free(data_tmp);
    cJSON_Delete(root);
}

int comm_status_poll(cloud_emmsv2_var_t *var)
{
    TIMER_CONFIRM(var->status_timer);
    time_t now;
    static time_t last_check = 0;
    static time_t heartbeat_time = 0;
    static time_t emsctrl_period_report_time = 0;
    static time_t subdev_period_report_time = 0;
    static time_t dashboard_report_time = 0;
    time(&now);
    struct tm *t;
    t = localtime(&now);
    if (!dashboard_report_time)
    {
        dashboard_report_time = now;
    }

    if (t->tm_mday != var->lastmday && var->controlMode == 1) //新的一天，并且是自动模式，向ems_ctrl下发此日的策略
    {
        uint tmscore = (t->tm_year + 1900) * 10000 + (t->tm_mon + 1) * 100 + t->tm_mday; //用年月日计算数据库中的score，公式为年*10000+月*100—+日，如2024-01-10为20240110
        cloud_emmsv2_pubstra(var, tmscore);
        var->lastmday = t->tm_mday;
    }

    if (now > last_check + 1)
    {
        last_check = now;
        if (var->comm_status == COMM_STATUS_CONNECTED)  //连接上云平台broker之后发login
        {
            gateway_login_msg(var);
        }
        else if (var->comm_status == COMM_STATUS_LOGIN) //login成功之后根据上报间隔进行上报
        {
            if (now >= heartbeat_time + var->heartbeat_interval)
            {
                heartbeat_time = now;
                timer_heart_beat(var);
            }
            if (now >= emsctrl_period_report_time + var->emsctrl_interval)
            {
                emsctrl_period_report_time = now;
                timer_emsctrl_report(var);
            }
            if (now >= subdev_period_report_time + var->dev_interval)
            {
                subdev_period_report_time = now;
                timer_subdev_report(var);
            }
        }
    }

    if ((now < var->db_endtime) && (dashboard_report_time + var->db_period < now)) //大屏上报
    {
        dashboard_report_time = now; 
        timer_dashboard_report(var);
    }

    return 0;
}

static int load_emmsv2_cfg(cloud_emmsv2_var_t *var, char *cfg_file)
{
    char *data = NULL;
    cJSON *root = NULL;
    int ret = -1;
    int lens;

    if (cfg_file == NULL)
    {
        dbg_syslog(LOG_ERR, "cfg_file:%s not exist, use defaut MQTT server", cfg_file);
        goto out;
    }

    data = read_file_data_and_lens(cfg_file, &lens);
    if (data == NULL)
    {
        dbg_syslog(LOG_ERR, "read cfg file %s error, load default", cfg_file);
        goto out;
    }

    root = cJSON_Parse(data);
    if (!root)
    {
        dbg_syslog(LOG_ERR, "parse cfg file %s error, load default", cfg_file);
        goto out;
    }

    GET_JSON_VALUE_INT(root, "heartbeat_interval", var->heartbeat_interval);
    GET_JSON_VALUE_INT(root, "emsctrl_interval", var->emsctrl_interval);
    GET_JSON_VALUE_INT(root, "dev_interval", var->dev_interval);

    cJSON_Delete(root);
    ret = 0;

out:
    if (data)
    {
        free(data);
    }
    if (var->heartbeat_interval == 0)
    {
        var->heartbeat_interval = 60; // default 1 min
    }
    if (var->emsctrl_interval == 0)
    {
        var->emsctrl_interval = 5 * 60; // default 5 min
    }
    if (var->dev_interval == 0)
    {
        var->dev_interval = 5 * 60; // default 5 min
    }
    return ret;
}

// 建立与broker之间的MQTT连接
int cloud_emmsv2_mqtt_init(cloud_emmsv2_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, 2 * MAX_CLIENT_ID_LEN, "cloud_emmsv2_%s", var->sn_str);
    var->session_cloud = mqtt_session_new(clientId,  (void *)var);
    if (var->session_cloud == NULL)
        return -1;

    load_server_config(var->session_cloud, EMMSV2_SERVER_CONFIG);
    load_emmsv2_cfg(var, EMMSV2_SERVER_CONFIG);

    mqtt_session_set_opts(var->session_cloud, DEFAULT_QOS, KEEPALIVEINTERVAL);
    mqtt_session_set_callbacks(var->session_cloud, recv_host_msg, cloud_emmsv2_state_change);

    var->comm_status = COMM_STATUS_CONNECTING;
    cloud_emmsv2_subscribe_all(var);
    mqtt_session_start(var->session_cloud);
    return 0;
}
