【ESP8266物联网天气时钟】解决太极创客物联网天气时钟二三页出现NA的问题——新版和风天气API以及gzip数据解压

本文主要是介绍【ESP8266物联网天气时钟】解决太极创客物联网天气时钟二三页出现NA的问题——新版和风天气API以及gzip数据解压,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1. 前言
  • 2. 遇到的问题以及解决思路
    • 2.1 遇到的问题
    • 2.2 解决思路
  • 3. 使用ESP8266_Heweather开源库
  • 4. 成果展示
  • 5. 结语

1. 前言

  前几天想要找一个开源项目做一下,然后一番搜索后找到了太极创客在B站发布的一个物联网小项目制作:“物联网天气时钟粉丝数显示oled小电视”。
  这个项目主要用到的资源就是一块 ESP01S 和一块四脚的0.96寸 OLED 屏幕,正好手头也有,就打算复刻下这个项目,原项目的开源地址如下:

https://gitee.com/taijichuangke/bilibili_weather_clock

2. 遇到的问题以及解决思路

2.1 遇到的问题

  该项目的最终效果是在第一页显示当前时间、粉丝数;第二页显示的是当前天气;第三页显示的是未来三天的天气预报。但是经过测试后,发现只有第一页是能够正常显示的,二、三页的天气数据一直显示NA或者null。通过串口监视器发现访问B站的返回json数据解析是正确的,但是从和风天气返回的json数据就开始出错。
在这里插入图片描述

2.2 解决思路

  经过代码分析以及网上搜索资料后发现,这个项目是2020年发布的,当时使用的和风天气API还是s6版本的,在项目的 Esp8266_Clock_Weather 文件夹里面的 HeFeng.cpp 文件中获取当前天气以及获取预测天气函数中的访问URL如下:

//HeFeng.cpp文件中doUpdateCurr函数里的原本的访问URL,已不可用
String url = "https://free-api.heweather.net/s6/weather/now?lang=en&location=" + location + "&key=" + key;//HeFeng.cpp文件中doUpdateFore函数里的原本的访问URL,已不可用
String url = "https://free-api.heweather.net/s6/weather/forecast?lang=en&location=" + location + "&key=" + key;

  如今和风天气使用的是v7版本,访问域名也发生了变化,并且自2022年3月之后,和风天气的返回数据强制进行了Gzip压缩。后来看到B站的另一个up主详细讲解了复刻太极创客这个物联网时钟的一个视频:OELD+ESP8266 时钟天气显示小电视 制作教程!!(超细致)(太极创客开源项目)。
  在该视频中也提到了解决二三页出现NA的问题,解决的博主是konger123,其更改后的 HeFeng.cpp 文件地址如下:

https://gitee.com/konger123/bilibili_weather_clock/blob/master/bilibili_clock_weather/HeFeng.cpp

  该博主对原 HeFeng.cpp 文件中的 doUpdateCur、doUpdateFore 、getMeteoconIcon函数进行了更新。其中 getMeteoconIcon函数是没有任何问题的,主要就是对天气图标代码进行了更新,可以直接拿来使用,更新后的 getMeteoconIcon函数内容如下:

