一、项目介绍
此项目是基于ESP32-S2系列开发板完成的一个本地气象站,具体功能如下:
1、联网获取当前日期、时间
2、联网获取目前北京天气
3、联网获取北京未来两天天气预报
4、通过板载oled屏幕将结果显示出来
二、元件分析
此次采用了硬禾学堂开发的基于ESP 32-S2控制器的物联网/音频信号处理平台,其中板载了许多的资源。其中串口、OLED与WIFI通信模块为本项目所需要的主要功能模块。
图1:物联网/音频信号处理平台功能图
ESP32本身具有较为出色的物联网功能,可以很好与互联网交互。
三、方案选取
1、开发平台
对于ESP系列模块,主流的开发链有三种:ESP-IDF,PlatformIO,Arduino。
ESP-IDF是乐鑫官方推出的开发框架,功能较为齐全,但是本身主要以命令行为主,作为初学者上手有些难度。
PlatformIO是一种常用于嵌入式开发的软件工具链,但因为我此前未接触过相应语法,所有本次为采用该方案。
Arduino是一种普遍的开源嵌入式规范,语法较为简单,且与C语言契合度高,易上手。esp32也推出了适用于esp的arduino扩展包,可以很方便的下载使用。
综上所述,选用了Arduino作为本次的开发平台。
2、获取天气
常用的获取天气信息的手段有网页爬虫和调用API接口。
网页爬虫是一种比较通用的获取网络信息的手段,通过对网页报文的解析和切片从而提取出特定的信息部分。
API接口可以理解为由服务提供商主动整理好了需要网页信息为json格式,使用者仅需将此网页的报文提取并按json规范解析即可得到所需信息。
API接口的方式较为规范、安全性高且稳定性高,因此采用调用API接口的方式。
本次使用的获取天气的API接口来自心知天气https://www.seniverse.com/,注册即可免费试用。
3、OLED显示
本平台使用的是基于ssd1306的128*64OLED屏幕。对于Arduino语言,常用的方式有arduino官方提供Adafruit_GFX库 &Adafruit_SSD1306库的和跨平台常用的u8g2库。后者基本包含前者所提供的全部内容,且增加了预设字库等强大功能。故采用后者。
图2:SSD1306显存方式
综上可以得出本项目的设计流程如下:
图3:本项目流程图
四、部分思路介绍
1、动态延时
在本项目中,ESP32似乎并没有RTC时钟(因为没有额外电池),而通过定时器进行时间管理虽然可行但较为复杂。几经考虑后还是选择通过联网获取时间(获取+显示)而非联网同步时间(同步本地计算的时间+显示)。
由于时间通过联网获取,那一定会存在网络延迟而造成的数据不准确。延迟的范围大约在一分钟内,因此秒的数据并不可靠,所以本项目删掉了秒的显示,仅保留时分。其中分钟数据可能因为秒钟的不准确而不精确。且高频率的获取时间也是对互联网资源的浪费。
所以,考虑每分钟仅获取一次时间信息及天气信息,同时每次获取控制在真实时间的每分钟初始五秒内,以此保证时间更新的准确性。
在loop循环中,我使用了下面两个语句实现动态调整信息更新时间。其中millis()-runtime为接收信息到显示信息间的时间差,second_int为上次一获取时间所得秒钟数据。通过这样计算得到的delaytime经过延迟后理论上就是真实时间下一个一分钟的时候。
void loop() {
get_text();
int runtime = millis();
json_handle();
time_handle();
//show_weather_in_serial();
show_in_oled_time();
delay(20000);
//show_in_oled_weather();
int delaytime = 60000 - second_int*1000 - (millis() - runtime) - 5000;
Serial.print(delaytime);
if (delaytime<=1000)
delaytime = 1000;
//这里根据秒数来定下一次循环的时间保持每分钟一次
delay(delaytime);
}
2、仅保留部分信息
在获取网页报文时,会同时获取大批量的信息,网上的许多教程都是将所有数据保存在字符串中,后续在通过切片实现数据提取。而这些信息中绝大多数都是无用的请求信息。通过测试发现json数据都存在于同一行中且时间数据和json数据都含有明显的特征关键词。因此我考虑在获取每行数据时都通过indexOf函数先判断这行数据是否含有所需信息,若不含有就不保存,以此可减少程序运行时的空间使用。
while(client.available())
{
String line = client.readStringUntil('\r');
//choose the line with time
if(line.indexOf("Date: ")!= -1)
{
Timeinfo = line;
//Serial.print(Timeinfo);
}
//choose the line with weather json
if(line.indexOf("results")!= -1)
{
jsontext = line;
//Serial.print(jsontext);
}
}
五、待改进
1、多页面显示
原计划将本程序拆成三个页面显示,可以通过图标的方式显示天气状况且可以显示天气预报。但由于推迟返校导致时间不太够了…
2、定位确定所在地
当前程序中,天气信息的所在地为手动设置的北京。但个人感觉应该有办法通过网络连接的方式确定当前接入网络所在地的位置,从而对应获取当地的时间。
六、小结
之前接触过FPGA和部分Arduino Uno,但是没有涉及到联网的应用,所以对网页请求和json获取等部分不太了解。这次是一个很好的机会让我体会到了从连接服务器到发送请求,到接收json,再到解析json这一个完整的互联网访问的流程。虽然这是一个简单的http交互,但是对我而言已经迈出了一大步。
除此之外,这也是我第一次使用u8g2这个库来开发oled,个人感觉确实比原先的库好用一些。也算是多掌握了一种显示屏的编程方式。
最后,感谢电子森林和硬禾学堂提供的开发板和项目实战,让我借此机会学习到了很多。