当前位置:   article > 正文

【项目1】多功能墨水屏新闻、天气台历(一)_墨水屏日历开源

墨水屏日历开源

非广告,真心推荐:太极创客

太极创客 – Arduino, ESP8266物联网的应用、开发和学习资料http://www.taichi-maker.com/

项目来源:【开源】教程——4.2寸多功能微雪墨水屏新闻台历gxepd2版本_哔哩哔哩_bilibili


目录

显示效果

esp32

通用驱动板

DHT11

代码部分

GxEPD2_Version_4in2_epd_calendar.ino文件下代码

初始化

主函数

定义部分

Webserver.h关于wifi代码

参数配置

初始化setup()调用的wifi_init()

配网

等待连接

配网模式

setupMode()

对字符串进行URL解码

makePage()

gatData文件关于GetData()函数

CallHttps.ino

JsonWeather.ino和天气相关的数据处理

ParseActualWeather(String content, struct LifeIndex* data)解析生活指数

ParseActualWeather(String content, struct ActualWeather* data)解析实况天气

ParseFutureWeather(String content, struct FutureWeather* data)解析未来天气

JsonHitokoto文件,与一言处理数据相关。

JsonNews文件中新闻数据处理


这个项目看起来不太简单。

ArduinoJson:ArduinoJson: Efficient JSON serialization for embedded C++

GxEPD2:屏幕驱动库https://github.com/jeason-j/GxEPD2GitHub - ZinggJM/GxEPD2: Arduino Display Library for SPI E-Paper Displays

Timezone:Arduino时区库GitHub - JChristensen/Timezone: Arduino library to facilitate time zone conversions and automatic daylight saving (summer) time adjustments.

U8g2:图形库Home · olikraus/u8g2 Wiki · GitHub

U8g2_for_Adafruit_GFX.h:joe/U8g2_for_Adafruit_GFX

Dht11:这个方面库很多,随便搜搜吧。没找到参考文档之类的。

显示效果

 

啧~违规,拉倒吧!GitHub - zhushengji/GxEPD2_Version_4in2_epd_calendar: 基于GXEPD2库文件开发的通用版多功能墨水屏台历

esp32

图片来源:ESP32 GPIO_我不想35岁失业的博客-CSDN博客_esp32 gpio

通用驱动板

说实话,按照作者的说法没找到。但是在立创开源社区有许多大佬画的板子。基本相仿,按照接线规则连接即可。

DHT11

DHT11接到GPIO21

由displayCode文件可知引脚连接到

  1. /*温度*/
  2. dht11 DHT11;
  3. void gettem(){
  4. DHT11.read(21);
  5. String temperature=String(DHT11.temperature)+"℃";
  6. String humidity = String(DHT11.humidity)+"%";
  7. u8g2Fonts.setFont(chinese_city_gb2312);
  8. u8g2Fonts.setForegroundColor(GxEPD_BLACK); // 设置前景色
  9. u8g2Fonts.setBackgroundColor(GxEPD_WHITE); // 设置背景色
  10. u8g2Fonts.setCursor(272,222);
  11. u8g2Fonts.print("室内");
  12. display.drawInvertedBitmap(312, 210, wendu, 16, 16, GxEPD_BLACK);//画图
  13. u8g2Fonts.setCursor(330,222);
  14. u8g2Fonts.print(temperature);
  15. display.drawInvertedBitmap(358, 210, shidu, 16, 16, GxEPD_BLACK);//画图
  16. u8g2Fonts.setCursor(376,222);
  17. u8g2Fonts.print(humidity);
  18. }

余下还有电池等外围电路与控制无关,不做分析。

代码部分

GxEPD2_Version_4in2_epd_calendar.ino文件下代码

初始化

  1. void setup()
  2. {
  3. Serial.begin(115200); //串口波特率
  4. EEPROM.begin(4096); //申请size内存
  5. display.init(); //display初始化
  6. u8g2Fonts.begin(display);//将u8g2连接到display
  7. display.firstPage(); //firstPage方法会把当前页码位置变成0
  8. display.display(1); //延时
  9. wifi_init(); //wifi初始化
  10. }

主函数

  1. void loop() {
  2. /*后台配置*/
  3. if (settingMode) { //Webserver.h中定义,配置网络的问题
  4. dnsServer.processNextRequest();
  5. }
  6. webServer.handleClient();
  7. if (!settingMode) {
  8. GetData(); //获取Json数据 //定义在gatData
  9. initNTP(); //初始化时间 //定义在NTP.h
  10. display.fillScreen(GxEPD_WHITE); //初始化屏幕
  11. get_weather(); //获取天气 //定义在displayCode
  12. updatetime(); //时间 //定义在displayCode
  13. hitokoto(); //一言 //定义在displayCode
  14. newsdisplay(); //新闻 //定义在displayCode
  15. gettem(); //温湿度 //定义在displayCode
  16. udc++; //计数 //心知天气免费20次每分钟
  17. display.nextPage();
  18. /* 1.轻度休眠会关闭WiFi蓝牙以降低功耗,所以唤醒后需要重新联网
  19. * 2.之所以不用功耗更低的深度休眠,因为深度休眠只保留RTC,内存
  20. * 中的数据会丢失
  21. * 3.休眠函数中时间单位是微秒,所以数据要X1000000
  22. */
  23. //轻度休眠有概率导致连不上网
  24. /*esp_sleep_enable_timer_wakeup(300000000);//5分钟刷新一次
  25. esp_light_sleep_start();
  26. delay(1000);
  27. wifi_init();//休眠后需要重新联网*/
  28. delay(300000);//5分钟更新一次
  29. }
  30. /*深度睡眠会导致内存中数据丢失让新闻切换出问题,故弃用
  31. * esp_sleep_enable_timer_wakeup(20000000);
  32. * esp_deep_sleep_start();
  33. */
  34. }