String HeFeng::getMeteoconIcon(String cond_code) {  //获取天气图标  见 https://dev.qweather.com/docs/start/icons/if (cond_code == "100" || cond_code == "150" || cond_code == "9006") {//晴 Sunny/Clearreturn "B";}if (cond_code == "101") {//多云 Cloudyreturn "Y";}if (cond_code == "102") {//少云 Few Cloudsreturn "N";}if (cond_code == "103" || cond_code == "153") {//晴间多云 Partly Cloudy/return "H";}if (cond_code == "104" || cond_code == "154") {//阴 Overcastreturn "D";}if (cond_code == "300" || cond_code == "301") {//阵雨 Shower Rain 301-强阵雨 Heavy Shower Rainreturn "T";}if (cond_code == "302" || cond_code == "303") {//302-雷阵雨  Thundershower / 303-强雷阵雨return "P";}if (cond_code == "304" || cond_code == "313" || cond_code == "404" || cond_code == "405" || cond_code == "406") {//304-雷阵雨伴有冰雹 Freezing Rain//313-冻雨 Freezing Rain//404-雨夹雪 Sleet//405-雨雪天气 Rain And Snow//406-阵雨夹雪  Shower Snowreturn "X";}if (cond_code == "305" || cond_code == "308" || cond_code == "309" || cond_code == "314" || cond_code == "399") {//305-小雨 Light Rain//308-极端降雨 Extreme Rain//309-毛毛雨/细雨 Drizzle Rain//314-小到中雨 Light to moderate rain//399-雨 Light to moderate rainreturn "Q";}if (cond_code == "306" || cond_code == "307" || cond_code == "310" || cond_code == "311" || cond_code == "312" || cond_code == "315" || cond_code == "316" || cond_code == "317" || cond_code == "318") {//306-中雨 Moderate Rain//307-大雨 Heavy Rain//310-暴雨  Storm//311-大暴雨 Heavy Storm//312-特大暴雨 Severe Storm//315-中到大雨 Moderate to heavy rain//316-大到暴雨 Heavy rain to storm//317-暴雨到大暴雨 Storm to heavy storm//318-大暴雨到特大暴雨 Heavy to severe stormreturn "R";}if (cond_code == "400" || cond_code == "408") {//400-小雪 Light Snow//408-小到中雪 Light to moderate snowreturn "U";}if (cond_code == "401" || cond_code == "402" || cond_code == "403" || cond_code == "409" || cond_code == "410") {//401-中雪 Moderate Snow//402-大雪 Heavy Snow//403-暴雪 Snowstorm//409-中到大雪 Moderate to heavy snow//410-大到暴雪 Heavy snow to snowstormreturn "W";}if (cond_code == "407") {//407-阵雪 Snow Flurryreturn "V";}if (cond_code == "499" || cond_code == "901") {//499-雪 Snow//901-冷 Coldreturn "G";}if (cond_code == "500") {//500-薄雾 Mistreturn "E";}if (cond_code == "501" || cond_code == "509" || cond_code == "510" || cond_code == "514" || cond_code == "515") {//501-雾 Foggyreturn "M";}if (cond_code == "502" || cond_code == "511" || cond_code == "512" || cond_code == "513") {//502-霾 Hazereturn "L";}if (cond_code == "503" || cond_code == "504" || cond_code == "507" || cond_code == "508") {//503-扬沙 Sandreturn "F";}if (cond_code == "999") {//未知return ")";}if (cond_code == "213") {return "O";}if (cond_code == "200" || cond_code == "201" || cond_code == "202" || cond_code == "203" || cond_code == "204" || cond_code == "205" || cond_code == "206" || cond_code == "207" || cond_code == "208" || cond_code == "209" || cond_code == "210" || cond_code == "211" || cond_code == "212") {return "S";}return ")";
}

   doUpdateCur、doUpdateFore函数主要是对访问和风天气的URL进行了更新,更新后的URL内容如下:

//HeFeng.cpp文件中更新后的doUpdateCurr函数里的访问URLString url = "https://devapi.qweather.com/v7/weather/now?lang=en&gzip=n&location=" + location + "&key=" + key;//HeFeng.cpp文件中更新后doUpdateFore函数里的访问URL
String url = "https://devapi.qweather.com/v7/weather/3d?lang=en&gzip=n&location=" + location + "&key=" + key;

  这个更新后URL也是正确的,可以访问到数据,但是对于和风天气返回的json格式数据,则只是在https请求中增加了“gzip=n”这个选项,以表示返回的数据不要进行Gzip压缩。
  但经过我的试验测试后该方法并不可行,自2022年3月之后,和风天气的json返回数据强制进行了Gzip压缩,从而极大减少网络流量,加快请求。所以接下来的主要任务就是先要对返回的json数据进行Gzip解压。
  在和风天气的官方文档中有给出不同开发语言如何处理Gzip的一些官方参考文档,具体链接如下:

