OneNET平台提供设备全生命周期管理相关工具,帮助个人、企业快速实现大规模设备的云端管理;开放第三方API接口,推进个性化应用系统构建;提供定制化“和物”APP,加速个性化智能应用生成。注册地址为
https://open.iot.10086.cn/ <https://open.iot.10086.cn/>
,用户可以根据其中的官方文档注册账号,创建设备应用。

本教程使用stm32系列芯片,完成硬件与onenet物联网平台进行交互。
stm32外接Enc28j60网卡芯片,该芯片内置以太网mac,phy层。使用该芯片完成网络传输,需要在该芯片上搭建一个软件TCP/IP协议栈,而UIP协议栈是一个很好的选择。在stm32上移植该协议栈,就可以把stm32采集到的传感器数据上传到onenet云平台。onenet平台支持多种协议,比如Http,MQTT,EDP等协议,而通过HTTP方式上传至云平台是一种常见而且简单的方式,只需要把stm32作为HTTP客户端,通过HTTP的一些标准请求,比如Get,Post等,就可以把数据上传到云端,或者从云端获取数据。
RestFul API 基于HTTP 协议(详见//www.w3.org/Protocols/HTTP/1.0/spec.html)
<http://www.w3.org/Protocols/HTTP/1.0/spec.html%EF%BC%89> 和json数据格式(详见//
www.json.org/json-zh.html) <http://www.json.org/json-zh.html%EF%BC%89>
 ,适合平台资源管理、平台与平台之间数据对接、使用短连接上报终端数据、时间序列化数据存储等场景。

HTTP协议

HTTP是一个基于TCP/IP通信协议来传递数据,HTTP连接报文分为请求和响应两种,一次请求消息包含请求行,请求头部,空行和请求数据四部分组成。

* 请求行
用来说明请求类型,要访问的资源目录以及HTTP使用版本,HTTP请求类型包含GET,POST等,它们的具体差别可以查看相关文档

* 请求头部
接着请求行之后的部分,包含若干属性值,比如指定主机HOST,和onenet交互的API

* 空行
空行位于报文首部和报文主体之间。

* 请求数据
对于不同的请求过程,得到的请求数据不一样,比如HTML,JSON等.

 

OneNet HTTP
API按照RESTful的方式向外提供服务,其资源模型中包含的资源种类有:用户、设备(device)、数据流(datastream)、数据点(datapoint)、触发器(trigger)、API
key、命令等。

* 数据点(Datapoint)

即一个数据流中的一个具体的数据值。数据点采用“Key-Value”的方式存储。其中Key的组成包括设备ID、数据流ID、时间等信息,value部分可以为任何数据对象,如整数、字符串或者JSON数据类型。

* 数据流(Datastream)
一个数据流可以理解为一类数据,如传感器之温度、位置之经纬度,空气之湿度等。用户可以自定义数据流名称,即数据流ID;一个设备可以添加多个数据流。


根据onenet官方文档,使用onenet上传数据的POST请求如下所示,请求头部需要指定三个属性,分别为api-key,Host,Content-Length。Content-Length为请求数据的字节大小,在报文首部和报文主体之间还存在空行。使用restful上传的数据格式为json,请求资源的目录为
/devices/509226975/datapoints,其中509226975为创建的设备ID。
POST /devices/509226975/datapoints HTTP/1.1
api-key:aH2orrDNlT1gKXrdurQBoPbm5SI= Host:api.heclouds.com Content-Length:63
{"datastreams":[{"id":"sys_time","datapoints":[{"value":50}]}]}
 


先使用上面的POST请求内容,通过网络调试组手上传到onenet服务器,由以下的截图得出,数据上传之后,服务器就会给客户端回复响应的响应。HTTP响应也由状态行、消息报头、空行和响应正文四个部分组成,其中响应的第一行为状态行,有HTTP协议版本号(HTTP/1.1),状态码(200),状态消息(OK)。其中第二行和第三行为消息报头,用来说明客户端要使用的附加信息,Date:生成响应的日期和时间;Content-Type:指定了MIME类型的json,Content-Length为效能感应正文的大小。第三部分为空行,消息报头后面的空行是必须的。第四部分为响应正文,服务器返回给客户端的文本信息,图中是返回得到的json数据。



 