初始化和主函数看起来都不难理解。

定义部分

定义要统一格式啊!为什么不统一格式!

统一格式增加可读性!!!

  1. #include <U8g2_for_Adafruit_GFX.h>
  2. #include <GxEPD2_3C.h>
  3. #include <ArduinoJson.h>
  4. #include <Timezone.h>
  5. GxEPD2_3C<GxEPD2_420c, GxEPD2_420c::HEIGHT> display(GxEPD2_420c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW042Z15
  6. #include "gb2312.c"
  7. #include "imagedata.h"
  8. #include "Webserver.h"
  9. #include "NTP.h"
  10. #include <dht11.h>
  11. extern const uint8_t chinese_city_gb2312[239032] //这么多,真占内存 U8G2_FONT_SECTION("chinese_city_gb2312"); //国标2312
  12. /* 自己写代码喜欢这样,看别人代码就不喜欢这样 */
  13. U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;
  14. //****** HTTP服务器配置 ******
  15. String language = "zh-Hans"; // 请求语言
  16. String url_yiyan = "https://v1.hitokoto.cn/";//一言获取地址
  17. String url_ActualWeather; //实况天气地址
  18. String url_FutureWeather; //未来天气地址
  19. //****** 天气数据
  20. //我们要从此网页中提取的数据的类型
  21. //定义结构体
  22. struct ActualWeather
  23. {
  24. char status_code[64]; //错误代码
  25. char city[16]; //城市名称
  26. char weather_name[16]; //天气现象名称
  27. char weather_code[4]; //天气现象代码
  28. char temp[5]; //温度
  29. char last_update[25]; //最后更新时间
  30. };
  31. ActualWeather actual; //创建结构体变量 目前的
  32. //未来天气
  33. struct FutureWeather
  34. {
  35. char status_code[64]; //错误代码
  36. char date0[14]; //今天日期
  37. char date0_text_day[20]; //白天天气现象名称
  38. char date0_code_day[4]; //白天天气现象代码
  39. char date0_text_night[16]; //晚上天气现象名称
  40. char date0_code_night[4]; //晚上天气现象代码
  41. char date0_high[5]; //最高温度
  42. char date0_low[5]; //最低温度
  43. char date0_humidity[5]; //相对湿度
  44. char date0_wind_scale[5]; //风力等级
  45. char date1[14]; //明天日期
  46. char date1_text_day[20]; //白天天气现象名称
  47. char date1_code_day[4]; //白天天气现象代码
  48. char date1_text_night[16]; //晚上天气现象名称
  49. char date1_code_night[4]; //晚上天气现象代码
  50. char date1_high[5]; //最高温度
  51. char date1_low[5]; //最低温度
  52. //char date1_humidity[5]; //相对湿度
  53. char date2[14]; //后天日期
  54. char date2_text_day[20]; //白天天气现象名称
  55. char date2_code_day[4]; //白天天气现象代码
  56. char date2_text_night[16]; //晚上天气现象名称
  57. char date2_code_night[4]; //晚上天气现象代码
  58. char date2_high[5]; //最高温度
  59. char date2_low[5]; //最低温度
  60. //char date2_humidity[5]; //相对湿度
  61. };
  62. FutureWeather future; //创建结构体变量 未来
  63. struct LifeIndex //生活指数
  64. {
  65. char status_code[64]; //错误代码
  66. char uvi[10]; //紫外线指数
  67. };
  68. LifeIndex life_index; //创建结构体变量 未来
  69. struct News //新闻API
  70. {
  71. char status_code[64]; //错误代码
  72. char title[11][64]; //作者规划只显示11行
  73. };
  74. News xinwen; //创建结构体变量 新闻
  75. struct Hitokoto //一言API
  76. {
  77. char status_code[64]; //错误代码
  78. char hitokoto[64];
  79. };
  80. Hitokoto yiyan; //创建结构体变量 一言
  81. //****** 一些变量 ******
  82. String webServer_news = " ";
  83. uint8_t client_count = 0; //连接服务器的超时计数,暂未使用
  84. uint8_t client_error = 0; //错误代码,暂未使用
  85. boolean night_updated = 1; //夜间更新 1-不更新 0-更新
  86. //RTC临时数据
  87. #define RTC_hour_dz 0 //小时地址
  88. #define RTC_night_count_dz 1 //夜间计数地址
  89. #define RTC_peiwang_state_dz 2 //配网状态地址
  90. uint32_t RTC_hour = 100; //小时
  91. uint32_t RTC_night_count = 0; //24-6点,夜间不更新计数
  92. int32_t night_count_max = 0; //需要跳过几次
  93. uint32_t RTC_peiwang_state = 0; //配网状态 1-需要
  94. //int daydate;//当天日期
  95. int udc=0;//更新次数记录 //在loop函数里++

Webserver.h关于wifi代码

wifi_init()函数在Webserver.h

参数配置

  1. #include <DNSServer.h>
  2. #include <EEPROM.h>
  3. #include <WebServer.h>
  4. #include <HTTPClient.h>
  5. #include "WiFi.h"
  6. const IPAddress apIP(192, 168, 1, 1);
  7. const char* apSSID = "码蜂科技配网WiFi";
  8. boolean settingMode;
  9. String ssidList;
  10. String xz_code;
  11. DNSServer dnsServer;
  12. WebServer webServer(80);
  13. bool flag =false;

初始化setup()调用的wifi_init()

  1. void wifi_init(){
  2. delay(10);
  3. if (restoreConfig()) { //有没有存储过wifi账号密码、心知天气的密钥,没有则启动配网
  4. if (checkConnection()) {
  5. settingMode = false;
  6. startWebServer();
  7. return;
  8. }
  9. }
  10. settingMode = true;
  11. setupMode();
  12. }

配网

  1. boolean restoreConfig() {
  2. Serial.println("Reading EEPROM...");
  3. String ssid = ""; //字符串
  4. String pass = "";
  5. String authcode= "";
  6. if (EEPROM.read(4000) != 0) {
  7. for (int i = 4000; i < 4032; ++i) {
  8. char ch = EEPROM.read(i);
  9. if (isalpha(ch) || isdigit(ch)) { //判断字母||十进制数
  10. ssid += char(EEPROM.read(i));
  11. }
  12. }
  13. Serial.print("WiFi: ");
  14. Serial.println(ssid);
  15. for (int i = 4032; i < 4064; ++i) {
  16. char ch = EEPROM.read(i);
  17. if (isalpha(ch) || isdigit(ch)) {
  18. pass += char(EEPROM.read(i));
  19. }
  20. }
  21. Serial.print("密码: ");
  22. Serial.println(pass);
  23. //心知天气密钥
  24. for (int i = 4064; i < 4096; ++i) {
  25. char ch = EEPROM.read(i);
  26. if (isalpha(ch) || isdigit(ch)||ch=='-') {
  27. authcode += char(EEPROM.read(i));
  28. }
  29. }
  30. Serial.print("密钥: ");
  31. Serial.println(authcode);
  32. WiFi.begin(ssid.c_str(), pass.c_str()); //c_str()返回当前字符串的首字符地址
  33. xz_code = authcode.c_str(); //心知天气密钥
  34. WiFi.begin(ssid.c_str(), pass.c_str());
  35. return true;
  36. }
  37. else {
  38. Serial.println("Config not found.");
  39. return false;
  40. }
  41. }

等待连接

  1. boolean checkConnection() {
  2. int count = 0;
  3. Serial.println("正在等待连接");
  4. while ( count < 30 ) { //30s
  5. if (WiFi.status() == WL_CONNECTED) {
  6. Serial.println("成功连接!");
  7. return (true);
  8. }
  9. delay(500);
  10. Serial.print(".");
  11. count++;
  12. }
  13. Serial.println("连接超时.");
  14. return false;
  15. }

配网模式

  1. void startWebServer() {
  2. // display.drawInvertedBitmap(0, 0, jitang, 400, 300, GxEPD_BLACK);//画图
  3. // Serial.println("开屏动画");
  4. if (settingMode) {
  5. Serial.print("Starting Web Server at ");
  6. Serial.println(WiFi.softAPIP());
  7. webServer.on("/settings", []() {
  8. //自己生成一个网页
  9. String s = "<head><meta charset=\"utf-8\"></head><h1>码蜂Wi-Fi配置</h1><p>请在选择WiFi名称后输入对应的WiFi密码.</p>";
  10. s += "<form method=\"get\" action=\"setap\"><label>网络:</label><select name=\"ssid\">";
  11. s += ssidList;
  12. //提交数据
  13. s += "</select><br>密码:<input name=\"pass\" length=64 type=\"password\"><br>心知密钥:<input name=\"authcode\" length=64 type=\"password\"><br>";
  14. s += "<input name=\"保存并提交\" type=\"submit\"></form>";
  15. webServer.send(200, "text/html", makePage("码蜂Wi-Fi配置", s)); //向客户端发送响应信息。
  16. });
  17. webServer.on("/setap", []() {
  18. //清空数据,防止出现WiFi账号密码长度不一致导致的无法联网问题
  19. for (int i = 4000; i < 4096; ++i) {
  20. EEPROM.begin(4096);
  21. EEPROM.write(i, 0);
  22. EEPROM.commit();
  23. }
  24. String ssid = urlDecode(webServer.arg("ssid"));
  25. Serial.print("SSID: ");
  26. Serial.println(ssid);
  27. String pass = urlDecode(webServer.arg("pass"));
  28. Serial.print("Password: ");
  29. Serial.println(pass);
  30. String authcode = urlDecode(webServer.arg("authcode"));
  31. Serial.print("authcode: ");
  32. Serial.println(authcode);
  33. Serial.println("Writing ssid to EEPROM...");
  34. for (int i = 0; i < ssid.length(); ++i) {
  35. EEPROM.begin(4096);
  36. EEPROM.write(4000 + i, ssid[i]);
  37. EEPROM.commit();
  38. }
  39. Serial.println("Writing Password to EEPROM...");
  40. for (int i = 0; i < pass.length(); ++i) {
  41. EEPROM.begin(4096);
  42. EEPROM.write(4032 + i, pass[i]);
  43. EEPROM.commit();
  44. }
  45. EEPROM.end(); //这两行多余了吧
  46. Serial.println("Write EEPROM done!");
  47. Serial.println("Writing authcode to EEPROM...");
  48. for (int i = 0; i < authcode.length(); ++i) {
  49. EEPROM.begin(4096);
  50. EEPROM.write(4064 + i, authcode[i]);
  51. EEPROM.commit();
  52. }
  53. EEPROM.end();
  54. Serial.println("Write EEPROM done!");
  55. String s = "<h1>设置结束!</h1><p>设备即将在重启后接入 \"";
  56. s += ssid;
  57. s += "\" ";
  58. webServer.send(200, "text/html", makePage("码蜂Wi-Fi配置", s));
  59. ESP.restart(); //重启
  60. });
  61. webServer.onNotFound([]() {
  62. String s = "<h1>配网模式</h1><p><a href=\"/settings\">点击配网</a></p>";
  63. webServer.send(200, "text/html", makePage("配网模式", s));
  64. });
  65. }
  66. else {
  67. Serial.print("Starting Web Server at ");
  68. Serial.println(WiFi.localIP());
  69. webServer.on("/", []() {
  70. String s = "<h1>STA mode</h1><p><a href=\"/reset\">重置WiFi设置</a></p>";
  71. webServer.send(200, "text/html", makePage("STA mode", s));
  72. });
  73. webServer.on("/reset", []() {
  74. for (int i = 4000; i < 4096; ++i) {
  75. EEPROM.begin(4096);
  76. EEPROM.write(i, 0);
  77. // EEPROM.commit();
  78. EEPROM.end();
  79. }
  80. String s = "<h1>Wi-Fi 设置已重置</h1><p>请重启设备.</p>";
  81. webServer.send(200, "text/html", makePage("Reset Wi-Fi Settings", s));
  82. });
  83. }
  84. webServer.begin();
  85. }

setupMode()

  1. void setupMode() {
  2. WiFi.mode(WIFI_STA); //无线终端模式
  3. WiFi.disconnect(); //断开连接
  4. delay(100);
  5. int n = WiFi.scanNetworks();//扫描周围wifi
  6. delay(100);
  7. Serial.println("");
  8. for (int i = 0; i < n; ++i) {
  9. ssidList += "<option value=\"";
  10. ssidList += WiFi.SSID(i); //路由器发送的无线信号的名字
  11. ssidList += "\">";
  12. ssidList += WiFi.SSID(i);
  13. ssidList += "</option>";
  14. }
  15. delay(100);
  16. WiFi.mode(WIFI_AP);
  17. WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); //配置接入点网络信息:IP地址,网关,子网掩码。
  18. WiFi.softAP(apSSID); //用于启动校验式wifi网络或开放式wifi网络
  19. dnsServer.start(53, "*", apIP); //启动ESP8266模块的DNS服务
  20. /*如果联网失败就显示失败提醒*/
  21. display.fillScreen(GxEPD_WHITE);
  22. display.drawInvertedBitmap(0, 0, jitang, 400, 300, GxEPD_BLACK);//画图
  23. display.nextPage();
  24. startWebServer();
  25. Serial.print("Starting Access Point at \"");
  26. Serial.print(apSSID);
  27. Serial.println("\"");
  28. }

