#include "main.h"
#define PRINT_TIME_TAG
#define DBG_TAG "main"
#define DBG_LVL DBG_INFO
#include "debug_print.h"
#include <sys/prctl.h>
#include <sys/statvfs.h>
#include "curl_arm64/include/curl.h"
#include "redis_sn/redis_sn_client.h"
#if 0
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/serial.h>

#define DMA_START_TX _IOW('U', 0x10, struct dma_config)
struct dma_config {
    void *buf;
    size_t len;
};
#endif
pthread_t pt_uart_send;
pthread_t pt_uart_recv_ack;
pthread_t pt_uart_recv_data;
pthread_t pt_uart_recv_back;
pthread_t pt_vm_heartbeat;
pthread_t pt_mqtt_recv;
pthread_t pt_readqr; // 禁用二维码扫描线程
pthread_t pt_ota;
pthread_t pt_doota;
pthread_t pt_mqtt;
pthread_t pt_removelog;
pthread_t pt_reboot;
pthread_t pt_watchdog;
pthread_t pt_tagsearch;
pthread_t pt_removeduplicatetag;
uart_utils_t uartSend = {0};
uart_utils_t uartRecvData = {0};
uart_utils_t uartRecvBack = {0};
mqtt_parm_t mqtt_parm={0};
mqtt_utils_t mqtt_config;
struct input_event buff;

bool isTimeToReboot=false;
bool isLightOn=false;
bool isLightOnByRule=false;
bool isLabelUp=false;
bool isSearchLabel=false;
bool isSearchReport=false;
bool isSearchLabelOn=false;
bool isSearchLabelOntest=false;
bool isLightEnable=true;
bool isSendComEnd=true;
bool isOtaEnable=false;
bool isLEDOtaSuccess=false;
bool isAPOtaSuccess=false;
bool isAPBack=false;
jt_only_tag_t onlyTags[5000]={0};
jt_only_tag_t onlyTagsNew[5000]={0};
int tagCount=0;
int tagCountNew=0;
int tagIndex=0;
int otaCount=0;
int fd;
int UPCASE=0;
int count_value=0;
int getPayloadTime=120*1000;//usecond
char softwareVersion[16]="1.1.41";
char stationsn[16]="TJ251372224247";//TJ250995217957
char productid[8]="10045";
char appKey[32]="fdhQmhqhvbL1cf1K9mUqt";
char appSecret[64]="s3izIliw0CF48Pcsi16rjOmoFRf5WEt8";
char mqttRawPassword[64]="";
char input_value[1024]={0};//94b4e39caf1d45ee9a071d701cc037b4
char input_value_copy[1024]={0};
char *getDevRegisterStatusUrl="https://gaea-zt-express.com/device/modifyRegisterInfo";
//char *logUploadUrl="http://pda.pupumall.net:1180/open/api/device/log/upload";
char *getDevRawPasswordUrl="https://gaea.zt-express.com/device/modifyRegisterInfo";
char *hostDomain="tx-mqtt.zt-express.com";
char lightsn1[32]={0};
char lightsn2[32]={0};
char lightsn3[32]={0};
char lightsn4[32]={0};
char lightsn5[32]={0};
char lightsn6[32]={0};
char lightsn7[32]={0};
char lightsn8[32]={0};
char lightsn9[32]={0};
char lightsn10[32]={0};
char lightsn11[32]={0};
char lightsn12[32]={0};
char lightsn13[32]={0};
char lightsn14[32]={0};
char lightsn15[32]={0};
char lightsn16[32]={0};
char lightsn17[32]={0};
char lightsn18[32]={0};
char lightsn19[32]={0};
char lightsn20[32]={0};
char lightsn21[32]={0};
char lightsn22[32]={0};
char lightsn23[32]={0};
char lightsn24[32]={0};
char lightsn25[32]={0};
char lightsn26[32]={0};
char lightsn27[32]={0};
char lightsn28[32]={0};
char lightsn29[32]={0};
char lightsn30[32]={0};
int searchTimeOut=0;
int searchTimeOld=0;
int searchTimeNew=0;
int lightsnNum=0;
int mqtt_port=1883;

uint32_t Tag1=0;
uint32_t Tag2=0;
uint32_t Tag3=0;
uint32_t Tag4=0;
uint32_t Tag5=0;

static time_t last_2323_time = 0;  // 记录上次收到0x2323的时间
static bool waiting_for_4646 = false;  // 是否在等待0x4646

// ====== 3015合并点亮相关全局变量 ======
#define MAX_LIGHTSN_BUFFER 4096
static char lightsn_buffer[MAX_LIGHTSN_BUFFER][32] = {0};
static char color_buffer[MAX_LIGHTSN_BUFFER][8] = {0}; // 颜色缓冲区，与sn一一对应
static char sound_buffer[MAX_LIGHTSN_BUFFER][8] = {0}; // 声音缓冲区
static char flash_buffer[MAX_LIGHTSN_BUFFER][8] = {0}; // 闪光缓冲区
static int lightsn_buffer_count = 0;
static time_t first_3015_time = 0;
static bool is_3015_collecting = false;
static pthread_mutex_t lightsn_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;

// 3022合包缓存定义（放在文件顶部或main函数外部）
#define LABEL_BATCH_SIZE 20
static uint32_t tags_buf[LABEL_BATCH_SIZE] = {0};
static uint8_t lable1_buf[LABEL_BATCH_SIZE] = {0};
static uint16_t lable2_buf[LABEL_BATCH_SIZE] = {0};
static uint32_t lable3_buf[LABEL_BATCH_SIZE] = {0};
static int label_buf_count = 0;
static time_t label_buf_first_time = 0;

// 函数声明
void *thread_timeout_check(void *arg);
void *thread_3015_lighton_merge(void *arg);
void *thread_label_batch_send(void *arg);

int getLedOtaVersion(char *filename);
int getApOtaVersion(char *filename,char *modename);
void hmacsha1(char *key,char* data,char *signbase64,int signbase64_len);
void light_off_tag_report(uint32_t name,uint16_t batteryv);
void light_battery_report(uint32_t tagCode, uint16_t batteryV);
void search_tag_report();
void copyOnlyTag(void);

// 安全的命令执行函数
static int safe_exec_cmd(const char *cmd) {
    LOG_I("Executing command: %s\n", cmd);
    int ret = system(cmd);
    if (ret != 0) {
        LOG_E("Command failed: %s, return code: %d, error: %s", cmd, ret, strerror(errno));

        // 如果是init.d脚本失败，记录更多信息
        if (strstr(cmd, "/etc/init.d/tx_server") != NULL) {
            FILE *log_file = fopen("/var/log/tx_server_restart.log", "a");
            if (log_file != NULL) {
                time_t now = time(NULL);
                struct tm *tm_info = localtime(&now);
                char time_str[26];
                strftime(time_str, 26, "%Y-%m-%d %H:%M:%S", tm_info);

                fprintf(log_file, "[%s] DEBUG: Command that failed: %s\n", time_str, cmd);
                fprintf(log_file, "[%s] DEBUG: Return code: %d\n", time_str, ret);
                fprintf(log_file, "[%s] DEBUG: errno: %d (%s)\n", time_str, errno, strerror(errno));

                // 检查脚本是否存在且可执行
                if (access("/etc/init.d/tx_server", F_OK) == 0) {
                    fprintf(log_file, "[%s] DEBUG: Script exists\n", time_str);
                    if (access("/etc/init.d/tx_server", X_OK) == 0) {
                        fprintf(log_file, "[%s] DEBUG: Script is executable\n", time_str);
                    } else {
                        fprintf(log_file, "[%s] DEBUG: Script is NOT executable\n", time_str);
                    }
                } else {
                    fprintf(log_file, "[%s] DEBUG: Script does NOT exist\n", time_str);
                }

                fclose(log_file);
            }
        }

        return -1;
    }
    LOG_I("Command succeeded: %s\n", cmd);
    return 0;
}

// 兼容的服务重启函数，支持systemctl和init.d两种方式
int restart_tx_server_service(void) {
    // 首先尝试使用systemctl方式
    if (access("/bin/systemctl", F_OK) == 0) {
        LOG_I("Using systemctl to restart tx_server service\n");
        int ret = safe_exec_cmd("systemctl restart tx_server");
        if (ret == 0) {
            LOG_I("Successfully restarted tx_server using systemctl\n");
            return 0;
        } else {
            LOG_W("systemctl restart failed, trying init.d method\n");
        }
    }

    // 如果systemctl不可用或失败，尝试使用init.d方式
    if (access("/etc/init.d/tx_server", F_OK) == 0) {
        LOG_I("Using init.d script to restart tx_server service\n");

        // 详细诊断信息
        FILE *log_file = fopen("/var/log/tx_server_restart.log", "a");
        if (log_file != NULL) {
            time_t now = time(NULL);
            struct tm *tm_info = localtime(&now);
            char time_str[26];
            strftime(time_str, 26, "%Y-%m-%d %H:%M:%S", tm_info);

            // 记录执行前的系统状态
            fprintf(log_file, "[%s] INFO: Starting tx_server restart process\n", time_str);
            fprintf(log_file, "[%s] INFO: Current UID: %d, GID: %d\n", time_str, getuid(), getgid());

            // 检查脚本权限
            struct stat st;
            if (stat("/etc/init.d/tx_server", &st) == 0) {
                fprintf(log_file, "[%s] INFO: Script permissions: %o\n", time_str, st.st_mode & 0777);
                fprintf(log_file, "[%s] INFO: Script owner: %d, group: %d\n", time_str, st.st_uid, st.st_gid);
            }

            // 检查当前进程状态
            fprintf(log_file, "[%s] INFO: Current working directory: ", time_str);
            char cwd[256];
            if (getcwd(cwd, sizeof(cwd)) != NULL) {
                fprintf(log_file, "%s\n", cwd);
            } else {
                fprintf(log_file, "unknown\n");
            }

            // 检查环境变量
            fprintf(log_file, "[%s] INFO: PATH=%s\n", time_str, getenv("PATH") ? getenv("PATH") : "not set");

            fclose(log_file);
        }

        system("echo 0 > /sys/class/gpio/gpio1/value");

        int ret = safe_exec_cmd("/etc/init.d/tx_server restart");

        log_file = fopen("/var/log/tx_server_restart.log", "a");
        if (log_file != NULL) {
            time_t now = time(NULL);
            struct tm *tm_info = localtime(&now);
            char time_str[26];
            strftime(time_str, 26, "%Y-%m-%d %H:%M:%S", tm_info);

            if (ret == 0) {
                fprintf(log_file, "[%s] SUCCESS: tx_server restarted successfully using init.d\n", time_str);
                LOG_I("Successfully restarted tx_server using init.d\n");
            } else {
                fprintf(log_file, "[%s] FAILED: tx_server restart failed using init.d (return code: %d)\n", time_str, ret);
                fprintf(log_file, "[%s] ERROR: errno=%d, error=%s\n", time_str, errno, strerror(errno));
                LOG_E("init.d restart also failed\n");

                // 尝试获取更多错误信息
                FILE *cmd_output = popen("/etc/init.d/tx_server restart 2>&1", "r");
                if (cmd_output != NULL) {
                    char buffer[1024];
                    fprintf(log_file, "[%s] DEBUG: Command output:\n", time_str);
                    while (fgets(buffer, sizeof(buffer), cmd_output) != NULL) {
                        fprintf(log_file, "[%s] DEBUG: %s", time_str, buffer);
                    }
                    pclose(cmd_output);
                }
            }
            fclose(log_file);
        }

        if (ret == 0) {
            return 0;
        }
    } else {
        LOG_E("Neither systemctl nor init.d script found for tx_server\n");
    }

    LOG_E("All service restart methods failed\n");
    return -1;
}

/*================================================================================*/
void doCommand_help(int argc, char *argv[])
{
    printf("************************************************************\r\n"\
           "all commands are case insensitive\r\n"\
           "help                            print this message\r\n"\
           "SND [01-60]                     set sound S01-S60\r\n"\
           "************************************************************\r\n");
}

static int safe_rename(const char *src, const char *dst) {
    if (rename(src, dst) != 0) {
        LOG_E("Failed to rename %s to %s: %s", src, dst, strerror(errno));
        return -1;
    }
    return 0;
}

static int safe_remove_dir(const char *path) {
    if (rmdir(path) != 0) {
        LOG_E("Failed to remove directory %s: %s", path, strerror(errno));
        return -1;
    }
    return 0;
}

static int safe_remove_file(const char *path) {
    if (unlink(path) != 0) {
        LOG_E("Failed to remove file %s: %s", path, strerror(errno));
        return -1;
    }
    return 0;
}

static int safe_mkdir(const char *path) {
    if (mkdir(path, 0755) != 0 && errno != EEXIST) {
        LOG_E("Failed to create directory %s: %s", path, strerror(errno));
        return -1;
    }
    return 0;
}

void doCommand(int argc, char *argv[])
{
    //sendData(argv[1],argv[0]);
}

__command_initialize("RON", doCommand);
__command_initialize("help",doCommand_help);

/*================================================================================*/
void do_removelog(void)
{
    LOG_I("%s\n",__func__);
    FILE *fp;
    char buffer[5];
    char syscmd[32];
    int logcount=0;

    fp=popen("ls Log.*|wc -l", "r");
    if (fp) {
        fgets(buffer,sizeof(buffer),fp);
        logcount=atoi(buffer);
        pclose(fp);
    }
    LOG_I("logcount:%d\n",logcount);
    if(logcount>=2){
        sprintf(syscmd,"ls Log.*|head -%d|xargs rm -fr",logcount-1);
        LOG_I("%s\n",syscmd);
        system(syscmd);
    }else{
        LOG_I("logcount less than 3,not remove\n");
    }
}