https://dev.qweather.com/docs/best-practices/gzip/

  另外基于Arduino和ESP8266的JSON数据获取与解压之和风天气以及和风天气接口返回的gzip格式数据解析–esp32–espidf这两篇博客分别用了 zlib 库和 ArduinoZlib 库来实现对Gzip数据的解析。
  不过个人感觉可能都写得比较略微简单了点,对于我这种刚刚接触这方面的菜鸟小白来说,只能说看得有点头大。秉持着“能白嫖就白嫖”的原则,我开始寻找有没有哪位大神已经把内容全部都封装好了,这样我就可以直接拿来用了,毕竟医生告诉我胃不好,只能吃软饭(开个玩笑,只是自己懒得写gzip解压罢了)。

在这里插入图片描述
  经过我的一番搜索查找后,发现了tignioj大佬写的一个ESP8266_Heweather开源库,大佬直接将繁杂的https请求以及json解析部分直接封装好了,直接调用几个函数就能获取到和风天气的具体解析信息,这就相当于直接把饭喂到了我嘴里,而且还亲测可用,简直是不要太棒!其开源链接如下:

https://github.com/tignioj/ESP8266_Heweather

在这里插入图片描述

  所以接下来我将详细介绍下如何用 ESP8266_Heweather 开源库来解决太极创客物联网天气时钟二三页出现NA的问题。

3. 使用ESP8266_Heweather开源库

  从GitHub上将 ESP8266_Heweather 库下载完之后,还不能直接将其添加到Arduino的库里面,有些地方还需要修改下。不过在此之前,也请大家仔细阅读一下里面的README文档,里面有说到需要前期准备的工作,比如申请和风天气的API、安装相应的库等等,如下图所示:
在这里插入图片描述
  上图这些准备工作我相信大家除了 ArduinoUZlib 库没有安装,别的应该都是完成了的。 ArduinoUZlib 库主要就是用来解压gzip数据的,其地址如下:

https://github.com/tignioj/ArduinoUZlib

  之后我们需要对库中src目录下的 AirQuality.cpp HttpsGetUtils.cpp 两个文件进行修改,在 AirQuality.cpp 文件下的 AirQuality::get()函数的末尾加上一句“return false;”,在 HttpsGetUtils.cpp 文件下的 HttpsGetUtils::get(String url)函数的末尾加上一句“return “”;”,分别如下图所示:

  其实代码的逻辑是没有问题的,只是Arduino编译器定义有返回值的函数时一定得在函数末尾加上return XXX才能通过编译,不然就会报下面这个错误:

error: control reaches end of non-void function [-Werror=return-type]

  解决好这个问题后,我们就可以把修改好的压缩包添加到Arduino的库里面了。接下来就是对 HeFeng.cpp 文件进行修改,我直接将修改后的代码放上来:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <ESP8266_Heweather.h>