对字符串进行URL解码

  1. String urlDecode(String input) {
  2. String s = input;
  3. s.replace("%20", " ");
  4. s.replace("+", " ");
  5. s.replace("%21", "!");
  6. s.replace("%22", "\"");
  7. s.replace("%23", "#");
  8. s.replace("%24", "$");
  9. s.replace("%25", "%");
  10. s.replace("%26", "&");
  11. s.replace("%27", "\'");
  12. s.replace("%28", "(");
  13. s.replace("%29", ")");
  14. s.replace("%30", "*");
  15. s.replace("%31", "+");
  16. s.replace("%2C", ",");
  17. s.replace("%2E", ".");
  18. s.replace("%2F", "/");
  19. s.replace("%2C", ",");
  20. s.replace("%3A", ":");
  21. s.replace("%3A", ";");
  22. s.replace("%3C", "<");
  23. s.replace("%3D", "=");
  24. s.replace("%3E", ">");
  25. s.replace("%3F", "?");
  26. s.replace("%40", "@");
  27. s.replace("%5B", "[");
  28. s.replace("%5C", "\\");
  29. s.replace("%5D", "]");
  30. s.replace("%5E", "^");
  31. s.replace("%5F", "-");
  32. s.replace("%60", "`");
  33. return s;
  34. }

