[WiFi] 【萤火虫ESP32体验】+筑巢三:物联网控制LED亮灭

[复制链接]
 楼主| 冒险武者 发表于 2018-3-1 17:15 | 显示全部楼层 |阅读模式
本帖最后由 冒险武者 于 2018-3-1 17:15 编辑

由于这次我想用http协议数据来控制LED的亮灭
但是HTTP不支持平台数据下发,这就需要我们获取平台数据,采用的是GET
相对上传数据,数据的获取与解析比较复杂,因此留在上传数据后讲解。

先简单看看协议,如下图所示:

HTTP方法

GET

URL

//api.heclouds.com/devices/device_id/datapoints

URL参数

datastream_id=a,b,c             //查询的数据流,多个数据流之间用逗号分隔(可选)

start=2015-01-10T08:00:35  //提取数据点的开始时间(可选)

end=2015-01-10T08:00:35   //提取数据点的结束时间(可选)

duration=3600                      //查询时间区间(可选,单位为秒)

                                              start+duration:按时间顺序返回从start开始一段时间内的数据点

                                              end+duration:按时间倒序返回从end回溯一段时间内的数据点

limit=100                              //限定本次请求最多返回的数据点数,0<n<=6000(可选,默认1440)

cursor=                                 //指定本次请求继续从cursor位置开始提取数据(可选)

sort=DESC | ASC              //值为DESC|ASC时间排序方式,DESC:倒序,ASC序,(不带任何参数或仅携带limit参数-默认降序,其他情况-默认升序)

HTTP头部

api-key: 242RprHyALimOZLCKiXeT7IRdLM=  //masterkey 或者 该设备的设备apikey


根据协议,我们需要上传数据到平台
  1. void sendGetCmd(void)
  2. {
  3.         char TXbuf[256];
  4.         memset(TXbuf, 0, sizeof(TXbuf));
  5.         sprintf(TXbuf, "GET /devices/%s/datapoints?datastream_id=num&type=3 HTTP/1.1\r\napi-key:%s\r\nHost:api.heclouds.com\r\n\r\n\r\n",
  6.         DEVID, APIKEY);   //Temperature,Humidity
  7.         client.print(TXbuf);
  8. }


代码主要上传的数据是:

  1. GET /devices/DEVID/datapoints?datastream_id=num&type=3 HTTP/1.1
  2. api-key:APIKEY
  3. Host:api.heclouds.com
  4. Connection:close



DEVID,是设配ID号
APIKEY,是产品密钥
替换上去就可以了

通过sendGetCmd到ONENET平台后,需要ESP32获取平台的数据
我设置的缓冲数据有点大,主要是担心溢出,因为平台下发的数据是cjson格式的,
对于cjson格式的讲解,有需要很大篇幅,在后面简介一下。

  1. #define BUFNUM 1500
反复获取服务器发来的数据
  1. while (client.available())
  2.   {
  3.           char c = client.read();
  4.           if (c == '{')
  5.                 ResponseBegin = true;
  6.                
  7.           if (ResponseBegin)
  8.           {
  9.                 //returnValue += c
  10.                 if (bufCount >= BUFNUM) bufCount = 0;
  11.                 TCPBUF[bufCount++] = c;
  12.           }        
  13.   }


数据获取后就是对数据的解析:
先来看看完整的数据
  1. HTTP/1.1 200 OK
  2. Date: Wed, 28 Feb 2018 14:11:21 GMT
  3. Content-Type: application/json
  4. Content-Length: 132
  5. Connection: close
  6. Server: Apache-Coyote/1.1
  7. Pragma: no-cache

  8. {"errno":0,"data":{"count":1,"datastreams":[{"datapoints":[{"at":"2018-02-14 20:17:37.000","value":1}],"id":"num"}]},"error":"succ"}
前面一段时HTTP格式响应GET的报文数据
后面一段{}包括起来的数据才是我们需要分析的数据,可以看到,我们仅仅获取了一个数据单元num就有这么复杂,
这一段就是cjson格式数据流

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。(来自“开源中国”资料)。
cJSON从名字可知,整个项目都是以极标准的C来写的,意思说,可以跨各种平台使用了。cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。


