\mainpage OneNetPost应用 \section note1 整体说明 本应用实现: - 监控主机采集原始数据及报警数据上传onenet移动云平台 - 传感器在OneNet平台注册设备。 - Http请求数据上传 \section note2 功能模块 本应用划分为以下模块: - 应用框架模块 - 授权检查 - 检查设备注册状态 - 注册设备 - 数据上传 \section note3 修改日志 \page pageLog 修改日志 \section log2 20170508 修正 20170508 \section log1 20170508 \page pageApp 应用框架模块 \section app1-1 基本功能 检查设备配置,授权处理,注册设备 \section app1-2 设计 - 通用上传数据基类-》应用实现类 - 配置管理对象 读取ini文件形式,可随时扩展修改。 - 工作线程 - 消息机制 支持消息响应 - 守护机制 定时发消息到守护进程,异常中断阻塞或退出,由守护进程自动运行 - 日志记录 支持日志记录,通过global.h文件全局变量打开/关闭或日志模式 \section app1-3 流程 \page post OneNeT授权模块 \section accredit1-1 基本功能 功能描述 - 实现对设备的授权管理 \section accredit1-2 设计 - 读取设备授权码,对设备授权进行授权 \section accredit1-3 流程 (1) 读取设备授权信息 (2) 是否授权,否跳到(3),是跳到(5) (3) 试用期, 到期?是退出,否跳到(4) (4) 初始化执行程序,采集数据 (5) 授权已过期?是退出,否跳到(4) \section accredit1-4 注意 注意事项: - 及时判断设备授权是否过期 \section accredit1-5 示例 示例参考 \page post OneNeT检查注册模块 \section accredit1-1 基本功能 功能描述 - 实现对设备注册检查是否注册判断 \section accredit1-2 设计 - 请求核对设备注册情况 - 对设备进行标记 \section accredit1-3 流程 (1) 加载设备 (2) 遍历设备对列 (3) 判断设备是否注册,否跳到(6),是跳到(4) (4) 判断设备信息是否更新,是跳到(5),否转(2) (5) OneNet设备发出http请求,跳到(7) (6) 向OneNet注册设备 (7) 判断遍历设备是否完成,是退出,否跳到(2) \section accredit1-4 注意 注意事项: - 对设备注册进行唯一性核查 \section accredit1-5 示例
  int COneNetPost::OneNet_CheckDeviceRegist(void)
	{

		std::map::iterator itPostItem = m_PostItem.begin();
		std::map::iterator it;
		for (; itPostItem != m_PostItem.end(); itPostItem++)
		{		
			it = m_PostDevice.find(iSid);
			if (it == m_PostDevice.end())//设备未注册
			{
				OneNet_RegistDevice(itPostItem->second);
			}
		}
		return m_PostDevice.size();
	}