makePage()

  1. String makePage(String title, String contents) {
  2. String s = "<!DOCTYPE html><html><head>";
  3. s += "<meta name=\"viewport\" content=\"width=device-width,user-scalable=0\">";
  4. s += "<title>";
  5. s += title;
  6. s += "</title></head><body>";
  7. s += contents;
  8. s += "</body></html>";
  9. return s;
  10. }

下面从loop函数开始分析操作流程

首先是GetData()函数,获取Json数据,定义在gatData文件中,整个gatData文件也只有这一个函数。

gatData文件关于GetData()函数

定义在GxEPD2_Version_4in2_epd_calendar.ino文件下

  1. String url_ActualWeather; //实况天气地址
  2. String url_FutureWeather; //未来天气地址

 心知天气、一言、新闻等数据接口。

  1. void GetData()
  2. {
  3. //"http://api.seniverse.com/v3/weather/now.json?key=S6pG_Q54kjfnBAi6i&location=深圳&language=zh-Hans&unit=c"
  4. //拼装实况天气API地址
  5. url_ActualWeather = "https://api.seniverse.com/v3/weather/now.json";
  6. url_ActualWeather += "?key=" + xz_code;
  7. url_ActualWeather += "&location=ip" ;
  8. url_ActualWeather += "&language=" + language;
  9. url_ActualWeather += "&unit=c";
  10. //https://api.seniverse.com/v3/weather/daily.json?key=S6pG_Q54kjfnBAi6i&location=深圳&language=zh-Hans&unit=c&start=0&days=3
  11. //拼装实况未来API地址
  12. url_FutureWeather = "https://api.seniverse.com/v3/weather/daily.json";
  13. url_FutureWeather += "?key=" + xz_code;
  14. url_FutureWeather += "&location=ip";
  15. url_FutureWeather += "&language=" + language;
  16. url_FutureWeather += "&unit=c";
  17. url_FutureWeather += "&start=0";
  18. url_FutureWeather += "&days=3";
  19. //https://api.seniverse.com/v3/life/suggestion.json?key=S6pG_Q54kjfnBAi6i&location=shanghai&language=zh-Hans
  20. //拼装生活指数
  21. //在GxEPD2_Version_4in2_epd_calendar.ino没定义跑在这里定义了
  22. String url_LifeIndex = "https://api.seniverse.com/v3/life/suggestion.json";
  23. url_LifeIndex += "?key=" + xz_code;
  24. url_LifeIndex += "&location=ip";
  25. //新闻地址
  26. //就这俩在GxEPD2_Version_4in2_epd_calendar.ino中定义多好啊
  27. String url_News="";
  28. if(udc%3==0){
  29. url_News="https://api.vvhan.com/api/wbhot";//微博
  30. }else if(udc%3==1){
  31. url_News = "https://api.iyk0.com/ysxw/";//央视新闻
  32. }else{
  33. url_News = "http://api.rosysun.cn/zhihu/"; //知乎的不能用了
  34. }
  35. // String url_News = "https://api.iyk0.com/ysxw/";//央视新闻
  36. // String url_News = "http://api.rosysun.cn/zhihu/";
  37. // String url_News = "https://api.iyk0.com/bdr";//百度头条
  38. // String url_News = "https://api.vvhan.com/api/douban";
  39. //请求数据并Json处理
  40. // display_partialLine(7, "获取生活指数");
  41. /*两个半小时更新一次天气,节省访问次数且不影响使用*/
  42. //第二个参数为结构体!! //callHttps定义在CallHttps
  43. if(udc%30==0){ //函数定义在JsonWeather
  44. ParseActualWeather(callHttps(url_LifeIndex), &life_index); //获取生活指数
  45. ParseActualWeather(callHttps(url_ActualWeather), &actual);
  46. // display_bitmap_bottom(Bitmap_wlq2, "获取未来天气数据中");
  47. ParseFutureWeather(callHttps(url_FutureWeather), &future);
  48. }
  49. ParseHitokoto(callHttps(url_yiyan), &yiyan); //函数定义在JsonHitokoto
  50. ParseNews(callHttps(url_News),&xinwen); //函数定义在JsonNews
  51. }

