
/************************************************************
*版权所有 （C）2020，公司（或个人）名称
*
*文件名称： midware.c
*内容摘要： 数据中转中心，上对云端，下对网关，承上启下
*其他说明：
*当前版本：
*************************************************************/


#include<stdio.h>
#include"com_api.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include "cJSON.h"
#include "kk_product.h"
#include "kk_tsl_common.h"
#include "kk_tsl_api.h"
#include "kk_dm_api.h"
#include "kk_dm_msg.h"
#include "kk_dm_mng.h"
#include "kk_log.h"
#include "kk_dm_queue.h"
#include "kk_property_db.h"
#include "sqlite3.h"
#include "kk_linkkit.h"
#include "kk_dm_heartbeat.h"
#include "kk_sub_db.h"
#include "kk_hal.h"
#include "kk_scene_handle.h"
#include "dm_ota.h"

#include "kk_area_handle.h"
#include "kk_property_get_handle.h"
#include "kk_motor_bind_db.h"
#include "kk_group_db.h"
#include "kk_alarm_handle.h"
#include "kk_history_db.h"
#include "kk_mutictrl_handle.h"

int g_timezone = 8;
char * g_filerToPlatTable[] =
{
	(char *){KK_REGISTER_TOPIC_REPLY},
	(char *){KK_ADD_TOPIC_REPLY},
	(char *){KK_LOGIN_TOPIC_REPLY},
	(char *){KK_THING_SERVICE_PROPERTY_GET},
	(char *){KK_THING_CLOUDSTATE_MSG},
	(char *){KK_THING_CLOUDHB_MSG},
	(char *){KK_THING_SERVICE_ADDSCENC},
	(char *){KK_THING_SERVICE_UPDATESCENC},
	(char *){KK_THING_SERVICE_DELETESCENC},
	(char *){KK_THING_SERVICE_NEGATIVE},
	(char *){KK_THING_SERVICE_SYNCINFO},
	(char *){KK_THING_SERVICE_BINDSCENE},
	(char *){KK_THING_SERVICE_UNBINDSBUTTTON},
	(char *){KK_THING_SERVICE_ACTIVEBUTTON},
	(char *){KK_THING_SERVICE_HISTORYALARM},
	(char *){KK_THING_SERVICE_DEL_HISTORYALARM},
	(char *){KK_THING_SERVICE_GETKEYLIST},
};
static char s_ccuid[DEVICE_CODE_LEN] = {0};
static char s_Version[VERSION_MAXLEN] = {0};
char s_pid[PRODUCT_CODE_LEN] = {0};
static int kk_pid_init(void)
{
    char pid[PRODUCT_CODE_LEN] = {0};
    int pid_len = 0;
    HAL_Execel_cmd(GET_PRODUCTID_CMD,(char *)pid,sizeof(pid),&pid_len);
    if(pid_len > 0 && pid_len <= PRODUCT_CODE_LEN){
		memcpy(s_pid,pid,pid_len-1);
		INFO_PRINT("s_pid:%s\n",s_pid);
    }else{
		return -1;
    }
	return 0;
}
int kk_get_pid(char *productId)
{
	strncpy(productId, s_pid, strlen(s_pid));
	printf("kk_get_pid:%s\n",s_pid);
	return strlen(s_pid);
}
static void HAL_Ccuid_version(void)
{
	FILE *fp;

	if(!(fp =  fopen(KK_VERSION_FILE_PATH,"r")))
	{
		ERROR_PRINT("can't open the file tslPath:%s\n",KK_VERSION_FILE_PATH);
		strncpy(s_Version, KK_CCU_VERSION, strlen(KK_CCU_VERSION));
		return ;
	}
	fread(s_Version, 1, VERSION_MAXLEN, fp);
	if(strlen(s_Version) == 0){
		strncpy(s_Version, KK_CCU_VERSION, strlen(KK_CCU_VERSION));
	}
	INFO_PRINT("HAL_Ccuid_version version:%s!!!\n",s_Version);
	fclose(fp);
	return;
}
int HAL_GetVersion(_OU_ char *version)
{
	strncpy(version, s_Version, strlen(s_Version));
	version[strlen(s_Version)] = '\0';
	return strlen(s_Version);
}