curl是利用URL语法在命令行方式下工作的开源文件传输工具,在ubuntu主机上可以通过apt-get方式安装,使用它可以使用命令行的方式,完成一些HTTP请求。在请求行中指定http方法,使用--request
GET或--request POST来指定,请求头部使用--header "请求头内容" 来指定,报文内容使用--data
"请求内容"来指定。ubuntu上通过curl工具来向onenet请求获取数据命令如下所示:
//向设备513591948查询数据 curl --request GET --header "api-key:
oueSPcHZ0YdDypDfxY56ynJs=4o="
http://api.heclouds.com/devices/513591948/datastreams //向设备509226975上传数据 curl
--request POST --data
"{\"datastreams\":[{\"id\":\"sys_time\",\"datapoints\":[{\"value\":888}]}]}"
--header "api-key: aH2orrDNlT1gKXrdurQBoPbm5SI="
http://api.heclouds.com/devices/509226975/datapoints
 

 


stm32上传温度数据给onenet,使用stm32开启一个定时器,在定时器中将发送标志位置位,在UIp状态机空闲时不断判断该标志位是否置位,如果置位就将采集到的温度数据打包成上述讲解的HTTP报文并通过POST上传到onenet,然后用户在浏览器就可以看到相关数据。相关核心代码如下所示:
void onenet_send() { float value=get_temperature();//获取stm32内部温度传感器数据 //打包请求数据
sprintf(http_content,"{\"datastreams\":[{\"id\":\"temp\",\"datapoints\":[{\"value\":%3.1f}]}]}",value);
//请求行 sprintf(http_header,"POST %s HTTP/1.1\r\n",remote_path);
strcpy(http_request,http_header); //请求头部的属性
sprintf(http_attribute,"Host:%s\r\n",remote_server);
strcat(http_request,http_attribute);
memset(http_attribute,0,sizeof(http_attribute)); //添加请求头部的属性
sprintf(http_attribute,"api-key:%s\r\n",apikey);
strcat(http_request,http_attribute);
memset(http_attribute,0,sizeof(http_attribute)); //添加请求头部的属性
sprintf(http_attribute,"Content-Length:%d\r\n",strlen(http_content));
strcat(http_request,http_attribute);
memset(http_attribute,0,sizeof(http_attribute)); strcat(http_request,"\r\n");
strcat(http_request,http_content); uip_send(http_request,sizeof(http_request));
} //uip回调接口 void tcp_client_appcall() { if(uip_connected())//已经连接上服务器? {
uip_sock_flag =CLIENT_CONNECT; uip_log("tcp_client connected!\r\n");// return;
} if(uip_aborted())//意外终止? { //uip_abort(); uip_sock_flag =CLIENT_DISCONNECT;
uip_log("tcp_client aborted!\r\n");//´òÓ¡log tcp_client_reconnect(); }
if(uip_timedout())//超时? { uip_sock_flag =CLIENT_TIMEOUT; uip_log("tcp_client
timeout!\r\n");// tcp_client_reconnect(); } if(uip_acked())//确认发出数据? {
uip_ack_flag=1; uip_log("tcp_client acked!\r\n");//±íʾ³É¹¦·¢ËÍ }
if(uip_newdata())//远程主机已经发出数据 { if(uip_ack_flag) {
uip_log("*************tcp_client recv data!*********\r\n");//±íʾ³É¹¦·¢ËÍ
printf("\r\n%s\r\n",uip_appdata); } } if(uip_rexmit())//重发? {
uip_log("tcp_rexmit\r\n"); onenet_send(); return; } if(uip_poll())//应用程序循环运行 {
uip_log("uip_poll\r\n"); // if(uip_sock_flag!=CLIENT_CONNECT) // { //
uip_abort(); // } if(uip_send_flag)//判断发送标志位是否置位? { uip_send_flag=0;
onenet_send(); } } if(uip_closed())//由于onenet上传一次数据,连接会自动关闭 关闭后就重连 {
uip_ack_flag=0; uip_sock_flag=CLIENT_DISCONNECT; uip_log("tcp_client closed!
reconnect!\r\n");//´òÓ¡log tcp_client_reconnect(); return; } } //定时器中断服务函数 void
TIM3_IRQHandler(void) { static u8 tcnt; if (TIM_GetITStatus(TIM3,
TIM_IT_Update) != RESET) // { GPIOE->ODR ^= GPIO_Pin_8; if(uip_sock_flag ==
CLIENT_CONNECT)//连接是否还存在? { uip_send_flag=1; } } TIM_ClearITPendingBit(TIM3,
TIM_IT_Update ); // }
 

打开浏览器,进入onenet中的设备列表,进入此设备的设备流展示的选项,就可以观察到温度数据已经上传到云平台上了。

 



 

