前言
玩ESP一定会需要获取网络上的各种讯息,而比较入门的内容就是获取网络时间,通过连接NTP服务器来完成。
另一个家是获取气温和天气,通常用在时钟类的项目上面。
这里提供最简单的方法说明如何获取,以及要怎么样方便快捷的解析JSON
用到的头文件以及功能
#include <Thread.h> //多线程
#include <U8g2lib.h> //U8glib,一个知名绘图库
#include <Wire.h> //I2C相关函数
#include <WiFi.h> //ESP32 Wifi相关函数
#include "time.h" //时间的处理
#include <HTTPClient.h> //获取http
#include <ArduinoJson.h> //解析json
1. 连接网络和时间获取
所有的基本就是连接网络,这里使用Wifi进行连接,因为从简所以先定义ssid和密码
const char *ssid = "wifi账号"; //
const char *password = "wifi的密码";
然后就是定义ntp服务器,使用的是阿里云的服务器需要注意的是夏令时和时区的时间偏移,我们是北京时间,GMT+8所以就是28800
const char *ntpServer = "ntp.aliyun.com"; //时间服务器
const long gmtOffset_sec = 28800; //时间偏移
const int daylightOffset_sec = 0;
然后就是启动wifi,等待wifi连接,这里用到的连接函数是Wifi.begin(),然后通过判断Wifi.status()是否是WL_CONNECTED来判断ESP32这会儿有没有连接到路由器
这里我用一个变量i来做计数器,达到127时候就提示出错,连不上网。
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(50);
Serial.print(".");
//u8g2.setCursor(2 + (i++), );
u8g2.drawLine(0, 0, (i++), 0);
u8g2.sendBuffer();
if (i == 127)
{
DisError();
}
}
如果连接上,就是获取时间,使用configTime函数来完成
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
最后断开连接,关闭ESP32的Wifi功能达到省电的目的,实测关闭Wifi仅打开OLED的情况下功耗在20ma左右。
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
整个函数如下
//获取网上的时间
void getNetTime()
{
int i = 0;
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(50);
Serial.print(".");
//u8g2.setCursor(2 + (i++), );
u8g2.drawLine(0, 0, (i++), 0);
u8g2.sendBuffer();
if (i == 127)
{
Desirer();
}
}
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
u8g2.setDrawColor(1);
u8g2.setFont(font1);
u8g2.setCursor(10, 48);
clearHalf();
u8g2.setDrawColor(1);
u8g2.print("Get Time!"); //TODO 获取时间的提示
// u8g2.sendBuffer();
printLocalTime();
Serial.println(" CONNECTED");
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
获取天气和JSON解析
要获取天气需要在连接Wifi的情况下,具体在上一章节进行了说明,在连接到Wifi热点/路由器的情况下,访问API,获取JSON并且解析出天气和气温,这是ESP32在这一个章节要做的事情。
因为是在线获取,所以需要使用动态JSON解析,这里使用的库是AduinoJson,使用DynamicJsonDocument 来初始化一个存储Json数据的内存空间
DynamicJsonDocument doc(2048);
我们使用的是心知天气,它的api格式如下,需要自行去注册账号并且申请API(完全免费),如何申请在本文中略过。需要自定义的有API私钥和你所在的城市。
String tagethttp = "https://api.seniverse.com/v3/weather/now.json?key=这里填写你的API Key &location=这里填城市拼音名称&language=en";
这里需要实例化一个HTTPClient,然后使用begin函数去尝试连接
HTTPClient https;
https.begin(tagethttp);
完成https连接后,在这里需要描述一下ArduinoJson的用法,用于解析我们用API获取到的数据
直接获取的天气的Json数据是这样的:
{"results":[{"location":{"id":"WX4FBXXFKE4F","name":"Beijing","country":"CN","path":"Beijing,Beijing,China","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"Overcast","code":"9","temperature":"26"},"last_update":"2021-08-11T21:24:24+08:00"}]}
浏览器优化后可以看出来是一个多层结构,分为location和now
ArduinoJson可以帮助我们快速简单的解析数据,它是以层层分析的形式,首先获取到Json数据,此时是字符串
String payload = https.getString();
之后需要解析为Json,存储到刚才划分的DynamicJsonDocument存储空间
deserializeJson(doc, payload);
接着就是先用JsonObject来获取整个Json数据中,now那部分内容
JsonObject results_0 = doc["results"][0];
JsonObject results_0_now = results_0["now"];
接着是获取天气
weather = results_0_now["text"];
以及气温
temperature = results_0_now["temperature"];
这样就可以完成所有解析了。
整个获取天气和气温,解析JSON代码如下,我用U8G2来实现OLED显示:
int temperature = 0;
const char *weather;
void getHttp() //TODO 获取http网页
{
DynamicJsonDocument doc(2048);
HTTPClient https;
https.begin(tagethttp);
int httpCode = https.GET();
u8g2.setFont(font1);
u8g2.clear();
u8g2.setCursor(3, 50);
if (httpCode > 0)
{
u8g2.sendBuffer();
String payload = https.getString();
deserializeJson(doc, payload);
JsonObject results_0 = doc["results"][0];
JsonObject results_0_now = results_0["now"];
weather = results_0_now["text"];
temperature = results_0_now["temperature"];
}
else
{
u8g2.print("Get http Failed");
u8g2.sendBuffer();
delay(1000);
}
}
更多工具
这里还要提供一个方法,是使用在线工具来快速的预览你获得的数据,以及筛选他们的结果
https://wandbox.org/permlink/hcB7LwkuBtcUc3u6
在上面这边写一些代码,就可以在下面直接查看到最终输出的结果,可以说是非常快速而且容易使用。