int HAL_Get_ccuid(_OU_ char *device_code)
{
    strncpy(device_code, s_ccuid, strlen(s_ccuid));
    printf("HAL_Get_ccuid:%s\n",s_ccuid);
    return strlen(s_ccuid);
}
static int _setDevice_Code(_IN_ char *device_code,int len)
{
    memset(s_ccuid, 0x0, DEVICE_CODE_LEN);
    printf("_setDevice_Code:%s\n",device_code);
    strncpy(s_ccuid, device_code, len);
    return len;
}
static int HAL_Ccuid_init(void)
{
#ifdef CONFIG_A133_PLATFORM
    char data[128] = {0};
    int data_len = 0;
	char uuid[32] = {0};
	char *pstart = NULL;
	char *pEnd = NULL;
    HAL_Execel_cmd(GET_CCUID_CMD,(char *)data,sizeof(data),&data_len);
    printf("GET_CCUID_CMD:%s\n",data);

    if(data_len > 0 && data_len <= 128){
		pstart = data;
		pEnd = strstr(data,"-");
		if(pstart != NULL && pEnd != NULL){
			printf("-------123---------------------\n");
			memcpy(uuid,pstart,pEnd-pstart);
			_setDevice_Code(uuid,pEnd-pstart);
		}else{
        	return -1;
		}
    }else{
        return -1;
    }
#elif CONFIG_8197_PLATFORM
	//_setDevice_Code("CCU_232536",strlen("CCU_232536")+1);
	//return 0;
	char ccuid[DEVICE_CODE_LEN] = {0};
	char ccuidTmp[DEVICE_CODE_LEN] = {0};
    int ccuid_len = 0;
    HAL_Execel_cmd(GET_CCUID_CMD,(char *)ccuid,sizeof(ccuid),&ccuid_len);
    printf("GET_CCUID_CMD:%s\n",ccuid);
    if(ccuid_len > 0 && ccuid_len <= DEVICE_CODE_LEN){
		sprintf(ccuidTmp,"CCU_%s",ccuid);
        _setDevice_Code(ccuidTmp,strlen(ccuidTmp)-1);
    }else{
        //_setDevice_Code(KK_CCU_ID,strlen(KK_CCU_ID));
		return -1;
    }
#else
    char ccuid[DEVICE_CODE_LEN] = {0};
	char ccuidTmp[DEVICE_CODE_LEN] = {0};
    int ccuid_len = 0;
    HAL_Execel_cmd(GET_CCUID_CMD,(char *)ccuid,sizeof(ccuid),&ccuid_len);
    printf("GET_CCUID_CMD:%s\n",ccuid);
    if(ccuid_len > 0 && ccuid_len <= DEVICE_CODE_LEN){
		sprintf(ccuidTmp,"CCU_%s",ccuid);
        _setDevice_Code(ccuidTmp,strlen(ccuidTmp)-1);
    }else{
        //_setDevice_Code(KK_CCU_ID,strlen(KK_CCU_ID));
		return -1;
    }
#endif
	return 0;
}
/************************************************************
*功能描述：过滤不需要下发给网关的消息
*输入参数：msgtype：消息类型
*输出参数：无
*返 回 值：1:过滤；0：不过滤
*其他说明：
*************************************************************/
static int _kk_filter_to_plat(const char* msgtype)
{
	int i = 0,num = 0;
	num = sizeof(g_filerToPlatTable)/sizeof(char *);

	for(i =0; i < num; i++){
		if(strstr(msgtype,g_filerToPlatTable[i]))
		{
			INFO_PRINT("this msg do not send to platform!!!\n");
			return 1;
		}
	}
	return 0;
}
#define KK_PRINTF_PER_LEN 1000
void kk_print_long_data(char *data,int len)
{
	int lenTemp = len;
	int count = 0;
	char *pTmp = NULL;
	pTmp = malloc(KK_PRINTF_PER_LEN+1);
	if(pTmp == NULL){
		return;
	}
	while(1)
	{
		memset(pTmp,0x0,KK_PRINTF_PER_LEN+1);
		if(lenTemp > KK_PRINTF_PER_LEN)
		{
			memcpy(pTmp,data + count,KK_PRINTF_PER_LEN);
			INFO_PRINT("%s \n",pTmp);
			lenTemp -= KK_PRINTF_PER_LEN;
			count += KK_PRINTF_PER_LEN;
		}else{
			memcpy(pTmp,data + count,lenTemp);
			INFO_PRINT("%s \n",pTmp);
			break;
		}
	}
	if(pTmp){
		free(pTmp);
		pTmp = NULL;
	}
}
/************************************************************
*功能描述：向网关发送信息
*输入参数：data：消息内容
          len:消息长度
     	  chalMark：消息通道，一般是网关MAC
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void kk_sendData2gw(void* data, int len, char* chalMark){
	int newLen = 0;
	if (data == NULL || chalMark== NULL || strlen(chalMark) == 0){
		ERROR_PRINT(" chalMark is null");
		return;
	}
	cJSON_Minify((char*)data);
	newLen = strlen(data);
	if (kk_is_tcp_channel(chalMark) > -1){
		kk_tcp_channel_ser_send(data, newLen, chalMark);
	}else{
		kk_ipc_send_ex(IPC_MID2PLAT, data, newLen + 1, chalMark);
	}
	//INFO_PRINT("start to send data to gw srart\n");
	kk_print_long_data(data,newLen);
	//INFO_PRINT("start to send data to gw end\n");
}
void split(char *src,const char *separator,char **dest,int *num) {
    char *pNext;
    int count = 0;
    if (src == NULL || strlen(src) == 0)
        return;
    if (separator == NULL || strlen(separator) == 0)
         return;
    pNext = strtok(src,separator);
    while(pNext != NULL) {
        *dest++ = pNext;
        ++count;
        pNext = strtok(NULL,separator);
    }
    *num = count;
 }


/************************************************************
*功能描述：属性参数校验
*输入参数：payload：消息内容
          deviceCode:设备devieCode
*输出参数：无
*返 回 值： 0:成功；其他：失败
*其他说明：
*************************************************************/
static int kk_property_set_data_check(cJSON * payload,const char *deviceCode){
	cJSON *params = NULL;
	dm_mgr_dev_node_t *node = NULL;
	kk_tsl_data_t *property = NULL;
	cJSON *propertyItem = NULL;
	cJSON *epNum = NULL;
	int epNumInt = 1;
	int num = 0;
	int res = 0;
	int idx = 0;
	int value = 0;
	char *propertiesbuf[64] = {0};
	char propertiesTmp[64] = {0};

	res = dm_mgr_get_device_by_devicecode((char*)deviceCode,&node);
	if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
		return FAIL_RETURN;
	}
	params = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(params != NULL){
		//传感器安防等级设置
		if(strcmp(node->productType ,"sensor") == 0){
			cJSON* sensorType =  cJSON_GetObjectItem(params, "SensorType");
			if(sensorType != NULL){
				int level = sensorType->valueint;
				res = kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,"SensorType",&level,NULL);
				if(res != SUCCESS_RETURN)
				{
					ERROR_PRINT(" error res:%d\n",res);
				}
				char tmpValue[16] = {0};
				sprintf(tmpValue,"%d",level);
				kk_property_db_update_value(deviceCode,"SensorType",tmpValue);
				return SUCCESS_RETURN;
			}
		}
		epNum = cJSON_GetObjectItem(params, "epNum");
		if(epNum != NULL){
			epNumInt = atoi(epNum->valuestring);
		}else{
			epNumInt = 1;
		}
		//printf("----------------->epNumInt:%d\n",epNumInt);
		for(idx = 0; idx < node->dev_shadow->property_number; idx++){
			property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
			if(property == NULL){
				continue;
			}
			//printf("----------------->property->identifier:%s\n",property->identifier);
			memset(propertiesTmp,0x0,sizeof(propertiesTmp));
			memcpy(propertiesTmp,property->identifier,strlen(property->identifier));
			split(propertiesTmp,"_",propertiesbuf,&num);
			if(num == 2){
				if(atoi(propertiesbuf[1]) == epNumInt){
					//printf("----------------->propertiesbuf[0]:%s\n",propertiesbuf[0]);
					propertyItem = cJSON_GetObjectItem(params, propertiesbuf[0]);
					if(propertyItem != NULL){
						//cJSON_AddNumberToObject(params,tmpPS,PowerSwitch->valueint);
						//cJSON_DeleteItemFromObject(params, "PowerSwitch");
						//printf("----------------->property->data_value.type:%d\n",property->data_value.type);
						if(property->data_value.type == KK_TSL_DATA_TYPE_STRUCT){
								kk_tsl_data_value_complex_t *complex_struct = NULL;
								kk_tsl_data_t *current_data = NULL;
								int index;
								complex_struct = property->data_value.value;
								for (index = 0; index < complex_struct->size; index++) {
									current_data = (kk_tsl_data_t *)complex_struct->value + index;
									cJSON *propertyItem_1 = NULL;
									propertyItem_1 = cJSON_GetObjectItem(propertyItem, current_data->identifier);
									if(propertyItem_1 == NULL){
										continue;
									}

									if(current_data->data_value.type != KK_TSL_DATA_TYPE_STRUCT){
										if(current_data->data_value.type == KK_TSL_DATA_TYPE_INT){
											value = propertyItem_1->valueint;
											//if(value < current_data->data_value.mix ||value > current_data->data_value.max ){
												//ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,current_data->data_value.mix,current_data->data_value.max);
												//return INVALID_PARAMETER;
											//}
										}
										else if(current_data->data_value.type == KK_TSL_DATA_TYPE_TEXT){
											//if(strlen(propertyItem_1->valuestring) > current_data->data_value.length ){

												//ERROR_PRINT("ERROR !!!strlen(propertyItem_1->valuestring):%d,current_data->data_value.length:%d\n",strlen(propertyItem_1->valuestring),current_data->data_value.length);
												//return INVALID_PARAMETER;
											//}
										}
									}
									else{
										kk_tsl_data_value_complex_t *complex_struct_1 = NULL;
										kk_tsl_data_t *current_data_1 = NULL;
										int index_1;
										complex_struct_1 = current_data->data_value.value;
										for(index_1 = 0; index_1 < complex_struct_1->size; index_1++){
											current_data_1 = (kk_tsl_data_t *)complex_struct_1->value + index_1;
											cJSON *propertyItem_2 = NULL;
											propertyItem_2 = cJSON_GetObjectItem(propertyItem_1, current_data_1->identifier);
											if(propertyItem_2 == NULL){
												continue;
											}
											if(current_data_1->data_value.type == KK_TSL_DATA_TYPE_INT){
												value = propertyItem_2->valueint;
												//if(value < current_data_1->data_value.mix ||value > current_data_1->data_value.max ){
													//ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,current_data_1->data_value.mix,current_data_1->data_value.max);
													//return INVALID_PARAMETER;
												//}
											}
											else if(current_data_1->data_value.type == KK_TSL_DATA_TYPE_TEXT){
												//if(strlen(propertyItem_2->valuestring) > current_data_1->data_value.length ){

													//ERROR_PRINT("ERROR !!!strlen(propertyItem_2->valuestring):%d,propertyItem_2->data_value.length:%d\n",strlen(propertyItem_2->valuestring),current_data_1->data_value.length);
													//return INVALID_PARAMETER;
												//}
											}
										}

									}
								}
								cJSON_AddItemToObject(params,property->identifier,propertyItem);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
							else if(property->data_value.type == KK_TSL_DATA_TYPE_INT){
								value = propertyItem->valueint;
								//if(value < property->data_value.mix ||value > property->data_value.max ){
									//ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,property->data_value.mix,property->data_value.max);
									//return INVALID_PARAMETER;
								//}
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_INT-------------------\n");
								cJSON_AddNumberToObject(params,property->identifier,propertyItem->valueint);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
							else if(property->data_value.type == KK_TSL_DATA_TYPE_FLOAT || property->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
								value = propertyItem->valuedouble;
								//if(value < property->data_value.mix ||value > property->data_value.max ){
									//ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,property->data_value.mix,property->data_value.max);
									//return INVALID_PARAMETER;
								//}
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_DOUBLE-------------------\n");
								cJSON_AddNumberToObject(params,property->identifier,propertyItem->valuedouble);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
							else if(property->data_value.type == KK_TSL_DATA_TYPE_TEXT){
								//if(strlen(propertyItem->valuestring) > property->data_value.length ){
									//ERROR_PRINT("ERROR !!!strlen(propertyItem->valuestring):%d,property->data_value.length:%d\n",strlen(propertyItem->valuestring),property->data_value.length );
									//return INVALID_PARAMETER;
								//}
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_TEXT-------------------\n");
								cJSON_AddStringToObject(params,property->identifier,propertyItem->valuestring);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
							else if(property->data_value.type == KK_TSL_DATA_TYPE_ENUM || property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_ENUM-------------------\n");
								cJSON_AddNumberToObject(params,property->identifier,propertyItem->valueint);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
					}
				}
			}
			//propertyItem = cJSON_GetObjectItem(params, property->identifier);
			//if(propertyItem != NULL){
				//if(strcmp(property->accessMode,"rw") != 0){
					//ERROR_PRINT("ERROR !!!property->accessMode:%s\n",property->accessMode);
					//return INVALID_PARAMETER;
				//}

			//}

		}
	}
	return SUCCESS_RETURN;

}


#define KK_MOTOR_BIND_INFO_MAX					6

#define KK_SERVICE_REBIND_MOTORS				0
#define KK_SERVICE_ADDBIND_MOTORS				1
#define KK_SERVICE_UNBIND_MOTORS				2

static int kk_panel_bind_motor_delete(const char* deviceCode,int dummyId)
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_node = NULL;
	char msgId[MSG_MAX_LEN] = {0};
	char sceneId[33] = {0};
	char tm[33] = {0};

	cJSON *root = cJSON_CreateObject();
	cJSON *info = cJSON_CreateObject();
	cJSON *payload = cJSON_CreateObject();
	cJSON *paras = cJSON_CreateObject();


	if(SUCCESS_RETURN!=dm_mgr_get_device_by_devicecode((char*)deviceCode,&node)){
		cJSON_Delete(root);
		cJSON_Delete(info);
		cJSON_Delete(payload);
		cJSON_Delete(paras);
		return -1;
	}
	if(SUCCESS_RETURN!=dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node)){
		cJSON_Delete(root);
		cJSON_Delete(info);
		cJSON_Delete(payload);
		cJSON_Delete(paras);		
		return -1;
	}

	cJSON_AddStringToObject(info,"msgtype",KK_THING_SERVICE_DELETESCENC);
	cJSON_AddStringToObject(info,"productCode",gw_node->productCode);
	cJSON_AddStringToObject(info,"deviceCode",gw_node->deviceCode);
	cJSON_AddItemToObject(root, "info", info);

	iotx_report_id(msgId);
	cJSON_AddStringToObject(payload,"msgId",msgId);
	cJSON_AddStringToObject(payload,"version","1.0");
	memset(sceneId,0,sizeof(sceneId));
	snprintf(sceneId,sizeof(sceneId),"%d",dummyId);
	cJSON_AddStringToObject(paras,"sceneId",sceneId);
	cJSON_AddItemToObject(payload, "params", paras);
	snprintf(tm,sizeof(tm),"%ld",time(NULL));
	cJSON_AddStringToObject(payload,"time",tm);
	cJSON_AddStringToObject(payload,"method",KK_THING_METHOD_DELETESCENC);
	cJSON_AddItemToObject(root, "payload", payload);

	char *data = cJSON_Print(root);
	kk_sendData2gw(data,strlen(data), node->fatherDeviceCode);
	cJSON_Delete(root);
	free(data);
//printf("---------------------------->[%s][%d]\n",__FUNCTION__,__LINE__);
	return 0;
}



static int kk_panel_bind_motor_add_actions(const char* deviceCode,cJSON* actions,int dummyId)
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;
	dm_mgr_dev_node_t *gw_node = NULL;
	char msgId[MSG_MAX_LEN] = {0};
	char sceneId[33] = {0};
	char tm[33] = {0};

	cJSON *root = cJSON_CreateObject();
	cJSON *info = cJSON_CreateObject();
	cJSON *payload = cJSON_CreateObject();
	cJSON *paras = cJSON_CreateObject();

	if(SUCCESS_RETURN!=dm_mgr_get_device_by_devicecode((char*)deviceCode,&node)){
		cJSON_Delete(root);
		cJSON_Delete(info);
		cJSON_Delete(payload);
		cJSON_Delete(paras);		
		return -1;
	}
	if(SUCCESS_RETURN!=dm_mgr_get_device_by_devicecode(node->fatherDeviceCode,&gw_node)){
		cJSON_Delete(root);
		cJSON_Delete(info);
		cJSON_Delete(payload);
		cJSON_Delete(paras);		
		return -1;
	}

	cJSON_AddStringToObject(info,"msgtype",KK_THING_SERVICE_ADDSCENC);
	cJSON_AddStringToObject(info,"productCode",gw_node->productCode);
	cJSON_AddStringToObject(info,"deviceCode",gw_node->deviceCode);
	cJSON_AddItemToObject(root, "info", info);

	iotx_report_id(msgId);
	cJSON_AddStringToObject(payload,"msgId",msgId);
	cJSON_AddStringToObject(payload,"version","1.0");
	memset(sceneId,0,sizeof(sceneId));
	snprintf(sceneId,sizeof(sceneId),"%d",dummyId);
	cJSON_AddStringToObject(paras,"sceneId",sceneId);
	cJSON_AddItemToObject(paras, "actions", actions);
	cJSON_AddItemToObject(payload, "params", paras);
	snprintf(tm,sizeof(tm),"%ld",time(NULL));
	cJSON_AddStringToObject(payload,"time",tm);
	cJSON_AddStringToObject(payload,"method",KK_THING_METHOD_ADDSCENC);
	cJSON_AddItemToObject(root, "payload", payload);

	char *data = cJSON_Print(root);
	kk_sendData2gw(data,strlen(data), node->fatherDeviceCode);
	cJSON_Delete(root);
	free(data);

	return 0;
}