#include "HeFeng.h"HeFeng::HeFeng() {
}WeatherNow weatherNow;
WeatherForecast weatherForecast;void HeFeng::fans(HeFengCurrentData *data, String id) {  //获取粉丝数std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);client->setInsecure();HTTPClient https;String url = "https://api.bilibili.com/x/relation/stat?vmid=" + id;Serial.print("[HTTPS] begin...bilibili\n");if (https.begin(*client, url)) {  // HTTPS// start connection and send HTTP headerint httpCode = https.GET();// httpCode will be negative on errorif (httpCode > 0) {// HTTP header has been send and Server response header has been handledSerial.printf("[HTTPS] GET... code: %d\n", httpCode);if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {String payload = https.getString();Serial.println(payload);DynamicJsonDocument  jsonBuffer(2048);deserializeJson(jsonBuffer, payload);JsonObject root = jsonBuffer.as<JsonObject>();String follower = root["data"]["follower"];data->follower = follower;jsonBuffer.clear();}} else {Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());data->follower = "-1";}https.end();} else {Serial.printf("[HTTPS] Unable to connect\n");data->follower = "-1";}
}void HeFeng::doUpdateCurr(HeFengCurrentData *data, String key, String location) {  //获取天气weatherNow.config(key, location, "m", "en");if (weatherNow.get()) { // 获取天气更新Serial.println(F("======Weahter Now Info======"));Serial.print("Server Response: ");Serial.println(weatherNow.getTemp());        // 获取实况温度data->tmp = weatherNow.getTemp();Serial.print(F("FeelsLike: "));Serial.println(weatherNow.getFeelLike());    // 获取实况体感温度data->fl = weatherNow.getFeelLike();Serial.print(F("Icon: "));Serial.println(weatherNow.getIcon());        // 获取当前天气图标代码String cond_code = (String)weatherNow.getIcon();String meteoconIcon = getMeteoconIcon(cond_code);data->iconMeteoCon = meteoconIcon;Serial.print(F("Weather Now: "));Serial.println(weatherNow.getWeatherText()); // 获取实况天气状况的文字描述data->cond_txt = weatherNow.getWeatherText();Serial.print(F("windDir: "));Serial.println(weatherNow.getWindDir());     // 获取实况风向data->wind_dir = weatherNow.getWindDir();Serial.print(F("WindScale: "));Serial.println(weatherNow.getWindScale());   // 获取实况风力等级data->wind_sc = weatherNow.getWindScale();Serial.print(F("Humidity: "));Serial.println(weatherNow.getHumidity());    // 获取实况相对湿度百分比数值data->hum = weatherNow.getHumidity();Serial.println(F("========================"));} else {    // 更新失败Serial.println("Update Failed...");Serial.print("Server Response: ");Serial.println(weatherNow.getServerCode()); // 参考 https://dev.heweather.com/docs/start/status-code}
}void HeFeng::doUpdateFore(HeFengForeData *data, String key, String location) {  //获取预报weatherForecast.config(key, location, "m", "en"); // 配置请求信息if (weatherForecast.get()) { // 获取天气更新for (int i = 0; i < 3; i++) {Serial.print(F("==========Day "));Serial.print(i);Serial.println(F("=========="));Serial.print(F("Fx Data: "));Serial.println(weatherForecast.getFxDate(i));    // 获取预测的时间String datestr = weatherForecast.getFxDate(i);data[i].datestr = datestr.substring(5, datestr.length());Serial.print(F("TempMax: "));Serial.println(weatherForecast.getTempMax(i));      // 获取最高温度data[i].tmp_max = weatherForecast.getTempMax(i);Serial.print(F("TempMin: "));Serial.println(weatherForecast.getTempMin(i));      // 获取最低温度data[i].tmp_min = weatherForecast.getTempMin(i);Serial.print(F("Icon: "));Serial.println(weatherForecast.getIconDay(i));      // 获取天气图标代码String cond_code = (String)weatherForecast.getIconDay(i);String meteoconIcon = getMeteoconIcon(cond_code);data[i].iconMeteoCon = meteoconIcon;Serial.println(F("========================="));}} else {    // 更新失败Serial.println("Update Failed...");Serial.print("Server Response: ");Serial.println(weatherForecast.getServerCode()); // 参考 https://dev.heweather.com/docs/start/status-code}
}String HeFeng::getMeteoconIcon(String cond_code) {  //获取天气图标  见 https://dev.qweather.com/docs/start/icons/if (cond_code == "100" || cond_code == "150" || cond_code == "9006") {//晴 Sunny/Clearreturn "B";}if (cond_code == "101") {//多云 Cloudyreturn "Y";}if (cond_code == "102") {//少云 Few Cloudsreturn "N";}if (cond_code == "103" || cond_code == "153") {//晴间多云 Partly Cloudy/return "H";}if (cond_code == "104" || cond_code == "154") {//阴 Overcastreturn "D";}if (cond_code == "300" || cond_code == "301") {//阵雨 Shower Rain 301-强阵雨 Heavy Shower Rainreturn "T";}if (cond_code == "302" || cond_code == "303") {//302-雷阵雨  Thundershower / 303-强雷阵雨return "P";}if (cond_code == "304" || cond_code == "313" || cond_code == "404" || cond_code == "405" || cond_code == "406") {//304-雷阵雨伴有冰雹 Freezing Rain//313-冻雨 Freezing Rain//404-雨夹雪 Sleet//405-雨雪天气 Rain And Snow//406-阵雨夹雪  Shower Snowreturn "X";}if (cond_code == "305" || cond_code == "308" || cond_code == "309" || cond_code == "314" || cond_code == "399") {//305-小雨 Light Rain//308-极端降雨 Extreme Rain//309-毛毛雨/细雨 Drizzle Rain//314-小到中雨 Light to moderate rain//399-雨 Light to moderate rainreturn "Q";}if (cond_code == "306" || cond_code == "307" || cond_code == "310" || cond_code == "311" || cond_code == "312" || cond_code == "315" || cond_code == "316" || cond_code == "317" || cond_code == "318") {//306-中雨 Moderate Rain//307-大雨 Heavy Rain//310-暴雨  Storm//311-大暴雨 Heavy Storm//312-特大暴雨 Severe Storm//315-中到大雨 Moderate to heavy rain//316-大到暴雨 Heavy rain to storm//317-暴雨到大暴雨 Storm to heavy storm//318-大暴雨到特大暴雨 Heavy to severe stormreturn "R";}if (cond_code == "400" || cond_code == "408") {//400-小雪 Light Snow//408-小到中雪 Light to moderate snowreturn "U";}if (cond_code == "401" || cond_code == "402" || cond_code == "403" || cond_code == "409" || cond_code == "410") {//401-中雪 Moderate Snow//402-大雪 Heavy Snow//403-暴雪 Snowstorm//409-中到大雪 Moderate to heavy snow//410-大到暴雪 Heavy snow to snowstormreturn "W";}if (cond_code == "407") {//407-阵雪 Snow Flurryreturn "V";}if (cond_code == "499" || cond_code == "901") {//499-雪 Snow//901-冷 Coldreturn "G";}if (cond_code == "500") {//500-薄雾 Mistreturn "E";}if (cond_code == "501" || cond_code == "509" || cond_code == "510" || cond_code == "514" || cond_code == "515") {//501-雾 Foggyreturn "M";}if (cond_code == "502" || cond_code == "511" || cond_code == "512" || cond_code == "513") {//502-霾 Hazereturn "L";}if (cond_code == "503" || cond_code == "504" || cond_code == "507" || cond_code == "508") {//503-扬沙 Sandreturn "F";}if (cond_code == "999") {//未知return ")";}if (cond_code == "213") {return "O";}if (cond_code == "200" || cond_code == "201" || cond_code == "202" || cond_code == "203" || cond_code == "204" || cond_code == "205" || cond_code == "206" || cond_code == "207" || cond_code == "208" || cond_code == "209" || cond_code == "210" || cond_code == "211" || cond_code == "212") {return "S";}return ")";
}

  另外,需要对 HeFeng.h 文件中的HeFengCurrentData这个结构体变量增加一个“风向”成员变量,即String wind_dir,更改后的结构体变量如下:

typedef struct HeFengCurrentData {String cond_txt;String fl;String tmp;String hum;String wind_sc;String wind_dir;String iconMeteoCon;String follower;
}
HeFengCurrentData;

4. 成果展示

  做完这些后基本就可以解决天气时钟二三页出现NA的问题了,由于时间比较仓促,3D外壳就没打印,简单焊接了一个洞洞板测试了下功能,演示视频以及运行中的界面如下:

物联网天气时钟演示视频

5. 结语

  这是我第一次写博客,有很多不足之处,也请大家多多批评指正。
在这里插入图片描述

这篇关于【ESP8266物联网天气时钟】解决太极创客物联网天气时钟二三页出现NA的问题——新版和风天气API以及gzip数据解压的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/zhanwudi/article/details/130884413
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/157612

相关文章

解决mysql插入数据锁等待超时报错:Lock wait timeout exceeded;try restarting transaction

《解决mysql插入数据锁等待超时报错:Lockwaittimeoutexceeded;tryrestartingtransaction》:本文主要介绍解决mysql插入数据锁等待超时报... 目录报错信息解决办法1、数据库中执行如下sql2、再到 INNODB_TRX 事务表中查看总结报错信息Lock

MySQL启动报错:InnoDB表空间丢失问题及解决方法

《MySQL启动报错:InnoDB表空间丢失问题及解决方法》在启动MySQL时,遇到了InnoDB:Tablespace5975wasnotfound,该错误表明MySQL在启动过程中无法找到指定的s... 目录mysql 启动报错:InnoDB 表空间丢失问题及解决方法错误分析解决方案1. 启用 inno

