基于Arduino和ESP8266的JSON数据获取与解压之和风天气

Posted 梦幻之心星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Arduino和ESP8266的JSON数据获取与解压之和风天气相关的知识,希望对你有一定的参考价值。

简要比较了几个免费天气数据接口;介绍了通过HTTP和HTTPS获取数据,以及Gzip压缩格式数据的获取;解压Gzip格式数据的方法;介绍了获取网络数据时的注意事项,包括数据完整性、数据存储、内存分配、数据有效性检查。推荐了一个获取并解析和风天气数据的第三方库。

基于Arduino和ESP8266的JSON数据获取与解压之和风天气

摘要

  • 简要比较了几个免费天气数据接口;介绍了通过HTTP和HTTPS获取数据,以及Gzip压缩格式数据的获取;解压Gzip格式数据的方法;介绍了获取网络数据时的注意事项,包括数据完整性、数据存储、内存分配、数据有效性检查。推荐了一个获取并解析和风天气数据的第三方库。

背景说明

  • 起因:点灯科技气象数据接口暂停使用,寻找替代方案。

  • 免费天气数据接口比较

    数据来源 网络协议 内容编码 数据格式 接口限制 更新频率
    点灯科技 HTTPS None JSON 30次/天 2小时
    和风天气 HTTPS Gzip JSON 1000次/天 10分钟
    高德天气 HTTPS None JSON 300000/天 多次/时

操作实践

获取数据

  • 通过 HTTP 获取数据

    HTTPClient httpclient;
    WiFiClient wificlient;
    
    if(httpclient.begin(wificlient, URL))
    
        httpCode = httpclient.GET();
        if(httpCode == HTTP_CODE_OK) 
            String payload = httpclient.getString();
        else
            Serial.printf("[HTTP] GET... failed, error: %s\\n", httpclient.errorToString(httpCode).c_str());
        httpclient.end();
    
    
  • 通过 HTTPS 获取数据

    HTTPClient httpsclient;
    BearSSL::WiFiClientSecure wificlient;
    
    wificlient.setInsecure();
    
    if(httpsclient.begin(wificlient, URL))
    
        httpCode = httpsclient.GET();
        if(httpCode == HTTP_CODE_OK) 
            String payload = httpsclient.getString();
        else
            Serial.printf("[HTTP] GET... failed, error: %s\\n", httpsclient.errorToString(httpCode).c_str());
        httpsclient.end();
    
    
  • 通过 HTTPS 获取压缩格式数据

    HTTPClient httpsclient;
    BearSSL::WiFiClientSecure wificlient;
    
    wificlient.setInsecure();
    
    if(httpsclient.begin(wificlient, URL))
    
        httpCode = httpsclient.GET();      
        if(httpCode == HTTP_CODE_OK) 
        
            content_len = httpsclient.getSize(); // get length of document (is -1 when Server sends no Content-Length header)
            content_encoding = httpsclient.header("content-encoding");
    
            if((httpsclient.hasHeader("content-encoding")) && (content_encoding.equals("gzip"))) 
            
                while((httpsclient.connected()) && ((content_len > 0) || (content_len == -1))) 
                
                    available_size = wificlient.available(); // !返回值最大只有245.
    
                    if(available_size) 
                    
                        realsize = (available_size > payload_buffer_size) ? payload_buffer_size : available_size;
                        readBytesSize = wificlient.readBytes(payload_buffer+offset, realsize); 
                        offset += readBytesSize;
    
                        if(content_len > 0)
                            content_len -= readBytesSize;
                    
                
                *payload_size = offset;
          
        
    
    

解压数据

  • 采用tignioj/ArduinoZlib库对gzip格式的数据进行解压。ArduinoZlib封装了zlib库的解压缩功能。

  • zlib库支持对gzip和Zip格式的数据进行解压和压缩。

注意事项

  • 数据完整性:函数wificlient.available()返回的等待读取的数据字节数似乎有限制(245),需要多次读取才能获得完整的数据,因此应增加数据完整性检查。

  • 数据存储:在进行 HTTP/HTTPS 访问时使用大数组会导致网络访问出错,使用malloc()手动分配堆可以解决这个问题。

  • 内存分配:使用malloc()分配堆时需要切换内存管理方案为16KB cache + 48KB IRAM and 2nd Heap (shared),此时才支持标准的malloc()API。具体信息可参见调整ICACHE与IRAM的比率

  • 数据检查:返回的天气数据不一定是正确的,可以使用String.indexOf()查找返回的字符串数据中是否有指定的关键字。

  • 和风天气:返回的数据已强制使用gzip压缩,在请求头中添加&gzip=n的方法已失效。如果仅使用和风天气的数据接口,可使用tignioj/ESP8266_Heweather库提供的接口来获取和风天气提供的天气数据。

参考资料


版权声明:本文为「梦幻之心星」原创,依据 CC BY-NC-SA 4.0 许可证进行授权,转载请附上原文出处链接及本声明。


博客园地址:https://www.cnblogs.com/Sky-seeker