以上是通过一个POST请求将上传上传到云平台的例子,首先在网络调试助手中,通过一个get请求查询数据,使用报文如下:
GET /devices/513591948/datastreams HTTP/1.1 Host:api.heclouds.com
api-key:oueSPcHZ0YdDypDfxY56ynJs=4o=

下面将使用stm32通过get请求不断查询服务器的数据,来控制板载LED灯的量灭,在使用过程中开启一个定时器每隔一段时间通过一个Get请求,查询其中的数据,然后在uip状态机的接受过程中接收服务器响应的数据,得到数据就解析其中的响应报文,然后解析json中的数据包,然后得到开关量,控制LED的亮灭
//发送一个GET请求 void onenet_send() { //打包请求数据 sprintf(http_header,"GET %s
HTTP/1.1\r\n",remote_path); strcpy(http_request,http_header); //请求行
sprintf(http_attribute,"Host:%s\r\n",remote_server);
strcat(http_request,http_attribute);
memset(http_attribute,0,sizeof(http_attribute)); //请求行添加属性
sprintf(http_attribute,"api-key:%s\r\n",apikey);
strcat(http_request,http_attribute);
memset(http_attribute,0,sizeof(http_attribute)); strcat(http_request,"\r\n");
uip_send(http_request,sizeof(http_request)); } //uip回调接口 void
tcp_client_appcall() { if(uip_connected())//已经连接上服务器? { uip_sock_flag
=CLIENT_CONNECT; uip_log("tcp_client connected!\r\n");//±íʾÁ¬½Ó³É¹¦ return; }
if(uip_aborted())//意外终止? { //uip_abort(); uip_sock_flag =CLIENT_DISCONNECT;
uip_log("tcp_client aborted!\r\n");//´òÓ¡log tcp_client_reconnect();
//uip_resolv_connect(remote_server,80); } if(uip_timedout())//超时? {
uip_sock_flag =CLIENT_TIMEOUT; uip_log("tcp_client timeout!\r\n");//´òÓ¡log
tcp_client_reconnect(); //uip_resolv_connect(remote_server,80); return; }
if(uip_acked())//确认已经发出数据? { uip_ack_flag=1; uip_log("tcp_client
acked!\r\n");//±íʾ³É¹¦·¢ËÍ } if(uip_newdata())//远程主机已经发出数据 { if(uip_ack_flag)
{ uip_ack_flag=0; uip_log("*************tcp_client recv
data!*********\r\n");//±íʾ³É¹¦·¢ËÍ len_temp=uip_datalen();
memcpy(tcp_client_databuf,uip_appdata,len_temp);
printf("\r\n%s\r\n",uip_appdata); value_info=(u8
*)strstr(tcp_client_databuf,"\"current_value\"");//截取"\"current_value\""开头的子串
if(value_info!=NULL) { len_temp=strlen("\"current_value\":");
status=*(value_info+len_temp); printf("\r\n%c\r\n",status); if(status =='0') {
printf("switch close!\r\n"); // GPIOE->ODR |= GPIO_Pin_8; GPIOE->BRR =
GPIO_Pin_8; } else { printf("switch open!\r\n"); //GPIOE->ODR &= ~GPIO_Pin_8;
GPIOE->BSRR = GPIO_Pin_8; } }
memset(tcp_client_databuf,0,sizeof(tcp_client_databuf)); } }
if(uip_rexmit())//重发 { uip_log("tcp_rexmit\r\n"); onenet_send(); return; }
if(uip_poll())//应用程序循环运行 { //uip_log("uip_poll\r\n");
if(uip_sock_flag!=CLIENT_CONNECT) { uip_abort(); } if(uip_send_flag)//发送标志位是否置位
{ uip_send_flag=0; onenet_send(); } return; }
if(uip_closed())//由于onenet上传一次数据,连接会自动关闭 关闭后就重连 { uip_ack_flag=0;
uip_sock_flag=CLIENT_DISCONNECT; uip_log("tcp_client closed!
reconnect!\r\n");//´òÓ¡log tcp_client_reconnect(); return; } } //定时器3中断服务函数
void TIM3_IRQHandler(void) { static u8 tcnt; if (TIM_GetITStatus(TIM3,
TIM_IT_Update) != RESET) { if(uip_sock_flag == CLIENT_CONNECT)//还存在连接 {
uip_send_flag=1; } } TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); // }
 

在浏览器中进入onenet中的应用管理,打开该应用,按下ON/OFF按钮,就可以控制板载LED灯的亮灭



 


友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信