基于ESP32-S2模块的物联网/音频信号处理平台实现本地气象台
基于ESP32-S2模块的物联网/音频信号处理平台实现本地气象台,能够在OLED显示当前本地的时间、温度和气象信息,系统能够自动校时,开机后自动调节到准确的时间(年、月、日、时、分、秒)。
标签
Arduino
ESP32
物联网
2022寒假在家练
本地气象台
student
更新2022-03-01
南京邮电大学
900

写在最前面

注意!附件中的工程不能拿来直接用,需要修改ssid,password,和链接中的[your key]。[your key]为高德开发平台创建应用产生的key id。

项目介绍

基于ESP32-S2模块的物联网/音频信号处理平台实现本地气象台,能够在OLED显示当前本地的时间、温度和气象信息,系统能够自动校时,开机后自动调节到准确的时间(年、月、日、时、分、秒)。

 

设计思路

总体的思路是,将处理平台连接wifi,通过api获取时间、日期、位置和气象等数据,经过解析后,通过OLED显示出来。

 

软件流程图

Fmpnlfis0dG7pAiNiG0gUJVOdDD5

硬件介绍

基于ESP32-S2模块的物联网/音频信号处理平台是硬禾学堂推出的一款开发平台。平台使用了乐鑫公司的ESP32-S2模块作为MCU模组,支持WiFi连接,128*64的SPI接口OLED,4路按键,以及其他音频输入输出接口,可以用来开发物联网应用和音频信号处理。

 

实现的功能

1.OLED显示及连接WiFi

待平台上电以后,OLED显示等待联网界面,直到网络连接成功。

Fi_rVQC9bigZ_lBhZpyRQdA3g82c

2.显示本地日期、时间和星期

在联网后,OLED将界面跳转为本地日期界面,显示本地日期、时间和星期。

FnOU8cW9l92677AhRo1YxMD8zFEw

3.显示位置和天气实况

按动下翻键(sw2),OLED界面跳转到天气实况界面,显示本地位置,实时温度,实时湿度和气象情况。

FvvT00HUaQkoXIJZJhXmLu1geGNs

4.显示天气预报

再次按动下翻键,OLED界面跳转到天气预报界面,显示今日白天温度与夜间温度、明日白天温度与夜间温度和后日白天温度与夜间温度。

FtgTOXXpy-dGhr3smXaM37Oe8If3

5.显示标语

再次按动下翻键,OLED界面跳转到标语界面,这里的标语可以自定义。此时按动下翻键将回到本地日期界面。上翻键也是类似的操作逻辑。

Fjswx4JUnHg1Flom_d1ufgMd1AKv

主要代码片段及说明

0. 软件环境的搭建

ESP32的开发方式主要分为两种,第一种是采用乐鑫提供的ESP32 IDF进行开发,另外一种是采用Arduino进行开发。前者需要较为复杂的环境安装,后者的话,软件的安装比较简单。由于在安装ESP32 IDF的时候出现了比较多的错误,所以最终选择了Arduino的开发方式。这也是我第一次系统采用Arduino进行开发,也是一次很好的学习过程。

关于Arduino的环境搭建,网上的教程有很多,在此不再赘述。需要一提的是,采用Arduino IDE编译和上传的速度较慢,本来计划采用VSCode+PlatformIO+Arduino的方式进行开发,可是PlatformIO对ESP32S2的支持不太好,所以最终选择了VSCode+Arduino的方式。

1.oled的显示

OLED的显示一开始采用的是Adafruit_SSD1306的库,后续为了能够较好的支持中文,选择了u8g2的库。示例来自PrintUTF8.ino。

void setup(void) {
  u8g2.begin();
  u8g2.enableUTF8Print();		// enable UTF8 support for the Arduino print() function
}

void loop(void) {
  u8g2.setFont(u8g2_font_unifont_t_chinese2);  // use chinese2 for all the glyphs of "你好世界"
  u8g2.setFontDirection(0);
  u8g2.clearBuffer();
  u8g2.setCursor(0, 15);
  u8g2.print("Hello World!");
  u8g2.setCursor(0, 40);
  u8g2.print("你好世界");		// Chinese "Hello World" 
  u8g2.sendBuffer();
  
  delay(1000);
}

通过示例可以较为清楚的了解到u8g2库的使用方式。后续其他的显示本质上也是采用的上述的方式。

2. Wifi

连接wifi是非常关键的一步。示例来自WiFiClientBasic.ino。

void setup()
{
    Serial.begin(115200);
    delay(10);

    // We start by connecting to a WiFi network
    WiFiMulti.addAP("SSID", "passpasspass");

    Serial.println();
    Serial.println();
    Serial.print("Waiting for WiFi... ");

    while(WiFiMulti.run() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());

    delay(500);
}