既然使用了callHttps()函数,那就先看CallHttps.ino

CallHttps.ino

仅有一个函数定义于此文件下。

  1. String callHttps(String url)
  2. {
  3. String payload;
  4. Serial.print("requesting URL: ");
  5. Serial.println(url);
  6. //###***---+++===~~~!!!$$$^^^&&&
  7. HTTPClient https;
  8. if (https.begin(url)) //通过HTTP协议向网络服务器发送HTTP请求
  9. {
  10. int httpsCode = https.GET(); //从指定的资源请求数据,返回服务器状态码
  11. if (httpsCode > 0) //判断有无返回值
  12. {
  13. /*payload = https.getString();
  14. Serial.println(payload);
  15. return payload;*/
  16. if (httpsCode == 200 || httpsCode == 304 || httpsCode == 403 || httpsCode == 404 || httpsCode == 500) //判断请求是正确
  17. {
  18. payload = https.getString(); //可用于获取服务器响应中的响应体信息。响应体信息将以字符串的形式进行返回。
  19. // Serial.println(payload);
  20. Serial.println(" ");
  21. return payload;
  22. }
  23. else
  24. {
  25. Serial.print("请求错误:"); Serial.println(httpsCode); Serial.println(" ");
  26. char* httpsCode_c = new char[8];
  27. itoa(httpsCode, httpsCode_c, 10); //int转char* 10是进制
  28. payload = "{\"status_code\":\"" + String("请求错误:") + String(httpsCode_c) + "\"}";
  29. return payload;
  30. }
  31. }
  32. else
  33. {
  34. Serial.println(" "); Serial.print("GET请求错误:"); Serial.println(httpsCode);
  35. Serial.printf("[HTTPS] GET... 失败, 错误: %s\n", https.errorToString(httpsCode).c_str());
  36. payload = "{\"status_code\":\"" + String(https.errorToString(httpsCode).c_str()) + "\"}";
  37. //Serial.println(payload);
  38. return payload;
  39. }
  40. }
  41. else
  42. {
  43. Serial.printf("[HTTPS] 无法连接服务器\n");
  44. payload = "{\"status_code\":\"" + String("无法连接服务器") + "\"}";
  45. return payload;
  46. }
  47. https.end();
  48. }

通过类似ParseActualWeather(callHttps(url_LifeIndex), &life_index); 处理的读取函数,所以下面看ParseActualWeather()函数,定义在JsonWeather中!

JsonWeather.ino和天气相关的数据处理