关注微信公众号,获取即时推送;点击左下角阅读原文,享受最佳阅读体验!


基于Arduino IDE的ESP8266 ESP8266编程问题

我决定使用Arduino IDE for ESP8266在我的ESP8266上进行编程,目标是读取数据(来自TTL摄像机的字节数组)。 ESP8266-01(8Mbits Flash ROM)有8个引脚,因此我决定使用GPIO16(TXD)和GPIO2(RXD)作为SoftwareSerial引脚来实现这一目标。但ESP8266打印了一个例外,我不确定它发生了什么。

The crash report

所以我对这次崩溃有一些疑问。

  1. 我想知道我是否可以在ESP8266上运行SoftwareSerial(ESP8266有2个UART,Serial0用于串行打印,我们无法通过Serial1发送数据),所以我决定使用SoftwareSerial。
  2. 我不知道异常信息对于我无法理解汇编语言意味着什么。
  3. 我在Github上阅读了针对ESP8266的Arduino IDE的文档,但是在使用Arduino IDE进行编程时,我对ESP8266的引脚定义并不了解。例如,当使用GPIO16(TXD)和GPIO2(RXD)作为SoftwareSerial时,我们可能会使用Constructor SoftwareSerial Camera(int Pin1, int Pin2)。我想知道GPIO2和GPIO16的相应Pin1和Pin2是什么。该文件让我很困惑。

这是我的关键代码。

#include <Arduino.h>
#include "camera_VC0706.h"
#include <SoftwareSerial.h>
HTTPClient httpClient;
//define camera and bytes array, I am not sure whether the pins are correct or not
int rxPin=2;
int txPin=16;
SoftwareSerial cameraSerial(rxPin,txPin); //RX,TX
camera_VC0706 Camera = camera_VC0706(&cameraSerial);
//take photo
bool takePhoto() {
  byte time=0;
  writeRawSerial(F("<STATUS>WAITING</STATUS>"),true);
  while(!Camera.begin(115200)) {
    if(+time<=5){//try 5 times
      writeRawSerial(F("."),false);
    } else {
      writeRawSerial("",true);
      writeSerial(F("<STATUS>NO_CAMERA</STATUS>"));
      return false;
    }
  }
  writeRawSerial(F("<STATUS>CAMERA_ON</STATUS>"), false);
  writeRawSerial(F("<VERSION>"), false);
  writeRawSerial(Camera.getVersion(), false);
  writeSerial(F("</VERSION>"));
  Camera.setImageSize(VC0706_320x240);
  if (!Camera.takePicture()) {
    writeSerial(F("<STATUS>TAKE_PHOTO_FAIL</STATUS>"));
    return false;
  } else {
    byte imgSize = Camera.frameLength();
    writeSerial(F("<STATUS>TAKE_PHOTO_SUCCESS</STATUS>"));
    writeRawSerial(F("<IMAGE_SIZE>"),false);
    writeRawSerial(String(imgSize,DEC),false);
    writeSerial(F("</IMAGE_SIZE>"));
    freeHeap();//It was defined, but not key function, only for showing free heap of esp8266
    imgBuffer=Camera.readPicture(imgSize);
    freeHeap();
    Camera.resumeVideo();
    writeSerial(F("<STATUS>SAVE_PHOTO_SUCCESS</STATUS>"));
    return true;
  }
}

感谢您阅读我的问题。

答案

因此,显示的堆栈跟踪对于任何系统都是非常标准的,并且它为您提供了跟踪它所需的几乎所有内容 - 它不是汇编代码,它是二进制文件的十六进制地址。

首先,你有一个异常28 - 如果我们查看ESP8266 Reference,你可以看到28表示你有一个坏指针,或者你试图从中断/缓存中访问非缓存数据被关闭。

接下来,你有一个地址,epc1。这是代码崩溃的地方,它是您上传的二进制文件的十六进制地址。另外,ctx:cont很有用,因为它表示程序在代码中崩溃而不是系统代码。

你也有excvaddr,这是你试图访问的地址,0x10。

鉴于此,您几乎肯定在代码中的某个位置有一个NULL指针,您正在解除引用。您应该使用ESP异常解码器来确定哪个行有令人讨厌的崩溃和错误的指针使用。

关于使用软件序列 - 您只需使用数据表中的引脚编号。 GPIO 14在构造函数中将是14。我发现它有效,但在我使用1天以上的生产产品中造成了非常奇怪的崩溃,所以不要推荐它。我们最终使用Serial1进行调试打印,并释放Serial0用于一般UART通信 - 方式更可靠。

以上是关于基于Arduino和ESP8266的JSON数据获取与解压之和风天气的主要内容,如果未能解决你的问题,请参考以下文章

ESP8266和ESP32基于Arduino EspNow组播通讯

基于MacOS搭建ESP8266 NodeMCU CP2102开发环境

基于MacOS搭建ESP8266 NodeMCU CP2102开发环境

基于MacOS搭建ESP8266 NodeMCU CP2102开发环境

esp8266 基于arduino实现ota

在Arduino IDE中安装固件ESP32,ESP8266板