1.功能点概述
设备可以采用HTTP协议与OneNET对接,实现数据点的上传和保存。
2.协议文档
3.接入流程
登录注册->新建产品->新增设备->添加数据流->查看数据->新建应用
(1)特别注意在新增产品时选择公开协议的HTTP协议。
(2)新增设备
(3)添加数据流
进详情
进数据展示->添加数据流
(5)上传数据
利用api-key鉴权,参考restful api上传数据
(4)查看数据
(5)新建应用
点击进入后按应用流程完成
4.Http协议说明
A 文本数据类型上传
HTTP方法POST
URL//api.heclouds.com/devices//datapoints
HTTP头部api-key:xxxx-ffff-zzzzz
HTTP内容有多种数据格式,具体见下面说明
请求返回{
"errno": 0,
"error":“succ”,
}
说明:
1)可以一次性向设备云上传多个数据流,每个数据流中有可以包括多个数据点。示例程序表示向设备云上数据流temperature和数据流key上传数据。其中temperature数据流有两个数据点,key数据流也有两个数据点。
2)如果某个数据流不存在,也就是事先没有通过新增数据流的API创建本数据流,则在增加数据点时,设备云会自动创建一个新的数据流,注意新数据流的streamid不可为空。
3)数据点表示在某个时刻,该数据流的值为多少。其at表示时间,为可选字段。如果为空,则设备云会取当前时间。如果存在其格式必须为"2013-04-22T00:35:43"的形式。
4)数据点中的value表示具体的值,其值为JSON对象,可以为整型、字符串多种类型。如果value部分用双引号括起来,则其在设备云存储为字符串,如果不用双引号括起来,则其表示数字。
5)数据点对应的时间是数据点的标识的一部分,相同时间的两个数据点,后一个会把前一个覆盖。一般如果at部分取空,设备云会取系统时间,精度为毫秒,如果在一条命令中某一个数据流包含多个数据点都没有at字段,会导致设备云只保存了最后一条。
6)为了节省流量,增加数据点支持如下简写方式。在请求的URL中增加type字段,指示所使用的简写方式。目前type支持3,4,5三种情况
///devices//datapoints?type=3
{"temperature":22.5,"humidity":"95.2%"}
表示在数据流temperature中增加一个数据点22.5,在humidity中增加一个数据点95.2%。
///devices//datapoints?type=4
{"temperature":{"2015-03-22T22:31:12":22.5}}
表示在数据流temperature中加一个数据点,在2015年2月22日22点31分12秒的值为22.5
///devices//datapoints?type=5
,;temperature,2015-03-22T22:31:12,22.5;102;pm2.5,89;10
补充说明:
消息中最前面两位为用户自定义的域中分隔符和域间分隔符,这两个分隔符不能相同。比如采用逗号作为域中分隔符,分号作为域间分隔符的格式如下:
,;feild0;feild1;…;feildn
其中,每个field格式支持3种,下面以逗号作为域中分隔符进行说明:
field格式1: 3个子字段,分别是数据流ID,时间戳,数据值。通用格式:
Datastream_id,datetime,value
field格式2: 2个子字段,分别是数据流ID和数据值,省略时间戳。通用格式:
Datastream_id,value
field格式3: 1个子字段,省略了数据ID和时间戳,只传输数据值,平台将用该域所在的位置号(从0开始)作为数据流ID。通用格式:
注意:此格式中的数据点值均视为字符串。
示例:
(1),;temperature,2015-03-22T22:31:12,22.5;102;pm2.5,89
此段数据一共包括3个数据点,改写为基本格式为:{
"datastreams": [
{
"id": "temperature",
"datapoints": {
"at": "2015-03-22T22:31:12",
"value": "22.5"
}
},
{
"id": "1",
"datapoints": {
"value": "102"
}
},
{
"id": "pm2.5",
"datapoints": {
"value": "89"
}
}
]
}
报文示例:
POST /devices/1078739/datapoints?type=5 HTTP/1.1
api-key:bryNsFvy26sbj91Isu5mHXp322fwIvtc=
Host:api.heclouds.com
Content-Length:10
,;pm2.5,89
B 二进制数据上传:
功能:将二进制的数据保存到设备云,设备云返回该二进制数据的索引;并根据参数,将二进制数据作为数据点保存到设备下的某个数据流。HTTP方法POST
URL//api.heclouds.com/bindata
HTTP头部api-key:xxxx-ffff-zzzzz
URL参数device_id,必选,该数据所属设备。
datastream_id,必选,该数据所属数据流。
HTTP内容普通二进制数据、文件、图像
请求返回{
"errno": 0,
"error": "succ",
"data": {
//该数据在设备云的索引
"index": "AJOWFW1133OFO2Z93"
}
}
报文示例:
POST /bindata?device_id=1078739&datastream_id=ir HTTP/1.1
api-key:bryNFvy26sbj91Isu5mHXp322fwIvtc=
Host:api.heclouds.com
Content-Length:4
1234
5.Http协议数据点上传,简单例子
#define SERVER_ADDR "api.heclouds.com" //OneNet RestFul API服务器地址
#define SERVER_PORT 80 //OneNet RestFul API服务器端口
void edp_demo(void * arg)
{
int sockfd, ret;
/*初始化内存*/
uMEM_Init();
/*读取当前时钟Tick*/
sys_timer = sys_now();
while(1)
{
/*和服务器建立socket连接*/
sockfd = open(SERVER_ADDR, SERVER_PORT);
/*如果连接失败,继续下一次建立连接*/
if(sockfd
{
close(sockfd);
continue;
}
/*数据接收和发送函数*/
client_process_func(&sockfd);
/*关闭socket*/
close(sockfd);
}
}
client_process_func函数的主要功能是实现数据的发送和接收:
int client_process_func(void* arg)
{
int sockfd = *(int*)arg;
fd_set readset;
fd_set writeset;
int i, maxfdp1;
for(;;)
{
maxfdp1 = sockfd+1;
/*套节字集合清空 */
FD_ZERO(&readset);
FD_ZERO(&writeset);
/*加入读写套接字集合*/
FD_SET(sockfd, &readset);
FD_SET(sockfd, &writeset);
/*检测套接字是否可读可写*/
i = select(maxfdp1, &readset, &writeset, 0, 0);
/*套接字不可读不可写*/
if(i == 0)
continue;
/*检测sockfd是否在读套接字集合里面*/
if(FD_ISSET(sockfd, &readset))
{
/* 如果可读,接收网络数据*/
if(recv_func(sockfd)
break;
}
/* 如果socket 准备好可写,调用write_func函数发送数据*/
if(FD_ISSET(sockfd, &writeset))
{
if(write_func(sockfd)
break;
}
}
return -1;
}
write_func完成数据HTTP报的封装并发送,实现如下:
int write_func(int arg)
{
unsigned int now = sys_now();
int sockfd = arg;
int32 ret = 0;
char text[100] = {0};
char tmp[25] = {0};
/*每10s发送一次数据*/
if(now - sys_timer
{
return 0;
}
sys_timer = now;
/*准备JSON串*/
strcat(text,"{\"datastreams\":[{");
strcat(text,"\"id\":\"sys_time\",");
strcat(text,"\"datapoints\":[");
strcat(text,"{");
sprintf(tmp, "\"value\":%d", sys_timer/1000);
strcat(text,tmp);
//strcat(text, "\"value\":50");
strcat(text,"}]}]}");
/*准备HTTP报头*/
send_buf[0] = 0;
strcat(send_buf,"POST /devices/");
strcat(send_buf,DEV_ID);
strcat(send_buf,"/datapoints HTTP/1.1\r\n");//注意后面必须加上\r\n
strcat(send_buf,"api-key:");
strcat(send_buf,API_KEY);
strcat(send_buf,"\r\n");
strcat(send_buf,"Host:");
strcat(send_buf,SERVER_ADDR);
strcat(send_buf,"\r\n");
sprintf(tmp,"Content-Length:%d\r\n\r\n", strlen(text));//计算JSON串长度
strcat(send_buf,tmp);
strcat(send_buf,text);
ret = DoSend(sockfd, send_buf, strlen(send_buf));//发送数据
return ret;
}
recv_func函数实现服务器返回数据的接收,实现如下:
int recv_func(int arg)
{
int sockfd = arg;
int n, rtn, error;
int ret = 0;
do
{
/*接收网络数据*/
n = recv(sockfd, buffer, 512, 0);
if(n <= 0)
{
Printf("recv error, bytes: %d\n", n);
error = -1;
break;
}
/*串口打印接收到的网络数据,这里接收的到的数据是服务器对设备上传数据的结果响应*/
printf("recv from server, bytes: %d\n", n);
printf("*****return result******\n%s\n\n", buffer);
}
while(0);
return error;
}
6.SDK
7.案例链接
(1)麒麟开发板之HTTP控制LED
(2)onenet http 协议汇总
(3)教你如何运用 ARM mbed OS 接入 OneNET—HTTP 篇
(4)通过实例学习 HTTP 协议
(5)针对 Arduino 设备接入的 HTTP 报文封装 SDK(Arduino) 出炉啦!