Java使用MethodHandle来替代反射,提高性能问题

《Java使用MethodHandle来替代反射,提高性能问题》:本文主要介绍Java使用MethodHandle来替代反射,提高性能问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录一、认识MethodHandle1、简介2、使用方式3、与反射的区别二、示例1、基本使用2、(重要)

使用C#删除Excel表格中的重复行数据的代码详解

《使用C#删除Excel表格中的重复行数据的代码详解》重复行是指在Excel表格中完全相同的多行数据,删除这些重复行至关重要,因为它们不仅会干扰数据分析,还可能导致错误的决策和结论,所以本文给大家介绍... 目录简介使用工具C# 删除Excel工作表中的重复行语法工作原理实现代码C# 删除指定Excel单元

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

Nacos日志与Raft的数据清理指南

《Nacos日志与Raft的数据清理指南》随着运行时间的增长,Nacos的日志文件(logs/)和Raft持久化数据(data/protocol/raft/)可能会占用大量磁盘空间,影响系统稳定性,本... 目录引言1. Nacos 日志文件(logs/ 目录)清理1.1 日志文件的作用1.2 是否可以删除

基于Python实现智能天气提醒助手

《基于Python实现智能天气提醒助手》这篇文章主要来和大家分享一个实用的Python天气提醒助手开发方案,这个工具可以方便地集成到青龙面板或其他调度框架中使用,有需要的小伙伴可以参考一下... 目录项目概述核心功能技术实现1. 天气API集成2. AI建议生成3. 消息推送环境配置使用方法完整代码项目特点

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

电脑蓝牙连不上怎么办? 5 招教你轻松修复Mac蓝牙连接问题的技巧

《电脑蓝牙连不上怎么办?5招教你轻松修复Mac蓝牙连接问题的技巧》蓝牙连接问题是一些Mac用户经常遇到的常见问题之一,在本文章中,我们将提供一些有用的提示和技巧,帮助您解决可能出现的蓝牙连接问... 蓝牙作为一种流行的无线技术,已经成为我们连接各种设备的重要工具。在 MAC 上,你可以根据自己的需求,轻松地

Java 中的跨域问题解决方法

《Java中的跨域问题解决方法》跨域问题本质上是浏览器的一种安全机制,与Java本身无关,但Java后端开发者需要理解其来源以便正确解决,下面给大家介绍Java中的跨域问题解决方法,感兴趣的朋友一起... 目录1、Java 中跨域问题的来源1.1. 浏览器同源策略(Same-Origin Policy)1.