ParseActualWeather(String content, struct LifeIndex* data)解析生活指数

  1. //使用Json解析天气数据,天气实况
  2. bool ParseActualWeather(String content, struct LifeIndex* data)
  3. {
  4. DynamicJsonDocument json(1536); //分配内存,动态 建立了DynamicJsonDocument对象,该对象名称为json
  5. DeserializationError error = deserializeJson(json, content); //解析json
  6. //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
  7. if (error)
  8. {
  9. Serial.print("天气指数加载json配置失败:");
  10. Serial.println(error.c_str());
  11. Serial.println(" ");
  12. String z = "天气指数json配置失败:" + String(error.c_str()) + " " + content;
  13. //display_partialLine(7, z);
  14. // esp_sleep(0);
  15. return false;
  16. }
  17. //检查API是否有返回错误信息,有返回则进入休眠
  18. if (json["status_code"].isNull() == 0) //检查到不为空
  19. {
  20. strcpy(data->status_code, json["status_code"]);
  21. String z;
  22. if (String(actual.status_code) == "AP010001") z = "API 请求参数错误" ;
  23. else if (String(actual.status_code) == "AP010002") z = "没有权限访问这个 API 接口" ;
  24. else if (String(actual.status_code) == "AP010003") z = "API 密钥 key 错误" ;
  25. else if (String(actual.status_code) == "AP010004") z = "签名错误" ;
  26. else if (String(actual.status_code) == "AP010005") z = "你请求的 API 不存在" ;
  27. else if (String(actual.status_code) == "AP010006") z = "没有权限访问这个地点: ";
  28. else if (String(actual.status_code) == "AP010007") z = "JSONP 请求需要使用签名验证方式" ;
  29. else if (String(actual.status_code) == "AP010008") z = "没有绑定域名" ;
  30. else if (String(actual.status_code) == "AP010009") z = "API 请求的 user-agent 与你设置的不一致" ;
  31. else if (String(actual.status_code) == "AP010010") z = "没有这个地点" ;
  32. else if (String(actual.status_code) == "AP010011") z = "无法查找到指定 IP 地址对应的城市" ;
  33. else if (String(actual.status_code) == "AP010012") z = "你的服务已经过期" ;
  34. else if (String(actual.status_code) == "AP010013") z = "访问量余额不足" ;
  35. else if (String(actual.status_code) == "AP010014") z = "访问频率超过限制" ;
  36. else if (String(actual.status_code) == "AP010015") z = "暂不支持该城市的车辆限行信息" ;
  37. else if (String(actual.status_code) == "AP010016") z = "暂不支持该城市的潮汐数据" ;
  38. else if (String(actual.status_code) == "AP010017") z = "请求的坐标超出支持的范围" ;
  39. else if (String(actual.status_code) == "AP100001") z = "心知系统内部错误:数据缺失" ;
  40. else if (String(actual.status_code) == "AP100002") z = "心知系统内部错误:数据错误" ;
  41. else if (String(actual.status_code) == "AP100003") z = "心知系统内部错误:服务内部错误" ;
  42. else if (String(actual.status_code) == "AP100004") z = "心知系统内部错误:网关错误" ;
  43. else z = "天气指数异常:" + String(actual.status_code);
  44. //display_partialLine(7, z);
  45. Serial.print("天气指数异常:"); Serial.println(actual.status_code);
  46. //esp_sleep(60);
  47. }
  48. // 复制我们感兴趣的字符串 ,先检查是否为空,空会导致系统无限重启
  49. // isNull()检查是否为空 空返回1 非空0
  50. if (json["results"][0]["suggestion"]["uv"]["brief"].isNull() == 0) //紫外线指数
  51. strcpy(data->uvi, json["results"][0]["suggestion"]["uv"]["brief"]);
  52. //if (json["results"][0]["now"]["text"].isNull() == 0)
  53. //strcpy(data->weather_name, json["results"][0]["now"]["text"]);
  54. // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内,所以你需要确保
  55. // 当你读取字符串时它仍在内存中
  56. return true;
  57. }

ParseActualWeather(String content, struct ActualWeather* data)解析实况天气

都差不多啦!~

  1. //使用Json解析天气数据,天气实况
  2. bool ParseActualWeather(String content, struct ActualWeather* data)
  3. {
  4. DynamicJsonDocument json(1536); //分配内存,动态
  5. DeserializationError error = deserializeJson(json, content); //解析json
  6. //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
  7. if (error)
  8. {
  9. Serial.print("实况天气加载json配置失败:");
  10. Serial.println(error.c_str());
  11. Serial.println(" ");
  12. String z = "实况天气json配置失败:" + String(error.c_str()) + " " + content;
  13. //display_partialLine(7, z);
  14. // esp_sleep(0);
  15. return false;
  16. }
  17. //检查API是否有返回错误信息,有返回则进入休眠
  18. if (json["status_code"].isNull() == 0) //检查到不为空
  19. {
  20. strcpy(data->status_code, json["status_code"]);
  21. String z;
  22. if (String(actual.status_code) == "AP010001") z = "API 请求参数错误" ;
  23. else if (String(actual.status_code) == "AP010002") z = "没有权限访问这个 API 接口" ;
  24. else if (String(actual.status_code) == "AP010003") z = "API 密钥 key 错误" ;
  25. else if (String(actual.status_code) == "AP010004") z = "签名错误" ;
  26. else if (String(actual.status_code) == "AP010005") z = "你请求的 API 不存在" ;
  27. else if (String(actual.status_code) == "AP010006") z = "没有权限访问这个地点" ;
  28. else if (String(actual.status_code) == "AP010007") z = "JSONP 请求需要使用签名验证方式" ;
  29. else if (String(actual.status_code) == "AP010008") z = "没有绑定域名" ;
  30. else if (String(actual.status_code) == "AP010009") z = "API 请求的 user-agent 与你设置的不一致" ;
  31. else if (String(actual.status_code) == "AP010010") z = "没有这个地点";
  32. else if (String(actual.status_code) == "AP010011") z = "无法查找到指定 IP 地址对应的城市" ;
  33. else if (String(actual.status_code) == "AP010012") z = "你的服务已经过期" ;
  34. else if (String(actual.status_code) == "AP010013") z = "访问量余额不足" ;
  35. else if (String(actual.status_code) == "AP010014") z = "访问频率超过限制" ;
  36. else if (String(actual.status_code) == "AP010015") z = "暂不支持该城市的车辆限行信息" ;
  37. else if (String(actual.status_code) == "AP010016") z = "暂不支持该城市的潮汐数据" ;
  38. else if (String(actual.status_code) == "AP010017") z = "请求的坐标超出支持的范围" ;
  39. else if (String(actual.status_code) == "AP100001") z = "心知系统内部错误:数据缺失" ;
  40. else if (String(actual.status_code) == "AP100002") z = "心知系统内部错误:数据错误" ;
  41. else if (String(actual.status_code) == "AP100003") z = "心知系统内部错误:服务内部错误" ;
  42. else if (String(actual.status_code) == "AP100004") z = "心知系统内部错误:网关错误" ;
  43. else z = "实况天气异常:" + String(actual.status_code);
  44. //display_partialLine(7, z);
  45. Serial.print("实况天气异常:"); Serial.println(actual.status_code);
  46. //esp_sleep(60);
  47. }
  48. // 复制我们感兴趣的字符串 ,先检查是否为空,空会导致系统无限重启
  49. // isNull()检查是否为空 空返回1 非空0
  50. if (json["results"][0]["location"]["name"].isNull() == 0)
  51. strcpy(data->city, json["results"][0]["location"]["name"]);
  52. if (json["results"][0]["now"]["text"].isNull() == 0)
  53. strcpy(data->weather_name, json["results"][0]["now"]["text"]);
  54. if (json["results"][0]["now"]["code"].isNull() == 0)
  55. strcpy(data->weather_code, json["results"][0]["now"]["code"]);
  56. if (json["results"][0]["now"]["temperature"].isNull() == 0)
  57. strcpy(data->temp, json["results"][0]["now"]["temperature"]);
  58. if (json["results"][0]["last_update"].isNull() == 0)
  59. strcpy(data->last_update, json["results"][0]["last_update"]);
  60. // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内,所以你需要确保
  61. // 当你读取字符串时它仍在内存中
  62. return true;
  63. }