输入wifi的名称和密码即可连接wifi。实际应用中,通过手机开热点,将ESP32接入WiFi须先给ESP32上电,之后再打开WIFI才可以。

3. 时间

时间的获取参考了示例NTPClient的Advance.ino。

NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);

void setup(){
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    Serial.print ( "." );
  }

  timeClient.begin();
}

void loop() {
  timeClient.update();

  Serial.println(timeClient.getFormattedTime());

  delay(1000);
}

应当注意,中国位于东八区,这里默认的参数提供的时间是东一区的,所以需要将参数3600改为8*3600。

同时,我将域名从欧洲的服务器修改为了中国的服务器,理论上会有更好的稳定性。

4. 日期

虽然NTP也可以获取到日期,但是为了正式接触http的api,日期的获取我采用了api的方式。

网友perseverance52 的 Arduino ESP32 获取网络数据(HTTP GET方式) 

https://blog.csdn.net/weixin_42880082/article/details/120904803 

介绍了苏宁易购提供的api接口,接口为 http://quan.suning.com/getSysTime.do 

需要注意,这个接口有事会出现 404 当前页面访问人数过多,请您稍后再试!的问题,所以我在程序中设置了连续3次进行读取以解决读取失败的问题。

接口的返回为

{"sysTime2":"2022-02-23 13:31:28","sysTime1":"20220223133128"}

关于如何从数据中解析出需要的内容,这部分将在json中进行介绍。

5. JSON

上一部分中,接口返回数据的格式是JSON。这时我们无法直接从返回数据中提取出我们想要的内容,通过arduinojson的库就可以快速地完成数据解析。

https://arduinojson.org/ 提供的quickstart可以帮助快速实现对数据的解析。

char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";

DynamicJsonDocument doc(1024);
deserializeJson(doc, json);

const char* sensor = doc["sensor"];
long time          = doc["time"];
double latitude    = doc["data"][0];
double longitude   = doc["data"][1];

只要将输入输出进行修改,即可快速完成开发。

6. 位置

为了通过IP获得本地位置,在网络上进行了调查与研究。很多方案提供的方法是使用百度或者腾讯等企业提供的API。但是这些公司要求只有先登录个人账号才能够使用API,较为麻烦。
这里要感谢网友 夏时 整理的 分享几个IP获取地理位置的API接口

来自  https://cloud.tencent.com/developer/article/1152362 

在其中,我选择了太平洋网络IP地址查询Web接口 ,因为这个网站的接口资料很详细,不需要登录,而且可以获得地区代码,方便下一步通过地区代码直接获得地区的气象信息。
https://whois.pconline.com.cn/ipJson.jsp?json=true

返回格式为

{
"ip": "255.255.255.255",
"pro": "江苏省",
"proCode": "320000",
"city": "南京市",
"cityCode": "320100",
"region": "",
"regionCode": "0",
"addr": "江苏省南京市 移动",
"regionNames": "",
"err": ""
}


ip地址部分为了保护隐私人为修改了。可以看到能够获得所在城市名称和城市代码,方便后续通过城市代码获取天气。

7. 气象

下一步是通过城市代码获得城市的气象信息,这里参考了网友 蒋川 的 最好的 6 个免费天气 API 接口对比测评

来自  https://kalacloud.com/blog/free-weather-api/ 

考虑到api的可靠性和实用性,选择了高德地图的天气API,具体过程可以参考上述链接。
实况天气和预报天气如下
https://restapi.amap.com/v3/weather/weatherInfo?key=[your_key]&city=320100&extensions=base 

https://restapi.amap.com/v3/weather/weatherInfo?key=[your_key]&city=320100&extensions=all  

返回值分别为

{
"status": "1",
"count": "1",
"info": "OK",
"infocode": "10000",
"lives": [
{
"province": "江苏",
"city": "南京市",
"adcode": "320100",
"weather": "多云",
"temperature": "7",
"winddirection": "南",
"windpower": "≤3",
"humidity": "24",
"reporttime": "2022-02-21 13:05:56"
}
]
}

 