附上cjson库函数,直接可以调用来解析数据
cJSONFiles.zip (24.83 KB, 下载次数: 0)
下面自己编写printCjson解析数据流,仅供参考
  1. void printCjson(cJSON * root)
  2. {
  3.         uint8_t i = 0;
  4.         for (;i < cJSON_GetArraySize(root); i++)
  5.         {
  6.                 cJSON * item = cJSON_GetArrayItem(root, i);
  7.                 if (item->type == cJSON_Object)
  8.                 printCjson(item);
  9.                 else
  10.                 {
  11.                         Serial.print(item->string);
  12.                         Serial.print("-> ");
  13.                         Serial.println((char *)cJSON_Print(item));
  14.                 }
  15.         }
  16. }


下面用过getOnenet详细解析数据,控制LED亮灭
  1. void getOnenet(char *dataBuf)
  2. {
  3.         char * ptrCjson = NULL;
  4.         char numBuf1[8],numBuf2[8];
  5.         int num = 0,k;
  6.         
  7.         if (strstr((char *)dataBuf, "CLOSED"))
  8.         {
  9.                 Serial.println("TCP CLOSED...");
  10.         }
  11.         else
  12.         {
  13.                 if (strstr((char *)dataBuf, "succ"))
  14.                 {
  15.                         //Serial.println("TCP SUCCESS...");
  16.                         
  17.                         //Serial.println("...................................");
  18.                         Serial.println((char *)dataBuf);
  19.                         //Serial.println();
  20.                         
  21.                         ptrCjson = strchr((char *)dataBuf, '{');
  22.                         if (ptrCjson != NULL)
  23.                         {
  24.                                 cJSON * root = cJSON_Parse((char *)ptrCjson);
  25.                                 if (root)
  26.                                 {
  27.                                         printCjson(root);
  28.                                 }
  29.                                 else
  30.                                 {
  31.                                         Serial.println("CJSON Error...");
  32.                                         Serial.println(cJSON_GetErrorPtr());
  33.                                 }
  34.                         }
  35.                         
  36.                         
  37.                         ptrCjson = strstr((char *)ptrCjson, "num");
  38.                         if (ptrCjson != NULL)
  39.                         {
  40.                                 Serial.println("Get Temperature Value ...");
  41.                                 //ptrCjson -= 9;
  42.                                 for(int i=0;i<10;i++)
  43.                                 {
  44.                                         Serial.print(*ptrCjson--);
  45.                                 }
  46.                                 Serial.println();
  47.                                 
  48.                                 while (((*ptrCjson >= '0')&&(*ptrCjson <= '9'))||(*ptrCjson == '.'))
  49.                                 {
  50.                                         numBuf1[num++] = *ptrCjson--;
  51.                                         //Serial.println(numBuf1[num]);
  52.                                 }
  53.                                 
  54.                                 Serial.println(numBuf1);
  55.                                 k = num;
  56.                                 //Serial.print("num : ");
  57.                                 //Serial.println(num);
  58.                                 num--;
  59.                                 for (uint8_t ii=0;ii<k;ii++)
  60.                                 {
  61.                                         numBuf2[ii] = numBuf1[num--];
  62.                                 }
  63.                                 Serial.println(numBuf2);
  64.                                 num = (int)atoi((const char *)numBuf2);
  65.                                 //float ttt = (float)atof((const char *)numBuf2);                                //转为数值形式
  66.                               
  67.                                 //Serial.println(ttt);
  68.                                 Serial.println(num);
  69.                                 //onenet_info.ledStatus = num;
  70.                                 if (num == 1)
  71.                                 {
  72.                                         LEN_ON();
  73.                                         dataInfo.ledStatus = 1;
  74.                                 }
  75.                                 else
  76.                                 {
  77.                                         LEN_OFF();
  78.                                         dataInfo.ledStatus = 0;
  79.                                 }
  80.                         }
  81.                 }
  82.                 else
  83.                 {
  84.                         Serial.println("TCP ERR...");
  85.                 }
  86.         }
  87. }

亲自测量使用,完全可以通过手机客户端点亮熄灭LED,且不影响硬件数据的上传平台
http://bbs.21ic.com/forum.php?mo ... 1&extra=#pid9160022
到此为止,一个完成的项目就结束,项目包括连接温湿度数据的采集,wifi与物联网平台的连接,温湿度数据打包上传,
与通过APP控制LED,做到了数据的采集与控制。


您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

127

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

12

主题

127

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部