\page postReg OneNET注册模块 \section reg1-1 基本功能 功能描述 - 使用POST方法向OneNet平台注册设备。 - 设备注册成功后自动向数据中插入注册的设备信息,以便在下次启动时更好地检查设备注册情况。 \section reg1-2 设计 - 检查配置的传感器是否已向OneNet平台注册,若没有注册则向平台注册设备 - 已经注册向OneNet平台更新设备信息 - 没有注册,向OneNet平台注册注册设备 - 参考 OneNET devices \section reg1-3 流程 (1) 加载设备 (2) 遍历注册设备对列 (3) 向平台发出删除设备 (4) 删除本地设备注册信息 (5) 设备遍历完成?,否转到(2),是转到(6) (6) 检查设备注册状态 (7) 退出 \section reg1-4 注意 注意事项: - 注册前先检查设备是否已经注册 - 设备有更新要及时更新数据库 \section reg1-5 示例 示例参考 //向平台注册注册设备
int COneNetPost::OneNet_RegistDevice(TPostMsgItem& item)
{
    char postdata[_BUF1K];	//Post数据输入缓冲区,用于向平台发送Post数据
    char outdata[_BUF2K];	//Post数据输出缓冲区,用于存储平台返回的数据
	long outlen = 0;			//Post返回数据长度,用于记录平台返回的数据大小
	
	int iSid = item.Sid;
	int iKind = item.Kind;
	int iDevId = 0;
	std::string sDevApiKey;
	
	std::string sUrl;
	std::string sUrlHeader;
    cJSON *nd = NULL;
    cJSON *json = NULL;
    cJSON *child = NULL;
	//注册设备
	sUrl = Format("http://%s:%d/register_de?register_code=%s", m_sPostHost.c_str(), m_iPostPort, m_PostRegCode[item.SubSys].c_str());//URL
	sUrlHeader=Format("");//Http头
	if (iSid > 0)
		sprintf(postdata, "{\"sn\": \"%s-%d\"}", m_sMacID.c_str(), iSid);
	else
		sprintf(postdata, "{\"sn\": \"%s\"}", m_sMacID.c_str());
	if (DoHttpRequest(sUrl.c_str(), sUrlHeader.c_str(), postdata, outdata, &outlen) <= 0)
	{
		return 0;
	}
	//处理返回数据
	json = cJSON_Parse((const char*)outdata);
	nd = cJSON_GetObjectItem(json, "error");
	int res = 0;
	if (strcmp(nd->valuestring, "succ") != 0)
	{
		cJSON_Delete(json);
		return 0;
	}
	child = cJSON_GetObjectItem(json, "data");
	nd = cJSON_GetObjectItem(child, "device_id");//取得设备ID
	iDevId = atol(nd->valuestring);
	nd = cJSON_GetObjectItem(child, "key");//取得设备ApiKey
	sDevApiKey = nd->valuestring;
	strcpy(item.ApiKey, nd->valuestring);
	item.DevID = iDevId;
	m_PostDevice[iSid] = item;
	sprintf(postdata, "insert into tbRegDevDef(DevID, SID, Kind, Type, SubSys, Name, Note, ApiKey, Mask, Ext0, Ext1) \
						values(%d, %d, %d, %d, %d, '%s', '%s', '%s', 0, 0, 0)",
						item.DevID, item.Sid, item.Kind, item.Type, item.SubSys, item.Name, item.ANote, item.ApiKey);
	m_dbCfg->execDML(postdata);
	cJSON_Delete(json);
	
	//更新设备信息
	OneNet_UpdateDeviceInfo(item);
	
	return 1;
}
\page postOneNet OneNeT上传模块 \section post1-1 基本功能 功能描述 - 传感器数据上传 - 报警数据上传 \section post1-2 设计 - 遍历查表 - 查询数据 - 上传数据 - 参考 OneNeT datapoints \section post1-3 流程 (1) 获取设备列表 (2) 遍历设备数据记录 (3) 检查数据是否更新?,否转(2),是转(4) (4) 有数据更新http请求数据上传 (5) 判断是否遍历完成?,是转到(6),否转(2) (6) 结束 \section post1-4 注意 注意事项 - 检查表格是否存在 - 检查数据是否更新 - 数据上传是否成功 \section post1-5 示例 示例参考 //上传传感器数据
	std::map::iterator itPostItem = m_PostItem.begin();
	std::map::iterator itDateUpd;
	for (; itPostItem != m_PostItem.end(); itPostItem++)//遍历
	{
		itDateUpd = m_PostDateUpd.find(itPostItem->second.Sid); //数据更新时间
		if (itDateUpd == m_PostDateUpd.end())//没有相关更新记录
			continue;
		sTable = m_PostDbTabName[iType];
		if (m_dbDat->tableExists(sTable.c_str()))//数据表存在
		{
			ssql = Format(_T("select * from %s where SID=%d"),sTable.c_str(),iSid);
			iqry = m_dbDat->qryExec(ssql.data());
			if (!m_dbDat->qryEof(iqry))
			{
				sDateUpd = m_dbDat->qryFieldStr(iqry, _T("DateUpd"));//数据更新时间
				if (sDateUpd != itDateUpd->second)//数据有更新
				{
					itDateUpd->second = sDateUpd;
					//TODO: 检查数据库是否存在并取出想应的数据,然后打包成Post数据帧
					iFieldCount = m_dbDat->qryFieldCount(iqry);
					sprintf(postdata,"{");
					for(int k=1; kqryFieldName(iqry,k), m_dbDat->qryFieldInt(iqry, _T(m_dbDat->qryFieldName(iqry, k))));
						strcat(postdata, abuf);										
					}
					strcat(postdata,"}");
					sUrl = Format("http://%s:%d/devices/%ld/%s", m_sPostHost.c_str(), m_iPostPort, m_PostDevice[iSid].DevID, m_sPostPath.c_str());
					sUrlHeader=Format("api-key:%s", m_PostApiKey[itPostItem->second.SubSys].c_str());
					if (DoHttpRequest(sUrl.c_str(), sUrlHeader.c_str(), postdata, outdata, &outlen) <= 0)
					{
					   ;
					}
				}
			}
			m_dbDat->qryFinalize(iqry);
		}
		_sleep(1);
	}