{
"status": "1",
"count": "1",
"info": "OK",
"infocode": "10000",
"forecasts": [
{
"city": "南京市",
"adcode": "320100",
"province": "江苏",
"reporttime": "2022-02-21 15:32:29",
"casts": [
{
"date": "2022-02-21",
"week": "1",
"dayweather": "多云",
"nightweather": "多云",
"daytemp": "8",
"nighttemp": "0",
"daywind": "南",
"nightwind": "南",
"daypower": "≤3",
"nightpower": "≤3"
},
{
"date": "2022-02-22",
"week": "2",
"dayweather": "多云",
"nightweather": "阴",
"daytemp": "6",
"nighttemp": "2",
"daywind": "东南",
"nightwind": "东南",
"daypower": "≤3",
"nightpower": "≤3"
},
{
"date": "2022-02-23",
"week": "3",
"dayweather": "阴",
"nightweather": "多云",
"daytemp": "7",
"nighttemp": "-2",
"daywind": "东",
"nightwind": "东",
"daypower": "≤3",
"nightpower": "≤3"
},
{
"date": "2022-02-24",
"week": "4",
"dayweather": "多云",
"nightweather": "多云",
"daytemp": "9",
"nighttemp": "0",
"daywind": "东",
"nightwind": "东",
"daypower": "≤3",
"nightpower": "≤3"
}
]
}
]
}

其中,第一个为实况天气,第二个为预报天气。

需要注意,在api中填写在高德开发平台中创建应用的key id,这一部分,在上文提到的链接中有较为详细的介绍。

api中的城市编号是固定的,city=320100,但是在程序中,为了增加普适性,采用的是拼接字符串的方法,所以,只要你在中国境内,无论哪个城市,只要能够正确获取你的IP地址对应的位置,就可以提供你的气象信息。

8. 交互界面

交互界面采用了翻页式设计,第一页显示本地时间,包括日期,时间和星期;第二页显示天气实况,包括地区,实时温度,实时湿度,实时气象;第三页显示天气预报,包括,今日白天温度与夜间温度、明日白天温度与夜间温度和后日白天温度与夜间温度。第四页为标语页面,可自定义标语。

在平台刚上电,或者联网后断网时,显示等待上电,并且显示滚动动画。

翻页的方式通过按键进行控制,sw1为上翻页,sw2为下翻页,sw3未设置功能,sw4为手动同步数据按键。

按键逻辑参考了慕容流年的《Arduino》开发 之 基于 u8g2 库 的 OLED 菜单界面 https://blog.csdn.net/qq_41868901/article/details/105970873  

9. 刷新方式

刷新方式上,每个页面都单独写了刷新函数。采用定时器的方式,每秒刷新一次屏幕。数据刷新上,每秒同步一次时间数据,每小时同步一次气象数据。

 

遇到的主要难题及解决方法

遇到的难题太多了,多到一时不知道从哪里讲起。持续时间最长的难题是WiFi的连接问题,无论是用手机开热点,或者是用电脑开热点,WiFi的连接都很玄学。在这其中也做过很多尝试,诸如设置手机的热点模式,设置2.4g与5g的频率,切换WiFi连接函数等等。最后经过大量的尝试以后,得到了一个较为稳健的连接方式,就是先让ESP32等待连接,再打开默认模式的2.4g的手机WiFi。虽然还是很麻烦,但是总是有了一个稳健的连接方式,可能通过路由器会简单很多,可惜手边没有。

第二个问题是OLED的刷新问题。如何刷新OLED,以什么样的频率刷新OLED都是问题。经过仔细研究,最终方案是,通过定时器产生标志信号,然后在循环中判断标志信号的状态来刷新屏幕。数据的刷新方式也是类似,不过由于天气的短期稳定性,所以每小时刷新一次,而不是和屏幕或者时间的每秒刷新一次。

第三个问题是按键的响应问题和屏幕的刷新问题,由于项目时间即将结束,这个问题要留到后续进行解决了。

 

未来的计划或建议等

后续有时间的话,首先要解决的是按键的响应问题。按键的判断是在循环中的,理论上每一轮循环都很快,按键的响应不应该出问题,然而实际上有时会存在按键响应丢失的问题。分析原因是有代码占据了控制器的时间,初步认为应该是网络连接判断函数占用了大量的时间。为了能够实时获取网络连接状态,每一轮都在读取网络连接,由于网络连接状态判断较为复杂,所以占用了较多时间。后续可以以时间变化为判断依据,若是未能更新时间,说明网络连接失败,这样就可以避免采用网络连接判断函数了。其余操作的话,诸如刷新屏幕,都无需占用时间。

解决方法二是采用外部中断的方式,把按键设为外部中断,就可以及时响应按键了。

屏幕刷新问题体现在,有时两秒钟才会刷新一次屏幕,这个问题的原因显然和上述问题一致,在于网络连接函数占用了大量的时间,可以采取上述问题的方法一解决。

除了解决现有问题以外,还有就是进一步开发平台的应用。ESP32模块在音频处理上有较大的优势,然而本项目未能体现出这些优势,下一步应该将这些优势挖掘出来。

附件下载
Project_without_privacy.zip
团队介绍
南京邮电大学是国家工业和信息化部与江苏省人民政府共建的高校。在长期的办学过程中,人才培养质量高、毕业生社会声誉好。
团队成员
student
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号