一、项目介绍
制作一个本地气象台/温度计
要求:1.利用OLED显示
2.显示当前本地的时间、温度和气象信息
二、设计思路
先简单介绍一下,具体代码在后面解释。通过wifi联网获取信息,根据从阿里云获取时间信息,处理后在再OLED 屏幕上显示;在从心知天气的api上获取本地(合肥)的天气信息,获取的信息是Json格式,所以用ArduinoJson来处理信息。最后再排版显示在OLED 屏幕上。
流程图
三、实现的功能和图片展示
时间显示
地点显示
温度和天气显示
四、主要代码片段和说明
Arduino的开始片段,在这段代码实现了wifi的配置和通过http协议从心知天气调用api获取天气信息。
本段代码需要注意的是变量weather,在代码中他保存要显示的天气信息并且在后面显示,本段代码中保存的是示例图片中的"text_day":"多云"的信息,所以保存下来的数据是多云。
void setup() {
// oled使能
u8g2.begin();
u8g2.enableUTF8Print();
// oled使能
////////////////////////WIFI配置
Serial.begin(115200);
Serial.printf("Connecting to %s",ssid);
WiFi.begin(ssid,password);
while(WiFi.status()!=WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
//////////////////////WIFI配置
//////////////////////天气信息获取
https.begin("https://api.seniverse.com/v3/weather/daily.json
key=SmLKKd0aGxnk67ZRE&location=hefei&language=zh-Hans&unit=c&start=0&days=5");
int httpCode = https.GET();
if(httpCode > 0)
{
String pageData = https .getString();
deserializeJson(doc,pageData);
JsonObject obj = doc.as<JsonObject>();
String weatherInfo = obj["results"][0];
deserializeJson(doc1,weatherInfo);
JsonObject obj1 = doc1.as<JsonObject>();
String dailytoday = obj1["daily"][0];
Serial.println(dailytoday);
deserializeJson(doc2,dailytoday);
JsonObject obj2 = doc2.as<JsonObject>();
String city = obj1["location"]["name"];
String temp1 = obj2["high"];
String temp2 = obj2["low"];
temp11=temp1;temp22=temp2;
String weather = obj2["text_day"];
wea = weather;
}
else
{
Serial.println("GET ERROR");
}
https.end();
/////////////////////天气信息获取
Serial.println(temp11);
configTime(8 * 3600, 0, NTP1, NTP2,NTP3);
}
接下来这段代码是获取时间的函数,实施条件如下:
- ESP32需要在:WIFI.MODE(WIFI_STA;)模式下,配网并接入网络。
- 使用下面函数从网络时间服务器上获取并设置时间:
参数说明:configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2 = nullptr, const char* server3 = nullptr)
gmtOffset_sec参数就是用来修正时区的,比如对于我们东八区(UTC/GMT+08:00)来说该参数就需要填写 8 * 3600 ;
daylightOffset_sec使用夏令时 daylightOffset_sec 就填写3600,否则就填写0; - 格式化输出
Serial.println(&timeinfo, "%F %T %A"); // 格式化输出:2021-10-24 23:00:44 Sunday Serial.print(asctime(&timeinfo));//默认打印格式:Mon Oct 25 11:13:29 2021
%a 星期几的简写
获取时间的实例代码
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十进制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符
void setClock() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo))
{//如果获取失败,就开启联网模式,获取时间
Serial.println("Failed to obtain time");
WiFi.disconnect(false);
WiFi.mode(WIFI_STA);//开启网络
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
configTime(8 * 3600, 0, NTP1, NTP2,NTP3);
return;
}
u8g2.firstPage();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(30, 20);
u8g2.print("当前时间");
u8g2.setCursor(2, 35);
u8g2.print(&timeinfo,"%T");
u8g2.print(str);
u8g2.sendBuffer();
//delay(1000);
Serial.println(&timeinfo, "%F %T %A"); // 格式化输出:2021-10-24 23:00:44 Sunday
Serial.print(asctime(&timeinfo));//默认打印格式:Mon Oct 25 11:13:29 2021
WiFi.disconnect(true);
}
OLED 屏幕显示代码,此段代码重复度较高,举一个例子说明
u8g2.clearBuffer(); //清除内部缓冲区
u8g2.setFontDirection(0); //设置字体方向
u8g2.setFont(u8g2_font_unifont_t_chinese2); //字体设置
u8g2.setCursor(30, 20); //位置设置
u8g2.print("天气");
u8g2.setCursor(25, 50);
u8g2.print("today");
u8g2.sendBuffer();
接下来的代码调用从心知天气获取的Json信息并且显示在oled上,可以看到这里获取的是前文提到的weather的信息,所以实例图片显示的是多云。
void disptianqii(String temp1,String temp2)
{
u8g2.firstPage();
u8g2.clearBuffer(); //清除内部缓冲区
u8g2.setFontDirection(0); //设置字体方向
drawWeatherSymbol(0,48, wea);
u8g2.setFont(u8g2_font_unifont_t_chinese2);
u8g2.setCursor(51,55);
u8g2.print("wea");
u8g2.setCursor(48+3, 20);
String tempInfo ="temp: ";
Serial.println(temp1 + "~" + temp2);
u8g2.print(tempInfo);
String tempInfoo = temp1+" 度~"+temp2+" 度";
u8g2.setCursor(48+3, 35);
u8g2.print(tempInfoo);
u8g2.sendBuffer();
}
五、遇到的问题及解决方法
在我选用的oled库时u8g2库,在我实验过程中有些中文会显示不出来,但是由于这个库功能齐全,所以我还是选择了这个库。以后我会在实践中学习自己编写字体库或者选择更全面的oled库。
六、未来的计划或者建议
未来我可能会更加加深对ESP32的学习,或许通过本次的学习制作一个天气手表。也会在本次寒假练后自己学习一下其他的项目来增加自己的经验。