ParseFutureWeather(String content, struct FutureWeather* data)解析未来天气

  1. //使用Json解析天气数据,今天和未来2天
  2. bool ParseFutureWeather(String content, struct FutureWeather* data)
  3. {
  4. DynamicJsonDocument json(2560); //分配内存,动态
  5. DeserializationError error = deserializeJson(json, content); //解析json
  6. // serializeJson(json, Serial);//构造序列化json,将内容从串口输出
  7. if (error)
  8. {
  9. Serial.print("未来天气json配置失败:");
  10. Serial.println(error.c_str());
  11. Serial.println(" ");
  12. String z = "未来天气加载json配置失败:" + String(error.c_str()) + " " + content;
  13. //display_partialLine(7, z);
  14. // esp_sleep(0);
  15. return false;
  16. }
  17. //检查API是否有返回错误信息,有返回则进入休眠
  18. if (json["status_code"].isNull() == 0) //检查到不为空
  19. {
  20. strcpy(data->status_code, json["status_code"]);
  21. String z;
  22. if (String(future.status_code) == "AP010001") z = "API 请求参数错误" ;
  23. else if (String(future.status_code) == "AP010002") z = "没有权限访问这个 API 接口" ;
  24. else if (String(future.status_code) == "AP010003") z = "API 密钥 key 错误" ;
  25. else if (String(future.status_code) == "AP010004") z = "签名错误" ;
  26. else if (String(future.status_code) == "AP010005") z = "你请求的 API 不存在" ;
  27. else if (String(future.status_code) == "AP010006") z = "没有权限访问这个地点: ";
  28. else if (String(future.status_code) == "AP010007") z = "JSONP 请求需要使用签名验证方式" ;
  29. else if (String(future.status_code) == "AP010008") z = "没有绑定域名" ;
  30. else if (String(future.status_code) == "AP010009") z = "API 请求的 user-agent 与你设置的不一致" ;
  31. else if (String(future.status_code) == "AP010010") z = "没有这个地点" ;
  32. else if (String(future.status_code) == "AP010011") z = "无法查找到指定 IP 地址对应的城市" ;
  33. else if (String(future.status_code) == "AP010012") z = "你的服务已经过期" ;
  34. else if (String(future.status_code) == "AP010013") z = "访问量余额不足" ;
  35. else if (String(future.status_code) == "AP010014") z = "访问频率超过限制" ;
  36. else if (String(future.status_code) == "AP010015") z = "暂不支持该城市的车辆限行信息" ;
  37. else if (String(future.status_code) == "AP010016") z = "暂不支持该城市的潮汐数据" ;
  38. else if (String(future.status_code) == "AP010017") z = "请求的坐标超出支持的范围" ;
  39. else if (String(future.status_code) == "AP100001") z = "心知系统内部错误:数据缺失" ;
  40. else if (String(future.status_code) == "AP100002") z = "心知系统内部错误:数据错误" ;
  41. else if (String(future.status_code) == "AP100003") z = "心知系统内部错误:服务内部错误" ;
  42. else if (String(future.status_code) == "AP100004") z = "心知系统内部错误:网关错误" ;
  43. else z = "未来天气异常:" + String(future.status_code);
  44. //display_partialLine(7, z);
  45. Serial.print("未来天气异常:"); Serial.println(future.status_code);
  46. //esp_sleep(60);
  47. }
  48. // 复制我们感兴趣的字符串,先检查是否为空,空会复制失败导致系统无限重启
  49. if (json["results"][0]["daily"][0]["date"].isNull() == 0) //日期
  50. strcpy(data->date0, json["results"][0]["daily"][0]["date"]);
  51. if (json["results"][0]["daily"][1]["date"].isNull() == 0)
  52. strcpy(data->date1, json["results"][0]["daily"][1]["date"]);
  53. if (json["results"][0]["daily"][2]["date"].isNull() == 0)
  54. strcpy(data->date2, json["results"][0]["daily"][2]["date"]);
  55. if (json["results"][0]["daily"][0]["text_day"].isNull() == 0) //白天天气现象
  56. strcpy(data->date0_text_day, json["results"][0]["daily"][0]["text_day"]);
  57. if (json["results"][0]["daily"][1]["text_day"].isNull() == 0)
  58. strcpy(data->date1_text_day, json["results"][0]["daily"][1]["text_day"]);
  59. if (json["results"][0]["daily"][2]["text_day"].isNull() == 0)
  60. strcpy(data->date2_text_day, json["results"][0]["daily"][2]["text_day"]);
  61. if (json["results"][0]["daily"][0]["text_night"].isNull() == 0) //晚间天气现象
  62. strcpy(data->date0_text_night, json["results"][0]["daily"][0]["text_night"]);
  63. if (json["results"][0]["daily"][1]["text_night"].isNull() == 0)
  64. strcpy(data->date1_text_night, json["results"][0]["daily"][1]["text_night"]);
  65. if (json["results"][0]["daily"][2]["text_night"].isNull() == 0)
  66. strcpy(data->date2_text_night, json["results"][0]["daily"][2]["text_night"]);
  67. if (json["results"][0]["daily"][0]["high"].isNull() == 0)
  68. strcpy(data->date0_high, json["results"][0]["daily"][0]["high"]); //最高温度
  69. if (json["results"][0]["daily"][1]["high"].isNull() == 0)
  70. strcpy(data->date1_high, json["results"][0]["daily"][1]["high"]);
  71. if (json["results"][0]["daily"][2]["high"].isNull() == 0)
  72. strcpy(data->date2_high, json["results"][0]["daily"][2]["high"]);
  73. if (json["results"][0]["daily"][0]["low"].isNull() == 0) //最低温度
  74. strcpy(data->date0_low, json["results"][0]["daily"][0]["low"]);
  75. if (json["results"][0]["daily"][1]["low"].isNull() == 0)
  76. strcpy(data->date1_low, json["results"][0]["daily"][1]["low"]);
  77. if (json["results"][0]["daily"][2]["low"].isNull() == 0)
  78. strcpy(data->date2_low, json["results"][0]["daily"][2]["low"]);
  79. if (json["results"][0]["daily"][0]["humidity"].isNull() == 0) //湿度
  80. strcpy(data->date0_humidity, json["results"][0]["daily"][0]["humidity"]);
  81. if (json["results"][0]["daily"][0]["wind_scale"].isNull() == 0) //风力等级
  82. strcpy(data->date0_wind_scale, json["results"][0]["daily"][0]["wind_scale"]);
  83. // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内,所以你需要确保
  84. // 当你读取字符串时它仍在内存中
  85. return true;
  86. }