static int kk_panel_bind_motor_add(const char* deviceCode,int epNum,int dummyId)
{
	cJSON *item = NULL;

	struct kk_motor_bind_info *info = (struct kk_motor_bind_info *)malloc(sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
	memset(info,0,sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
	int info_size = kk_motor_bind_db_find_ex(dummyId,info,KK_MOTOR_BIND_INFO_MAX);

	cJSON *actionsAry = cJSON_CreateArray();
	item = cJSON_CreateObject();
	cJSON_AddStringToObject(item,"deviceCode",deviceCode);
	cJSON_AddNumberToObject(item,"epNum",epNum);
	cJSON_AddStringToObject(item,"type","action/thing/group");
	cJSON_AddItemToArray(actionsAry,item);
	for(int i=0;i<info_size;i++){
		item = cJSON_CreateObject();
		cJSON_AddStringToObject(item,"deviceCode",info[i].deviceCode);
		cJSON_AddNumberToObject(item,"epNum",info[i].epNum);
		cJSON_AddStringToObject(item,"type","action/thing/group");
		cJSON_AddItemToArray(actionsAry,item);
	}
	kk_panel_bind_motor_add_actions(deviceCode,actionsAry,dummyId);
	free(info);
	return 0;

}
int kk_service_delete_bind_2gw(char *deviceCode,int type)//type 0:panel;1:motor
{
	int info_size = 0;
	int i = 0;
	struct kk_motor_bind_info *info = (struct kk_motor_bind_info *)malloc(sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
	if(info == NULL){
		return -1;
	}
	memset(info,0x0,sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
	if(type == 0){
		//printf("---------------------------->[%s][%d]\n",__FUNCTION__,__LINE__);
		info_size = kk_motor_bind_db_find_byDeviceCode(deviceCode,info,KK_MOTOR_BIND_INFO_MAX);
	}else{
		//printf("---------------------------->[%s][%d]\n",__FUNCTION__,__LINE__);
		info_size = kk_motor_bind_db_find_byMotorDeviceCode(deviceCode,info,KK_MOTOR_BIND_INFO_MAX);
	}
	//printf("-------------------------info_size:%d--->[%s][%d]\n",info_size,__FUNCTION__,__LINE__);
	for(i=0;i<info_size;i++){
		kk_panel_bind_motor_delete(deviceCode,info[i].dummyId);
	}
	free(info);
	info = NULL;
	return 0;
}

int kk_service_panel_bind_motor_handle(cJSON *deviceCode,cJSON *param,cJSON * msgId,int act)
{
	int i;
	int panel_ep = 1,motor_ep = 1;
	int actionCnt;
	cJSON *panel_dCode,*panelEpNum;
	cJSON *motor_dCode,*motorEpNum;
	cJSON *actions,*actionItem;
	const char *motor_dCodeStr = NULL;
	int dummyId = (int)time(NULL);

	if(deviceCode==NULL||param==NULL||msgId==NULL){
		return -1;
	}

	if(deviceCode->type!=cJSON_String||param->type!=cJSON_Object||msgId->type!=cJSON_String){
		return -1;
	}

	panel_dCode = deviceCode;

	if((panelEpNum =  cJSON_GetObjectItem(param,"epNum"))!=NULL){
		if(panelEpNum->type!=cJSON_String){
			INFO_PRINT("[ERR] epNum  \n");
			return -1;
		}else{
			panel_ep = atoi(panelEpNum->valuestring);
		}
	}

	if((actions =  cJSON_GetObjectItem(param,"actions"))==NULL||
		actions->type!=cJSON_Array){
		INFO_PRINT("[ERR] actions \n");
		return -1;
	}

	INFO_PRINT("\n\n\n\n**************************panel bind motor act [%d]**************************************\n\n\n\n",act);

	if(act==KK_SERVICE_REBIND_MOTORS){
		struct kk_motor_bind_info *info = (struct kk_motor_bind_info *)malloc(sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
		memset(info,0x0,sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
		int info_size = kk_motor_bind_db_find(panel_dCode->valuestring,panel_ep,info,KK_MOTOR_BIND_INFO_MAX);
		for(int i=0;i<info_size;i++){
			kk_panel_bind_motor_delete(panel_dCode->valuestring,info[i].dummyId);
		}
		free(info);
		kk_motor_bind_db_delete_ex(panel_dCode->valuestring);

	}


	actionCnt = cJSON_GetArraySize(actions);
	for(i=0;i<actionCnt;i++){
		actionItem = cJSON_GetArrayItem(actions,i);
		if(actionItem==NULL||actionItem->type!=cJSON_Object){
			INFO_PRINT("[ERR] item \n");
			continue;
		}

		motor_dCode = cJSON_GetObjectItem(actionItem,"deviceCode");
		if(motor_dCode==NULL||motor_dCode->type!=cJSON_String){
			INFO_PRINT("[ERR] motor_dCode \n");
			continue;
		}
		if((motorEpNum = cJSON_GetObjectItem(actionItem,"epNum"))!=NULL){
			if(motorEpNum->type!=cJSON_String){
				INFO_PRINT("[ERR] motorEpNum \n");
				continue;
			}else{
				motor_ep = atoi(motorEpNum->valuestring);
			}
		}
		char *ptr = strrchr(motor_dCode->valuestring,'_');
		if(ptr==NULL){
			motor_dCodeStr = motor_dCode->valuestring;
		}else{
			motor_dCodeStr=ptr+1;
		}
		if(act==KK_SERVICE_REBIND_MOTORS||act==KK_SERVICE_ADDBIND_MOTORS){
			dummyId = (int)time(NULL)+i;
			kk_motor_bind_db_insert(panel_dCode->valuestring,panel_ep,motor_dCodeStr,motor_ep,dummyId);
			kk_panel_bind_motor_add(panel_dCode->valuestring,panel_ep,dummyId);
		}else if(act==KK_SERVICE_UNBIND_MOTORS){
			int dummyId=kk_motor_bind_db_find_dummyId(panel_dCode->valuestring,panel_ep,motor_dCodeStr,motor_ep);
			if(dummyId!=-1){
				kk_panel_bind_motor_delete(panel_dCode->valuestring,dummyId);
				kk_motor_bind_db_delete(panel_dCode->valuestring,panel_ep,motor_dCodeStr,motor_ep);
			}

		}
	}

	return 0;
}



int kk_service_query_bind_motor(cJSON *deviceCode,cJSON *param,struct kk_motor_bind_info *info,int max)
{

	int panel_ep = 1;
	int info_size = 0;

	cJSON *panel_dCode,*panelEpNum;

	INFO_PRINT("\n\n\n\n**************************query bind motor**************************************\n\n\n\n");

	if(deviceCode==NULL||deviceCode->type!=cJSON_String){
		return -1;
	}

	panel_dCode = deviceCode;

	if(param!=NULL){
		if(param->type!=cJSON_Object){
			return -1;
		}
		if((panelEpNum =  cJSON_GetObjectItem(param,"epNum"))!=NULL){
			if(panelEpNum->type!=cJSON_String){
				INFO_PRINT("[ERR] panelEpNum \n");
				return -1;
			}else{
				panel_ep = atoi(panelEpNum->valuestring);
			}
		}
	}

	info_size = kk_motor_bind_db_find(panel_dCode->valuestring,panel_ep,info,max);

	return info_size;
}



int kk_dm_device_subdev_filter(char *data)
{
	char *out;
	int res = 0;
	cJSON *json;
	cJSON *info_root;
	cJSON *payload,*typeJson;
	cJSON *deviceCode = NULL;

	if ((json=cJSON_Parse(data)) == NULL) {
		WARNING_PRINT("Error before: [%s]\n","cJSON_Parse");
		return -1;
	}
	if((info_root = cJSON_GetObjectItem(json, "info")) == NULL){
		cJSON_Delete(json);
		return -1;
	}
	if((typeJson = cJSON_GetObjectItem(info_root, "msgtype"))== NULL){
		cJSON_Delete(json);
		return -1;
	}
	if((payload = cJSON_GetObjectItem(json, "payload")) == NULL){
		cJSON_Delete(json);
		return -1;
	}
	if((deviceCode = cJSON_GetObjectItem(info_root, "deviceCode")) == NULL){
		cJSON_Delete(json);
		return -1;
	}

	if(strcmp(typeJson->valuestring,KK_THING_SERVICE_REBIND_MOTORS) == 0){
		INFO_PRINT("REBIND_MOTORS \n");
		cJSON *msgId = cJSON_GetObjectItem(payload, "msgId");
		cJSON *paramStr = cJSON_GetObjectItem(payload,"params");

		kk_service_panel_bind_motor_handle(deviceCode,paramStr,msgId,KK_SERVICE_REBIND_MOTORS);
		kk_service_common_reply(info_root,msgId,KK_THING_SERVICE_REBIND_MOTORS_REPLY,NO_ERROR);
	}
	else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_ADDBIND_MOTOR) == 0){
		INFO_PRINT("ADDBIND_MOTOR \n");

		deviceCode = cJSON_GetObjectItem(info_root, MSG_DEVICE_CODE_STR);
		cJSON *msgId = cJSON_GetObjectItem(payload, MSG_COMMON_MSGID);
		cJSON *paramStr = cJSON_GetObjectItem(payload,MSG_PARAMS_STR);

		kk_service_panel_bind_motor_handle(deviceCode,paramStr,msgId,KK_SERVICE_ADDBIND_MOTORS);
		kk_service_common_reply(info_root,msgId,KK_THING_SERVICE_ADDBIND_MOTOR_REPLY,NO_ERROR);
	}else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_UNBIND_MOTORS) == 0){
		INFO_PRINT("UNBIND_MOTORS \n");

		deviceCode = cJSON_GetObjectItem(info_root, MSG_DEVICE_CODE_STR);
		cJSON *msgId = cJSON_GetObjectItem(payload, MSG_COMMON_MSGID);
		cJSON *paramStr = cJSON_GetObjectItem(payload,MSG_PARAMS_STR);

		kk_service_panel_bind_motor_handle(deviceCode,paramStr,msgId,KK_SERVICE_UNBIND_MOTORS);
		kk_service_common_reply(info_root,msgId,KK_THING_SERVICE_UNBIND_MOTORS_REPLY,NO_ERROR);
	}else if(strcmp(typeJson->valuestring,KK_THING_SERVICE_QUERY_BIND_MOTORS) == 0){
		INFO_PRINT("QUERY_BIND_MOTORS \n");
		cJSON *msgId = cJSON_GetObjectItem(payload, MSG_COMMON_MSGID);
		cJSON *paramStr = cJSON_GetObjectItem(payload,MSG_PARAMS_STR);

		struct kk_motor_bind_info *info = (struct kk_motor_bind_info *)malloc(sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
		if(info == NULL){
			cJSON_Delete(json);
			return -1;
		}
		memset(info,0x0,sizeof(struct kk_motor_bind_info)*KK_MOTOR_BIND_INFO_MAX);
		int info_size = kk_service_query_bind_motor(deviceCode,paramStr,info,KK_MOTOR_BIND_INFO_MAX);

		cJSON *ary = cJSON_CreateArray();
		for(int i=0;i<info_size;i++){
			cJSON *item = cJSON_CreateObject();
			cJSON_AddStringToObject(item,"deviceCode",info[i].deviceCode);
			cJSON_AddNumberToObject(item,"epNum",info[i].epNum);
			cJSON_AddItemToArray(ary,item);
		}
		kk_service_common_reply_ex(info_root,msgId,KK_THING_SERVICE_QUERY_BIND_MOTORS_REPLY,ary);

		free(info);

	}else{
		cJSON_Delete(json);
		return -1;
	}
	cJSON_Delete(json);
	return 0;
}


static int kk_get_ccu_info_reply(cJSON *param,char *msgType)
{
	int res = 0;
	int i = 0,num = 0;
	SensorType_t *pList = NULL;
	char version[VERSION_MAXLEN] = {0};
	if(param == NULL){
		return INVALID_PARAMETER;
	}

	cJSON *info = cJSON_CreateObject();
	cJSON_AddStringToObject(info, MSG_TYPE_STR, msgType);
	char *infff=cJSON_Print(info);
	cJSON *payload = cJSON_CreateObject();

	cJSON_AddItemToObject(payload, "params", param);
	char *payload11=cJSON_Print(payload);
	kk_sendData2app(infff,payload11,0);
	free(payload11);
	free(infff);
	cJSON_Delete(payload);
	cJSON_Delete(info);
	return res;
}

static int _kk_handle_airswitch_property(char *fatherDeviceCode,cJSON *info_root,cJSON *payload)
{
	cJSON *params = NULL;
	cJSON *epNums = NULL;
	cJSON * pSub = NULL;
	char epStr[4] = {0};
	int i = 0;
	if(payload == NULL){
		return INVALID_PARAMETER;
	}
	params = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(params == NULL){
		return FAIL_RETURN;
	}
	epNums = cJSON_GetObjectItem(params, "epNums");
	if(epNums == NULL || epNums->type != cJSON_Array){
		return FAIL_RETURN;
	}
	int  array_size   = cJSON_GetArraySize (epNums);
	for(i = 0; i < array_size; i++){
		memset(epStr,0x0,sizeof(epStr));
		pSub = cJSON_GetArrayItem(epNums, i);
		if(pSub == NULL){continue;}
		sprintf(epStr,"%d",pSub->valueint);
		cJSON * rootData=cJSON_CreateObject();
		cJSON_DeleteItemFromObject(params,"epNums");
		cJSON_DeleteItemFromObject(params,"epNum");
		cJSON_AddStringToObject(params,"epNum",epStr);
		char *info_rootS=cJSON_Print(info_root);
		char *payloadS = cJSON_Print(payload);
		cJSON_AddItemToObject(rootData,MSG_INFO_STR, cJSON_Parse(info_rootS));
		cJSON_AddItemToObject(rootData,MSG_PAYLOAD_STR, cJSON_Parse(payloadS));
		char *pnewout=cJSON_Print(rootData);
		kk_sendData2gw(pnewout, strlen(pnewout), fatherDeviceCode);//send to sub device
		cJSON_Delete(rootData);
		free(info_rootS);
		free(payloadS);
		free(pnewout);
	}
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述：nanomsg数据回调，app to mid
*输入参数：data：从app 层发来的数据
          len: 数据长度
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void mid_cb(void* data, int len){
	if (data != NULL){
		cJSON* payload;
		cJSON *json;
		cJSON *info_root,*type;
		cJSON*deviceCode;
		int res;

		json=cJSON_Parse(data);
		if (!json) {
			ERROR_PRINT("Error before: [%s]\n","cJSON_Parse");
		}else{
			info_root = cJSON_GetObjectItem(json, MSG_INFO_STR);
			if (info_root == NULL){
				ERROR_PRINT(" params [%s] can't find \n",MSG_INFO_STR);
				cJSON_Delete(json);
				return;
			}
			deviceCode = cJSON_GetObjectItem(info_root, MSG_DEVICE_CODE_STR);
			type = cJSON_GetObjectItem(info_root, MSG_TYPE_STR);
			if (deviceCode == NULL || type == NULL){
				ERROR_PRINT(" params [%s] or [%s] can't find \n",MSG_DEVICE_CODE_STR, MSG_TYPE_STR);
				cJSON_Delete(json);
				return;
			}
			payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
			if (payload == NULL){
				ERROR_PRINT(" params [%s] can't find \n",MSG_PAYLOAD_STR);
				cJSON_Delete(json);
				return;
			}

			if (strcmp(type->valuestring, KK_THING_SERVICE_GET_CCU_INFO)==0){
				cJSON *param = dm_mgr_get_ccu_info();
				kk_get_ccu_info_reply(param,KK_THING_SERVICE_GET_CCU_INFO_REPLY);
				cJSON_Delete(json);
				return;
			}
			dm_mgr_dev_node_t *node = NULL;
			res = dm_mgr_get_device_by_devicecode(deviceCode->valuestring,&node);
			if (res != SUCCESS_RETURN) {
				ERROR_PRINT("res:%d\n",res);
				cJSON_Delete(json);
				return;
			}	
			if(node->dev_type  == KK_DM_DEVICE_SUBDEV && node->isOffline == KK_DEV_OFFLINE){
				ERROR_PRINT("do not handle the device is offline:%s\n",deviceCode->valuestring);
				cJSON_Delete(json);
				return;
			}						
			/*****属性设置需要先检测设置参数是否超出物模型给定范围*******/
			if (strcmp(type->valuestring, KK_THING_SERVICE_PROPERTY_SET)==0){
				res = kk_property_set_data_check(payload,deviceCode->valuestring);
				if(res != SUCCESS_RETURN){
					cJSON_Delete(json);
					return;
				}
			}
			if (strcmp(type->valuestring, KK_THING_SERVICE_PROPERTY_GET)==0){
				res = kk_property_get_handle(payload,deviceCode->valuestring,info_root);
				if(res != SUCCESS_RETURN){
					ERROR_PRINT(" kk_property_get_handle error \n");
				}
				cJSON_Delete(json);
				return;
			}

			//主机的device或过滤的
			if(node->dev_type == KK_DM_DEVICE_CCU ||_kk_filter_to_plat(type->valuestring)){
				void* buf = malloc(len);
				memcpy(buf, data, len);
				res = dm_queue_msg_insert((void *)buf);
				if (res != SUCCESS_RETURN) {
					free(buf);
				}
			}else if(node->dev_type  == KK_DM_DEVICE_GATEWAY){
				/*手机端主动删除设备，需要删除数据库相关内容，再下发给网关*/
				if (strcmp(type->valuestring, KK_THING_TOPO_CHANGE_MSG)==0){
					//kk_topo_delete_handle(payload,data);
				}
				kk_sendData2gw(data, strlen(data), deviceCode->valuestring);//send to gw itself
			}else if(node->dev_type  == KK_DM_DEVICE_SUBDEV){			
				if(kk_dm_device_subdev_filter(data)==0){
					ERROR_PRINT("\n\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n");
					//
				}else{
					cJSON * rootData=cJSON_CreateObject();
					char *info_rootS=cJSON_Print(info_root);
					char *payloadS = cJSON_Print(payload);
					cJSON_AddItemToObject(rootData,MSG_INFO_STR, cJSON_Parse(info_rootS));
					cJSON_AddItemToObject(rootData,MSG_PAYLOAD_STR, cJSON_Parse(payloadS));
					char *pnewout=cJSON_Print(rootData);
					kk_sendData2gw(pnewout, strlen(pnewout), node->fatherDeviceCode);//send to sub device
					cJSON_Delete(rootData);
					free(info_rootS);
					free(payloadS);
					free(pnewout);
				}
			}
			else{
				ERROR_PRINT("wrong type\n");
			}
			cJSON_Delete(json);
		}
	}
}

/************************************************************
*功能描述：nanomsg数据回调，从gw  to mid
*输入参数：data：从gw 层发来的数据
          len: 数据长度
          chalMark:网关通道，一般用mac
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void mid2p_cb(void* data, int len, char* chalMark){
	if (data != NULL){
		//printf("mid2plat_cb: %s RECEIVED \r\n", data);
		int res = 0;
		void* buf = NULL;
		dm_queue_msg_t *queue_msg = NULL;
		queue_msg = malloc(sizeof(dm_queue_msg_t));
		if (queue_msg == NULL){
			ERROR_PRINT("mid2p_cb malloc queue_msg failed ");
			return;
		}
		buf = malloc(len);
		if (buf == NULL){
			ERROR_PRINT("mid2p_cb malloc buf failed ");
			return;
		}
		memcpy(buf, data, len);
		queue_msg->data = buf;
		memset(queue_msg->chalMark, 0, sizeof(queue_msg->chalMark));
		if(chalMark != NULL){
			memcpy(queue_msg->chalMark, chalMark, strlen(chalMark));
		}
		res = dm_queue_msg_insert2((void *)queue_msg);
		if (res != SUCCESS_RETURN) {
			free(queue_msg);
			free(buf);
			buf = NULL;
			return ;
		}

		//kk_ipc_send(IPC_MID2APP, data, len);
	}
}

/************************************************************
*功能描述：nanomsg数据回调，从gw  to mid
*输入参数：data：从gw 层发来的数据
          len: 数据长度
          chalMark:网关通道，一般用mac
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void gw2mid_cb(void* data, int len, char* chalMark){
	if (data != NULL){
		printf("gw2mid_cb chalMark=%s, data: %s [%d]RECEIVED \r\n", chalMark, (char*)data,len);
		mid2p_cb(data,len,chalMark);
	}
}
static int _kk_subDevice_property_single_save(cJSON *params,char *deviceCode,int type)
{
	int res = 0;
	int epNumInt = 0;
	dm_mgr_dev_node_t *node = NULL;
	kk_tsl_data_t *property = NULL;
	cJSON *propertyItem = NULL;	
	int idx = 0;	
	res = dm_mgr_get_device_by_devicecode(deviceCode,&node);
	if (res < SUCCESS_RETURN) {
		return FAIL_RETURN;
	}	
	cJSON *epNum = cJSON_GetObjectItem(params, "epNum");
	if(epNum == NULL) return FAIL_RETURN;
	if(epNum->type == cJSON_Number){
		epNumInt = epNum->valueint;
	}else if(epNum->type == cJSON_String){
		epNumInt = atoi(epNum->valuestring);
	}
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		if(property == NULL){
			continue;
		}
		propertyItem = cJSON_GetObjectItem(params, property->identifier);
		if(propertyItem != NULL){
			if(property->data_value.type == KK_TSL_DATA_TYPE_INT ||property->data_value.type == KK_TSL_DATA_TYPE_ENUM
			||property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
				char valBuf[16] = {0};
				int value = propertyItem->valueint;
				sprintf(valBuf,"%d",value);
				if(type == 0){
					kk_indoorAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}else if(type == 1){
					kk_subAirSwitch_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}else if(type == 2){
					kk_subFreshAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}
			}else if(property->data_value.type == KK_TSL_DATA_TYPE_FLOAT || property->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
				char valBuf[16] = {0};
				sprintf(valBuf,"%f",propertyItem->valuedouble);
				if(type == 0){
					kk_indoorAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}else if(type == 1){
					kk_subAirSwitch_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}else if(type == 2){
					kk_subFreshAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}						
			}else if(property->data_value.type == KK_TSL_DATA_TYPE_TEXT ){
				if(type == 0){
					kk_indoorAir_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
				}else if(type == 1){
					kk_subAirSwitch_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
				}else if(type == 2){
					kk_subFreshAir_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
				}					
			}
		}	
	}
	return 0;	
}
static int kk_subDevice_property_save(cJSON *payload,char *deviceCode,int type)
{
	dm_mgr_dev_node_t *node = NULL;
	kk_tsl_data_t *property = NULL;
	cJSON *propertyItem = NULL;
	int res = 0;
	int idx = 0;
	int epNumInt = 0;
	cJSON *params = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(params == NULL) return FAIL_RETURN;
	cJSON *eps = cJSON_GetObjectItem(params, "eps");
	if(eps == NULL || eps->type != cJSON_Array){
		//return FAIL_RETURN;
		return _kk_subDevice_property_single_save(params,deviceCode,type);
	}
	res = dm_mgr_get_device_by_devicecode(deviceCode,&node);
	if (res < SUCCESS_RETURN) {
		return FAIL_RETURN;
	}	
	cJSON *client_list  = eps->child;
	while(client_list != NULL){
		cJSON *epNum = cJSON_GetObjectItem(client_list, "epNum");
		if(epNum == NULL){
			client_list = client_list->next;
		//	printf("-----------------------------------------------------------------------222\n");
			continue;
		}
		if(epNum->type == cJSON_Number){
			epNumInt = epNum->valueint;
		}else if(epNum->type == cJSON_String){
			epNumInt = atoi(epNum->valuestring);
		}
		for(idx = 0; idx < node->dev_shadow->property_number; idx++){
			property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
			if(property == NULL){
				client_list = client_list->next;
				continue;
			}
			propertyItem = cJSON_GetObjectItem(client_list, property->identifier);
			if(propertyItem != NULL){
				if(property->data_value.type == KK_TSL_DATA_TYPE_INT ||property->data_value.type == KK_TSL_DATA_TYPE_ENUM
				||property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
					char valBuf[16] = {0};
					int value = propertyItem->valueint;
					sprintf(valBuf,"%d",value);
					if(type == 0){
						kk_indoorAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
					}else if(type == 1){
						kk_subAirSwitch_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
					}else if(type == 2){
						kk_subFreshAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
					}
				}else if(property->data_value.type == KK_TSL_DATA_TYPE_FLOAT || property->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
					char valBuf[16] = {0};
					sprintf(valBuf,"%f",propertyItem->valuedouble);
					if(type == 0){
						kk_indoorAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
					}else if(type == 1){
						kk_subAirSwitch_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
					}else if(type == 2){
						kk_subFreshAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
					}
				}else if(property->data_value.type == KK_TSL_DATA_TYPE_TEXT ){
					if(type == 0){
						kk_indoorAir_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
					}else if(type == 1){
						kk_subAirSwitch_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
					}else if(type == 2){
						kk_subFreshAir_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
					}
				}
			}

		}
		client_list = client_list->next;
	}
	return 0;
}
/*type : 0,air condition gw;1,air switch gw;2,fresh air switch*/
static int kk_subDevice_property_handle(cJSON *info,cJSON *payload,char *deviceCode,int type)
{
	int snapshot = 0;
	cJSON * jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(jsonPay == NULL){
		return -1;
	}
	cJSON *eps = cJSON_GetObjectItem(jsonPay, "eps");
	if(eps != NULL){
		snapshot = 1;
	}
	kk_subDevice_property_save(payload,deviceCode,type);
	cJSON_AddStringToObject(payload, MSG_DEVICE_CODE_STR, deviceCode);
	char *payload11=cJSON_Print(payload);
	char *infff=cJSON_Print(info);
	kk_sendData2app(infff,payload11,0);
	free(payload11);
	free(infff);
	if(!snapshot){//快照信息不处理
		kk_scene_iftt_check(deviceCode,jsonPay);
	}
	return 0;
}
static int _kk_subDevice_online_to_app(cJSON *info,cJSON *payload)
{
	char ccuid[32] = {0};
	HAL_Get_ccuid(ccuid);
	cJSON *param = cJSON_GetObjectItem(payload, "params");
	if(param == NULL){
		return -1;
	}
	cJSON_AddStringToObject(param, "ccuCode", ccuid);
	char *payload11=cJSON_Print(payload);
	char *infff=cJSON_Print(info);
	kk_sendData2app(infff,payload11,0);
	free(payload11);
	free(infff);
	return 0;
}
static int kk_indoorAir_online_handle(dm_mgr_dev_node_t *node ,char *deviceCode,int epNum)
{
	int idx = 0;
	int gwExist = 0;
	char roomId[32] = {0};
	char roomName[256] = {0};
	char epNumStr[10] = {0};
	kk_tsl_data_t *property = NULL;
	if(node == NULL){
		return -1;
	}
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		if(property == NULL){
			continue;
		}
		kk_indoorAir_db_insert(deviceCode,property->identifier,property->data_value.type,epNum);
	}
	//gwExist = kk_get_device_roomInfo(deviceCode,1,roomName,roomId);//获取网关房间信息
	//if(gwExist){
		//char name[128] = {0};
		//sprintf(name,"空调%d",epNum);
		//sprintf(epNumStr,"%d",epNum);
		//kk_room_dev_add(roomId,roomName,deviceCode,epNumStr,name);

	//}
	return 0;
}
static int kk_subAirSwitch_online_handle(dm_mgr_dev_node_t *node ,char *deviceCode,int epNum)
{
	int idx = 0;
	int gwExist = 0;
	char roomId[32] = {0};
	char roomName[256] = {0};
	char epNumStr[10] = {0};
	kk_tsl_data_t *property = NULL;
	if(node == NULL){
		return -1;
	}
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		if(property == NULL){
			continue;
		}
		kk_subAirSwitch_db_insert(deviceCode,property->identifier,property->data_value.type,epNum);
	}
	//gwExist = kk_get_device_roomInfo(deviceCode,1,roomName,roomId);//获取网关房间信息
	//if(gwExist){
		//char name[128] = {0};
		//sprintf(name,"空开%d",epNum);
		//sprintf(epNumStr,"%d",epNum);
		//kk_room_dev_add(roomId,roomName,deviceCode,epNumStr,name);

	//}
	return 0;
}
static int kk_subFreshair_online_handle(dm_mgr_dev_node_t *node ,char *deviceCode,int epNum)
{
	int idx = 0;
	int gwExist = 0;
	char roomId[32] = {0};
	char roomName[256] = {0};
	char epNumStr[10] = {0};
	kk_tsl_data_t *property = NULL;
	if(node == NULL){
		return -1;
	}
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		if(property == NULL){
			continue;
		}
		kk_subFreshAir_db_insert(deviceCode,property->identifier,property->data_value.type,epNum);
	}
	//gwExist = kk_get_device_roomInfo(deviceCode,1,roomName,roomId);//获取网关房间信息
	//if(gwExist){
		//char name[128] = {0};
		//sprintf(name,"新风%d",epNum);
		//sprintf(epNumStr,"%d",epNum);
		//kk_room_dev_add(roomId,roomName,deviceCode,epNumStr,name);

	//}
	return 0;
}
void kk_platMsg_handle(void* data, char* chalMark){
	int res = 0;
	cJSON *json;
	cJSON *info;
	cJSON *info_dcode;
	cJSON *jsonPay;
	cJSON *msgType;
	cJSON *proCode;
	cJSON *devCode;
	cJSON *mac;
	cJSON *payload;
	cJSON *version;
	char versionBuf[32] = {0};
	json=cJSON_Parse(data);
	if (!json) {
		WARNING_PRINT("Error before: [%s]\n","cJSON_Parse");
	}
	else{
		info = cJSON_GetObjectItem(json, MSG_INFO_STR);
		payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
		if (info == NULL || payload == NULL){
			ERROR_PRINT("info or payload params error\n");
			goto error;
		}
		msgType = cJSON_GetObjectItem(info, MSG_TYPE_STR);
		info_dcode = cJSON_GetObjectItem(info, MSG_DEVICE_CODE_STR);
		if (msgType == NULL || info_dcode == NULL){
			ERROR_PRINT("msgType info_dcode or jsonPay params are error\n");
			goto error;
		}

		//if (chalMark != NULL){
			//if(strcmp(msgType->valuestring,"/thing/service/property/set_reply") != 0){
				//dm_mgr_update_timestamp_by_devicecode(chalMark,HAL_Uptimes());
			//}
		//}
		//printf("msgType->valuestring:%s [%s][%d]\n",msgType->valuestring,__FUNCTION__,__LINE__);
		if(strcmp(msgType->valuestring,"/thing/service/property/get_reply") != 0 &&
				strcmp(msgType->valuestring,"/thing/service/property/set_reply") != 0){
			dm_mgr_update_timestamp_by_devicecode(info_dcode->valuestring,HAL_Uptimes());
		}

		if (strcmp(msgType->valuestring, KK_THING_TOPO_ADD_MSG)==0){
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			proCode = cJSON_GetObjectItem(jsonPay, MSG_PRODUCT_CODE_STR);
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			mac = cJSON_GetObjectItem(jsonPay, "mac");
			if (proCode == NULL || devCode == NULL || mac == NULL){
				ERROR_PRINT("productCode, deviceCode mac params are error\n");
				goto error;
			}
			version = cJSON_GetObjectItem(jsonPay, "version");
			if(version != NULL ){
				memcpy(versionBuf,version->valuestring,strlen(version->valuestring));
			}else{
				memcpy(versionBuf,"1.1.0",strlen("1.1.0"));
			}
			INFO_PRINT("deviceCode productCode mac: [%s][%s] [%s] \n",devCode->valuestring, proCode->valuestring, mac->valuestring);
			//判断网关还是子设备
			if (strcmp(info_dcode->valuestring, devCode->valuestring) == 0){
				char ccu_deviceCode[DEVICE_CODE_MAXLEN] = {0};
				HAL_Get_ccuid(ccu_deviceCode);
				kk_mid_subdev_add(KK_DM_DEVICE_GATEWAY,proCode->valuestring,devCode->valuestring, mac->valuestring,ccu_deviceCode,versionBuf);
				cJSON * sceneSupportStr = cJSON_GetObjectItem(jsonPay, MSG_SCENE_SUPPORT);
				if(sceneSupportStr != NULL&&!strcmp(sceneSupportStr->valuestring,"1")){
					kk_subDev_update_sceneSupport(1,devCode->valuestring);
				}
				kk_dm_gw_status_update_online(info_dcode->valuestring);
			}else{
				kk_mid_subdev_add(KK_DM_DEVICE_SUBDEV,proCode->valuestring,devCode->valuestring, mac->valuestring,info_dcode->valuestring,versionBuf);
			}
			dm_mgr_update_timestamp_by_devicecode(devCode->valuestring,HAL_Uptimes());
		}
		else if (strstr(msgType->valuestring, KK_THING_STATUS_ONLINE) != NULL){//空调内机上报处理
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			dm_mgr_dev_node_t *search_node = NULL;
			res = dm_mgr_get_device_by_devicecode(devCode->valuestring,&search_node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			if(strcmp(search_node->productType,KK_DM_AIR_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_indoorAir_online_handle(search_node,devCode->valuestring,epNumJson->valueint);
				_kk_subDevice_online_to_app(info,payload);
			}else if(strcmp(search_node->productType,KK_DM_AIR_SWITCH_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_subAirSwitch_online_handle(search_node,devCode->valuestring,epNumJson->valueint);
				_kk_subDevice_online_to_app(info,payload);
			}else if(strcmp(search_node->productType,KK_DM_FRESHAIR_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_subFreshair_online_handle(search_node,devCode->valuestring,epNumJson->valueint);
				_kk_subDevice_online_to_app(info,payload);
			}
		}
		else if (strstr(msgType->valuestring, KK_THING_STATUS_OFFLINE) != NULL){//空调内机上报处理
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			dm_mgr_dev_node_t *search_node = NULL;
			res = dm_mgr_get_device_by_devicecode(devCode->valuestring,&search_node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			if(strcmp(search_node->productType,KK_DM_AIR_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_indoorAir_db_update_online((char*)search_node->deviceCode,0,epNumJson->valueint);
				_kk_subDevice_online_to_app(info,payload);
			}else if(strcmp(search_node->productType,KK_DM_AIR_SWITCH_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_subAirSwitch_db_update_online((char*)search_node->deviceCode,0,epNumJson->valueint);
				_kk_subDevice_online_to_app(info,payload);
			}else if(strcmp(search_node->productType,KK_DM_FRESHAIR_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_subFreshAir_db_update_online((char*)search_node->deviceCode,0,epNumJson->valueint);
				_kk_subDevice_online_to_app(info,payload);
			}
		}
		else if (strstr(msgType->valuestring, KK_THING_TOPO_BATCH_ADD_MSG) != NULL){
			kk_ipc_send(IPC_MID2APP,data,strlen(data));
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			cJSON *devices = cJSON_GetObjectItem(jsonPay, MSG_TOPO_CHANGE_DEVICES_STR);
			if(devices == NULL) goto error;
			cJSON * item = devices->child;
			while(item != NULL){
				char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
				char *productCode = cJSON_GetObjectItem(item,MSG_PRODUCT_CODE_STR)->valuestring;
				char *mac_s = cJSON_GetObjectItem(item,MSG_DEVICE_MAC)->valuestring;
				char *fatherMac = cJSON_GetObjectItem(item,MSG_DEVICE_PARENTCODE)->valuestring;
				version = cJSON_GetObjectItem(item, "version");
				if(version != NULL ){
					memcpy(versionBuf,version->valuestring,strlen(version->valuestring));
				}else{
					memcpy(versionBuf,"1.1.0",strlen("1.1.0"));
				}
				kk_mid_subdev_batch_add(productCode,deviceCode,mac_s,fatherMac,versionBuf);
				item = item->next;
			}
		}else if (strstr(msgType->valuestring, KK_THING_PROPERTY_POST) != NULL){
			INFO_PRINT("save property and send to cloud \n");
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			dm_mgr_dev_node_t *search_node = NULL;
			res = dm_mgr_get_device_by_devicecode(info_dcode->valuestring,&search_node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			if(search_node->isOffline){
				/*如果是离线状态，上报在线给云端*/
				dm_mgr_set_dev_onoffline(search_node,0);
			}
			if(strcmp(search_node->productType ,KK_DM_AIR_GATEWAY_TYPE) == 0){
				kk_subDevice_property_handle(info,payload,info_dcode->valuestring,0);
			}else if(strcmp(search_node->productType ,KK_DM_AIR_SWITCH_GATEWAY_TYPE) == 0){
				kk_subDevice_property_handle(info,payload,info_dcode->valuestring,1);
			}else if(strcmp(search_node->productType ,KK_DM_FRESHAIR_GATEWAY_TYPE) == 0){
				kk_subDevice_property_handle(info,payload,info_dcode->valuestring,2);
			}
			else{
				/*插座类设备保存功率历史记录*/
				//if(strcmp(search_node->productType ,"outlet") == 0){
					//cJSON *power = cJSON_GetObjectItem(jsonPay,"Power");
					//if(power != NULL){
						//char buf[16] = {0};
						//sprintf(buf,"%f",power->valuedouble);
						//kk_history_insert_Outlet_info(info_dcode->valuestring,buf,"",HAL_GetTime());
					//}
				//}
				char* outstr = cJSON_Print(payload);
				kk_tsl_property_set_by_shadow(search_node->dev_shadow, outstr, strlen(outstr)+1);
				proCode = cJSON_GetObjectItem(info, MSG_PRODUCT_CODE_STR);
				dm_msg_thing_property_post_by_identify(proCode->valuestring,info_dcode->valuestring,jsonPay);
				//如果带version，代表的是快照信息，快照信息不需要触发iftt
				cJSON *version = cJSON_GetObjectItem(jsonPay, "version");
				if(version == NULL && is_BodySensor_dev(proCode->valuestring)==0){
					kk_scene_iftt_check(info_dcode->valuestring,jsonPay);
				}
				free(outstr);
			}
		}else if(strstr(msgType->valuestring, KK_THING_TOPO_DELETE_MSG) != NULL){
			dm_mgr_dev_node_t *node = NULL;
			INFO_PRINT("kk_platMsg_handle data: handle delete\n");
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			res = dm_mgr_get_device_by_devicecode(devCode->valuestring,&node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			dm_mgr_update_timestamp_by_devicecode(node->deviceCode,0);
			dm_mgr_set_dev_onoffline(node,1);
			kk_delete_LockUser_info((const char*)node->deviceCode);
			//kk_ipc_send(IPC_MID2APP,data,strlen(data)+1);
			//dm_mgr_subdev_delete(devCode->valuestring);

		}else if(strstr(msgType->valuestring, KK_THING_EVENT_MESSAGE) != NULL && \
			strstr(msgType->valuestring, KK_THING_EVENT_POST) != NULL){
			dm_mgr_dev_node_t *node = NULL;
			int idx = 0;
			kk_tsl_event_t *eventItem =NULL;
			char tmpStr[128] = {0};
			char valueBuf[32] = {0};
			cJSON * itemStr = NULL;
			int sensorDev = 0;
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			res = dm_mgr_get_device_by_devicecode(info_dcode->valuestring,&node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			if(node->isOffline){
				/*如果是离线状态，上报在线给云端*/
				dm_mgr_set_dev_onoffline(node,0);
			}
			/*如果是传感器类设备，事件上报的同时需要记录数据到数据库*/
			if(strcmp(node->productType ,"sensor" ) == 0 || 
				strcmp(node->productType ,"Doorlock" ) == 0 ||
				strcmp(node->productType ,"siren" ) == 0){
				sensorDev = 1;
			}
			if(strcmp(msgType->valuestring, "/thing/event/SceneRecall/post") == 0){
				char btnId[16] = {0};
				cJSON *buttonId = cJSON_GetObjectItem(jsonPay, "SceneNum");
				if(buttonId == NULL || buttonId->type != cJSON_Number){
					ERROR_PRINT("DATA ERROR!!!\n");
					goto error;
				}	
				sprintf(btnId,"%d",buttonId->valueint);
				kk_scene_execute_quickpanel(btnId,info_dcode->valuestring);				
			}
			INFO_PRINT("-------------------kk_platMsg_handle event post enters:%s \n",msgType->valuestring);
			for(idx = 0; idx < node->dev_shadow->event_number; idx++){
				eventItem = node->dev_shadow->events + idx;
				if(eventItem != NULL){
					if(eventItem->identifier==NULL){
						INFO_PRINT("eventItem->identifier = NULL\n");
						continue ;
					}

					if(strcmp(eventItem->identifier,MSG_PROPERTY_STR) != 0 &&
						eventItem->output_data_number > 0){
						int index = 0;
						kk_tsl_data_t *itemData = NULL;
						if(strstr(msgType->valuestring, eventItem->identifier) == NULL){
							continue ;
						}
						//门锁特殊处理,打包事件上报
						int pack = 0;
						if(strcmp(eventItem->identifier,"LockOpenNotification") == 0 ||
							strcmp(eventItem->identifier,"KeyAddNotification") == 0 ||
							strcmp(eventItem->identifier,"KeyDeletedNotification") == 0 ){
							pack = 1;
						}
						for(index = 0; index < eventItem->output_data_number;index++){
							itemStr = cJSON_GetObjectItem(jsonPay, eventItem->identifier);
							itemData = eventItem->output_datas + index;
							cJSON * itemDataIdentifier = cJSON_GetObjectItem(jsonPay, itemData->identifier);
							if(itemDataIdentifier != NULL){
								memset(tmpStr,0x0,sizeof(tmpStr));
								sprintf(tmpStr,"%s.%s",eventItem->identifier,itemData->identifier);
								if(itemData->data_value.type == KK_TSL_DATA_TYPE_INT||
									itemData->data_value.type == KK_TSL_DATA_TYPE_ENUM||
									itemData->data_value.type == KK_TSL_DATA_TYPE_BOOL){
									sprintf(valueBuf,"%d",itemDataIdentifier->valueint);
									kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,tmpStr,&itemDataIdentifier->valueint,NULL);
								}
								else if(itemData->data_value.type == KK_TSL_DATA_TYPE_FLOAT ||
									itemData->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
									sprintf(valueBuf,"%f",itemDataIdentifier->valuedouble);
									kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,tmpStr,&itemDataIdentifier->valuedouble,NULL);

								}
								else if(itemData->data_value.type == KK_TSL_DATA_TYPE_TEXT ||
									itemData->data_value.type == KK_TSL_DATA_TYPE_DATE){
									sprintf(valueBuf,"%s",itemDataIdentifier->valuestring);
									kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,tmpStr,NULL,itemDataIdentifier->valuestring);
								}
								if(sensorDev){
									kk_alarm_notify_handle(node,itemData->identifier,valueBuf,eventItem->identifier);//告警信息处理
								}
								if(pack==0){
									INFO_PRINT("kk_platMsg_handle data: event post,eventItem->identifier:%s\n",eventItem->identifier);
									if(strcmp(eventItem->identifier,"TamperAlarm") == 0 || strcmp(eventItem->identifier,"sirenAlarm") == 0){//TamperAlarm不需要上报，否则APP显示会有问题
										
									}else{
										dm_msg_thing_event_post(info_dcode->valuestring,eventItem->identifier,NULL);
									}
									kk_scene_iftt_check(info_dcode->valuestring,jsonPay);
								}
							}
						}
						if(pack==1){
							INFO_PRINT("kk_platMsg_handle data: event pack post\n");
							dm_msg_thing_event_post(info_dcode->valuestring,eventItem->identifier,NULL);
							if(strcmp(eventItem->identifier,"KeyAddNotification") == 0){
								char KeyTypeBuf[8] = {0};
								char KeyRoleBuf[8] = {0};
								cJSON * keyId = cJSON_GetObjectItem(jsonPay, "KeyID");
								cJSON * KeyRole = cJSON_GetObjectItem(jsonPay, "KeyRole");
								cJSON * KeyType = cJSON_GetObjectItem(jsonPay, "KeyType");
								if(keyId != NULL && KeyRole != NULL && KeyType != NULL){
									if(KeyType->type == cJSON_Number){
										sprintf(KeyTypeBuf,"%d",KeyType->valueint);
									}
									if(KeyRole->type == cJSON_Number){
										sprintf(KeyRoleBuf,"%d",KeyRole->valueint);
									}
									kk_LockUser_insert_db(keyId->valuestring,KeyTypeBuf,KeyRoleBuf,"",info_dcode->valuestring);
								}
							}
							if(strcmp(eventItem->identifier,"KeyDeletedNotification") == 0)
							{
								cJSON * keyId = cJSON_GetObjectItem(jsonPay, "KeyID");
								if(keyId != NULL){
									kk_delete_LockUser_info_byId(keyId->valuestring);
								}
							}
							if(strcmp(eventItem->identifier,"LockOpenNotification") == 0){
								kk_scene_iftt_check(info_dcode->valuestring,jsonPay);
							}
						}
					}
					else if(strcmp(eventItem->identifier,MSG_PROPERTY_STR) != 0 &&
						eventItem->output_data_number == 0){
						if(strstr(msgType->valuestring, eventItem->identifier) == NULL){
							continue ;
						}
						if(strcmp(eventItem->identifier,"DoorBell") != 0){//门铃事件不处理;	
							dm_msg_thing_event_post(info_dcode->valuestring,eventItem->identifier,NULL);
						}

					}
				}
			}
		}
		else if(strstr(msgType->valuestring, KK_THING_TOPO_BATCH_DELETE_MSG) != NULL){
			kk_ipc_send(IPC_MID2APP,data,strlen(data));
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			cJSON *devices = cJSON_GetObjectItem(jsonPay, MSG_TOPO_CHANGE_DEVICES_STR);
			cJSON * item = devices->child;
			while(item != NULL){
				char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
				dm_mgr_subdev_delete(deviceCode);
				item = item->next;
			}

		}
		else if(strstr(msgType->valuestring, KK_THING_SERVICE_PROPERTY_GET_REPLY) != NULL){
			INFO_PRINT("kk_platMsg_handle data: KK_THING_SERVICE_PROPERTY_GET_REPLY\n");
			int res = 0;
			dm_mgr_dev_node_t *node = NULL;
			res = dm_mgr_get_device_by_devicecode(info_dcode->valuestring,&node);
			if (res != SUCCESS_RETURN) {
				ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
				goto error;
			}
			/*开机先获取网关属性，网关返回relay，置网关状态在线*/
			if(node->dev_type == KK_DM_DEVICE_GATEWAY){
				kk_dm_gw_status_update_online(info_dcode->valuestring);
				if(node->isOffline){
					/*如果是离线状态，上报在线给云端*/
					dm_mgr_set_dev_onoffline(node,0);
				}
			}
		}
		else{
			INFO_PRINT("kk_platMsg_handle data: don't handle it\n");
		}
	error:
		cJSON_Delete(json);
	}
}

/************************************************************
*功能描述：从gw接收消息任务
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void kk_platMsg_dispatch(void)
{
	int count = 0;
	void *data = NULL;

	while (CONFIG_DISPATCH_QUEUE_MAXLEN == 0 || count++ < CONFIG_DISPATCH_QUEUE_MAXLEN) {
		if (dm_queue_msg_next2(&data) == SUCCESS_RETURN) {
			dm_queue_msg_t *msg = (dm_queue_msg_t *)data;
			//INFO_PRINT("kk_handle_platMsg_dispatch get call \n");
			kk_platMsg_handle(msg->data,(char*)msg->chalMark);
			if (msg->data != NULL){
				free(msg->data);
			}
			free(data);
			data = NULL;
		} else {
			break;
		}
	}
}


typedef struct {
    int auto_add_subdev;
    int master_devid;
    int cloud_connected;
    int master_initialized;
    int subdev_index;
    int permit_join;
	void *g_mid_dispatch_thread;
    void *g_ota_dispatch_thread;
    void *g_ccuProChg_dispatch_thread;
	void *g_udp_dispatch_thread;
	int g_mid_dispatch_thread_running;
    int g_ota_dispatch_thread_running;
	int g_ccuProChg_dispatch_thread_running;
	int g_udp_dispatch_thread_running;
} mid_ctx_t;
#define MID_YIELD_TIMEOUT_MS (200)


static mid_ctx_t g_mid_ctx;

static mid_ctx_t *kk_mid_get_ctx(void)
{
	return &g_mid_ctx;
}

extern void IOT_Linkkit_Yield(int timeout_ms);

/************************************************************
*功能描述：从app接收消息任务
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *mid_dispatch_yield(void *args)
{
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();

	while (mid_ctx->g_mid_dispatch_thread_running) {
		IOT_Linkkit_Yield(MID_YIELD_TIMEOUT_MS);
	}

	return NULL;
}
/************************************************************
*功能描述：接收OTA消息任务
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *ota_dispatch_yield(void *args)
{
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();

	while (mid_ctx->g_ota_dispatch_thread_running) {
		dm_ota_yield(MID_YIELD_TIMEOUT_MS);
	}

	return NULL;
}


#define UDP_LAN_PORT 25556
#define UDP_LAN_PORT_HOST 25555
#define test_
/************************************************************
*功能描述：网关发现server
*输入参数：args:传入参数
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *udp_dispatch_yield(void *args){
	INFO_PRINT("udp_dispatch_yield udp thread create\n");

	// 绑定地址
	struct sockaddr_in addrto;
	bzero(&addrto, sizeof(struct sockaddr_in));
	addrto.sin_family = AF_INET;
	addrto.sin_addr.s_addr = htonl(INADDR_ANY);
	addrto.sin_port = htons(UDP_LAN_PORT);

	// 发送地址
	struct sockaddr_in addrto_host;
	bzero(&addrto_host, sizeof(struct sockaddr_in));
	addrto_host.sin_family = AF_INET;
	addrto_host.sin_addr.s_addr = htonl(INADDR_ANY);
	//addrto_host.sin_port = htons(UDP_LAN_PORT);

	// 接收到的广播地址
	struct sockaddr_in from;
	bzero(&from, sizeof(struct sockaddr_in));


	int sock = -1;
	int sock_host = -1;
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		ERROR_PRINT("socket error\n");
	}

	if ((sock_host = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		ERROR_PRINT("socket error\n");
	}

	if(bind(sock,(struct sockaddr *)&(addrto), sizeof(struct sockaddr_in)) == -1)
	{
		ERROR_PRINT("bind error...\n");
	}

	socklen_t len = sizeof(struct sockaddr_in);
	char szOut[128] = {0};
	char szDec[1024] = {0};
	char host_ip[32] = {0};
	char mac[32] = {0};
	char device_code[DEVICE_CODE_LEN] = {0};
	kk_prop_raw_struct_t ipList[10] = {0};
	int idx = 0;

	kk_property_db_get_rawdata("IPAddress",4, ipList, sizeof(ipList));
	for(; idx < 10; idx++){
		//DEBUG_PRINT("ipList[%d][%s][%s] \n", idx, ipList[idx].deviceCode, ipList[idx].raw);
		if (strlen(ipList[idx].deviceCode)>0 && strlen(ipList[idx].raw)>0){
			kk_set_tcp_channel_by_idx(idx, ipList[idx].deviceCode, ipList[idx].raw);
		}
	}
	kk_TCP_channel_init(gw2mid_cb);

	while(1)
	{
		//从广播地址接受消息
		memset(szDec, 0 , sizeof(szDec));
		int size=recvfrom(sock, szDec, sizeof(szDec), 0, (struct sockaddr*)&from,(socklen_t*)&len);
		if(size<=0)
		{
			WARNING_PRINT("read error....\n");
		}
		else
		{
			DEBUG_PRINT("lan recmsg: %s\n", szDec);
			//DEBUG_PRINT("udp client ip:%s ,port is :%d htons(UDP_LAN_PORT)=%d \n",inet_ntoa(from.sin_addr),from.sin_port, htons(UDP_LAN_PORT));
			//"search_kk_ccu|deviceCode=1122334455667788;protocol=tcp"
			if(strstr(szDec, "search_kk_ccu|") != NULL){
				char* getConnet = szDec + strlen("search_kk_ccu|");
				char* tmp = NULL;
				char* endIdx = NULL;
				int itemLen = 0;
				int itemConnetLen = 0;
				char gwDevCode[DEVICE_CODE_LEN] = {0};
				char proto[10] = {0};
				char portStr[10] = {0};

				tmp = strstr(getConnet, "deviceCode=");
				itemLen = strlen("deviceCode=");
				if (tmp != NULL){
					endIdx = strstr(tmp, ";");
					if(endIdx == NULL){
						itemConnetLen = strlen(tmp) - itemLen;
					}else{
						itemConnetLen = endIdx - tmp - itemLen;
					}
					memcpy(gwDevCode, tmp + itemLen,itemConnetLen);
				}

				tmp = strstr(getConnet, "protocol=");
				itemLen = strlen("protocol=");
				if (tmp != NULL){
					endIdx = strstr(tmp, ";");
					if(endIdx == NULL){
						itemConnetLen = strlen(tmp) - itemLen;
					}else{
						itemConnetLen = endIdx - tmp - itemLen;
					}
					memcpy(proto, tmp + itemLen,itemConnetLen);
				}

				tmp = strstr(getConnet, "port=");
				itemLen = strlen("port=");
				if (tmp != NULL){
					endIdx = strstr(tmp, ";");
					if(endIdx == NULL){
						itemConnetLen = strlen(tmp) - itemLen;
					}else{
						itemConnetLen = endIdx - tmp - itemLen;
					}
					memcpy(portStr, tmp + itemLen,itemConnetLen);
				}

				DEBUG_PRINT("gwDevCode =%s proto=%s portStr=%s \n",gwDevCode,proto,portStr);
				if(strcmp(proto,"tcp") == 0){
					//
					kk_set_tcp_channel(gwDevCode,inet_ntoa(from.sin_addr));
				}

				memset(host_ip, 0, sizeof(host_ip));
				memset(mac, 0, sizeof(mac));
				memset(szOut, 0, sizeof(szOut));
				HAL_Get_IP(host_ip,NULL);
				HAL_Get_ccuid(device_code);
			//	printf("[%s][%d]inet_ntoa(from.sin_addr):%s\n",__FUNCTION__,__LINE__,inet_ntoa(from.sin_addr));
			//	printf("[%s][%d]host_ip:%s\n",__FUNCTION__,__LINE__,host_ip);
			//	if(strcmp(inet_ntoa(from.sin_addr),host_ip) == 0){



				sprintf(szOut,"search_kk_ccu_ack|deviceCode=%s;ip=%s;port=%d",device_code,host_ip,16565);
				DEBUG_PRINT("szOut:%s\n",szOut);
				DEBUG_PRINT("udp client ip:%s ,port is :%d \n",inet_ntoa(from.sin_addr),from.sin_port);
				//sendto(sock, szOut, strlen(szOut), 0, (struct sockaddr*)&from,len);

				addrto_host.sin_addr.s_addr = inet_addr(inet_ntoa(from.sin_addr));
				if(strlen(portStr) > 0){
					addrto_host.sin_port = htons(atoi(portStr));
				}else{
					addrto_host.sin_port = htons(UDP_LAN_PORT_HOST);
				}
				//addrto_host.sin_port = from.sin_port;
				//if(strcmp(host_ip,inet_ntoa(from.sin_addr)) == 0)
				//{
					sendto(sock_host, szOut, strlen(szOut), 0, (struct sockaddr*)&addrto_host,sizeof(addrto_host));
				//}
				//else
				//{
				//    DEBUG_PRINT("udp client is not local ip  , refused send ack to it\n");
				//}
			//	}
			}
		}
		usleep(100000);
	}

	close(sock);
	close(sock_host);
}
/************************************************************
*功能描述：主机IP后台检测任务，如IP有变化，上报消息给云端
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *ccu_property_monitor(void *args)
{
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();
 	char s_IP[NETWORK_ADDR_LEN];
	char s_IP_TSL[NETWORK_ADDR_LEN] = {0};
	int res = 0;
	int needReport  = 0;
	int time_second = 60;
	dm_mgr_dev_node_t *node = NULL;


	while (mid_ctx->g_ccuProChg_dispatch_thread_running) {
		if(kk_get_cloud_recv_status() == 0){
			iotx_dm_ccu_cloud_check();
			sleep(10);
			continue;
		}
		dm_mgr_search_dev_by_devid(KK_DM_DEVICE_CCU_DEVICEID,&node);
		//dm_mgr_update_timestamp_by_devicecode(node->deviceCode,HAL_GetTime());
		node->timestamp = HAL_Uptimes();
		HAL_Get_IP(s_IP,NULL);
		res = kk_tsl_get_value(kk_tsl_get_property_value,node->dev_shadow,KK_TSL_CCU_WANIP_IDENTIFIER,s_IP_TSL,NULL);
		if(res != SUCCESS_RETURN){
			ERROR_PRINT("kk_tsl_get_value Failed\n");
		}
		else{
			if(strcmp(s_IP,s_IP_TSL)){
				kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,KK_TSL_CCU_WANIP_IDENTIFIER,NULL,s_IP);
				kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,KK_TSL_CCU_LANIP_IDENTIFIER,NULL,s_IP);
				INFO_PRINT("current ip:%s,before ip:%s\n",s_IP,s_IP_TSL);
				kk_property_db_update(node->deviceCode);
			}
		}
		char *postStr = kk_tsl_get_post_property_str(node->dev_shadow,NULL);
		if(postStr != NULL){
			dm_mgr_upstream_thing_property_post(node->devid, postStr, strlen(postStr),0);
			free(postStr);
			postStr = NULL;
		}
		//iotx_dm_ccu_cloudHB_check();
		sleep(time_second);
	}
	return NULL;
}
sqlite3 *g_kk_pDb;


/************************************************************
*功能描述：主机数据库句柄创建
*输入参数：无
*输出参数：无
*返 回 值： 0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_sqlite_init(void)
{
	if (sqlite3_open_v2(KK_DB_FILE, &g_kk_pDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK)
	{
		ERROR_PRINT("Error initialising linkage database fail!!!\n");
		return FAIL_RETURN;
	}
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述：设置主机存储路径
*输入参数：存储path
*输出参数：int
*返 回 值： 0：成功；其他：失败
*其他说明：
*************************************************************/
#ifdef CONFIG_NDK
static int setStoragePath(char* path){
	if (path == NULL){
		ERROR_PRINT("[%s] path is null !!!!!!!!!!!\n", __FUNCTION__);
		return -1;
	}

	sprintf(KK_DEVICESECRET_PATH, "%s/%s", path, KK_DEVICESECRET_PATH_SUB);
	sprintf(KK_TOKEN_PATH, "%s/%s", path, KK_TOKEN_PATH_SUB);
	sprintf(KK_DEVICE_MAP_FILE_PATH, "%s/%s", path, KK_DEVICE_MAP_FILE_PATH_SUB);
	sprintf(KK_DB_FILE, "%s/%s", path, KK_DB_FILE_SUB);
	sprintf(KK_LAN_NODE_DB_FILE, "%s/%s", path, KK_LAN_NODE_DB_FILE_SUB);
	sprintf(TSL_SUBDEVICE_PATH_FILE, "%s/%s", path, TSL_SUBDEVICE_PATH_FILE_SUB);
	sprintf(TSL_GATEWAY_PATH_FILE, "%s/%s", path, TSL_GATEWAY_PATH_FILE_SUB);
	sprintf(TSL_CCU_PATH_FILE, "%s/%s", path, TSL_CCU_PATH_FILE_SUB);
	sprintf(TSL_SCENE_PATH_FILE, "%s/%s", path, TSL_SCENE_PATH_FILE_SUB);
	sprintf(OTA_IMG_PATH, "%s/%s", path, OTA_IMG_PATH_SUB);
	sprintf(OTA_IMG_FILE, "%s/%s", path, OTA_IMG_FILE_SUB);
	sprintf(OTA_IMG_FILE_MD5, "%s/%s", path, OTA_IMG_FILE_MD5_SUB);

	sprintf(KK_CONFIG_FILE_PATH, "%s/%s", path, KK_CONFIG_FILE_PATH_SUB);
#ifdef CONFIG_A133_PLATFORM
	sprintf(KK_DEFAULT_CONFIG_FILE_PATH, "%s/%s", path, KK_DEFAULT_CONFIG_FILE_PATH_SUB);
	sprintf(KK_AUTH_CONFIG_FILE_PATH, "%s/%s", path, KK_AUTH_CONFIG_FILE_PATH_SUB);
	sprintf(KK_VERSION_FILE_PATH, "%s/%s", path, KK_VERSION_FILE_PATH_SUB);
#endif

	kk_set_storage_dir(path);

	return 0;
}

#endif
/************************************************************
*功能描述：midware 主任务
*输入参数：argc：参数个数
           argv：参数内容
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
#ifdef CONFIG_NDK
int mid_main(char* path)
#else
int main(const int argc, const char **argv)
#endif
{
	int res = 0;
	//char *tsl_str;
	//int i;
	//kk_tsl_t *dev_shadow[30] = {NULL};
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();
	openlog("midware",LOG_PID,LOG_USER);
	memset(mid_ctx, 0, sizeof(mid_ctx_t));
#ifdef CONFIG_NDK
	setStoragePath(path);
#endif
	HAL_Ccuid_version();
	kk_pid_init();
	res = HAL_Ccuid_init();
	if(res == -1){
		ERROR_PRINT("CCUID GET FAIL!!!!!!!!!!!\n");
		return -1;
	}
	kk_sqlite_init();
	kk_tsl_api_init();
	kk_ipc_init(IPC_MID2APP, (ipc_cb*)mid_cb, NULL, NULL);
	kk_ipc_init(IPC_MID2PLAT, (ipc_cb*)mid2p_cb, NULL, "*");

	kk_init_dmproc();
	kk_heartbeat_init();
	kk_subDb_init();
	kk_area_init();
	kk_history_db_init();
	kk_group_db_init();
	kk_motor_bind_db_init();
	kk_scene_init();
	kk_mutictrl_init();
	g_timezone = HAL_Get_TimeZone();

	mid_ctx->g_mid_dispatch_thread_running = 1;
	res = pthread_create((pthread_t *)&mid_ctx->g_mid_dispatch_thread, NULL, mid_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate mid Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}

	mid_ctx->g_ota_dispatch_thread_running = 1;
	res = pthread_create((pthread_t *)&mid_ctx->g_ota_dispatch_thread, NULL, ota_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate ota Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}

	// recv gateway add cmd and ack to gateway
	res = pthread_create((pthread_t *)&mid_ctx->g_udp_dispatch_thread, NULL, udp_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate udp Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}

	mid_ctx->g_ccuProChg_dispatch_thread_running = 1;
	res = pthread_create((pthread_t *)&mid_ctx->g_ccuProChg_dispatch_thread, NULL, ccu_property_monitor, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate Failed\n");
		return -1;
	}

	//int ct = 0;
	for (;;) {
		usleep(200000);
		kk_platMsg_dispatch();
		BodySensorTrigger_check();
	}


}

