赞
踩
非广告,真心推荐:太极创客
太极创客 – Arduino, ESP8266物联网的应用、开发和学习资料http://www.taichi-maker.com/
项目来源:【开源】教程——4.2寸多功能微雪墨水屏新闻台历gxepd2版本_哔哩哔哩_bilibili
目录
GxEPD2_Version_4in2_epd_calendar.ino文件下代码
ParseActualWeather(String content, struct LifeIndex* data)解析生活指数
ParseActualWeather(String content, struct ActualWeather* data)解析实况天气
ParseFutureWeather(String content, struct FutureWeather* data)解析未来天气
这个项目看起来不太简单。
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 GPIO_我不想35岁失业的博客-CSDN博客_esp32 gpio
说实话,按照作者的说法没找到。但是在立创开源社区有许多大佬画的板子。基本相仿,按照接线规则连接即可。
DHT11接到GPIO21
由displayCode文件可知引脚连接到
- /*温度*/
- dht11 DHT11;
- void gettem(){
- DHT11.read(21);
- String temperature=String(DHT11.temperature)+"℃";
- String humidity = String(DHT11.humidity)+"%";
- u8g2Fonts.setFont(chinese_city_gb2312);
- u8g2Fonts.setForegroundColor(GxEPD_BLACK); // 设置前景色
- u8g2Fonts.setBackgroundColor(GxEPD_WHITE); // 设置背景色
- u8g2Fonts.setCursor(272,222);
- u8g2Fonts.print("室内");
- display.drawInvertedBitmap(312, 210, wendu, 16, 16, GxEPD_BLACK);//画图
- u8g2Fonts.setCursor(330,222);
- u8g2Fonts.print(temperature);
- display.drawInvertedBitmap(358, 210, shidu, 16, 16, GxEPD_BLACK);//画图
- u8g2Fonts.setCursor(376,222);
- u8g2Fonts.print(humidity);
- }
余下还有电池等外围电路与控制无关,不做分析。
-
- void setup()
- {
- Serial.begin(115200); //串口波特率
- EEPROM.begin(4096); //申请size内存
- display.init(); //display初始化
- u8g2Fonts.begin(display);//将u8g2连接到display
- display.firstPage(); //firstPage方法会把当前页码位置变成0
- display.display(1); //延时
- wifi_init(); //wifi初始化
- }
- void loop() {
- /*后台配置*/
- if (settingMode) { //Webserver.h中定义,配置网络的问题
- dnsServer.processNextRequest();
- }
- webServer.handleClient();
- if (!settingMode) {
- GetData(); //获取Json数据 //定义在gatData
- initNTP(); //初始化时间 //定义在NTP.h
- display.fillScreen(GxEPD_WHITE); //初始化屏幕
- get_weather(); //获取天气 //定义在displayCode
- updatetime(); //时间 //定义在displayCode
- hitokoto(); //一言 //定义在displayCode
- newsdisplay(); //新闻 //定义在displayCode
- gettem(); //温湿度 //定义在displayCode
- udc++; //计数 //心知天气免费20次每分钟
- display.nextPage();
- /* 1.轻度休眠会关闭WiFi蓝牙以降低功耗,所以唤醒后需要重新联网
- * 2.之所以不用功耗更低的深度休眠,因为深度休眠只保留RTC,内存
- * 中的数据会丢失
- * 3.休眠函数中时间单位是微秒,所以数据要X1000000
- */
- //轻度休眠有概率导致连不上网
- /*esp_sleep_enable_timer_wakeup(300000000);//5分钟刷新一次
- esp_light_sleep_start();
- delay(1000);
- wifi_init();//休眠后需要重新联网*/
- delay(300000);//5分钟更新一次
- }
- /*深度睡眠会导致内存中数据丢失让新闻切换出问题,故弃用
- * esp_sleep_enable_timer_wakeup(20000000);
- * esp_deep_sleep_start();
- */
- }
初始化和主函数看起来都不难理解。
定义要统一格式啊!为什么不统一格式!
统一格式增加可读性!!!
- #include <U8g2_for_Adafruit_GFX.h>
- #include <GxEPD2_3C.h>
- #include <ArduinoJson.h>
- #include <Timezone.h>
- GxEPD2_3C<GxEPD2_420c, GxEPD2_420c::HEIGHT> display(GxEPD2_420c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW042Z15
- #include "gb2312.c"
- #include "imagedata.h"
- #include "Webserver.h"
- #include "NTP.h"
- #include <dht11.h>
- extern const uint8_t chinese_city_gb2312[239032] //这么多,真占内存 U8G2_FONT_SECTION("chinese_city_gb2312"); //国标2312
-
- /* 自己写代码喜欢这样,看别人代码就不喜欢这样 */
- U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;
-
- //****** HTTP服务器配置 ******
- String language = "zh-Hans"; // 请求语言
- String url_yiyan = "https://v1.hitokoto.cn/";//一言获取地址
- String url_ActualWeather; //实况天气地址
- String url_FutureWeather; //未来天气地址
-
-
- //****** 天气数据
- //我们要从此网页中提取的数据的类型
- //定义结构体
- struct ActualWeather
- {
- char status_code[64]; //错误代码
- char city[16]; //城市名称
- char weather_name[16]; //天气现象名称
- char weather_code[4]; //天气现象代码
- char temp[5]; //温度
- char last_update[25]; //最后更新时间
- };
- ActualWeather actual; //创建结构体变量 目前的
-
- //未来天气
- struct FutureWeather
- {
- char status_code[64]; //错误代码
-
- char date0[14]; //今天日期
- char date0_text_day[20]; //白天天气现象名称
- char date0_code_day[4]; //白天天气现象代码
- char date0_text_night[16]; //晚上天气现象名称
- char date0_code_night[4]; //晚上天气现象代码
- char date0_high[5]; //最高温度
- char date0_low[5]; //最低温度
- char date0_humidity[5]; //相对湿度
- char date0_wind_scale[5]; //风力等级
-
- char date1[14]; //明天日期
- char date1_text_day[20]; //白天天气现象名称
- char date1_code_day[4]; //白天天气现象代码
- char date1_text_night[16]; //晚上天气现象名称
- char date1_code_night[4]; //晚上天气现象代码
- char date1_high[5]; //最高温度
- char date1_low[5]; //最低温度
- //char date1_humidity[5]; //相对湿度
-
- char date2[14]; //后天日期
- char date2_text_day[20]; //白天天气现象名称
- char date2_code_day[4]; //白天天气现象代码
- char date2_text_night[16]; //晚上天气现象名称
- char date2_code_night[4]; //晚上天气现象代码
- char date2_high[5]; //最高温度
- char date2_low[5]; //最低温度
- //char date2_humidity[5]; //相对湿度
- };
- FutureWeather future; //创建结构体变量 未来
-
- struct LifeIndex //生活指数
- {
- char status_code[64]; //错误代码
- char uvi[10]; //紫外线指数
- };
- LifeIndex life_index; //创建结构体变量 未来
-
- struct News //新闻API
- {
- char status_code[64]; //错误代码
- char title[11][64]; //作者规划只显示11行
- };
- News xinwen; //创建结构体变量 新闻
-
- struct Hitokoto //一言API
- {
- char status_code[64]; //错误代码
- char hitokoto[64];
- };
- Hitokoto yiyan; //创建结构体变量 一言
-
- //****** 一些变量 ******
- String webServer_news = " ";
- uint8_t client_count = 0; //连接服务器的超时计数,暂未使用
- uint8_t client_error = 0; //错误代码,暂未使用
- boolean night_updated = 1; //夜间更新 1-不更新 0-更新
-
- //RTC临时数据
- #define RTC_hour_dz 0 //小时地址
- #define RTC_night_count_dz 1 //夜间计数地址
- #define RTC_peiwang_state_dz 2 //配网状态地址
- uint32_t RTC_hour = 100; //小时
- uint32_t RTC_night_count = 0; //24-6点,夜间不更新计数
- int32_t night_count_max = 0; //需要跳过几次
- uint32_t RTC_peiwang_state = 0; //配网状态 1-需要
-
- //int daydate;//当天日期
- int udc=0;//更新次数记录 //在loop函数里++
wifi_init()函数在Webserver.h
- #include <DNSServer.h>
- #include <EEPROM.h>
- #include <WebServer.h>
- #include <HTTPClient.h>
- #include "WiFi.h"
- const IPAddress apIP(192, 168, 1, 1);
- const char* apSSID = "码蜂科技配网WiFi";
- boolean settingMode;
- String ssidList;
- String xz_code;
-
- DNSServer dnsServer;
-
- WebServer webServer(80);
- bool flag =false;
- void wifi_init(){
- delay(10);
- if (restoreConfig()) { //有没有存储过wifi账号密码、心知天气的密钥,没有则启动配网
- if (checkConnection()) {
- settingMode = false;
- startWebServer();
- return;
- }
- }
- settingMode = true;
- setupMode();
- }
- boolean restoreConfig() {
- Serial.println("Reading EEPROM...");
- String ssid = ""; //字符串
- String pass = "";
- String authcode= "";
- if (EEPROM.read(4000) != 0) {
- for (int i = 4000; i < 4032; ++i) {
- char ch = EEPROM.read(i);
- if (isalpha(ch) || isdigit(ch)) { //判断字母||十进制数
- ssid += char(EEPROM.read(i));
- }
-
- }
- Serial.print("WiFi: ");
- Serial.println(ssid);
-
- for (int i = 4032; i < 4064; ++i) {
- char ch = EEPROM.read(i);
- if (isalpha(ch) || isdigit(ch)) {
- pass += char(EEPROM.read(i));
- }
- }
- Serial.print("密码: ");
- Serial.println(pass);
-
- //心知天气密钥
- for (int i = 4064; i < 4096; ++i) {
- char ch = EEPROM.read(i);
- if (isalpha(ch) || isdigit(ch)||ch=='-') {
- authcode += char(EEPROM.read(i));
- }
- }
- Serial.print("密钥: ");
- Serial.println(authcode);
-
- WiFi.begin(ssid.c_str(), pass.c_str()); //c_str()返回当前字符串的首字符地址
-
- xz_code = authcode.c_str(); //心知天气密钥
-
- WiFi.begin(ssid.c_str(), pass.c_str());
- return true;
- }
- else {
- Serial.println("Config not found.");
- return false;
- }
- }
- boolean checkConnection() {
- int count = 0;
- Serial.println("正在等待连接");
- while ( count < 30 ) { //30s
- if (WiFi.status() == WL_CONNECTED) {
- Serial.println("成功连接!");
- return (true);
- }
- delay(500);
- Serial.print(".");
- count++;
- }
- Serial.println("连接超时.");
- return false;
- }
- void startWebServer() {
- // display.drawInvertedBitmap(0, 0, jitang, 400, 300, GxEPD_BLACK);//画图
- // Serial.println("开屏动画");
-
- if (settingMode) {
- Serial.print("Starting Web Server at ");
- Serial.println(WiFi.softAPIP());
- webServer.on("/settings", []() {
- //自己生成一个网页
- String s = "<head><meta charset=\"utf-8\"></head><h1>码蜂Wi-Fi配置</h1><p>请在选择WiFi名称后输入对应的WiFi密码.</p>";
- s += "<form method=\"get\" action=\"setap\"><label>网络:</label><select name=\"ssid\">";
- s += ssidList;
- //提交数据
- s += "</select><br>密码:<input name=\"pass\" length=64 type=\"password\"><br>心知密钥:<input name=\"authcode\" length=64 type=\"password\"><br>";
- s += "<input name=\"保存并提交\" type=\"submit\"></form>";
- webServer.send(200, "text/html", makePage("码蜂Wi-Fi配置", s)); //向客户端发送响应信息。
- });
-
- webServer.on("/setap", []() {
- //清空数据,防止出现WiFi账号密码长度不一致导致的无法联网问题
- for (int i = 4000; i < 4096; ++i) {
- EEPROM.begin(4096);
- EEPROM.write(i, 0);
- EEPROM.commit();
- }
-
- String ssid = urlDecode(webServer.arg("ssid"));
- Serial.print("SSID: ");
- Serial.println(ssid);
-
- String pass = urlDecode(webServer.arg("pass"));
- Serial.print("Password: ");
- Serial.println(pass);
-
- String authcode = urlDecode(webServer.arg("authcode"));
- Serial.print("authcode: ");
- Serial.println(authcode);
-
- Serial.println("Writing ssid to EEPROM...");
-
- for (int i = 0; i < ssid.length(); ++i) {
- EEPROM.begin(4096);
- EEPROM.write(4000 + i, ssid[i]);
- EEPROM.commit();
- }
- Serial.println("Writing Password to EEPROM...");
-
- for (int i = 0; i < pass.length(); ++i) {
- EEPROM.begin(4096);
- EEPROM.write(4032 + i, pass[i]);
- EEPROM.commit();
- }
- EEPROM.end(); //这两行多余了吧
- Serial.println("Write EEPROM done!");
- Serial.println("Writing authcode to EEPROM...");
-
- for (int i = 0; i < authcode.length(); ++i) {
- EEPROM.begin(4096);
- EEPROM.write(4064 + i, authcode[i]);
- EEPROM.commit();
- }
- EEPROM.end();
- Serial.println("Write EEPROM done!");
-
- String s = "<h1>设置结束!</h1><p>设备即将在重启后接入 \"";
-
- s += ssid;
- s += "\" ";
- webServer.send(200, "text/html", makePage("码蜂Wi-Fi配置", s));
-
- ESP.restart(); //重启
- });
- webServer.onNotFound([]() {
- String s = "<h1>配网模式</h1><p><a href=\"/settings\">点击配网</a></p>";
- webServer.send(200, "text/html", makePage("配网模式", s));
- });
- }
- else {
- Serial.print("Starting Web Server at ");
- Serial.println(WiFi.localIP());
- webServer.on("/", []() {
- String s = "<h1>STA mode</h1><p><a href=\"/reset\">重置WiFi设置</a></p>";
- webServer.send(200, "text/html", makePage("STA mode", s));
- });
- webServer.on("/reset", []() {
- for (int i = 4000; i < 4096; ++i) {
- EEPROM.begin(4096);
- EEPROM.write(i, 0);
- // EEPROM.commit();
- EEPROM.end();
- }
-
- String s = "<h1>Wi-Fi 设置已重置</h1><p>请重启设备.</p>";
- webServer.send(200, "text/html", makePage("Reset Wi-Fi Settings", s));
- });
- }
- webServer.begin();
- }
- void setupMode() {
- WiFi.mode(WIFI_STA); //无线终端模式
- WiFi.disconnect(); //断开连接
- delay(100);
- int n = WiFi.scanNetworks();//扫描周围wifi
- delay(100);
- Serial.println("");
- for (int i = 0; i < n; ++i) {
- ssidList += "<option value=\"";
- ssidList += WiFi.SSID(i); //路由器发送的无线信号的名字
- ssidList += "\">";
- ssidList += WiFi.SSID(i);
- ssidList += "</option>";
- }
- delay(100);
-
- WiFi.mode(WIFI_AP);
- WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); //配置接入点网络信息:IP地址,网关,子网掩码。
- WiFi.softAP(apSSID); //用于启动校验式wifi网络或开放式wifi网络
- dnsServer.start(53, "*", apIP); //启动ESP8266模块的DNS服务
-
- /*如果联网失败就显示失败提醒*/
- display.fillScreen(GxEPD_WHITE);
- display.drawInvertedBitmap(0, 0, jitang, 400, 300, GxEPD_BLACK);//画图
- display.nextPage();
- startWebServer();
- Serial.print("Starting Access Point at \"");
- Serial.print(apSSID);
- Serial.println("\"");
- }
- String urlDecode(String input) {
- String s = input;
- s.replace("%20", " ");
- s.replace("+", " ");
- s.replace("%21", "!");
- s.replace("%22", "\"");
- s.replace("%23", "#");
- s.replace("%24", "$");
- s.replace("%25", "%");
- s.replace("%26", "&");
- s.replace("%27", "\'");
- s.replace("%28", "(");
- s.replace("%29", ")");
- s.replace("%30", "*");
- s.replace("%31", "+");
- s.replace("%2C", ",");
- s.replace("%2E", ".");
- s.replace("%2F", "/");
- s.replace("%2C", ",");
- s.replace("%3A", ":");
- s.replace("%3A", ";");
- s.replace("%3C", "<");
- s.replace("%3D", "=");
- s.replace("%3E", ">");
- s.replace("%3F", "?");
- s.replace("%40", "@");
- s.replace("%5B", "[");
- s.replace("%5C", "\\");
- s.replace("%5D", "]");
- s.replace("%5E", "^");
- s.replace("%5F", "-");
- s.replace("%60", "`");
- return s;
- }
- String makePage(String title, String contents) {
- String s = "<!DOCTYPE html><html><head>";
- s += "<meta name=\"viewport\" content=\"width=device-width,user-scalable=0\">";
- s += "<title>";
- s += title;
- s += "</title></head><body>";
- s += contents;
- s += "</body></html>";
- return s;
- }
下面从loop函数开始分析操作流程
首先是GetData()函数,获取Json数据,定义在gatData文件中,整个gatData文件也只有这一个函数。
定义在GxEPD2_Version_4in2_epd_calendar.ino文件下
- String url_ActualWeather; //实况天气地址
- String url_FutureWeather; //未来天气地址
心知天气、一言、新闻等数据接口。
- void GetData()
- {
- //"http://api.seniverse.com/v3/weather/now.json?key=S6pG_Q54kjfnBAi6i&location=深圳&language=zh-Hans&unit=c"
- //拼装实况天气API地址
- url_ActualWeather = "https://api.seniverse.com/v3/weather/now.json";
- url_ActualWeather += "?key=" + xz_code;
- url_ActualWeather += "&location=ip" ;
- url_ActualWeather += "&language=" + language;
- url_ActualWeather += "&unit=c";
-
- //https://api.seniverse.com/v3/weather/daily.json?key=S6pG_Q54kjfnBAi6i&location=深圳&language=zh-Hans&unit=c&start=0&days=3
- //拼装实况未来API地址
- url_FutureWeather = "https://api.seniverse.com/v3/weather/daily.json";
- url_FutureWeather += "?key=" + xz_code;
- url_FutureWeather += "&location=ip";
- url_FutureWeather += "&language=" + language;
- url_FutureWeather += "&unit=c";
- url_FutureWeather += "&start=0";
- url_FutureWeather += "&days=3";
-
- //https://api.seniverse.com/v3/life/suggestion.json?key=S6pG_Q54kjfnBAi6i&location=shanghai&language=zh-Hans
- //拼装生活指数
- //在GxEPD2_Version_4in2_epd_calendar.ino没定义跑在这里定义了
- String url_LifeIndex = "https://api.seniverse.com/v3/life/suggestion.json";
- url_LifeIndex += "?key=" + xz_code;
- url_LifeIndex += "&location=ip";
-
- //新闻地址
- //就这俩在GxEPD2_Version_4in2_epd_calendar.ino中定义多好啊
- String url_News="";
- if(udc%3==0){
- url_News="https://api.vvhan.com/api/wbhot";//微博
- }else if(udc%3==1){
- url_News = "https://api.iyk0.com/ysxw/";//央视新闻
- }else{
- url_News = "http://api.rosysun.cn/zhihu/"; //知乎的不能用了
- }
- // String url_News = "https://api.iyk0.com/ysxw/";//央视新闻
- // String url_News = "http://api.rosysun.cn/zhihu/";
- // String url_News = "https://api.iyk0.com/bdr";//百度头条
- // String url_News = "https://api.vvhan.com/api/douban";
- //请求数据并Json处理
- // display_partialLine(7, "获取生活指数");
- /*两个半小时更新一次天气,节省访问次数且不影响使用*/
-
- //第二个参数为结构体!! //callHttps定义在CallHttps
- if(udc%30==0){ //函数定义在JsonWeather
- ParseActualWeather(callHttps(url_LifeIndex), &life_index); //获取生活指数
-
- ParseActualWeather(callHttps(url_ActualWeather), &actual);
-
- // display_bitmap_bottom(Bitmap_wlq2, "获取未来天气数据中");
- ParseFutureWeather(callHttps(url_FutureWeather), &future);
- }
-
-
- ParseHitokoto(callHttps(url_yiyan), &yiyan); //函数定义在JsonHitokoto
-
- ParseNews(callHttps(url_News),&xinwen); //函数定义在JsonNews
- }
既然使用了callHttps()函数,那就先看CallHttps.ino
仅有一个函数定义于此文件下。
- String callHttps(String url)
- {
- String payload;
- Serial.print("requesting URL: ");
- Serial.println(url);
-
- //###***---+++===~~~!!!$$$^^^&&&
- HTTPClient https;
-
- if (https.begin(url)) //通过HTTP协议向网络服务器发送HTTP请求
- {
- int httpsCode = https.GET(); //从指定的资源请求数据,返回服务器状态码
- if (httpsCode > 0) //判断有无返回值
- {
- /*payload = https.getString();
- Serial.println(payload);
- return payload;*/
- if (httpsCode == 200 || httpsCode == 304 || httpsCode == 403 || httpsCode == 404 || httpsCode == 500) //判断请求是正确
- {
- payload = https.getString(); //可用于获取服务器响应中的响应体信息。响应体信息将以字符串的形式进行返回。
- // Serial.println(payload);
- Serial.println(" ");
- return payload;
- }
- else
- {
- Serial.print("请求错误:"); Serial.println(httpsCode); Serial.println(" ");
- char* httpsCode_c = new char[8];
- itoa(httpsCode, httpsCode_c, 10); //int转char* 10是进制
- payload = "{\"status_code\":\"" + String("请求错误:") + String(httpsCode_c) + "\"}";
- return payload;
- }
- }
- else
- {
- Serial.println(" "); Serial.print("GET请求错误:"); Serial.println(httpsCode);
- Serial.printf("[HTTPS] GET... 失败, 错误: %s\n", https.errorToString(httpsCode).c_str());
- payload = "{\"status_code\":\"" + String(https.errorToString(httpsCode).c_str()) + "\"}";
- //Serial.println(payload);
- return payload;
- }
- }
- else
- {
- Serial.printf("[HTTPS] 无法连接服务器\n");
- payload = "{\"status_code\":\"" + String("无法连接服务器") + "\"}";
- return payload;
- }
- https.end();
- }
通过类似ParseActualWeather(callHttps(url_LifeIndex), &life_index); 处理的读取函数,所以下面看ParseActualWeather()函数,定义在JsonWeather中!
- //使用Json解析天气数据,天气实况
- bool ParseActualWeather(String content, struct LifeIndex* data)
- {
- DynamicJsonDocument json(1536); //分配内存,动态 建立了DynamicJsonDocument对象,该对象名称为json
- DeserializationError error = deserializeJson(json, content); //解析json
- //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
- if (error)
- {
- Serial.print("天气指数加载json配置失败:");
- Serial.println(error.c_str());
- Serial.println(" ");
- String z = "天气指数json配置失败:" + String(error.c_str()) + " " + content;
- //display_partialLine(7, z);
- // esp_sleep(0);
-
- return false;
- }
-
- //检查API是否有返回错误信息,有返回则进入休眠
- if (json["status_code"].isNull() == 0) //检查到不为空
- {
- strcpy(data->status_code, json["status_code"]);
- String z;
- if (String(actual.status_code) == "AP010001") z = "API 请求参数错误" ;
- else if (String(actual.status_code) == "AP010002") z = "没有权限访问这个 API 接口" ;
- else if (String(actual.status_code) == "AP010003") z = "API 密钥 key 错误" ;
- else if (String(actual.status_code) == "AP010004") z = "签名错误" ;
- else if (String(actual.status_code) == "AP010005") z = "你请求的 API 不存在" ;
- else if (String(actual.status_code) == "AP010006") z = "没有权限访问这个地点: ";
- else if (String(actual.status_code) == "AP010007") z = "JSONP 请求需要使用签名验证方式" ;
- else if (String(actual.status_code) == "AP010008") z = "没有绑定域名" ;
- else if (String(actual.status_code) == "AP010009") z = "API 请求的 user-agent 与你设置的不一致" ;
- else if (String(actual.status_code) == "AP010010") z = "没有这个地点" ;
- else if (String(actual.status_code) == "AP010011") z = "无法查找到指定 IP 地址对应的城市" ;
- else if (String(actual.status_code) == "AP010012") z = "你的服务已经过期" ;
- else if (String(actual.status_code) == "AP010013") z = "访问量余额不足" ;
- else if (String(actual.status_code) == "AP010014") z = "访问频率超过限制" ;
- else if (String(actual.status_code) == "AP010015") z = "暂不支持该城市的车辆限行信息" ;
- else if (String(actual.status_code) == "AP010016") z = "暂不支持该城市的潮汐数据" ;
- else if (String(actual.status_code) == "AP010017") z = "请求的坐标超出支持的范围" ;
- else if (String(actual.status_code) == "AP100001") z = "心知系统内部错误:数据缺失" ;
- else if (String(actual.status_code) == "AP100002") z = "心知系统内部错误:数据错误" ;
- else if (String(actual.status_code) == "AP100003") z = "心知系统内部错误:服务内部错误" ;
- else if (String(actual.status_code) == "AP100004") z = "心知系统内部错误:网关错误" ;
- else z = "天气指数异常:" + String(actual.status_code);
- //display_partialLine(7, z);
- Serial.print("天气指数异常:"); Serial.println(actual.status_code);
- //esp_sleep(60);
- }
-
- // 复制我们感兴趣的字符串 ,先检查是否为空,空会导致系统无限重启
- // isNull()检查是否为空 空返回1 非空0
- if (json["results"][0]["suggestion"]["uv"]["brief"].isNull() == 0) //紫外线指数
- strcpy(data->uvi, json["results"][0]["suggestion"]["uv"]["brief"]);
-
- //if (json["results"][0]["now"]["text"].isNull() == 0)
- //strcpy(data->weather_name, json["results"][0]["now"]["text"]);
-
- // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内,所以你需要确保
- // 当你读取字符串时它仍在内存中
- return true;
- }
都差不多啦!~
- //使用Json解析天气数据,天气实况
- bool ParseActualWeather(String content, struct ActualWeather* data)
- {
- DynamicJsonDocument json(1536); //分配内存,动态
- DeserializationError error = deserializeJson(json, content); //解析json
- //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
- if (error)
- {
- Serial.print("实况天气加载json配置失败:");
- Serial.println(error.c_str());
- Serial.println(" ");
- String z = "实况天气json配置失败:" + String(error.c_str()) + " " + content;
- //display_partialLine(7, z);
- // esp_sleep(0);
- return false;
- }
-
- //检查API是否有返回错误信息,有返回则进入休眠
- if (json["status_code"].isNull() == 0) //检查到不为空
- {
- strcpy(data->status_code, json["status_code"]);
- String z;
- if (String(actual.status_code) == "AP010001") z = "API 请求参数错误" ;
- else if (String(actual.status_code) == "AP010002") z = "没有权限访问这个 API 接口" ;
- else if (String(actual.status_code) == "AP010003") z = "API 密钥 key 错误" ;
- else if (String(actual.status_code) == "AP010004") z = "签名错误" ;
- else if (String(actual.status_code) == "AP010005") z = "你请求的 API 不存在" ;
- else if (String(actual.status_code) == "AP010006") z = "没有权限访问这个地点" ;
- else if (String(actual.status_code) == "AP010007") z = "JSONP 请求需要使用签名验证方式" ;
- else if (String(actual.status_code) == "AP010008") z = "没有绑定域名" ;
- else if (String(actual.status_code) == "AP010009") z = "API 请求的 user-agent 与你设置的不一致" ;
- else if (String(actual.status_code) == "AP010010") z = "没有这个地点";
- else if (String(actual.status_code) == "AP010011") z = "无法查找到指定 IP 地址对应的城市" ;
- else if (String(actual.status_code) == "AP010012") z = "你的服务已经过期" ;
- else if (String(actual.status_code) == "AP010013") z = "访问量余额不足" ;
- else if (String(actual.status_code) == "AP010014") z = "访问频率超过限制" ;
- else if (String(actual.status_code) == "AP010015") z = "暂不支持该城市的车辆限行信息" ;
- else if (String(actual.status_code) == "AP010016") z = "暂不支持该城市的潮汐数据" ;
- else if (String(actual.status_code) == "AP010017") z = "请求的坐标超出支持的范围" ;
- else if (String(actual.status_code) == "AP100001") z = "心知系统内部错误:数据缺失" ;
- else if (String(actual.status_code) == "AP100002") z = "心知系统内部错误:数据错误" ;
- else if (String(actual.status_code) == "AP100003") z = "心知系统内部错误:服务内部错误" ;
- else if (String(actual.status_code) == "AP100004") z = "心知系统内部错误:网关错误" ;
- else z = "实况天气异常:" + String(actual.status_code);
- //display_partialLine(7, z);
- Serial.print("实况天气异常:"); Serial.println(actual.status_code);
- //esp_sleep(60);
- }
-
- // 复制我们感兴趣的字符串 ,先检查是否为空,空会导致系统无限重启
- // isNull()检查是否为空 空返回1 非空0
- if (json["results"][0]["location"]["name"].isNull() == 0)
- strcpy(data->city, json["results"][0]["location"]["name"]);
- if (json["results"][0]["now"]["text"].isNull() == 0)
- strcpy(data->weather_name, json["results"][0]["now"]["text"]);
- if (json["results"][0]["now"]["code"].isNull() == 0)
- strcpy(data->weather_code, json["results"][0]["now"]["code"]);
- if (json["results"][0]["now"]["temperature"].isNull() == 0)
- strcpy(data->temp, json["results"][0]["now"]["temperature"]);
- if (json["results"][0]["last_update"].isNull() == 0)
- strcpy(data->last_update, json["results"][0]["last_update"]);
- // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内,所以你需要确保
- // 当你读取字符串时它仍在内存中
-
- return true;
- }
- //使用Json解析天气数据,今天和未来2天
- bool ParseFutureWeather(String content, struct FutureWeather* data)
- {
- DynamicJsonDocument json(2560); //分配内存,动态
- DeserializationError error = deserializeJson(json, content); //解析json
- // serializeJson(json, Serial);//构造序列化json,将内容从串口输出
- if (error)
- {
- Serial.print("未来天气json配置失败:");
- Serial.println(error.c_str());
- Serial.println(" ");
- String z = "未来天气加载json配置失败:" + String(error.c_str()) + " " + content;
- //display_partialLine(7, z);
- // esp_sleep(0);
- return false;
- }
-
- //检查API是否有返回错误信息,有返回则进入休眠
- if (json["status_code"].isNull() == 0) //检查到不为空
- {
- strcpy(data->status_code, json["status_code"]);
- String z;
- if (String(future.status_code) == "AP010001") z = "API 请求参数错误" ;
- else if (String(future.status_code) == "AP010002") z = "没有权限访问这个 API 接口" ;
- else if (String(future.status_code) == "AP010003") z = "API 密钥 key 错误" ;
- else if (String(future.status_code) == "AP010004") z = "签名错误" ;
- else if (String(future.status_code) == "AP010005") z = "你请求的 API 不存在" ;
- else if (String(future.status_code) == "AP010006") z = "没有权限访问这个地点: ";
- else if (String(future.status_code) == "AP010007") z = "JSONP 请求需要使用签名验证方式" ;
- else if (String(future.status_code) == "AP010008") z = "没有绑定域名" ;
- else if (String(future.status_code) == "AP010009") z = "API 请求的 user-agent 与你设置的不一致" ;
- else if (String(future.status_code) == "AP010010") z = "没有这个地点" ;
- else if (String(future.status_code) == "AP010011") z = "无法查找到指定 IP 地址对应的城市" ;
- else if (String(future.status_code) == "AP010012") z = "你的服务已经过期" ;
- else if (String(future.status_code) == "AP010013") z = "访问量余额不足" ;
- else if (String(future.status_code) == "AP010014") z = "访问频率超过限制" ;
- else if (String(future.status_code) == "AP010015") z = "暂不支持该城市的车辆限行信息" ;
- else if (String(future.status_code) == "AP010016") z = "暂不支持该城市的潮汐数据" ;
- else if (String(future.status_code) == "AP010017") z = "请求的坐标超出支持的范围" ;
- else if (String(future.status_code) == "AP100001") z = "心知系统内部错误:数据缺失" ;
- else if (String(future.status_code) == "AP100002") z = "心知系统内部错误:数据错误" ;
- else if (String(future.status_code) == "AP100003") z = "心知系统内部错误:服务内部错误" ;
- else if (String(future.status_code) == "AP100004") z = "心知系统内部错误:网关错误" ;
- else z = "未来天气异常:" + String(future.status_code);
- //display_partialLine(7, z);
- Serial.print("未来天气异常:"); Serial.println(future.status_code);
- //esp_sleep(60);
- }
-
- // 复制我们感兴趣的字符串,先检查是否为空,空会复制失败导致系统无限重启
- if (json["results"][0]["daily"][0]["date"].isNull() == 0) //日期
- strcpy(data->date0, json["results"][0]["daily"][0]["date"]);
- if (json["results"][0]["daily"][1]["date"].isNull() == 0)
- strcpy(data->date1, json["results"][0]["daily"][1]["date"]);
- if (json["results"][0]["daily"][2]["date"].isNull() == 0)
- strcpy(data->date2, json["results"][0]["daily"][2]["date"]);
-
- if (json["results"][0]["daily"][0]["text_day"].isNull() == 0) //白天天气现象
- strcpy(data->date0_text_day, json["results"][0]["daily"][0]["text_day"]);
- if (json["results"][0]["daily"][1]["text_day"].isNull() == 0)
- strcpy(data->date1_text_day, json["results"][0]["daily"][1]["text_day"]);
- if (json["results"][0]["daily"][2]["text_day"].isNull() == 0)
- strcpy(data->date2_text_day, json["results"][0]["daily"][2]["text_day"]);
-
- if (json["results"][0]["daily"][0]["text_night"].isNull() == 0) //晚间天气现象
- strcpy(data->date0_text_night, json["results"][0]["daily"][0]["text_night"]);
- if (json["results"][0]["daily"][1]["text_night"].isNull() == 0)
- strcpy(data->date1_text_night, json["results"][0]["daily"][1]["text_night"]);
- if (json["results"][0]["daily"][2]["text_night"].isNull() == 0)
- strcpy(data->date2_text_night, json["results"][0]["daily"][2]["text_night"]);
-
- if (json["results"][0]["daily"][0]["high"].isNull() == 0)
- strcpy(data->date0_high, json["results"][0]["daily"][0]["high"]); //最高温度
- if (json["results"][0]["daily"][1]["high"].isNull() == 0)
- strcpy(data->date1_high, json["results"][0]["daily"][1]["high"]);
- if (json["results"][0]["daily"][2]["high"].isNull() == 0)
- strcpy(data->date2_high, json["results"][0]["daily"][2]["high"]);
-
- if (json["results"][0]["daily"][0]["low"].isNull() == 0) //最低温度
- strcpy(data->date0_low, json["results"][0]["daily"][0]["low"]);
- if (json["results"][0]["daily"][1]["low"].isNull() == 0)
- strcpy(data->date1_low, json["results"][0]["daily"][1]["low"]);
- if (json["results"][0]["daily"][2]["low"].isNull() == 0)
- strcpy(data->date2_low, json["results"][0]["daily"][2]["low"]);
-
- if (json["results"][0]["daily"][0]["humidity"].isNull() == 0) //湿度
- strcpy(data->date0_humidity, json["results"][0]["daily"][0]["humidity"]);
-
- if (json["results"][0]["daily"][0]["wind_scale"].isNull() == 0) //风力等级
- strcpy(data->date0_wind_scale, json["results"][0]["daily"][0]["wind_scale"]);
- // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内,所以你需要确保
- // 当你读取字符串时它仍在内存中
- return true;
- }
读读到的Json数据,然后存入到结构体中。没啥难度。
ParseHitokoto(callHttps(url_yiyan), &yiyan);获取一言数据,在JsonHitokoto文件中定义。
String url_yiyan = "https://v1.hitokoto.cn/";//一言获取地址
- //****** 获取一言数据
- void ParseHitokoto(String content, struct Hitokoto* data)
- {
- DynamicJsonDocument json(1536); //分配内存,动态
- DeserializationError error = deserializeJson(json, content); //解析json
- //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
- if (error) //检查API是否有返回错误信息,有返回则进入休眠
- {
- Serial.print("一言加载json配置失败:");
- Serial.println(error.c_str());
- Serial.println(" ");
- String z = "一言json配置失败:" + String(error.c_str()) + " " + content;
- }
- if (json["status_code"].isNull() == 0) //检查到不为空
- {
- strcpy(data->status_code, json["status_code"]);
- String z = "一言异常:" + String(yiyan.status_code);
- Serial.print("一言异常:"); Serial.println(yiyan.status_code);
- }
- else
- {
- if (json["hitokoto"].isNull() == 0){
- strcpy(data->hitokoto, json["hitokoto"]);
- }
- else strcpy(data->hitokoto, "哎呀\"hitokoto\"没有数据呢");
- }
- // 复制我们感兴趣的字符串 ,先检查是否为空,空会导致系统无限重启
- // 这不是强制复制,你可以使用指针,因为他们是指向"内容"缓冲区内
- // 所以你需要确保 当你读取字符串时它仍在内存中
- // isNull()检查是否为空 空返回1 非空0
- }
比较简单啦~
接下来就是新闻。琪琪:接下来~ 老秦:接下来~
ParseNews(String content, struct News* data)
- //****** 获取新闻数据
- void ParseNews(String content, struct News* data)
- {
- DynamicJsonDocument json(8536); //分配内存,动态 1536
- DeserializationError error = deserializeJson(json, content); //解析json
- //serializeJson(json, Serial);//构造序列化json,将内容从串口输出
- if (error) //检查API是否有返回错误信息,有返回则进入休眠
- {
- Serial.print("新闻加载json配置失败:");
- Serial.println(error.c_str());
- Serial.println(" ");
- String z = "新闻json配置失败:" + String(error.c_str()) + " " + content;
- }
- if (json["status_code"].isNull() == 0) //检查到不为空
- {
- strcpy(data->status_code, json["status_code"]);
- String z = "新闻异常:" + String(xinwen.status_code);
- Serial.print("新闻异常:"); Serial.println(xinwen.status_code);
- }
- else
- {
- if (json["data"].isNull() == 0){
- for(int i = 0;i<11;i++){
- strcpy(data->title[i], json["data"][i]["title"]); //取前11个
- }
-
- }
- }
- }
这么多,原来才只看到loop函数里的第一步,啊~ 明天再看吧! 不慌!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。