读读到的Json数据,然后存入到结构体中。没啥难度。

ParseHitokoto(callHttps(url_yiyan), &yiyan);获取一言数据,在JsonHitokoto文件中定义。

JsonHitokoto文件,与一言处理数据相关。

String url_yiyan = "https://v1.hitokoto.cn/";//一言获取地址
  1. //****** 获取一言数据
  2. void ParseHitokoto(String content, struct Hitokoto* data)
  3. {
  4. DynamicJsonDocument json(1536); //分配内存,动态
  5. DeserializationError error = deserializeJson(json, content); //解析json
  6. //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
  7. if (error) //检查API是否有返回错误信息,有返回则进入休眠
  8. {
  9. Serial.print("一言加载json配置失败:");
  10. Serial.println(error.c_str());
  11. Serial.println(" ");
  12. String z = "一言json配置失败:" + String(error.c_str()) + " " + content;
  13. }
  14. if (json["status_code"].isNull() == 0) //检查到不为空
  15. {
  16. strcpy(data->status_code, json["status_code"]);
  17. String z = "一言异常:" + String(yiyan.status_code);
  18. Serial.print("一言异常:"); Serial.println(yiyan.status_code);
  19. }
  20. else
  21. {
  22. if (json["hitokoto"].isNull() == 0){
  23. strcpy(data->hitokoto, json["hitokoto"]);
  24. }
  25. else strcpy(data->hitokoto, "哎呀\"hitokoto\"没有数据呢");
  26. }
  27. // 复制我们感兴趣的字符串 ,先检查是否为空,空会导致系统无限重启
  28. // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内
  29. // 所以你需要确保 当你读取字符串时它仍在内存中
  30. // isNull()检查是否为空 空返回1 非空0
  31. }

比较简单啦~

接下来就是新闻。琪琪:接下来~        老秦:接下来~

ParseNews(String content, struct News* data)

JsonNews文件中新闻数据处理

  1. //****** 获取新闻数据
  2. void ParseNews(String content, struct News* data)
  3. {
  4. DynamicJsonDocument json(8536); //分配内存,动态 1536
  5. DeserializationError error = deserializeJson(json, content); //解析json
  6. //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
  7. if (error) //检查API是否有返回错误信息,有返回则进入休眠
  8. {
  9. Serial.print("新闻加载json配置失败:");
  10. Serial.println(error.c_str());
  11. Serial.println(" ");
  12. String z = "新闻json配置失败:" + String(error.c_str()) + " " + content;
  13. }
  14. if (json["status_code"].isNull() == 0) //检查到不为空
  15. {
  16. strcpy(data->status_code, json["status_code"]);
  17. String z = "新闻异常:" + String(xinwen.status_code);
  18. Serial.print("新闻异常:"); Serial.println(xinwen.status_code);
  19. }
  20. else
  21. {
  22. if (json["data"].isNull() == 0){
  23. for(int i = 0;i<11;i++){
  24. strcpy(data->title[i], json["data"][i]["title"]); //取前11个
  25. }
  26. }
  27. }
  28. }

这么多,原来才只看到loop函数里的第一步,啊~ 明天再看吧! 不慌!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/980242
推荐阅读
相关标签
  

闽ICP备14008679号