// 获取CPU使用率
float get_cpu_usage() {
    FILE *fp;
    char buf[256];
    unsigned long long user1, nice1, system1, idle1, iowait1, irq1, softirq1, steal1;
    unsigned long long user2, nice2, system2, idle2, iowait2, irq2, softirq2, steal2;
    fp = fopen("/proc/stat", "r");
    fgets(buf, sizeof(buf), fp);
    sscanf(buf, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu", &user1, &nice1, &system1, &idle1, &iowait1, &irq1, &softirq1, &steal1);
    fclose(fp);
    usleep(1000000); // 1秒采样
    fp = fopen("/proc/stat", "r");
    fgets(buf, sizeof(buf), fp);
    sscanf(buf, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu", &user2, &nice2, &system2, &idle2, &iowait2, &irq2, &softirq2, &steal2);
    fclose(fp);
    unsigned long long total1 = user1+nice1+system1+idle1+iowait1+irq1+softirq1+steal1;
    unsigned long long total2 = user2+nice2+system2+idle2+iowait2+irq2+softirq2+steal2;
    unsigned long long idle_diff = idle2 - idle1;
    unsigned long long total_diff = total2 - total1;
    if (total_diff == 0) return 0.0;
    return 100.0 * (1.0 - (float)idle_diff / total_diff);
}

// 获取内存信息
void get_mem_usage(long *total, long *free, long *available, long *used, float *percent) {
    FILE *fp = fopen("/proc/meminfo", "r");
    char key[64];
    long value;
    char unit[16];
    long mem_total = 0, mem_free = 0, mem_available = 0, buffers = 0, cached = 0;
    while (fscanf(fp, "%63s %ld %15s\n", key, &value, unit) == 3) {
        if (strcmp(key, "MemTotal:") == 0) mem_total = value;
        else if (strcmp(key, "MemFree:") == 0) mem_free = value;
        else if (strcmp(key, "MemAvailable:") == 0) mem_available = value;
        else if (strcmp(key, "Buffers:") == 0) buffers = value;
        else if (strcmp(key, "Cached:") == 0) cached = value;
    }
    fclose(fp);
    *total = mem_total / 1024;
    *free = mem_free / 1024;
    *available = mem_available / 1024;
    *used = (*total) - (*available);
    *percent = (*total) ? 100.0 * (*used) / (*total) : 0.0;
}

// 获取磁盘信息
void get_disk_usage(const char *path, long *total, long *free, long *used, float *percent) {
    struct statvfs stat;
    if (statvfs(path, &stat) == 0) {
        *total = (stat.f_blocks * stat.f_frsize) / 1024 / 1024;
        *free = (stat.f_bfree * stat.f_frsize) / 1024 / 1024;
        *used = *total - *free;
        *percent = (*total) ? 100.0 * (*used) / (*total) : 0.0;
    } else {
        *total = *free = *used = 0;
        *percent = 0.0;
    }
}

void removeLog(){
    int len=0;
    char *savedtime=NULL;
    char nowtime[16]={0};
    long now=0;
    long saved=0;

    while(1){
        now=getCurrentTime();
        sprintf(nowtime,"%ld",now);
        savedtime=file_to_buffer("logTime",&len);
        if(savedtime==NULL){
            buffer_to_file("logTime",nowtime,strlen(nowtime),"wb");
            savedtime=file_to_buffer("logTime",&len);
        }
        saved=atol(savedtime);
        LOG_I("now=%ld,saved=%ld,nowtime=%s,savedtime=%s\n",now,saved,nowtime,savedtime);
        if(now-saved>=(60*60*24*2)){
        //if(now-saved>=10){
            buffer_to_file("logTime",nowtime,strlen(nowtime),"wb");
            do_removelog();
        }
        sleep(60*60*1);
    }
}

void checkOtaKey(void){
    int len=0;
    int keycount=0;
    char *readresult=NULL;
    while(1){
        if(isOtaEnable){
            system("echo 0 > /sys/class/gpio/gpio113/value");
            sleep(1);
            system("echo 1 > /sys/class/gpio/gpio113/value");
            sleep(1);
        }else{
            readresult=file_to_buffer("/sys/class/gpio/gpio63/value",&len);
            //LOG_I("resetKey:%s\n",readresult);
            if(readresult!=NULL){
                if(strcmp(readresult,"0\n")==0){
                    keycount++;
                    if(keycount==3){
                        keycount=0;
                        isOtaEnable=true;
                        isLEDOtaSuccess=false;
                        isAPOtaSuccess=false;
                        isSendComEnd=true;
                        LOG_I("OTA enable\n");
                    }
                }
                free(readresult);
            }
            usleep(100*1000);
        }
    }
}

void otaLeds(){
#if 0
    int len=0,ver=0;
    char *readresult=NULL;
    char filename[128]={};
    uint16_t data_crc=0;
    ver=getLedOtaVersion(filename);
    LOG_I("ota %s ver:%d\n",filename,ver);
    readresult=file_to_buffer(filename,&len);
    if(readresult!=NULL){
        isSendComEnd=false;
        LOG_I("data len:%d\n",len);
        data_crc=CRC16_XMODEM(readresult,len);
        LOG_I("crc :%04x\n",data_crc);
        uart_data_send_head_ledota(&uartSend,len,data_crc,ver);//0xFF降级
        usleep(72*1000);
        int i=0;
        for(i=0;i<len/4096;i++){
            uart_data_send_ledota(&uartSend,readresult+i*4096,4096);
            usleep(72*1000);
        }
        uart_data_send_ledota(&uartSend,readresult+i*4096,len%4096);
    }
#else
    int len=0,ver=0;
    char *readresult=NULL;
    char filename[128]={};
    uint8_t senddata[4096]={};
    uint16_t data_crc=0;
    ver=getLedOtaVersion(filename);
    LOG_I("ota %s ver:%d\n",filename,ver);
    readresult=file_to_buffer(filename,&len);
    if(readresult!=NULL){
        isSendComEnd=false;
        LOG_I("data len:%d\n",len);
        data_crc=CRC16_XMODEM(readresult,len);
        LOG_I("crc :%04x\n",data_crc);
        uart_data_send_head_ledota(&uartSend,len,data_crc,ver);//0xFF降级
        int i=0;
        for(i=0;i<len/4096;i++){
            memset(senddata,0,4096);
            memcpy(senddata,readresult+i*4096,4096);
            uart_data_send_ledota(&uartSend,senddata,4096);
        }
        memset(senddata,0,4096);
        memcpy(senddata,readresult+i*4096,len%4096);
        uart_data_send_ledota(&uartSend,senddata,len%4096);

        free(readresult);
    }
#endif
}

void otaAp(){
    int len=0,ver=0;
    char *readresult=NULL;
    char filename[128]={};
    char modename[32]={};
    uint8_t dataori[2048]={0};
    uint16_t data_crc=0;
    uint16_t p_num=0;
    ver=getApOtaVersion(filename,modename);
    LOG_I("ota %s mode:%s ver:%d\n",filename,modename,ver);
    readresult=file_to_buffer(filename,&len);
    if(len%2048!=0){
        p_num=len/2048 + 1;
    }else{
        p_num=len/2048;
    }
    if(readresult!=NULL){
        isSendComEnd=false;
        LOG_I("data len:%d\n",len);
        if(strcmp(modename,"GTMODE")==0){
            uart_data_send_head_apota(&uartSend,len,p_num);
            usleep(60*1000);
            memset(dataori,0,2048);
            memcpy(dataori,readresult,2048);
            data_crc=CRC16_APOTA(dataori,2048);
            LOG_I("crc :%04x\n",data_crc);
            uart_data_send_apota(&uartSend,dataori,len,p_num,data_crc);
            while(!isAPBack){
                usleep(60*1000);
            }
            int i=0;
            for(i=1;i<len/2048;i++){
                isAPBack=false;
                memset(dataori,0,2048);
                memcpy(dataori,readresult+i*2048,2048);
                data_crc=CRC16_APOTA(dataori,2048);
                LOG_I("crc :%04x\n",data_crc);
                uart_data_send_apota(&uartSend,dataori,2048,i,data_crc);
                while(!isAPBack){
                    usleep(60*1000);
                }
            }
            if(len%2048!=0){
                memset(dataori,0,2048);
                memcpy(dataori,readresult+i*2048,len%2048);
                data_crc=CRC16_APOTA(dataori,2048);
                LOG_I("crc :%04x\n",data_crc);
                uart_data_send_apota(&uartSend,dataori,2048,i,data_crc);
            }
        }else if(strcmp(modename,"DTMODE")==0){

        }if(strcmp(modename,"HTMODE")==0){

        }

        free(readresult);
    }
}

void enableWatchDog() {
    int fd;
    char path[64];
    char value[2];

    // Enable watchdog pin SGM820
    fd = open("/sys/class/gpio/export", O_WRONLY);
    if (fd < 0) {
        LOG_I("Failed to open gpio export: %s\n", strerror(errno));
        return;
    }
    write(fd, "1", 1);
    close(fd);

    // Enable feed watchdog pin
    fd = open("/sys/class/gpio/export", O_WRONLY);
    if (fd < 0) {
        LOG_I("Failed to open gpio export: %s\n", strerror(errno));
        return;
    }
    write(fd, "112", 3);
    close(fd);

    // Set gpio1 direction
    fd = open("/sys/class/gpio/gpio1/direction", O_WRONLY);
    if (fd < 0) {
        LOG_I("Failed to open gpio1 direction: %s\n", strerror(errno));
        return;
    }
    write(fd, "out", 3);
    close(fd);

    // Set gpio112 direction
    fd = open("/sys/class/gpio/gpio112/direction", O_WRONLY);
    if (fd < 0) {
        LOG_I("Failed to open gpio112 direction: %s\n", strerror(errno));
        return;
    }
    write(fd, "out", 3);
    close(fd);

    // Set gpio1 value
    fd = open("/sys/class/gpio/gpio1/value", O_WRONLY);
    if (fd < 0) {
        LOG_I("Failed to open gpio1 value: %s\n", strerror(errno));
        return;
    }
    write(fd, "1", 1);
    close(fd);

    LOG_I("enable watchdog\n");

    // Set gpio112 value
    fd = open("/sys/class/gpio/gpio112/value", O_WRONLY);
    if (fd < 0) {
        LOG_I("Failed to open gpio112 value: %s\n", strerror(errno));
        return;
    }
    write(fd, "1", 1);
    close(fd);
}

void feedWatchDog() {
    int fd = open("/sys/class/gpio/gpio112/value", O_WRONLY);
    if (fd < 0) {
        LOG_I("can not open watchdog gpio112\n");
        return;
    }

    while(1) {
        write(fd, "0", 1);
        usleep(100*1000);
        write(fd, "1", 1);
        sleep(1);
    }

    close(fd);
    return;
}

void rebootSystem(void){
    while(!isTimeToReboot){
        if(!isTimeToReboot){
            struct tm *result;
            time_t timep;
            time (&timep);
            result = localtime(&timep);
            if(result->tm_hour==0 && result->tm_min==0 && result->tm_sec==10){
                isTimeToReboot=true;
                LOG_I("prepare to reboot\n");
            }
        }
        sleep(1);
    }
    system("sync");
    sleep(10);
    system("sync");
    system("reboot");
}

int readQrcode()
{
    fd = open("/dev/input/event2", O_RDONLY);
    if (fd < 0)
    {
        LOG_I("can not open scanner input event2!\n");
        goto error;
    }

    while (1)
    {
        while (read(fd, &buff, sizeof(struct input_event)) == 0)
        {
            ;
        }
        if (buff.type == EV_KEY){
            if(buff.value==0){
#if 0
                LOG_I("type:%d code:%d value:%d\n", buff.type, buff.code, buff.value);
#else
                switch(buff.code){
                    case 2:
                        if(UPCASE==1){
                            input_value[count_value]='!';
                        }else{
                            input_value[count_value]='1';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 3:
                        if(UPCASE==1){
                            input_value[count_value]='@';
                        }else{
                            input_value[count_value]='2';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 4:
                        if(UPCASE==1){
                            input_value[count_value]='#';
                        }else{
                            input_value[count_value]='3';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 5:
                        if(UPCASE==1){
                            input_value[count_value]='$';
                        }else{
                            input_value[count_value]='4';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 6:
                        if(UPCASE==1){
                            input_value[count_value]='%';
                        }else{
                            input_value[count_value]='5';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 7:
                        if(UPCASE==1){
                            input_value[count_value]='^';
                        }else{
                            input_value[count_value]='6';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 8:
                        if(UPCASE==1){
                            input_value[count_value]='&';
                        }else{
                            input_value[count_value]='7';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 9:
                        if(UPCASE==1){
                            input_value[count_value]='*';
                        }else{
                            input_value[count_value]='8';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 10:
                        if(UPCASE==1){
                            input_value[count_value]='(';
                        }else{
                            input_value[count_value]='9';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 11:
                        if(UPCASE==1){
                            input_value[count_value]=')';
                        }else{
                            input_value[count_value]='0';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 12:
                        if(UPCASE==1){
                            input_value[count_value]='_';
                        }else{
                            input_value[count_value]='-';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 13:
                        if(UPCASE==1){
                            input_value[count_value]='+';
                        }else{
                            input_value[count_value]='=';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 16:
                        if(UPCASE==1){
                            input_value[count_value]='Q';
                        }else{
                            input_value[count_value]='q';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 17:
                        if(UPCASE==1){
                            input_value[count_value]='W';
                        }else{
                            input_value[count_value]='w';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 18:
                        if(UPCASE==1){
                            input_value[count_value]='E';
                        }else{
                            input_value[count_value]='e';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 19:
                        if(UPCASE==1){
                            input_value[count_value]='R';
                        }else{
                            input_value[count_value]='r';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 20:
                        if(UPCASE==1){
                            input_value[count_value]='T';
                        }else{
                            input_value[count_value]='T';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 21:
                        if(UPCASE==1){
                            input_value[count_value]='Y';
                        }else{
                            input_value[count_value]='y';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 22:
                        if(UPCASE==1){
                            input_value[count_value]='U';
                        }else{
                            input_value[count_value]='u';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 23:
                        if(UPCASE==1){
                            input_value[count_value]='I';
                        }else{
                            input_value[count_value]='i';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                     case 24:
                        if(UPCASE==1){
                            input_value[count_value]='O';
                        }else{
                            input_value[count_value]='o';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 25:
                        if(UPCASE==1){
                            input_value[count_value]='P';
                        }else{
                            input_value[count_value]='p';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 26:
                        if(UPCASE==1){
                            input_value[count_value]='{';
                        }else{
                            input_value[count_value]='[';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 27:
                        if(UPCASE==1){
                            input_value[count_value]='}';
                        }else{
                            input_value[count_value]=']';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 28:
                        input_value[count_value]='\0';
                        //LOG_I("%s\n",input_value);
                        memset(input_value_copy,0,1024);
                        memcpy(input_value_copy,input_value,1024);
                        memset(input_value,0,1024);
                        count_value=0;
                        int ret=-1;
                        pthread_t pt_handleqrcode;
                        ret = pthread_create(&pt_handleqrcode,NULL,actHandleQrcode,input_value_copy);
                        if(ret!=0){
                            LOG_I("pthread_create handleqrcode fail\n");
                        }else{
                            pthread_detach(pt_handleqrcode);
                        }
                    break;
                    case 30:
                        if(UPCASE==1){
                            input_value[count_value]='A';
                        }else{
                            input_value[count_value]='a';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 31:
                        if(UPCASE==1){
                            input_value[count_value]='S';
                        }else{
                            input_value[count_value]='s';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 32:
                        if(UPCASE==1){
                            input_value[count_value]='D';
                        }else{
                            input_value[count_value]='d';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 33:
                        if(UPCASE==1){
                            input_value[count_value]='F';
                        }else{
                            input_value[count_value]='f';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 34:
                        if(UPCASE==1){
                            input_value[count_value]='G';
                        }else{
                            input_value[count_value]='g';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 35:
                        if(UPCASE==1){
                            input_value[count_value]='H';
                        }else{
                            input_value[count_value]='h';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 36:
                        if(UPCASE==1){
                            input_value[count_value]='J';
                        }else{
                            input_value[count_value]='j';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 37:
                        if(UPCASE==1){
                            input_value[count_value]='K';
                        }else{
                            input_value[count_value]='k';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 38:
                        if(UPCASE==1){
                            input_value[count_value]='L';
                        }else{
                            input_value[count_value]='l';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 39:
                        if(UPCASE==1){
                            input_value[count_value]=':';
                        }else{
                            input_value[count_value]=';';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 40:
                        if(UPCASE==1){
                            input_value[count_value]='"';
                        }else{
                            input_value[count_value]='\'';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 42:
                        UPCASE=1;
                    break;
                    case 43:
                        if(UPCASE==1){
                            input_value[count_value]='|';
                        }else{
                            input_value[count_value]='\\';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 44:
                        if(UPCASE==1){
                            input_value[count_value]='Z';
                        }else{
                            input_value[count_value]='z';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 45:
                        if(UPCASE==1){
                            input_value[count_value]='X';
                        }else{
                            input_value[count_value]='x';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 46:
                        if(UPCASE==1){
                            input_value[count_value]='C';
                        }else{
                            input_value[count_value]='c';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 47:
                        if(UPCASE==1){
                            input_value[count_value]='V';
                        }else{
                            input_value[count_value]='v';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 48:
                        if(UPCASE==1){
                            input_value[count_value]='B';
                        }else{
                            input_value[count_value]='b';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 49:
                        if(UPCASE==1){
                            input_value[count_value]='N';
                        }else{
                            input_value[count_value]='n';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 50:
                        if(UPCASE==1){
                            input_value[count_value]='M';
                        }else{
                            input_value[count_value]='m';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 51:
                        if(UPCASE==1){
                            input_value[count_value]='<';
                        }else{
                            input_value[count_value]=',';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 52:
                        if(UPCASE==1){
                            input_value[count_value]='>';
                        }else{
                            input_value[count_value]='.';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                    case 53:
                        if(UPCASE==1){
                            input_value[count_value]='?';
                        }else{
                            input_value[count_value]='/';
                        }
                        UPCASE=0;
                        count_value++;
                    break;
                }
#endif
            }
        }
    }

    close(fd);
    return 0;
error:
    return 1;
}
#if 0
void writeWpa(char *filename,char *ssid,char *psw){
   LOG_I("%s\n",__func__);
   buffer_to_file(filename,"# WPA-PSK/TKIP\n",strlen("# WPA-PSK/TKIP\n"),"wb");
   buffer_to_file(filename,"ap_scan=1\n",strlen("ap_scan=1\n"),"a");
   buffer_to_file(filename,"ctrl_interface=/var/run/wpa_supplicant\n",strlen("ctrl_interface=/var/run/wpa_supplicant\n"),"a");
   buffer_to_file(filename,"network={\n",strlen("network={\n"),"a");
   buffer_to_file(filename,"ssid=\"",strlen("ssid=\""),"a");
   buffer_to_file(filename,ssid,strlen(ssid),"a");
   buffer_to_file(filename,"\"",strlen("\""),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"key_mgmt=WPA-PSK\n",strlen("key_mgmt=WPA-PSK\n"),"a");
   buffer_to_file(filename,"proto=WPA RSN\n",strlen("proto=WPA RSN\n"),"a");
   buffer_to_file(filename,"pairwise=CCMP TKIP\n",strlen("pairwise=CCMP TKIP\n"),"a");
   buffer_to_file(filename,"group=CCMP TKIP\n",strlen("group=CCMP TKIP\n"),"a");
   buffer_to_file(filename,"psk=\"",strlen("psk=\""),"a");
   buffer_to_file(filename,psw,strlen(psw),"a");
   buffer_to_file(filename,"\"",strlen("\""),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"}\n",strlen("}\n"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
}

void writeWlan(char *filename,char *netway,char *gate,char *ip){
   LOG_I("%s\n",__func__);
   buffer_to_file(filename,"METHOD=",strlen("METHOD="),"wb");
   buffer_to_file(filename,netway,strlen(netway),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   if(strcmp(netway,"STATIC")==0){
       buffer_to_file(filename,"IPADDR=",strlen("IPADDR="),"a");
       buffer_to_file(filename,ip,strlen(ip),"a");
       buffer_to_file(filename,"\n",strlen("\n"),"a");
       buffer_to_file(filename,"NETMASK=255.255.255.0\n",strlen("NETMASK=255.255.255.0\n"),"a");
       buffer_to_file(filename,"GATEWAY=",strlen("GATEWAY="),"a");
       buffer_to_file(filename,gate,strlen(gate),"a");
       buffer_to_file(filename,"\n",strlen("\n"),"a");
   }
}
#endif
void writeNetworkInterface(char *filename,char *dest){
   buffer_to_file(filename,"# interfaces(5) file used by ifup(8) and ifdown(8)",
                    strlen("# interfaces(5) file used by ifup(8) and ifdown(8)"),"wb");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"# Include files from /etc/network/interfaces.d:",strlen("# Include files from /etc/network/interfaces.d:"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"source-directory /etc/network/interfaces.d",strlen("source-directory /etc/network/interfaces.d"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"auto lo",strlen("auto lo"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"iface lo inet loopback",strlen("iface lo inet loopback"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"auto eth0",strlen("auto eth0"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"iface eth0 inet dhcp",strlen("iface eth0 inet dhcp"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"# address 192.168.1.100",strlen("# address 192.168.1.100"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"# netmask 255.255.255.0",strlen("# netmask 255.255.255.0"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"# gateway 192.168.1.1",strlen("# gateway 192.168.1.1"),"a");
   buffer_to_file(filename,"\n",strlen("\n"),"a");
   buffer_to_file(filename,"hwaddress ether ",strlen("hwaddress ether "),"a");
   buffer_to_file(filename,dest,strlen(dest),"a");
   system("sync");
}

char* insert_colon(const char* src, int interval) {
    if (!src || interval <= 0) return NULL;

    size_t len = strlen(src);
    if (len == 0) {  // 空字符串返回空
        char* res = malloc(1);
        if (res) res[0] = '\0';
        return res;
    }

    // 计算新字符串长度
    size_t sections = (len + interval - 1) / interval;  // 总段数
    size_t new_len = len + (sections - 1);              // 新长度 = 原长 + 冒号数
    char* new_str = malloc(new_len + 1);                // 分配内存:ml-citation{ref="2" data="citationList"}
    if (!new_str) return NULL;

    size_t src_idx = 0, dst_idx = 0;
    while (src_idx < len) {
        // 计算本次复制的字符数
        size_t copy_size = (len - src_idx < (size_t)interval) ? (len - src_idx) : (size_t)interval;
        memcpy(new_str + dst_idx, src + src_idx, copy_size);  // 块复制:ml-citation{ref="3" data="citationList"}
        src_idx += copy_size;
        dst_idx += copy_size;

        // 非末尾段时插入冒号
        if (src_idx < len) new_str[dst_idx++] = ':';
    }
    new_str[dst_idx] = '\0';  // 终止符:ml-citation{ref="7" data="citationList"}
    return new_str;
}

void *actHandleQrcode(void *parm){
    char *str=(char *)parm;
    LOG_I("scan:%s\n",str);

    // 检查是否为T或D开头的生产批次号码
    if((str[0] == 'T' || str[0] == 'D') && strlen(str) > 1) {
        LOG_I("检测到生产批次号码: %s\n", str);

        char sn_buffer[64] = {0};
        char mac_buffer[32] = {0};

        // 从Redis中根据批次号码查找对应的SN和MAC
        int result = get_sn_mac_by_batch_number(str, sn_buffer, sizeof(sn_buffer), mac_buffer, sizeof(mac_buffer));

        if(result == 0) {
            // 成功获取到SN和MAC，保存到文件
            LOG_I("根据批次号码获取到SN: %s, MAC: %s\n", sn_buffer, mac_buffer);

            // 保存SN到文件
            buffer_to_file("savedDevSn", sn_buffer, strlen(sn_buffer), "wb");
            LOG_I("已保存SN到文件: %s\n", sn_buffer);

            // 保存原始MAC到文件
            buffer_to_file("savedDevMac", mac_buffer, strlen(mac_buffer), "wb");
            LOG_I("已保存MAC到文件: %s\n", mac_buffer);

            // 格式化MAC地址并更新网络接口配置
            char* formatted_mac = insert_colon(mac_buffer, 2);
            if(formatted_mac != NULL) {
                LOG_I("格式化后的MAC: %s\n", formatted_mac);
                writeNetworkInterface("/etc/network/interfaces", formatted_mac);
                writeNetworkInterface("/etc/network/interfaces.default", formatted_mac);
                free(formatted_mac);
            }

            // 更新全局变量stationsn
            if(strlen(sn_buffer) < sizeof(stationsn)) {
                strcpy(stationsn, sn_buffer);
                LOG_I("已更新全局stationsn: %s\n", stationsn);
            }

            // 发送审计记录到Redis
            if(send_audit_to_redis(str, mac_buffer, sn_buffer) == 0) {
                LOG_I("审计记录已发送到Redis: batch=%s, mac=%s, sn=%s\n", str, mac_buffer, sn_buffer);
            } else {
                LOG_I("发送审计记录到Redis失败\n");
            }
        } else {
            LOG_I("根据批次号码 %s 未找到对应的SN和MAC\n", str);
        }

        pthread_exit(NULL);
        return NULL;
    }

    if(strstr(str,"{")!=NULL){
#if 0
        char deviceSecret[64]={0};
        char deviceCode[64]={0};
        char netWorkType[64]={0};
        char netWorkSsid[64]={0};
        char netWorkPassword[64]={0};
        get_string_from_json_string_by_key_unescape(str, "deviceSecret",deviceSecret,64);
        LOG_I("deviceSecret:%s\n",deviceSecret);
        get_string_from_json_string_by_key_unescape(str, "deviceCode",deviceCode,64);
        LOG_I("deviceCode:%s\n",deviceCode);
        if(strcmp(deviceSecret,"")!=0 && strcmp(deviceCode,"")!=0){
            buffer_to_file("deviceSecret",deviceSecret,strlen(deviceSecret),"wb");
            buffer_to_file("savedDevSn",deviceCode,strlen(deviceCode),"wb");
        }
        get_string_from_json_string_by_key_unescape(str, "netWorkType",netWorkType,64);
        LOG_I("netWorkType:%s\n",netWorkType);

        if(strcmp(netWorkType,"net_wifi")==0){
            buffer_to_file("nettype","net_wifi",strlen("net_wifi"),"wb");
            get_string_from_json_string_by_key_unescape(str, "netWorkSsid",netWorkSsid,64);
            LOG_I("netWorkSsid:%s\n",netWorkSsid);
            get_string_from_json_string_by_key_unescape(str, "netWorkPassword",netWorkPassword,64);
            LOG_I("netWorkPassword:%s\n",netWorkPassword);
            if(strcmp(netWorkSsid,"")!=0 && strcmp(netWorkPassword,"")!=0){
                writeWpa("/etc/wpa_supplicant.conf",netWorkSsid,netWorkPassword);
                sleep(1);
                system("reboot");
            }else{
            }
        }else if(strcmp(netWorkType,"net_wired")==0){
            buffer_to_file("nettype","net_wired",strlen("net_wired"),"wb");
            LOG_I("use wired\n");
            sleep(1);
            system("reboot");
        }else if(strcmp(netWorkType,"net_mobile")==0){
            buffer_to_file("nettype","net_mobile",strlen("net_mobile"),"wb");
            LOG_I("use mobile\n");
            sleep(1);
            system("reboot");
        }
#endif
    }else{
        if(strstr(str,"TJ")!=NULL && strlen(str)==27){
            LOG_I("ok\n");
            char *result=NULL;
            char *p;
            result=strtok_r(str,":",&p);
            while(result!=NULL){
                if(strstr(result,"TJ")!=NULL){
                    LOG_I("save sn:%s\n",result);
                    buffer_to_file("savedDevSn",result,strlen(result),"wb");
                }else{
                    LOG_I("save mac:%s\n",result);
                    buffer_to_file("savedDevMac",result,strlen(result),"wb");
                    char* destmac = insert_colon(result, 2);
                    LOG_I("formatted mac:%s\n",destmac);
                    writeNetworkInterface("/etc/network/interfaces",destmac);
                    writeNetworkInterface("/etc/network/interfaces.default",destmac);
                }
                result=strtok_r(NULL,",",&p);
            }
        }
    }
    pthread_exit(NULL);
}

char *file_to_buffer(const char *pathname, unsigned int *size){
    FILE *fp = NULL;
    char *temp = NULL;
    fp = fopen(pathname, "rb");
    if(fp==NULL){
        //LOG_I("open %s error\n", pathname);
    }else{
        fseek(fp,0,2);
        *size = ftell(fp);
        rewind(fp);
        temp = (char *)malloc(*size);
        fread(temp, 1, *size, fp);
        fclose(fp);
    }
    return temp;
}

/*================================================================================*/
void showShellInfo(char *command){
    FILE *fp;
    char buffer[512]={0};
    fp=popen(command, "r");
    if (fp) {
        fread(buffer,1,sizeof(buffer),fp);
        pclose(fp);
        LOG_I("\n%s",buffer);
    }
}

void getTimeStr(char *buffer,int len){
    time_t timep;
    struct tm *p;
    time (&timep);
    p=localtime(&timep);
    strftime (buffer,len,"%Y-%m-%d %H:%M:%S",p);
}

long getCurrentTime(){
    struct timeval begin;
    gettimeofday(&begin,NULL);
    long long beginTime = (long long)begin.tv_sec * 1000 + (long long)begin.tv_usec / 1000;
    long last=beginTime/1000;
    return last;
}

void myrand(char *randnum,int len){
    int i;
    srand((unsigned)time(0));
    for(i=0;i<=len-1;i++)
        randnum[i]=rand()%10 +'0';
    randnum[len]='\0';
}

void removeSpaces(char *str) {
    int i = 0, j = 0;
    while (str[i] != '\0') {
        if (str[i] != ' ') {
            str[j++] = str[i];
        }
        i++;
    }
    str[j] = '\0';
}

void test_lighton_search(void){
    LOG_I("%s\n",__func__);
    isSendComEnd=false;
    isLightOn=true;
    isLightOnByRule=false;
    isLabelUp=false;
    isSearchLabel=false;
    if(tagCount<=5){
        lightsnNum=tagCount;
    }else{
        lightsnNum=5;
    }
    LOG_I("tagCount:%d\n",tagCount);
    LOG_I("lightsnNum:%d\n",lightsnNum);
    for(int i=0;i<lightsnNum;i++){
       LOG_I("onlyTags:%08X,%04x\n",onlyTags[i].name,onlyTags[i].battery);
       if(i==0){
           Tag1=onlyTags[i].name;
       }
       if(i==1){
           Tag2=onlyTags[i].name;
       }
       if(i==2){
           Tag3=onlyTags[i].name;
       }
       if(i==3){
           Tag4=onlyTags[i].name;
       }
       if(i==4){
           Tag5=onlyTags[i].name;
       }
    }
    tagCount=0;
    memset(onlyTags,0,sizeof(onlyTags));

    uart_data_send_head_lighton(&uartSend,5,lightsnNum);
    char *flash="1";
    char *light="10";
    jt_ledctrl_package_t led_ctrl={
        .s.color=4,
        .s.sound=1,
        .s.flash=1,
    };
    uart_data_send_lighton_test(&uartSend,led_ctrl.ch,atoi(flash),atoi(light),Tag1,Tag2,Tag3,Tag4,Tag5,lightsnNum);
}

void getDevRawPassword(char *devsn){
    LOG_I("devsn:%s\n",devsn);
    json_object *root = NULL;
    const char *payload = NULL;
    char payload_copy[256]={0};
    char send_request[256]={0};
    char signbase64[256]={0};
    char signtmp[256]={0};
    char jsondata[256] = {0};
    char tmpdata[256] = {0};
    //char tmpdata1[64] = {0};
    char buffer[512];
    FILE *fp;
    root = json_object_new_object();
    if(root == NULL){
        LOG_I("json_object_new_object error\n");
    }else{
        json_object_object_add(root, "deviceId",json_object_new_string(devsn));
        json_object_object_add(root, "oldPassword",json_object_new_string("12345"));
        payload = json_object_to_json_string(root);
        removeSpaces(payload);
        strcpy(signtmp,payload);
        strcat(signtmp,appSecret);
        //LOG_I("signtmp:%s\n",signtmp);
        get_base64_md5_from_string(signbase64, sizeof(signbase64), signtmp, strlen(signtmp));
        //LOG_I("signbase64:%s\n",signbase64);
        sprintf(send_request,"curl -X POST -H 'x-appKey:%s' -H 'x-datadigest:%s' -H 'Content-Type: application/json' -d '%s' %s",
                appKey,signbase64,payload,getDevRawPasswordUrl);
        LOG_I("send_request:%s\n",send_request);
        fp=popen(send_request,"r");
        fgets(buffer,sizeof(buffer),fp);
        //get_string_from_json_string_by_key_unescape(buffer, "message", tmpdata1, sizeof(tmpdata1));
        //LOG_I("message: %s\n",tmpdata1);
        get_string_from_json_string_by_key_unescape(buffer, "result", tmpdata, sizeof(tmpdata));
        LOG_I("result: %s\n",tmpdata);

        snprintf(jsondata, sizeof(jsondata), "{%s}", tmpdata);
        //LOG_I("jsondata:%s\n",jsondata);
        get_string_from_json_string_by_key_unescape(jsondata, "password", mqttRawPassword, sizeof(mqttRawPassword));
        LOG_I("save mqttRawPassword:%s\n",mqttRawPassword);

        if(strcmp(mqttRawPassword,"")!=0){
            int result = buffer_to_file("mqttRawPassword",mqttRawPassword,strlen(mqttRawPassword),"wb");
            if(result == 0) {
                LOG_I("mqttRawPassword saved successfully\n");
                sync();

                // 首次获取密码成功后启动搜索标签功能（只运行一次）
                LOG_I("Starting tag search after first registration...\n");
                isSearchLabelOntest = true;
                searchTimeOut=20;
                searchTimeOld=getCurrentTime();

                while(isSearchLabelOntest) {
                    isSearchLabel=true;
                    uart_data_send_head_search(&uartSend,5);
                    sleep(10);
                    searchTimeNew=getCurrentTime();
                    LOG_I("searchTimeNew:%d\n",searchTimeNew);
                    if((searchTimeNew-searchTimeOld)>=searchTimeOut){
                        isSearchLabelOntest=false;
                        //search_tag_report();
                        test_lighton_search();
                    }
                }

                // 从savedDevMac文件读取MAC地址
                unsigned int mac_file_size = 0;
                char *saved_mac = file_to_buffer("savedDevMac", &mac_file_size);
                char redis_mac[32] = {0};
                char formatted_mac[32] = {0};

                if (saved_mac != NULL && mac_file_size > 0) {
                    strncpy(redis_mac, saved_mac, sizeof(redis_mac) - 1);
                    redis_mac[sizeof(redis_mac) - 1] = '\0';
                    free(saved_mac);
                    LOG_I("Got MAC from saved file: %s\n", redis_mac);

                    // 格式化MAC地址
                    if(format_mac_address(redis_mac, formatted_mac, sizeof(formatted_mac)) == 0) {
                        LOG_I("Formatted MAC: %s\n", formatted_mac);

                        // 更新/etc/network/interfaces文件中的MAC地址
                        LOG_I("Updating MAC address in /etc/network/interfaces\n");

                        // 读取当前的interfaces文件内容
                        unsigned int file_size = 0;
                        char *interfaces_content = file_to_buffer("/etc/network/interfaces", &file_size);

                        if(interfaces_content != NULL) {
                            // 查找并替换hwaddress ether行
                            char *hwaddress_line = strstr(interfaces_content, "hwaddress ether");
                            if(hwaddress_line != NULL) {
                                // 找到行的结束位置
                                char *line_end = strchr(hwaddress_line, '\n');
                                if(line_end != NULL) {
                                    // 构建新的interfaces文件内容
                                    size_t before_len = hwaddress_line - interfaces_content;
                                    size_t after_len = strlen(line_end);

                                    char new_interfaces[4096] = {0};
                                    strncpy(new_interfaces, interfaces_content, before_len);
                                    snprintf(new_interfaces + before_len, sizeof(new_interfaces) - before_len, "hwaddress ether %s%s", formatted_mac, line_end);

                                    // 写入更新后的内容
                                    int write_result = buffer_to_file("/etc/network/interfaces", new_interfaces, strlen(new_interfaces), "wb");
                                    if(write_result == 0) {
                                        LOG_I("MAC address updated in /etc/network/interfaces successfully\n");
                                        sync();
                                    } else {
                                        LOG_I("Failed to update MAC address in /etc/network/interfaces\n");
                                    }
                                } else {
                                    LOG_I("Could not find end of hwaddress line\n");
                                }
                            } else {
                                LOG_I("hwaddress ether line not found in interfaces file\n");
                            }
                            free(interfaces_content);
                        } else {
                            LOG_I("Failed to read /etc/network/interfaces file\n");
                        }
                    } else {
                        LOG_I("Failed to format MAC address\n");
                    }
                } else {
                    LOG_I("Failed to read MAC from saved file\n");
                }
            } else {
                LOG_I("Failed to save mqttRawPassword\n");
            }
        }
    }
}
/*================================================================================*/
void mqtt_init(){
    int ret=0;
    char username[32] = {0};
    char password[32] = {0};
    char clientid[256] = {0};
    //char clientid[256] = "TJ250995217957|signmethod=hmacsha1|timestamp=1741416329331";
    char hostip[16]={0};
    //char protocol[64]="mqtt";
    //char RawPassword[64]="94b4e39caf1d45ee9a071d701cc037b4";
    struct timeval tv;
    //MQTTASYNC_TRACE_MAXIMUM
    //MQTTASYNC_TRACE_MEDIUM
    //MQTTASYNC_TRACE_MINIMUM
    //MQTTASYNC_TRACE_PROTOCOL
    //MQTTASYNC_TRACE_ERROR
    //MQTTASYNC_TRACE_SEVERE
    //MQTTASYNC_TRACE_FATAL
    //mqtt_config.tracelevel=get_trace_level_by_name("MQTTASYNC_TRACE_PROTOCOL");
    gettimeofday(&tv, NULL);
    snprintf(clientid,sizeof(clientid),"%s|signmethod=hmacsha1|timestamp=%ld",stationsn,tv.tv_sec*1000+tv.tv_usec);
    LOG_I("clientid:%s,mqttRawPassword:%s\n",clientid,mqttRawPassword);

    hmacsha1(mqttRawPassword,clientid,password,sizeof(password));
    mqtt_config.tracelevel=MQTTASYNC_TRACE_PROTOCOL;
    mqtt_config.retain=0;
    mqtt_config.port=mqtt_port;
    mqtt_config.keepalive=30;
    //memset(mqtt_config.protocol,0,sizeof(mqtt_config.protocol));
    //memcpy(mqtt_config.protocol,protocol,sizeof(protocol));
    memset(mqtt_config.clientid,0,sizeof(mqtt_config.clientid));
    memcpy(mqtt_config.clientid,clientid,sizeof(clientid));
    snprintf(username, sizeof(username), "%s", stationsn);
    LOG_I("username:%s,password:%s\n",username,password);
    memset(mqtt_config.productcode, 0, sizeof(mqtt_config.productcode));
    memcpy(mqtt_config.productcode, productid, strlen(productid));
    memset(mqtt_config.username, 0, sizeof(mqtt_config.username));
    memcpy(mqtt_config.username, username, strlen(username));
    memset(mqtt_config.password, 0, sizeof(mqtt_config.password));
    memcpy(mqtt_config.password, password, strlen(password));
    get_ip_by_domain(hostDomain,hostip,16);
    memset(mqtt_config.host, 0, sizeof(mqtt_config.host));
    memcpy(mqtt_config.host, hostip, strlen(hostip));
    mqtt_config.MQTTVersion = 4;

    /* will options */
    mqtt_config.will_topic = NULL;
    mqtt_config.will_payload = NULL;
    mqtt_config.will_qos = 2;
    mqtt_config.will_retain = 0;
    /* TLS options */
    mqtt_config.insecure = 0;
    mqtt_config.capath = NULL;
    mqtt_config.cert = NULL;
    mqtt_config.cafile = NULL;
    mqtt_config.key = NULL;
    mqtt_config.keypass = NULL;
    mqtt_config.ciphers = NULL;

    ret = sem_init(&mqtt_config.sem_connect, 0, 0);
    if (ret != 0)
    {
        LOG_I("sem_connect init error\n");
        goto error;
    }

    ret = mqtt_utils_init(&mqtt_config);
    if (ret < 0)
    {
        LOG_I("mqtt_utils_init error\n");
        ret = -1;
        goto error;
    }
    sem_wait(&mqtt_config.sem_connect);
    ret = 0;
error:
    return;
}

/*================================================================================*/
void *thread_ota(void *arg){
    prctl(PR_SET_NAME, "ota");
    checkOtaKey();
}

void *thread_mqtt(void *arg){
    prctl(PR_SET_NAME, "mqtt");
    mqtt_init();
}

void *thread_removelog(void *arg){
    prctl(PR_SET_NAME, "removelog");
    removeLog();
}

void *thread_reboot(void *arg){
    prctl(PR_SET_NAME, "reboot");
    rebootSystem();
}

void *thread_feed_watchdog(void *arg){
    prctl(PR_SET_NAME, "watchdog");
    feedWatchDog();
}

#if 1
void *thread_readqr(void *arg){
    prctl(PR_SET_NAME, "readqr");
    readQrcode();
}
#endif

void *thread_vm_heartbeat(void *arg) {
    char *client_id = (char *)arg;
    const char *url = "http://180.163.74.83:8428/api/v1/import/prometheus";
    char post_data[256];
    CURL *curl = curl_easy_init();

    if (!curl) {
        DEBUG_TX("curl init failed\n");
        pthread_exit(NULL);
    }

    system("ntpdate -u cn.pool.ntp.org");

    while (1) {
        time_t now = time(NULL);
        // Prometheus exposition format
        snprintf(post_data, sizeof(post_data),
            "client_online{client_id=\"%s\"} %ld\n", client_id, now);

        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
        CURLcode res = curl_easy_perform(curl);

        if (res != CURLE_OK) {
            DEBUG_TX("send to VictoriaMetrics failed: %s\n", curl_easy_strerror(res));
        } else {
            DEBUG_TX("heartbeat sent: %s", post_data);
        }

        sleep(3); // 3秒心跳
    }
    curl_easy_cleanup(curl);
    pthread_exit(NULL);
}

void *thread_tag_search_send(void *arg){
    prctl(PR_SET_NAME, "tag_search");
    while(1){
        if(isSearchLabelOn){
            sleep(10);
            searchTimeNew=getCurrentTime();
            if((searchTimeNew-searchTimeOld)>=(searchTimeOut-20)){
                isSearchReport=true;
                search_tag_report();
                isSearchReport=false;
                isSearchLabelOn=false;
            }
        } else {
            usleep(100000);  // 休眠100ms
        }
    }
}

void *thread_do_ota(void *arg){
    prctl(PR_SET_NAME, "do_ota");
    while(1){
        if(isOtaEnable && isSendComEnd && !isLEDOtaSuccess){
            sleep(1);
            otaLeds();
        } else {
            usleep(100000);  // 休眠100ms
        }
    }
}

//char *tag_1="00A04CCE";
//char *tag_2="00A04C0E";
//char *tag_3="00A04C0F";
//char *tag_4="00A04C11";
//char *tag_5="00A04CD0";
void *thread_uart_recv_ack(void *arg){
    prctl(PR_SET_NAME, "uart_ack");
    uint16_t parm_ack;
    int ret=0;

    while(1){
        ret=uart_data_receive_ack(&uartSend,&parm_ack);
        if(ret>0){
            LOG_I("ack:%x\n",parm_ack);
            if(parm_ack==0x2323){
                // 记录收到0x2323的时间，并设置等待0x4646标志
                time(&last_2323_time);
                waiting_for_4646 = true;
                #if 0
                if(isLightOn){
                    uint32_t tags[30] = {0};
                    uint8_t tag_leds[30] = {0};
                    int valid_count = 0;
                    for (int i = 0; i < lightsn_buffer_count; ++i) {
                        // 1. SN转MAC（HEX字符串转uint32_t）
                        if (strlen(lightsn_buffer[i]) == 8) {
                            tags[valid_count] = (uint32_t)strtoul(lightsn_buffer[i], NULL, 16);
                        } else {
                            LOG_I("[WARN] tag[%d] sn格式非法: %s, 跳过", i, lightsn_buffer[i]);
                            continue;
                        }
                        // 2. 颜色+闪光+声音合成LED控制字节（协议格式）
                        int flash = (strlen(flash_buffer[i]) > 0) ? atoi(flash_buffer[i]) : atoi(mqtt_parm.msg_flash);   // "1"=闪光, "0"=常亮
                        int sound = (strlen(sound_buffer[i]) > 0) ? atoi(sound_buffer[i]) : atoi(mqtt_parm.msg_sound);   // "1"=有声, "0"=无声
                        int changecolor = 0;
                        if(strcmp(color_buffer[i],"1")==0){
                            changecolor=4;
                        }else if(strcmp(color_buffer[i],"2")==0){
                            changecolor=6;
                        }else if(strcmp(color_buffer[i],"3")==0){
                            changecolor=1;
                        }else if(strcmp(color_buffer[i],"4")==0){
                            changecolor=2;
                        }else if(strcmp(color_buffer[i],"5")==0){
                            changecolor=3;
                        }else if(strcmp(color_buffer[i],"6")==0){
                            changecolor=7;
                        }else if(strcmp(color_buffer[i],"7")==0){
                            changecolor=5;
                        }else if(strcmp(color_buffer[i],"8")==0){
                            changecolor=0;
                        }
                        uint8_t led_val = 0;
                        if (flash) led_val |= 0x40; // Bit6
                        if (sound) led_val |= 0x10; // Bit4
                        led_val |= (changecolor & 0x0F); // 低4位为颜色
                        tag_leds[valid_count] = led_val;
                        LOG_I("tag[%d]: sn=%s, color=%s, led=0x%02X ",
                              valid_count, lightsn_buffer[i], color_buffer[i], tag_leds[valid_count]);
                        valid_count++;
                    }
                    if (valid_count > 0) {
                        uint8_t changecolor=0;
                        if(strcmp(mqtt_parm.msg_color,"1")==0){
                            changecolor=4;
                        }else if(strcmp(mqtt_parm.msg_color,"2")==0){
                            changecolor=6;
                        }else if(strcmp(mqtt_parm.msg_color,"3")==0){
                            changecolor=1;
                        }else if(strcmp(mqtt_parm.msg_color,"4")==0){
                            changecolor=2;
                        }else if(strcmp(mqtt_parm.msg_color,"5")==0){
                            changecolor=3;
                        }else if(strcmp(mqtt_parm.msg_color,"6")==0){
                            changecolor=7;
                        }else if(strcmp(mqtt_parm.msg_color,"7")==0){
                            changecolor=5;
                        }else if(strcmp(mqtt_parm.msg_color,"8")==0){
                            changecolor=0;
                        }
                        jt_ledctrl_package_t led_ctrl={
                            .s.color=changecolor,
                            .s.sound=atoi(mqtt_parm.msg_sound),
                            .s.flash=atoi(mqtt_parm.msg_flash),
                        };
                        uart_data_send_lightband(&uartSend, led_ctrl.ch, atoi(mqtt_parm.msg_flash), atoi(mqtt_parm.msg_lightDuration), tags, tag_leds, valid_count);
                    }
                    isLightOn=false;
                    // 处理完成后清空buffer
                    pthread_mutex_lock(&lightsn_buffer_mutex);
                    lightsn_buffer_count = 0;
                    memset(lightsn_buffer, 0, sizeof(lightsn_buffer));
                    memset(color_buffer, 0, sizeof(color_buffer));
                    memset(sound_buffer, 0, sizeof(sound_buffer));
                    memset(flash_buffer, 0, sizeof(flash_buffer));
                    pthread_mutex_unlock(&lightsn_buffer_mutex);
                }
                #endif
#if 1
                if(isSearchLabel){
                    uart_data_send_search(&uartSend,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF);
                    isSearchLabel=false;
                }
#endif
                if(isLightOnByRule){
                    #if 0
                    uint16_t label2=strtol("FF01",NULL,16)&0xFFFF;
                    uint32_t label3=strtol("663855c0",NULL,16);
                    uint16_t flash_i=strtol("1",NULL,16)&0xFFFF;
                    uint16_t light_d=strtol("5",NULL,16)&0xFFFF;
                    jt_ledctrl_package_t led_ctrl={
                        .s.color=1,
                        .s.sound=1,
                        .s.flash=1,
                    };
                    uart_data_send_light_rule(&uartSend,atoi("03"),label2,label3,
                                              atoi("0"), atoi("0"),atoi("0"),
                                              led_ctrl.ch,
                                              flash_i,light_d);
                    #else
                    uint16_t label2=strtol(mqtt_parm.msg_label2,NULL,16)&0xFFFF;
                    uint32_t label3=strtol(mqtt_parm.msg_label3,NULL,16);
                    uint16_t flash_i=strtol(mqtt_parm.msg_flashInterval,NULL,16)&0xFFFF;
                    uint16_t light_d=strtol(mqtt_parm.msg_lightDuration,NULL,16)&0xFFFF;
                    uint8_t changecolor=0;
                    //8灭 1红 2黄 3蓝 4绿 5青 6白 7紫 tuxi
                    //0灭 1蓝 2绿 3青 4红 5紫 6黄 7白 yitaile
                    if(strcmp(mqtt_parm.msg_color,"1")==0){
                        changecolor=4;
                    }else if(strcmp(mqtt_parm.msg_color,"2")==0){
                        changecolor=6;
                    }else if(strcmp(mqtt_parm.msg_color,"3")==0){
                        changecolor=1;
                    }else if(strcmp(mqtt_parm.msg_color,"4")==0){
                        changecolor=2;
                    }else if(strcmp(mqtt_parm.msg_color,"5")==0){
                        changecolor=3;
                    }else if(strcmp(mqtt_parm.msg_color,"6")==0){
                        changecolor=7;
                    }else if(strcmp(mqtt_parm.msg_color,"7")==0){
                        changecolor=5;
                    }else if(strcmp(mqtt_parm.msg_color,"8")==0){
                        changecolor=0;
                    }
                    jt_ledctrl_package_t led_ctrl={
                        .s.color=changecolor,
                        .s.sound=atoi(mqtt_parm.msg_sound),
                        .s.flash=atoi(mqtt_parm.msg_flash),
                    };
                    uart_data_send_light_rule(&uartSend,atoi(mqtt_parm.msg_label1),label2,label3,
                                              atoi(mqtt_parm.msg_label1Rule), atoi(mqtt_parm.msg_label2Rule),atoi(mqtt_parm.msg_label3Rule),
                                              led_ctrl.ch,
                                              flash_i,light_d);
                    #endif
                    isLightOnByRule=false;
                }
                if(isLabelUp){
                    #if 0
                    time_t now = time(NULL);
                    if(label_buf_count > 0 && (label_buf_count >= LABEL_BATCH_SIZE || (now - label_buf_first_time) >= 180)) {
                        uart_data_send_head_lableup(&uartSend, 5, label_buf_count);
                        usleep(10000);
                        uart_data_send_lable(&uartSend, tags_buf, lable1_buf, lable2_buf, lable3_buf, label_buf_count);
                        label_buf_count = 0;
                        label_buf_first_time = 0;
                        isLabelUp = false;
                    }
                    #endif
                }
            }else if(parm_ack==0x4646){
                last_2323_time = 0;  // 重置时间
                waiting_for_4646 = false;  // 重置等待状态
                isSendComEnd=true;
            }else if(parm_ack==0x4f4f){
                last_2323_time = 0;  // 重置时间
                waiting_for_4646 = false;  // 重置等待状态
                isSendComEnd=true;
                if(isOtaEnable){
                    otaCount++;
                    if(otaCount>=2){
                        otaCount=0;
                        isLEDOtaSuccess=true;
                        isOtaEnable=false;
                        system("echo 1 > /sys/class/gpio/gpio113/value");
                    }
                }
            }else if(parm_ack==0x5252){
                last_2323_time = 0;  // 重置时间
                waiting_for_4646 = false;  // 重置等待状态
                uart_data_receive_version(&uartSend);
                isSendComEnd=true;
                isAPOtaSuccess=true;
            }else if(parm_ack==0x6464){
                last_2323_time = 0;  // 重置时间
                waiting_for_4646 = false;  // 重置等待状态
                isSendComEnd=true;
            }else if(parm_ack==0x4848){
                last_2323_time = 0;  // 重置时间
                waiting_for_4646 = false;  // 重置等待状态
                isAPBack=true;
            }
        }
        usleep(100*1000);
    }
}

void *thread_uart_recv_data(void *arg){
    prctl(PR_SET_NAME, "uart_data");
    uint16_t parmAck;
    uint32_t tagCode;
    uint8_t tagSignal;
    uint8_t totalLen;
    uint8_t tagFeature;
    uint8_t count;
    uint16_t batteryV;
    uint16_t version;
    uint8_t ledCtrl;
    uint8_t lable1;
    uint16_t lable2;
    uint32_t lable3;
    while(1){
       uart_data_receive_data_back(&uartRecvData,&parmAck,&tagCode,&tagSignal,&totalLen,&tagFeature,
                                   &count,&batteryV,&version,&ledCtrl,&lable1,&lable2,&lable3);
       //LOG_I("recv_data:%04x,%08x,%02x,%02x,%02x,%02x,%04x,%04x,%02x,%02x,%04x,%08x\n",parmAck,tagCode,tagSignal,totalLen,
       //      tagFeature,count,batteryV,version,ledCtrl,lable1,lable2,lable3);
       //sleep(2);
    }
}

void *thread_uart_recv_back(void *arg){
    prctl(PR_SET_NAME, "uart_back");
    uint16_t parmAck;
    uint32_t tagCode;
    uint8_t tagSignal;
    uint8_t totalLen;
    uint8_t tagFeature;
    uint8_t count;
    uint16_t batteryV;
    uint16_t version;
    uint8_t ledCtrl;
    uint8_t lable1;
    uint16_t lable2;
    uint32_t lable3;
    while(1){
       uart_data_receive_data_back(&uartRecvBack,&parmAck,&tagCode,&tagSignal,&totalLen,&tagFeature,
                                   &count,&batteryV,&version,&ledCtrl,&lable1,&lable2,&lable3);
       //LOG_I("recv_back:%04x,%08x,%02x,%02x,%02x,%02x,%04x,%04x,%02x,%02x,%04x,%08x\n",parmAck,tagCode,tagSignal,totalLen,
       //tagFeature,count,batteryV,version,ledCtrl,lable1,lable2,lable3);
       //if(tagCode>0x90000000){
       //    PutDataIntoQueue(tagCode,batteryV);
       //}
       PutDataIntoQueue(tagCode,batteryV);
       if(tagFeature==0x83){
           //LOG_I("search tag:%08x,battery:%04x\n",tagCode,batteryV);
       }else if(tagFeature==0x82){
           //LOG_I("light down tag:%08x,battery:%04x\n",tagCode,batteryV);
           light_off_tag_report(tagCode,batteryV);
           //light_battery_report(tagCode,batteryV);
       }else if(tagFeature==0x81){
           LOG_I("key down tag:%08x,battery:%04x,version:%4x\n",tagCode,batteryV,version);
       }else if(tagFeature==0xff){
           //LOG_I("heart tag:%08x,battery:%04x,version:%4x\n",tagCode,batteryV,version);
       }
    }
}

void light_off_tag_report(uint32_t name,uint16_t batteryv){
   json_object *lights = NULL;
   lights=json_object_new_array();
   char tagName[9]={0};
   char battery[5]={0};
   sprintf(tagName,"%08X",name);
   sprintf(battery,"%d",batteryv);
   json_object *light = json_object_new_object();
   json_object_object_add(light, "sn", json_object_new_string(tagName));
   json_object_object_add(light, "battery", json_object_new_string(battery));
   json_object_array_add(lights,light);

    json_object *lights_2 = json_object_new_array();
    json_object *light_2 = json_object_new_object();
    json_object_object_add(light_2, "sn", json_object_new_string(tagName));
    json_object_object_add(light_2, "battery", json_object_new_string(battery));
    json_object_array_add(lights_2, light_2);
   char myid[32]={0};
   myrand(myid,19);
   mqtt_server_light_status_report(stationsn,myid,"2",lights);
   //mqtt_server_light_status_report_2(stationsn,myid,"2",lights_2);
}

void search_tag_report(){
   int report_num=0;
   int i=0,j=0,m=0,n=0;
   copyOnlyTag();
   LOG_I("%s tagCount:%d\n",__func__,tagCount);
   LOG_I("%s tagCountNew:%d\n",__func__,tagCountNew);
   if(tagCountNew>200){
       for(i=0;i<tagCountNew/200;i++){
           json_object *lights =json_object_new_array();
           json_object *lights2 =json_object_new_array();
           for(j=i*200;j<i*200+200;j++){
               LOG_I("onlyTags:%08X,%04x\n",onlyTagsNew[j].name,onlyTagsNew[j].battery);
               char tagName[9]={0};
               char battery[5]={0};
               sprintf(tagName,"%08X",onlyTagsNew[j].name);
               sprintf(battery,"%d",onlyTagsNew[j].battery);
               json_object *light = json_object_new_object();
               json_object_object_add(light, "sn", json_object_new_string(tagName));
               json_object_object_add(light, "battery", json_object_new_string(battery));
               json_object_array_add(lights,light);

               json_object *light2 = json_object_new_object();
                json_object_object_add(light2, "sn", json_object_new_string(tagName));
                json_object_object_add(light2, "battery", json_object_new_string(battery));
                json_object_array_add(lights2,light2);
           }
           report_num+=200;
           LOG_I("report_num:%d\n",report_num);
           mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
           mqtt_server_light_status_report_test(stationsn,mqtt_parm.msg_messageId,"1",lights2);
       }
       json_object *lights =json_object_new_array();
       json_object *lights2 =json_object_new_array();
       for(m=i*200;m<i*200+(tagCountNew%200);m++){
           LOG_I("onlyTags:%08X,%04x\n",onlyTagsNew[m].name,onlyTagsNew[m].battery);
           char tagName[9]={0};
           char battery[5]={0};
           sprintf(tagName,"%08X",onlyTagsNew[m].name);
           sprintf(battery,"%d",onlyTagsNew[m].battery);
           json_object *light = json_object_new_object();
           json_object_object_add(light, "sn", json_object_new_string(tagName));
           json_object_object_add(light, "battery", json_object_new_string(battery));
           json_object_array_add(lights,light);

           json_object *light2 = json_object_new_object();
            json_object_object_add(light2, "sn", json_object_new_string(tagName));
            json_object_object_add(light2, "battery", json_object_new_string(battery));
            json_object_array_add(lights2,light2);
       }
       report_num+=m-i*200;
       //report_num+=tagCountNew%200;
       LOG_I("report_num:%d\n",report_num);
       mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
       mqtt_server_light_status_report_test(stationsn,mqtt_parm.msg_messageId,"1",lights2);
   }else{
       json_object *lights =json_object_new_array();
       json_object *lights2 =json_object_new_array();
       for(n=0;n<tagCountNew;n++){
           LOG_I("onlyTags:%08X,%04x\n",onlyTagsNew[n].name,onlyTagsNew[n].battery);
           char tagName[9]={0};
           char battery[5]={0};
           sprintf(tagName,"%08X",onlyTagsNew[n].name);
           sprintf(battery,"%d",onlyTagsNew[n].battery);
           json_object *light = json_object_new_object();
           json_object_object_add(light, "sn", json_object_new_string(tagName));
           json_object_object_add(light, "battery", json_object_new_string(battery));
           json_object_array_add(lights,light);

           json_object *light2 = json_object_new_object();
            json_object_object_add(light2, "sn", json_object_new_string(tagName));
            json_object_object_add(light2, "battery", json_object_new_string(battery));
            json_object_array_add(lights2,light2);
       }
       report_num=tagCountNew;
       LOG_I("report_num:%d\n",report_num);
       mqtt_server_light_status_report(stationsn,mqtt_parm.msg_messageId,"1",lights);
       mqtt_server_light_status_report_test(stationsn,mqtt_parm.msg_messageId,"1",lights2);
   }
   mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
   tagCountNew=0;
   memset(onlyTagsNew,0,5000);
}

void copyOnlyTag(void){
   int i=0;
   tagCountNew=0;
   for(i=0;i<tagCount;i++){
      if(getCurrentTime()-onlyTags[i].time<=60*50){
          onlyTagsNew[tagCountNew]=onlyTags[i];
          tagCountNew++;
      }
   }
   LOG_I("tagCountNew:%d\n",tagCountNew);
}

void addOnlyTag(uint32_t tagname,uint16_t battery){
    int i=0;
    if(tagCount==0){
        jt_only_tag_t jt_only_tag = {
            .name=tagname,
            .battery=battery,
            .time=getCurrentTime(),
        };
        onlyTags[tagCount]=jt_only_tag;
        tagCount++;
    }else{
        for(i=0;i<tagCount;i++){
           if(tagname==onlyTags[i].name){
               onlyTags[i].time=getCurrentTime();
               break;
           }
        }
        if(i==tagCount){
            jt_only_tag_t jt_only_tag = {
                .name=tagname,
                .battery=battery,
                .time=getCurrentTime(),
            };
            onlyTags[tagCount]=jt_only_tag;
            tagCount++;
        }
    }
}

void *thread_remove_duplicate_tag(void *arg){
    prctl(PR_SET_NAME, "rm_dup_tag");
    uint32_t tagname=0;
    uint16_t battery=0;
    while(1){
        if(!isSearchReport){
            if(GetDataFromQueue(&tagname,&battery)==0){
                //LOG_I("%08x,%04x\n",tagname,battery);
                addOnlyTag(tagname,battery);
            }
        }
    }
}

// 检查文件是否存在的函数
static int file_exists(const char *path) {
    struct stat st;
    return (stat(path, &st) == 0);
}

// 检查压缩包是否解压完成
static int check_unzip_complete(const char *zip_file) {
    char cmd[256];
    char last_file[256] = {0};
    FILE *fp;

    // 获取压缩包中最后一个文件
    snprintf(cmd, sizeof(cmd), "unzip -l %s | tail -n 1 | awk '{print $4}'", zip_file);
    fp = popen(cmd, "r");
    if (fp == NULL) {
        LOG_E("Failed to execute command: %s", cmd);
        return -1;
    }

    if (fgets(last_file, sizeof(last_file), fp) == NULL) {
        LOG_E("Failed to get last file from zip");
        pclose(fp);
        return -1;
    }
    pclose(fp);

    // 去除换行符
    last_file[strcspn(last_file, "\n")] = 0;

    // 检查文件是否存在
    char full_path[512];
    snprintf(full_path, sizeof(full_path), "tx_ota/%s", last_file);

    int retry_count = 0;
    const int max_retries = 30; // 最多等待30秒

    while (!file_exists(full_path) && retry_count < max_retries) {
        usleep(1000000); // 等待1秒
        retry_count++;
    }

    if (retry_count >= max_retries) {
        LOG_E("Timeout waiting for unzip to complete");
        return -1;
    }

    return 0;
}

void *thread_mqtt_recv(void *arg){
    prctl(PR_SET_NAME, "mqtt_recv");
    char payload[1024]={0};
    char msg_body_value[1024] ={0};
    char msg_body[1024] = {0};
    char msg_data_value[1024] = {0};
    char msg_data[1024] = {0};
    char msg_labelconfig_value[1024] = {0};
    char msg_labelconfig[1024] = {0};
    char msg_lightsn_value[128] = {0};
    char msg_lightsn[128] = {0};
    while(1){
        if(isSendComEnd){
            if(GetDataFromMQueue(payload)==0){
                //getPayloadTime=120*1000;
	            LOG_I("payload:%s\n",payload);
	            get_string_from_json_string_by_key_unescape(payload,"messageId",mqtt_parm.msg_messageId,sizeof(mqtt_parm.msg_messageId));
	            //LOG_I("messageId:%s\n",mqtt_parm.msg_messageId);
	            if(isSearchLabelOn){
                        mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"search busy",0,productid);
                    }else{
                        get_string_from_json_string_by_key_unescape(payload,"deviceId",mqtt_parm.msg_deviceId,sizeof(mqtt_parm.msg_deviceId));
		            LOG_I("deviceId:%s\n",mqtt_parm.msg_deviceId);
		            get_int_from_json_string_by_key(payload,"timestamp",&mqtt_parm.msg_timestamp);
		            LOG_I("timestamp:%d\n",mqtt_parm.msg_timestamp);
		            get_string_from_json_string_by_key_unescape(payload, "msg", msg_body_value, sizeof(msg_body_value));
		            snprintf(msg_body, sizeof(msg_body), "%s", msg_body_value);
		            LOG_I("msg_body:%s\n",msg_body);
		            get_string_from_json_string_by_key_unescape(msg_body, "msgType", mqtt_parm.msg_type, sizeof(mqtt_parm.msg_type));
		            LOG_I("msgType:%s\n",mqtt_parm.msg_type);
		            get_string_from_json_string_by_key_unescape(msg_body, "data", msg_data_value, sizeof(msg_data_value));
		            snprintf(msg_data, sizeof(msg_data), "{%s}", msg_data_value);
		            LOG_I("msg_data:%s\n",msg_data);
		            if(strcmp(mqtt_parm.msg_type,"1001")==0){
		                LOG_I("1001 dev disable\n");
		                isLightEnable=false;
		                buffer_to_file("LightEnable","disable",strlen("disable"),"wb");
		                mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
		            }else if(strcmp(mqtt_parm.msg_type,"1002")==0){
		                LOG_I("1002 dev enable\n");
		                isLightEnable=true;
		                buffer_to_file("LightEnable","enable",strlen("enable"),"wb");
		                mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
		            }else if(strcmp(mqtt_parm.msg_type,"1005")==0){
		                LOG_I("1005 dev reboot\n");
		                mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
                        system("sync");
                        sleep(10);
                        system("sync");
		                system("reboot");
		            }else if(strcmp(mqtt_parm.msg_type,"1014")==0){
		                LOG_I("1014 update fw\n");
                        isSendComEnd=false;
		                get_int_from_json_string_by_key(msg_data, "needWifi", &mqtt_parm.msg_needWifi);
		                LOG_I("needWifi:%d\n",mqtt_parm.msg_needWifi);
		                get_string_from_json_string_by_key_unescape(msg_data, "zipPath", mqtt_parm.msg_zipPath, sizeof(mqtt_parm.msg_zipPath));
		                LOG_I("zipPath:%s\n",mqtt_parm.msg_zipPath);
		                get_int_from_json_string_by_key(msg_data, "installType", &mqtt_parm.msg_installType);
		                LOG_I("installType:%d\n",mqtt_parm.msg_installType);
		                get_int_from_json_string_by_key(msg_data, "immediately", &mqtt_parm.msg_immediately);
		                LOG_I("immediately:%d\n",mqtt_parm.msg_immediately);
		                get_int_from_json_string_by_key(msg_data, "installTime", &mqtt_parm.msg_installTime);
		                LOG_I("installTime:%d\n",mqtt_parm.msg_installTime);
		                get_string_from_json_string_by_key_unescape(msg_data, "version", mqtt_parm.msg_version, sizeof(mqtt_parm.msg_version));
		                LOG_I("version:%s\n",mqtt_parm.msg_version);
		                mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
		                char otaCmd[256]={0};
		                sprintf(otaCmd,"curl -o /userdata/tx_ota.zip %s",mqtt_parm.msg_zipPath);
		                //sprintf(otaCmd,"curl -o /root/tx_server https://fscdn.zto.com/cloudm/iot-device-package/7d609af2165b4d14ae318f17659b2fbf.bin");
		                system(otaCmd);
		                sleep(15);
                                system("unzip /userdata/tx_ota.zip");
                                //system("mv ../tx_ota/* /userdata/ota");
                                //system("rm -fr /userdata/ota/tx_ota");
                                system("rm -fr /userdata/ota");
                                system("mv /userdata/tx_ota /userdata/ota");
                                system("mv /userdata/ota/ustart.sh /userdata");
                                system("cp /userdata/ota/tx_server /tmp/tx_server_new");
                                LOG_I("cp /userdata/ota/tx_server /tmp/tx_server_new\n");
                                system("chmod +x /tmp/tx_server_new");
                                system("mv /tmp/tx_server_new /userdata/tx_server");
                                system("sync");
                                sleep(2);
                                restart_tx_server_service();
		            }else if(strcmp(mqtt_parm.msg_type,"5003")==0){
		                LOG_I("5003 need report station info\n");
		                updateStationInfo(mqtt_parm.msg_messageId);
		            }else if(strcmp(mqtt_parm.msg_type,"5005")==0){
		                LOG_I("5005 cloud search light\n");
		                //isSendComEnd=false;
		                isLightOn=false;
		                isLightOnByRule=false;
		                isLabelUp=false;
		                //isSearchLabel=true;
		                get_string_from_json_string_by_key_unescape(msg_data, "scene", mqtt_parm.msg_scene, sizeof(mqtt_parm.msg_scene));
		                LOG_I("scene:%s\n",mqtt_parm.msg_scene);
		                get_string_from_json_string_by_key_unescape(msg_data, "timeout", mqtt_parm.msg_timeout, sizeof(mqtt_parm.msg_timeout));
		                LOG_I("timeout:%s\n",mqtt_parm.msg_timeout);
		                searchTimeOut=atoi(mqtt_parm.msg_timeout);
		                LOG_I("searchTimeOut:%d\n",searchTimeOut);
		                searchTimeOld=getCurrentTime();
		                LOG_I("searchTimeOld:%d\n",searchTimeOld);
		                isSearchLabelOn=true;
		            }else if(strcmp(mqtt_parm.msg_type,"3015")==0){
		                LOG_I("3015 light on (merge mode)\n");
		                get_string_from_json_string_by_key_unescape(msg_data, "scene", mqtt_parm.msg_scene, sizeof(mqtt_parm.msg_scene));
		                DEBUG_TX("scene:%s\n",mqtt_parm.msg_scene);
		                get_string_from_json_string_by_key_unescape(msg_data, "lights", mqtt_parm.msg_lights, sizeof(mqtt_parm.msg_lights));
		                DEBUG_TX("lights:%s\n",mqtt_parm.msg_lights);
		                get_size_from_json_string_arry_by_key(msg_data, "lights", &mqtt_parm.msg_opNumber);
		                DEBUG_TX("lights size = %d\n", mqtt_parm.msg_opNumber);
		                get_string_from_json_string_by_key_unescape(msg_data, "color", mqtt_parm.msg_color, sizeof(mqtt_parm.msg_color));
		                DEBUG_TX("color:%s\n",mqtt_parm.msg_color);
		                get_string_from_json_string_by_key_unescape(msg_data, "sound", mqtt_parm.msg_sound, sizeof(mqtt_parm.msg_sound));
		                DEBUG_TX("sound:%s\n",mqtt_parm.msg_sound);
		                get_string_from_json_string_by_key_unescape(msg_data, "flash", mqtt_parm.msg_flash, sizeof(mqtt_parm.msg_flash));
		                DEBUG_TX("flash:%s\n",mqtt_parm.msg_flash);
		                get_string_from_json_string_by_key_unescape(msg_data, "flashInterval", mqtt_parm.msg_flashInterval, sizeof(mqtt_parm.msg_flashInterval));
		                DEBUG_TX("flashInterval:%s\n",mqtt_parm.msg_flashInterval);
		                get_string_from_json_string_by_key_unescape(msg_data, "lightDuration", mqtt_parm.msg_lightDuration, sizeof(mqtt_parm.msg_lightDuration));
		                DEBUG_TX("lightDuration:%s\n",mqtt_parm.msg_lightDuration);
		                pthread_mutex_lock(&lightsn_buffer_mutex);
		                if (!is_3015_collecting) {
		                    is_3015_collecting = true;
		                    first_3015_time = time(NULL);
		                    lightsn_buffer_count = 0;
		                    memset(lightsn_buffer, 0, sizeof(lightsn_buffer));
		                    memset(color_buffer, 0, sizeof(color_buffer));
		                    memset(sound_buffer, 0, sizeof(sound_buffer));
		                    memset(flash_buffer, 0, sizeof(flash_buffer));
		                }
		                int i;
		                char msg_lightsn_value[128] = {0};
		                char msg_lightsn[128] = {0};
		                for (i = 0; i < mqtt_parm.msg_opNumber && lightsn_buffer_count < MAX_LIGHTSN_BUFFER; i++) {
		                    get_string_from_json_string_arry_by_key(msg_data, "lights", msg_lightsn_value, 128, i);
		                    snprintf(msg_lightsn, sizeof(msg_lightsn), "{%s}", msg_lightsn_value);
		                    get_string_from_json_string_by_key_unescape(msg_lightsn, "sn", lightsn_buffer[lightsn_buffer_count], 32);
		                    get_string_from_json_string_by_key_unescape(msg_lightsn, "color", color_buffer[lightsn_buffer_count], 8);
		                    get_string_from_json_string_by_key_unescape(msg_lightsn, "sound", sound_buffer[lightsn_buffer_count], 8);
		                    get_string_from_json_string_by_key_unescape(msg_lightsn, "flash", flash_buffer[lightsn_buffer_count], 8);

		                    if (strlen(color_buffer[lightsn_buffer_count]) == 0) strcpy(color_buffer[lightsn_buffer_count], mqtt_parm.msg_color);
		                    if (strlen(sound_buffer[lightsn_buffer_count]) == 0) strcpy(sound_buffer[lightsn_buffer_count], mqtt_parm.msg_sound);
		                    if (strlen(flash_buffer[lightsn_buffer_count]) == 0) strcpy(flash_buffer[lightsn_buffer_count], mqtt_parm.msg_flash);
		                    LOG_I("buffered sn: %s, color: %s, sound: %s, flash: %s\n", lightsn_buffer[lightsn_buffer_count], color_buffer[lightsn_buffer_count], sound_buffer[lightsn_buffer_count], flash_buffer[lightsn_buffer_count]);
		                    lightsn_buffer_count++;
		                }
		                pthread_mutex_unlock(&lightsn_buffer_mutex);
		                mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "ok", 1, productid);
		            }else if(strcmp(mqtt_parm.msg_type,"3022")==0){
		                LOG_I("3022 updata lable\n");
		                char sn_str[32] = {0};
		                char label1_str[8] = {0};
		                char label2_str[8] = {0};
		                char label3_str[16] = {0};
		                get_string_from_json_string_by_key_unescape(msg_data, "sn", sn_str, sizeof(sn_str));
		                get_string_from_json_string_by_key_unescape(msg_data, "label1", label1_str, sizeof(label1_str));
		                get_string_from_json_string_by_key_unescape(msg_data, "label2", label2_str, sizeof(label2_str));
		                get_string_from_json_string_by_key_unescape(msg_data, "label3", label3_str, sizeof(label3_str));
		                LOG_I("sn:%s\n", sn_str);
		                LOG_I("label1:%s\n", label1_str);
		                LOG_I("label2:%s\n", label2_str);
		                LOG_I("label3:%s\n", label3_str);
		                if(strcmp(sn_str,"")!=0){
		                    if(label_buf_count == 0) {
		                        label_buf_first_time = time(NULL);
		                    }
		                    tags_buf[label_buf_count] = strtoul(sn_str, NULL, 16);
		                    lable1_buf[label_buf_count] = (uint8_t)atoi(label1_str);
		                    lable2_buf[label_buf_count] = (uint16_t)strtoul(label2_str, NULL, 16);
		                    lable3_buf[label_buf_count] = strtoul(label3_str, NULL, 16);
		                    label_buf_count++;
		                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "ok", 1, productid);
		                    isSendComEnd = true;
		                    isLightOn = false;
		                    isLightOnByRule = false;
		                    isLabelUp = true;
		                }else{
		                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "sn is empty", 0, productid);
		                }
		            }else if(strcmp(mqtt_parm.msg_type,"3023")==0){
		                LOG_I("3023 light on by rule\n");
		                get_string_from_json_string_by_key_unescape(msg_data, "labelConfig", msg_labelconfig_value, sizeof(msg_labelconfig_value));
		                snprintf(msg_labelconfig, sizeof(msg_labelconfig), "{%s}", msg_labelconfig_value);
		                LOG_I("msg_labelconfig:%s\n",msg_labelconfig);
		                get_string_from_json_string_by_key_unescape(msg_labelconfig, "label1", mqtt_parm.msg_label1, sizeof(mqtt_parm.msg_label1));
		                LOG_I("label1:%s\n",mqtt_parm.msg_label1);
		                get_string_from_json_string_by_key_unescape(msg_labelconfig, "label2", mqtt_parm.msg_label2, sizeof(mqtt_parm.msg_label2));
		                LOG_I("label2:%s\n",mqtt_parm.msg_label2);
		                get_string_from_json_string_by_key_unescape(msg_labelconfig, "label3", mqtt_parm.msg_label3, sizeof(mqtt_parm.msg_label3));
		                LOG_I("label3:%s\n",mqtt_parm.msg_label3);
		                get_string_from_json_string_by_key_unescape(msg_labelconfig, "label1Rule", mqtt_parm.msg_label1Rule,
		                                                            sizeof(mqtt_parm.msg_label1Rule));
		                LOG_I("label1Rule:%s\n",mqtt_parm.msg_label1Rule);
		                get_string_from_json_string_by_key_unescape(msg_labelconfig, "label2Rule", mqtt_parm.msg_label2Rule,
		                                                            sizeof(mqtt_parm.msg_label2Rule));
		                LOG_I("label2Rule:%s\n",mqtt_parm.msg_label2Rule);
		                get_string_from_json_string_by_key_unescape(msg_labelconfig, "label3Rule", mqtt_parm.msg_label3Rule,
		                                                            sizeof(mqtt_parm.msg_label3Rule));
		                LOG_I("label3Rule:%s\n",mqtt_parm.msg_label3Rule);
		                get_string_from_json_string_by_key_unescape(msg_data, "color", mqtt_parm.msg_color, sizeof(mqtt_parm.msg_color));
		                LOG_I("color:%s\n",mqtt_parm.msg_color);
		                get_string_from_json_string_by_key_unescape(msg_data, "sound", mqtt_parm.msg_sound, sizeof(mqtt_parm.msg_sound));
		                LOG_I("sound:%s\n",mqtt_parm.msg_sound);
		                get_string_from_json_string_by_key_unescape(msg_data, "flash", mqtt_parm.msg_flash, sizeof(mqtt_parm.msg_flash));
		                LOG_I("flash:%s\n",mqtt_parm.msg_flash);
		                get_string_from_json_string_by_key_unescape(msg_data, "flashInterval", mqtt_parm.msg_flashInterval,
		                                                            sizeof(mqtt_parm.msg_flashInterval));
		                LOG_I("flashInterval:%s\n",mqtt_parm.msg_flashInterval);
		                get_string_from_json_string_by_key_unescape(msg_data, "lightDuration", mqtt_parm.msg_lightDuration,
		                                                            sizeof(mqtt_parm.msg_lightDuration));
		                LOG_I("lightDuration:%s\n",mqtt_parm.msg_lightDuration);

		                if(strcmp(msg_labelconfig_value,"")!=0){
		                    mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);
		                    isSendComEnd=false;
		                    isLightOn=false;
		                    isLightOnByRule=true;
		                    isLabelUp=false;
		                    //isSearchLabel=false;
		                    uart_data_send_head_lightonrule(&uartSend,5);
		                }else{
		                    mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"labelconfig is empty",0,productid);
                                }
		            }else if(strcmp(mqtt_parm.msg_type,"3027")==0){
		                LOG_I("3027 All light on/off 广播点亮\n");

		                get_string_from_json_string_by_key_unescape(msg_data, "color", mqtt_parm.msg_color, sizeof(mqtt_parm.msg_color));
		                //strcpy(mqtt_parm.msg_color, "1");  // 默认关闭颜色
                        LOG_I("color:%s\n",mqtt_parm.msg_color);

		                get_string_from_json_string_by_key_unescape(msg_data, "sound", mqtt_parm.msg_sound, sizeof(mqtt_parm.msg_sound));
		                //strcpy(mqtt_parm.msg_sound, "0");  // 默认关闭声音
		                LOG_I("sound:%s\n",mqtt_parm.msg_sound);

		                get_string_from_json_string_by_key_unescape(msg_data, "flash", mqtt_parm.msg_flash, sizeof(mqtt_parm.msg_flash));
		                //strcpy(mqtt_parm.msg_flash, "0");  // 默认关闭闪烁
		                LOG_I("flash:%s\n",mqtt_parm.msg_flash);

		                get_string_from_json_string_by_key_unescape(msg_data, "flashInterval", mqtt_parm.msg_flashInterval, sizeof(mqtt_parm.msg_flashInterval));
		                LOG_I("flashInterval:%s\n",mqtt_parm.msg_flashInterval);

		                get_string_from_json_string_by_key_unescape(msg_data, "lightDuration", mqtt_parm.msg_lightDuration, sizeof(mqtt_parm.msg_lightDuration));
                        LOG_I("lightDuration:%s\n",mqtt_parm.msg_lightDuration);

		                if(isLightEnable){
		                    mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"ok",1,productid);

		                    // 设置规则并广播点亮，重置变量，防止被3015污染
		                    isSendComEnd=false;
		                    isLightOn=false;
		                    isLightOnByRule=true;  // 使用规则控制
		                    isLabelUp=false;

                            memset(lightsn1, 0, sizeof(lightsn1));
                            memset(lightsn2, 0, sizeof(lightsn2));
                            memset(lightsn3, 0, sizeof(lightsn3));
                            memset(lightsn4, 0, sizeof(lightsn4));
                            memset(lightsn5, 0, sizeof(lightsn5));
                            memset(lightsn6, 0, sizeof(lightsn6));
                            memset(lightsn7, 0, sizeof(lightsn7));
                            memset(lightsn8, 0, sizeof(lightsn8));
                            memset(lightsn9, 0, sizeof(lightsn9));
                            memset(lightsn10, 0, sizeof(lightsn10));
                            memset(lightsn11, 0, sizeof(lightsn11));
                            memset(lightsn12, 0, sizeof(lightsn12));
                            memset(lightsn13, 0, sizeof(lightsn13));
                            memset(lightsn14, 0, sizeof(lightsn14));
                            memset(lightsn15, 0, sizeof(lightsn15));
                            memset(lightsn16, 0, sizeof(lightsn16));
                            memset(lightsn17, 0, sizeof(lightsn17));
                            memset(lightsn18, 0, sizeof(lightsn18));
                            memset(lightsn19, 0, sizeof(lightsn19));
                            memset(lightsn20, 0, sizeof(lightsn20));
                            memset(lightsn21, 0, sizeof(lightsn21));
                            memset(lightsn22, 0, sizeof(lightsn22));
                            memset(lightsn23, 0, sizeof(lightsn23));
                            memset(lightsn24, 0, sizeof(lightsn24));
                            memset(lightsn25, 0, sizeof(lightsn25));
                            memset(lightsn26, 0, sizeof(lightsn26));
                            memset(lightsn27, 0, sizeof(lightsn27));
                            memset(lightsn28, 0, sizeof(lightsn28));
                            memset(lightsn29, 0, sizeof(lightsn29));
                            memset(lightsn30, 0, sizeof(lightsn30));

		                    // 设置label1和label2不参与匹配
		                    strcpy(mqtt_parm.msg_label1Rule, "04");  // ∅ 不参与匹配
		                    strcpy(mqtt_parm.msg_label2Rule, "04");  // ∅ 不参与匹配
		                    // 设置label3不等于386cd300的规则
		                    strcpy(mqtt_parm.msg_label3Rule, "03");  // ≠ 不等于
		                    strcpy(mqtt_parm.msg_label3, "386cd300");

		                    // 广播点亮命令
		                    LOG_I("Broadcasting light on command\n");
		                    uart_data_send_head_lightonrule(&uartSend, 5);

		                    // 再次广播，提升可靠性
		                    //usleep(100000);  // 等待100ms
		                    //LOG_I("Sending second broadcast\n");
		                    //uart_data_send_head_lightonrule(&uartSend, 5);
		                }else{
		                    mqtt_service_reply(stationsn,mqtt_parm.msg_messageId,"light disabled",0,productid);
		                }
		            } else if(strcmp(mqtt_parm.msg_type,"2333")==0){
                        LOG_I("2333 文件操作任务\n");
                        char action[16] = {0};
                        char filename[128] = {0};
                        char fullpath[256] = {0};
                        int op_result = 0;
                        // 解析action和filename
                        get_string_from_json_string_by_key_unescape(msg_data, "action", action, sizeof(action));
                        get_string_from_json_string_by_key_unescape(msg_data, "filename", filename, sizeof(filename));
                        LOG_I("action: %s, filename: %s\n", action, filename);
                        // 安全性校验：不允许..和/
                        if(strstr(filename, "..")){
                            LOG_I("非法文件名: %s\n", filename);
                            mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "invalid filename", 0, productid);
                        }else if(strlen(filename) == 0){
                            LOG_I("文件名为空\n");
                            mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "filename empty", 0, productid);
                        }else{
                            snprintf(fullpath, sizeof(fullpath), "%s", filename);
                            if(strcmp(action, "create")==0){
                                FILE *fp = fopen(fullpath, "w");
                                if(fp){
                                    fclose(fp);
                                    LOG_I("创建文件成功: %s\n", fullpath);
                                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "create ok", 1, productid);
                                }else{
                                    LOG_I("创建文件失败: %s, err: %s\n", fullpath, strerror(errno));
                                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "create failed", 0, productid);
                                }
                            }else if(strcmp(action, "delete")==0){
                                op_result = unlink(fullpath);
                                if(op_result == 0){
                                    LOG_I("删除文件成功: %s\n", fullpath);
                                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "delete ok", 1, productid);
                                }else if(errno == ENOENT){
                                    LOG_I("文件不存在, 视为成功: %s\n", fullpath);
                                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "delete ok (not exist)", 1, productid);
                                }else{
                                    LOG_I("删除文件失败: %s, err: %s\n", fullpath, strerror(errno));
                                    mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "delete failed", 0, productid);
                                }
                            }else{
                                LOG_I("未知action: %s\n", action);
                                mqtt_service_reply(stationsn, mqtt_parm.msg_messageId, "unknown action", 0, productid);
                            }
                        }
                    } else if(strcmp(mqtt_parm.msg_type,"2334")==0){
                        LOG_I("2334 获取系统资源任务\n");
                        float cpu_usage = get_cpu_usage();
                        long mem_total, mem_free, mem_available, mem_used;
                        float mem_percent;
                        get_mem_usage(&mem_total, &mem_free, &mem_available, &mem_used, &mem_percent);
                        long disk_total, disk_free, disk_used;
                        float disk_percent;
                        get_disk_usage("/", &disk_total, &disk_free, &disk_used, &disk_percent);

                        char json[512];
                        snprintf(json, sizeof(json),
                            "{\"cpu\":\"%.2f%%\",\"mem_total\":\"%ldMB\",\"mem_used\":\"%ldMB\",\"mem_free\":\"%ldMB\",\"mem_percent\":\"%.2f%%\"," \
                            "disk_total\":\"%ldMB\",\"disk_used\":\"%ldMB\",\"disk_free\":\"%ldMB\",\"disk_percent\":\"%.2f%%\"}",
                            cpu_usage, mem_total, mem_used, mem_free, mem_percent,
                            disk_total, disk_used, disk_free, disk_percent);

                        mqtt_resource_reply(stationsn, mqtt_parm.msg_messageId, "system", 1, productid, json);
                    } else if(strcmp(mqtt_parm.msg_type,"2335")==0){
                        LOG_I("2335 执行命令任务\n");
                        char cmd[128] = {0};
                        char result[1024] = {0};
                        get_string_from_json_string_by_key_unescape(msg_data, "cmd", cmd, sizeof(cmd));
                        LOG_I("cmd: %s\n", cmd);

                        if(strstr(cmd, "rm") || strstr(cmd, "reboot") || strstr(cmd, "shutdown")) {
                            LOG_I("非法或危险命令: %s\n", cmd);
                            mqtt_resource_reply(stationsn, mqtt_parm.msg_messageId, "system", 0, productid, "invalid or dangerous command");
                        } else if(strlen(cmd) == 0){
                            LOG_I("命令为空\n");
                            mqtt_resource_reply(stationsn, mqtt_parm.msg_messageId, "system", 0, productid, "command empty");
                        } else {
                            FILE *fp = popen(cmd, "r");
                            if(fp){
                                fread(result, 1, sizeof(result)-1, fp);
                                pclose(fp);
                                LOG_I("命令输出: %s\n", result);
                                mqtt_resource_reply(stationsn, mqtt_parm.msg_messageId, "system", 1, productid, result);
                            } else {
                                LOG_I("命令执行失败: %s\n", cmd);
                                mqtt_resource_reply(stationsn, mqtt_parm.msg_messageId, "system", 0, productid, "command exec failed");
                            }
                        }
                    }
                }
            }
            usleep(getPayloadTime);
        }else{
            usleep(getPayloadTime);
        }
    }
}
/*================================================================================*/
void hmacsha1(char *key,char* data,char *signbase64,int signbase64_len){
    char result[256]={0};
    size_t len=sizeof(result);
    //LOG_I("key_len:%d,data_len:%d\n",strlen(key),strlen(data));
    hmac_sha1(key,strlen(key),data,strlen(data),result,&len);
    //LOG_I("result_len:%d\n",len);
    //int t_i;
    //for(t_i=0;t_i<len;t_i++)
    //    printf("%x ",result[t_i]);
    Base64_encode( signbase64, signbase64_len, result,strlen(result));
    //printf("last:%s\n",signbase64);
}

void getLocalIp(char *local_ip){
    char hostname[32]={0};
    FILE *fp;
    char buffer[64]={0};
    //get_ip_by_domain(hostname, local_ip, 32);
    fp=popen("ifconfig eth0 | grep 'inet' | awk '{print $2}' | cut -d':' -f2","r");
    if (fp) {
        fgets(buffer,sizeof(buffer),fp);
        //LOG_I("buffer:%s\n",buffer);
        memcpy(local_ip,buffer,strlen(buffer)-1);
        pclose(fp);
    }
}

int getLedOtaVersion(char *filename){
    FILE *fp;
    char buffer[128]={0};
    int ver=0;
    fp=popen("ls ota/F8*.bin","r");//tx is F8 begin
    if (fp) {
        fgets(buffer,sizeof(buffer),fp);
        //LOG_I("buffer:%s\n",buffer);
        memcpy(filename,buffer,strlen(buffer)-1);
        pclose(fp);
    }
    fp=popen("ls ota/F8*.bin|cut -d'_' -f3|cut -d'.' -f3","r");
    if (fp) {
        fgets(buffer,sizeof(buffer),fp);
        //LOG_I("buffer:%s\n",buffer);
        ver=atoi(buffer);
        pclose(fp);
    }
    LOG_I("ver:%d\n",ver);
    return ver;
}

int getApOtaVersion(char *filename,char *modename){
    FILE *fp;
    char buffer[128]={0};
    int ver=0;

    fp = popen("ls ota/AP*.bin", "r"); // AP begin
    if (fp) {
        fgets(buffer, sizeof(buffer), fp);
        //LOG_I("buffer:%s\n",buffer);
        memcpy(filename, buffer, strlen(buffer) - 1);
        pclose(fp);
    }

    fp = popen("ls ota/AP*.bin|cut -d'_' -f6|cut -d'.' -f3", "r");
    if (fp) {
        fgets(buffer, sizeof(buffer), fp);
        //LOG_I("buffer:%s\n",buffer);
        ver = atoi(buffer);
        LOG_I("ver:%d\n", ver);
        pclose(fp);
    }

    fp = popen("ls ota/AP*.bin|cut -d'_' -f3", "r");
    if (fp) {
        fgets(buffer, sizeof(buffer), fp);
        //LOG_I("buffer:%s\n",buffer);
        memcpy(modename, buffer, strlen(buffer) - 1);
        pclose(fp);
    }

    return ver;
}

void saveStartUpTime(){
    system("rm ./startUpTime");
    struct timeval tv;
    char startUpTime[32] = {0};
    gettimeofday(&tv, NULL);
    snprintf(startUpTime,sizeof(startUpTime),"%ld",tv.tv_sec);
    buffer_to_file("startUpTime",startUpTime,strlen(startUpTime),"wb");
}

void calculateStartUpTime(char *startTime){
    char *result=NULL;
    struct timeval tv;
    int len=0;
    result=file_to_buffer("startUpTime",&len);
    if(result!=NULL){
        LOG_I("startUpTime:%s\n",result);
        gettimeofday(&tv, NULL);
        LOG_I("nowUpTime:%ld\n",tv.tv_sec);
        snprintf(startTime,11,"%ld",tv.tv_sec-atoi(result));
    }
}

void updateStationInfo(char *msg_id){
    char local_ip[32] = {0};
    char startTime[11]={0};
    getLocalIp(local_ip);
    LOG_I("local_ip:%s\n",local_ip);
    calculateStartUpTime(startTime);
    LOG_I("Time:%s\n",startTime);
    mqtt_server_station_status_report(msg_id,productid,stationsn,local_ip,softwareVersion,"1",startTime);
    mqtt_server_station_status_report_test(msg_id,productid,stationsn,local_ip,softwareVersion,"1",startTime);
}

bool timeNew(){
    struct timeval tv;
    gettimeofday(&tv, NULL);
    long gettime=tv.tv_sec*1000+tv.tv_usec;
    LOG_I("gettime:%ld\n",gettime);
    if(gettime<1744000000000){
        return false;
    }

    return true;
}
//==========================================================================================
int main(int argc, char *argv[])
{
    int ret = -1;
    uint32_t can_id;
    char recv_data[8]={0};
    char command_buffer[256] = "";
    uint32_t len=0;
    int getTimeCount=0;
    char *readresult=NULL;
    char networktype[32]={0};
    pthread_t timeout_thread;  // 添加超时检测线程变量
    char syscmd[256]={0};

    LOG_I("version:%s\n",softwareVersion);

    FILE *fp = fopen("/userdata/tx_version", "w");
    if (fp) {
        fprintf(fp, "%s\n", softwareVersion);
        fclose(fp);
    } else {
        LOG_I("Failed to write /userdata/tx_version\n");
    }

    #if 1
    system("insmod /system/lib/modules/wk2xxx_spi.ko");
    snprintf(syscmd, sizeof(syscmd), "ls Log.*|xargs rm -fr");
    system(syscmd);

    // 设置时区为 Asia/Shanghai，直接修改 /etc/localtime 软链接
    unlink("/etc/localtime");
    symlink("/usr/share/zoneinfo/Asia/Shanghai", "/etc/localtime");

    // 导出 GPIO 63
    {
        int fd = open("/sys/class/gpio/export", O_WRONLY);
        if (fd >= 0) {
            write(fd, "63", 2);
            close(fd);
        }
    }
    // 设置 GPIO 63 方向为 in
    {
        int fd = open("/sys/class/gpio/gpio63/direction", O_WRONLY);
        if (fd >= 0) {
            write(fd, "in", 2);
            close(fd);
        }
    }
    // 导出 GPIO 113
    {
        int fd = open("/sys/class/gpio/export", O_WRONLY);
        if (fd >= 0) {
            write(fd, "113", 3);
            close(fd);
        }
    }
    // 设置 GPIO 113 方向为 out
    {
        int fd = open("/sys/class/gpio/gpio113/direction", O_WRONLY);
        if (fd >= 0) {
            write(fd, "out", 3);
            close(fd);
        }
    }
    #endif
    #if 0
    system("insmod /system/lib/modules/wk2xxx_spi.ko");
    system("busybox udhcpc -i eth0");
    system("timedatectl set-timezone Asia/Shanghai");
    system("echo 63 > /sys/class/gpio/export");//reset key
    system("echo in > /sys/class/gpio/gpio63/direction");
    system("echo 113 > /sys/class/gpio/export");//pin 113 yellow
    system("echo out > /sys/class/gpio/gpio113/direction");
    #endif
    uart_open(&uartSend,"/dev/ttyS0");//GT U12 ttyS0,U14 ttyS4,U21 ttysWK0 U13 ttysWK1 U15 ttysWK2 U22 ttysWK3 U20 ttyS1
    uart_init(&uartSend,115200,8,1,'N',0);
    uart_open(&uartRecvData,"/dev/ttyS4");//DT
    uart_init(&uartRecvData,115200,8,1,'N',0);
    uart_open(&uartRecvBack,"/dev/ttysWK0");//HT
    uart_init(&uartRecvBack,115200,8,1,'N',0);

#if 0
    struct dma_config cfg = {
        .buf = malloc(256),
        .len = 256
    };
    // 填充测试数据
    memset(cfg.buf, 0x55, 256);
    // 启动DMA传输
    ioctl(uartSend.uart_fd, DMA_START_TX, &cfg);
#endif
    //doCommand_help(0, NULL);
#if 1
    enableWatchDog();
    ret = pthread_create(&pt_watchdog,NULL,thread_feed_watchdog,NULL);
    if(ret!=0){
       LOG_I("pthread_create watchdog fail\n");
    }else{
       LOG_I("pthread_create watchdog success\n");
       pthread_detach(pt_watchdog);
    }
#endif

#if 0
    ret = pthread_create(&pt_reboot,NULL,thread_reboot,NULL);
    if(ret!=0){
       LOG_I("pthread_create reboot fail\n");
    }else{
       LOG_I("pthread_create reboot success\n");
       pthread_detach(pt_reboot);
    }
#endif

    ret = pthread_create(&pt_uart_recv_ack,NULL,thread_uart_recv_ack,NULL);
    if(ret!=0){
       LOG_I("pthread_create uart_recv_ack fail\n");
    }else{
       pthread_detach(pt_uart_recv_ack);
       LOG_I("pthread_create uart_recv_ack success\n");
    }

    ret = pthread_create(&pt_uart_recv_data,NULL,thread_uart_recv_data,NULL);
    if(ret!=0){
       LOG_I("pthread_create uart_recv_data fail\n");
    }else{
       pthread_detach(pt_uart_recv_data);
       LOG_I("pthread_create uart_recv_data success\n");
    }

    ret = pthread_create(&pt_uart_recv_back,NULL,thread_uart_recv_back,NULL);
    if(ret!=0){
       LOG_I("pthread_create uart_recv_back fail\n");
    }else{
       pthread_detach(pt_uart_recv_back);
       LOG_I("pthread_create uart_recv_back success\n");
    }

    ret = pthread_create(&pt_mqtt_recv,NULL,thread_mqtt_recv,NULL);
    if(ret!=0){
       LOG_I("pthread_create mqtt_recv fail\n");
    }else{
       pthread_detach(pt_mqtt_recv);
       LOG_I("pthread_create mqtt_recv success\n");
    }

    ret = pthread_create(&pt_tagsearch,NULL,thread_tag_search_send,NULL);
    if(ret!=0){
       LOG_I("pthread_create tag search send fail\n");
    }else{
       LOG_I("pthread_create tag search success\n");
       pthread_detach(pt_tagsearch);
    }

    ret = pthread_create(&pt_removeduplicatetag,NULL,thread_remove_duplicate_tag,NULL);
    if(ret!=0){
       LOG_I("pthread_create remove duplicate tag send fail\n");
    }else{
       LOG_I("pthread_create remove duplicate tag success\n");
       pthread_detach(pt_removeduplicatetag);
    }
#if 0
    ret = pthread_create(&pt_vm_heartbeat, NULL, thread_vm_heartbeat, stationsn);
    if(ret!=0){
       LOG_I("pthread_create vm heartbeat fail\n");
    }else{
       LOG_I("pthread_create vm heartbeat success\n");
       pthread_detach(pt_vm_heartbeat);
    }
#endif
#if 1
    ret = pthread_create(&pt_removelog,NULL,thread_removelog,NULL);
    if(ret!=0){
       LOG_I("pthread_create removelog fail\n");
    }else{
       LOG_I("pthread_create removelog success\n");
       pthread_detach(pt_removelog);
    }
#endif

    // 创建超时检测线程
    ret = pthread_create(&timeout_thread, NULL, thread_timeout_check, NULL);
    if(ret!=0){
       LOG_I("pthread_create timeout_check fail\n");
    }else{
       LOG_I("pthread_create timeout_check success\n");
       pthread_detach(timeout_thread);
    }

    // 新增：3015合并点亮线程
    pthread_t pt_3015_merge;
    ret = pthread_create(&pt_3015_merge, NULL, thread_3015_lighton_merge, NULL);
    if (ret != 0) {
        LOG_I("pthread_create 3015_merge fail\n");
    } else {
        pthread_detach(pt_3015_merge);
        LOG_I("pthread_create 3015_merge success\n");
    }

    // 新增：3022合包批量下发线程
    pthread_t pt_label_batch_send;
    ret = pthread_create(&pt_label_batch_send, NULL, thread_label_batch_send, NULL);
    if (ret != 0) {
        LOG_I("pthread_create label_batch_send fail\n");
    } else {
        pthread_detach(pt_label_batch_send);
        LOG_I("pthread_create label_batch_send success\n");
    }

    ret = pthread_create(&pt_ota,NULL,thread_ota,NULL);
    if(ret!=0){
       LOG_I("pthread_create ota fail\n");
    }else{
       LOG_I("pthread_create ota success\n");
       pthread_detach(pt_ota);
    }

    ret = pthread_create(&pt_doota,NULL,thread_do_ota,NULL);
    if(ret!=0){
       LOG_I("pthread_create doota fail\n");
    }else{
       LOG_I("pthread_create doota success\n");
       pthread_detach(pt_doota);
    }
#if 1
    ret = pthread_create(&pt_readqr,NULL,thread_readqr,NULL);
    if(ret!=0){
       LOG_I("pthread_create readqr fail\n");
    }else{
       LOG_I("pthread_create readqr success\n");
       pthread_detach(pt_readqr);
    }
#endif

    // 字符串清理函数，去除末尾的空白字符
    void trim_whitespace(char *str) {
        if (str == NULL) return;
        int len = strlen(str);
        while (len > 0 && (str[len-1] == '\n' || str[len-1] == '\r' ||
               str[len-1] == ' ' || str[len-1] == '\t')) {
            str[--len] = '\0';
        }
    }

    readresult=file_to_buffer("savedDevSn",&len);
#if 0
    if(readresult==NULL){
        // savedDevSn文件不存在，尝试从Redis获取SN
        LOG_I("savedDevSn file not found, trying to get SN from Redis...\n");

        // 初始化Redis SN客户端
        if (init_redis_sn_client() == 0) {
            LOG_I("Redis SN client initialized successfully\n");

            // 尝试从Redis获取设备SN和MAC地址
            char redis_sn[32] = {0};
            char redis_mac[32] = {0};
            if (get_device_sn_and_mac_from_redis(redis_sn, sizeof(redis_sn), redis_mac, sizeof(redis_mac)) == 0) {
                // 成功获取到SN和MAC，保存SN到文件
                LOG_I("Got device SN: %s, MAC: %s from Redis\n", redis_sn, redis_mac);
                buffer_to_file("savedDevSn", redis_sn, strlen(redis_sn), "wb");

                // 保存MAC地址到文件供getDevRawPassword使用
                buffer_to_file("savedDevMac", redis_mac, strlen(redis_mac), "wb");
                LOG_I("Device MAC saved to file: %s\n", redis_mac);

                strncpy(stationsn, redis_sn, sizeof(stationsn) - 1);
                stationsn[sizeof(stationsn) - 1] = '\0';
                readresult = redis_sn; // 设置readresult避免进入while循环
                len = strlen(redis_sn);
            } else {
                LOG_I("Failed to get SN from Redis, waiting for manual scan...\n");
            }

            // 清理Redis客户端资源
            cleanup_redis_sn_client();
        } else {
            LOG_I("Redis SN client initialization failed, waiting for manual scan...\n");
        }
    }
#endif

    // 如果Redis获取失败或savedDevSn文件存在，按原逻辑处理
    while(readresult==NULL){
        readresult=file_to_buffer("savedDevSn",&len);
        sleep(5);
        LOG_I("please scan sn\n");
        //TODO输出日志到180.163.74.83网页
    }
    strncpy(stationsn,readresult,len);
    trim_whitespace(stationsn);  // 清理空白字符
    readresult=NULL;
    LOG_I("saved stationsn:%s\n",stationsn);
#if 1
    readresult=file_to_buffer("/userdata/mqttRawPassword",&len);
    if(readresult!=NULL){
        strncpy(mqttRawPassword,readresult,len);
        trim_whitespace(mqttRawPassword);  // 清理空白字符
        readresult=NULL;
        LOG_I("saved mqttRawPassword:%s\n",mqttRawPassword);
    }else{
        if((ping("8.8.8.8") == 0)||(ping("8.8.4.4") == 0)){
            getDevRawPassword(stationsn);
        }else{
            LOG_I("getDevRawPassword net not ready\n");
            sleep(3);
        }
    }
#endif
    readresult=file_to_buffer("/userdata/LightEnable",&len);
    if(readresult!=NULL){
        if(strcmp(readresult,"enable")==0){
            isLightEnable=true;
        }else{
            isLightEnable=false;
        }
        readresult=NULL;
    }
#if 1
    while(1){
        if((ping("8.8.8.8") == 0)||(ping("8.8.4.4") == 0)){
            LOG_I("net ok\n");
            while(!timeNew()){
                //LOG_I("sleep\n");
                getTimeCount++;
                if(getTimeCount==100){
                    break;
                }
                sleep(1);
            }
            saveStartUpTime();
            ret = pthread_create(&pt_mqtt,NULL,thread_mqtt,NULL);
            if(ret!=0){
                LOG_I("pthread_create mqtt fail\n");
            }else{
                pthread_detach(pt_mqtt);
                LOG_I("pthread_create mqtt success\n");
            }
            break;
        }else{
            DEBUG_TX("net not ready\n");
            sleep(3);
        }
    }
#endif
#if 1
    while(1)
    {
        // 先检查标准输入是否可用
        if (feof(stdin) || ferror(stdin)) {
            //LOG_I("stdin error or EOF, sleeping for 1 second\n");
            sleep(1);
            continue;
        }

        memset(command_buffer, 0, sizeof(command_buffer));
        if (fgets(command_buffer, sizeof(command_buffer), stdin) == NULL) {
            usleep(100000);
            continue;
        }

        command_buffer[strcspn(command_buffer, "\n")] = 0;

        if (strlen(command_buffer) == 0) {
            continue;
        }

        if(execute_command(command_buffer, (command_t *)&__start_command, (&__stop_command - &__start_command)/2) < 0)
        {
            LOG_I("unsupport command!\r\n");
        }
    }
#endif

    return 0;
}

// 超时检测线程
void *thread_timeout_check(void *arg) {
    prctl(PR_SET_NAME, "timeout_check");

    while(1) {
        if(last_2323_time != 0 && waiting_for_4646) {  // 只有在等待0x4646时才检查超时
            time_t current_time;
            time(&current_time);
            if(difftime(current_time, last_2323_time) >= 10.0) {  // 超过10秒
                LOG_I("thread_timeout_check: Timeout after receiving 0x2323, no 0x4646 received, setting isSendComEnd to 1\n");
                isSendComEnd = 1;
                last_2323_time = 0;  // 重置时间
                waiting_for_4646 = false;  // 重置等待状态
                isLightEnable = 1;  // 重置点亮使能标志
                isLightOn = false;  // 重置点亮状态
                isLightOnByRule = false;  // 重置规则点亮状态
                isLabelUp = false;  // 重置标签更新状态
            }
        }
        usleep(100*1000);  // 每100ms检查一次
    }
    return NULL;
}

// 合并点亮线程
void *thread_3015_lighton_merge(void *arg) {
    int total_all = 0;

     while (1) {
        pthread_mutex_lock(&lightsn_buffer_mutex);
        if (is_3015_collecting) {
            time_t now = time(NULL);
            if ((now - first_3015_time >= 3) || (lightsn_buffer_count >= MAX_LIGHTSN_BUFFER)) {
                int total = lightsn_buffer_count;
                total_all += total;
		        int batch_size = 10;
                int sent = 0;
                while (sent < total) {
                    int this_batch = (total - sent > batch_size) ? batch_size : (total - sent);
                    DEBUG_TX("-------total:%d, sent:%d, this batch: %d------\n", total, sent, this_batch);
		            if (isLightEnable && this_batch > 0) {
                        isLightOn = true;
                        isLightOnByRule = false;
                        isLabelUp = false;
                        uint32_t tags[10] = {0};
                        uint8_t tag_leds[10] = {0};
                        for (int i = 0; i < this_batch; i++) {
                            DEBUG_TX("sn[%d]=%s\n", sent + i + 1, lightsn_buffer[sent + i]);
                            // 1. SN转MAC（HEX字符串转uint32_t）
                            if (strlen(lightsn_buffer[sent + i]) == 8) {
                                tags[i] = (uint32_t)strtoul(lightsn_buffer[sent + i], NULL, 16);
                            } else {
                                DEBUG_TX("[WARN] tag[%d] sn格式非法: %s, 跳过", sent + i, lightsn_buffer[sent + i]);
                                continue;
                            }
                            // 2. 颜色+闪光+声音合成LED控制字节（协议格式）
                            int flash = (strlen(flash_buffer[sent + i]) > 0) ? atoi(flash_buffer[sent + i]) : atoi(mqtt_parm.msg_flash);   // "1"=闪光, "0"=常亮
                            int sound = (strlen(sound_buffer[sent + i]) > 0) ? atoi(sound_buffer[sent + i]) : atoi(mqtt_parm.msg_sound);   // "1"=有声, "0"=无声
                            int changecolor = 0;
                            if(strcmp(color_buffer[sent + i],"1")==0){
                                changecolor=4;
                            }else if(strcmp(color_buffer[sent + i],"2")==0){
                                changecolor=6;
                            }else if(strcmp(color_buffer[sent + i],"3")==0){
                                changecolor=1;
                            }else if(strcmp(color_buffer[sent + i],"4")==0){
                                changecolor=2;
                            }else if(strcmp(color_buffer[sent + i],"5")==0){
                                changecolor=3;
                            }else if(strcmp(color_buffer[sent + i],"6")==0){
                                changecolor=7;
                            }else if(strcmp(color_buffer[sent + i],"7")==0){
                                changecolor=5;
                            }else if(strcmp(color_buffer[sent + i],"8")==0){
                                changecolor=0;
                            }
                            uint8_t led_val = 0;
                            if (flash) led_val |= 0x40; // Bit6
                            if (sound) led_val |= 0x10; // Bit4
                            led_val |= (changecolor & 0x0F); // 低4位为颜色
                            tag_leds[i] = led_val;
                        }
                        uint8_t changecolor=0;
                        if(strcmp(mqtt_parm.msg_color,"1")==0){
                            changecolor=4;
                        }else if(strcmp(mqtt_parm.msg_color,"2")==0){
                            changecolor=6;
                        }else if(strcmp(mqtt_parm.msg_color,"3")==0){
                            changecolor=1;
                        }else if(strcmp(mqtt_parm.msg_color,"4")==0){
                            changecolor=2;
                        }else if(strcmp(mqtt_parm.msg_color,"5")==0){
                            changecolor=3;
                        }else if(strcmp(mqtt_parm.msg_color,"6")==0){
                            changecolor=7;
                        }else if(strcmp(mqtt_parm.msg_color,"7")==0){
                            changecolor=5;
                        }else if(strcmp(mqtt_parm.msg_color,"8")==0){
                            changecolor=0;
                        }
                        jt_ledctrl_package_t led_ctrl={
                            .s.color=changecolor,
                            .s.sound=atoi(mqtt_parm.msg_sound),
                            .s.flash=atoi(mqtt_parm.msg_flash),
                        };
                        uart_data_send_head_lightband(&uartSend, 2, this_batch);
                        usleep(50000);
                        uart_data_send_lightband(&uartSend, led_ctrl.ch, atoi(mqtt_parm.msg_flash), atoi(mqtt_parm.msg_lightDuration), tags, tag_leds, this_batch);
                    }
                    sent += this_batch;
                    if (sent < total) {
                        sleep(3);
                    }

                    DEBUG_TX("total_all: %d\n", total_all);
                }

                // 不要立即清空buffer，等待isLightOn处理完成
                is_3015_collecting = false;
                first_3015_time = 0;
                isLightOn = false;
            }
        }
        pthread_mutex_unlock(&lightsn_buffer_mutex);
        usleep(100*1000);
    }
    return NULL;
}

// 3022合包批量下发线程
void *thread_label_batch_send(void *arg) {
    while (1) {
        if (isLightOnByRule == false && isLightOn == false) {
            time_t now = time(NULL);
            if (label_buf_count > 0 && (label_buf_count >= 10 || (now - label_buf_first_time) >= 60)) {
                uart_data_send_head_lableup(&uartSend, 5, label_buf_count);
                usleep(10000);
                uart_data_send_lable(&uartSend, tags_buf, lable1_buf, lable2_buf, lable3_buf, label_buf_count);
                label_buf_count = 0;
                label_buf_first_time = 0;
                isLabelUp = false;
            }
        }
        usleep(1000 * 1000); // 每秒检查一次
    }
    return NULL;
}

void light_battery_report(uint32_t tagCode, uint16_t batteryV) {
    const char *url = "http://180.163.74.83:8428/api/v1/import/prometheus";
    char post_data[256];
    CURL *curl = curl_easy_init();
    if (!curl) {
        DEBUG_TX("curl init failed\n");
        return;
    }
    time_t now = time(NULL);
    // Prometheus exposition format: light_battery{tag="xxxxxx"} value timestamp
    snprintf(post_data, sizeof(post_data),
        "light_battery{tag=\"%08X\"} %d\n", tagCode, batteryV);
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        DEBUG_TX("send light_battery_report failed: %s\n", curl_easy_strerror(res));
    } else {
        DEBUG_TX("light_battery_report sent: %s", post_data);
    }
    curl_easy_cleanup(curl);
}
