ESP32-太空人天气时钟(完结)

原创 DQ笔记 2022-06-14 23:04

ESP32太空人天气时钟整体展示:

上述视频中TFT屏幕插在ESP32扩展板上。ESP32扩展板原理图如下,包含一路TFT屏幕SPI接口,一路I2C接口,4个按键以及蜂鸣器电路。

PCB图如下:

焊接后的扩展板实物如下:

ESP32太空人天气时钟程序如下,通过按键进行时钟和天气界面切换:
#include #include #include #include     //wifi库#include     //NTP库#include   //Json库#include   //HTTP库#include #include "Arduino.h"#include "Ticker.h"      //定时器库#include "MyFont.h"  // 自制字体模板库#include "./Pic/ConnectWifi/Connect.h"#include "./Pic/Astronaut/As.h"#include "./Pic/weather/Weather.h"#include "./Pic/picture/Picture.h"
int a;/*********注意填写自己Wifi的账号密码**********/const char *ssid = "********"; //Wifi账号const char *password = "********"; //Wifi密码const char* host = "api.seniverse.com"; //心知天气服务器地址
String now_address="",now_time="",now_high_tem="",now_low_tem="",now_rainfall="",now_wind_direction="",now_wind_scale="",now_hum="",now_weather=""; //用来存储报文得到的字符串String weekDays[7]={"周日", "周一", "周二","周三", "周四", "周五", "周六"};String weekEnglish[7] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};String months[12]={"January", "February", "March", "April","May", "June", "July", "August", "September", "October", "November", "December"};
WiFiUDP ntpUDP;NTPClient timeClient(ntpUDP, "ntp.aliyun.com"); // NTP获取时间Ticker t1; // 获取天气间隔时间TFT_eSPI tft = TFT_eSPI(); //设定屏幕char determineqing[]="晴";char determineduoyun[]="多云";char determineyin[]="阴";char determineyu[]="雨";char determinexue[]="雪";unsigned long currentSec;int i = 0;int k = 0;int ph;int flag = 1;char* now_wea;int tm_Hour,tm_Minute,monthDay,tm_Month;String weekDay;char* week;
/*************Connect Wifi********************/void get_wifi(){ WiFi.begin(ssid, password); // 连接网络 while (WiFi.status() != WL_CONNECTED) //等待wifi连接 { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); //连接成功 Serial.print("IP address: "); //打印IP地址 Serial.println(WiFi.localIP()); tft.fillScreen(TFT_WHITE); tft.pushImage(14, 65, 100, 20, ConnectWifi[5]);//调用图片数据 tft.setCursor(20, 30, 1); //设置文字开始坐标(20,30)及1号字体 tft.setTextSize(1); tft.println("WiFi Connected!"); delay(200);}
/***************Weather******************/void get_weather(){ //创建TCP连接 WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("Connection failed"); //网络请求无响应打印连接失败 return; } //URL请求地址 String url ="/v3/weather/daily.json?key=SiFlIC-Dte98pIK7z&location=haerbin&language=zh-Hans&unit=c&start=0&days=5"; //发送网络请求 client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(2000); //定义answer变量用来存放请求网络服务器后返回的数据 String answer; while(client.available()) { String line = client.readStringUntil('\r'); answer += line; } //断开服务器连接 client.stop(); Serial.println(); Serial.println("closing connection"); //获得json格式的数据 String jsonAnswer; int jsonIndex; //找到有用的返回数据位置i 返回头不要 for (int i = 0; i < answer.length(); i++) { if (answer[i] == '{') { jsonIndex = i; break; } } jsonAnswer = answer.substring(jsonIndex); Serial.println(); Serial.println("JSON answer: "); Serial.println(jsonAnswer); StaticJsonDocument<1536> doc; deserializeJson(doc, jsonAnswer); JsonObject results_0 = doc["results"][0]; JsonObject results_0_location = results_0["location"]; const char* results_0_location_name = results_0_location["name"]; // "哈尔滨" now_address = results_0_location_name; for (JsonObject results_0_daily_item : results_0["daily"].as()) { //const char* date = results_0_daily_item["date"]; // "2021-07-20", "2021-07-21", "2021-07-22" const char* text_day = results_0_daily_item["text_day"]; // "中雨", "小雨", "小雨" now_weather = text_day; const char* high = results_0_daily_item["high"]; // "28", "29", "27" now_high_tem = high; const char* low = results_0_daily_item["low"]; // "22", "23", "22" now_low_tem = low; const char* rainfall = results_0_daily_item["rainfall"]; // "19.55", "11.51", "0.42" now_rainfall = rainfall; //const char* precip = elem["precip"]; // "0.99", "0.94", "0.33" const char* wind_direction = results_0_daily_item["wind_direction"]; // "东", "东", "东" now_wind_direction = wind_direction; //const char* wind_direction_degree = elem["wind_direction_degree"]; // "80", "89", "85" //const char* wind_speed = elem["wind_speed"]; // "13.46", "8.64", "10.84" const char* wind_scale = results_0_daily_item["wind_scale"]; // "3", "2", "2" now_wind_scale = wind_scale; const char* humidity = results_0_daily_item["humidity"]; // "100", "100", "98" now_hum = humidity; break; } if(strstr(now_weather.c_str(),determineqing)!=0) { now_wea = "晴"; ph = 0; } if(strstr(now_weather.c_str(),determineduoyun)!=0) { now_wea = "多云"; ph = 1; } if(strstr(now_weather.c_str(),determineyin)!=0) { now_wea = "阴"; ph = 2; } if(strstr(now_weather.c_str(),determineyu)!=0) { now_wea = "雨"; ph = 4; } if(strstr(now_weather.c_str(),determinexue)!=0) { now_wea = "雪"; ph = 7; }}
/**************Setup***********************/void setup(){ pinMode(5,INPUT); Serial.begin(115200); Serial.println("Start"); tft.init(); //初始化显示寄存器 tft.fillScreen(TFT_WHITE); //屏幕颜色 tft.setTextColor(TFT_BLACK); //设置字体颜色黑色 tft.setCursor(15, 30, 1); //设置文字开始坐标(15,30)及1号字体 tft.setTextSize(1); tft.println("Connecting Wifi..."); //tft.setRotation(4);//屏幕内容镜像显示或者旋转屏幕0-4 ST7735_Rotation中设置
tft.setSwapBytes(true); //使图片颜色由RGB->BGR for (int j = 0; j < 5; j++) { tft.pushImage(14, 65, 100, 20, ConnectWifi[j]); //调用图片数据 delay(400); } get_wifi(); // Wifi连接 get_weather(); timeClient.begin(); timeClient.setTimeOffset(28800); //设置偏移时间(以秒为单位)以调整时区 tft.fillScreen(TFT_BLACK);}
/*******************Loop*******************/
void loop(){ timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); //Serial.println(epochTime); if(flag == 1) { currentSec = epochTime; flag = 0; } String formattedTime = timeClient.getFormattedTime(); int tm_Hour = timeClient.getHours(); int tm_Minute = timeClient.getMinutes(); int tm_Second = timeClient.getSeconds();    String weekDay = weekDays[timeClient.getDay()]; char week[weekDay.length() + 1];    weekDay.toCharArray(week,weekDay.length() + 1); struct tm *ptm = gmtime ((time_t *)&epochTime); int monthDay = ptm->tm_mday; int tm_Month = ptm->tm_mon+1; String currentMonthName = months[tm_Month-1]; int tm_Year = ptm->tm_year+1900; String currentDate = String(tm_Month) + "/" + String(monthDay); String currentTime, hour, minute; if (tm_Hour < 10) hour = "0" + String(tm_Hour); else hour = String(tm_Hour); if (tm_Minute < 10) minute = "0" + String(tm_Minute); else minute = String(tm_Minute); currentTime = hour + ":" + minute; a=digitalRead(5); if(a==LOW) { tft.fillScreen(TFT_BLACK); show_weather(TFT_GREEN,TFT_BLACK); // 显示天气界面 delay(3000); tft.fillScreen(TFT_BLACK); } else { show_time(TFT_GREEN, TFT_BLACK, Astronaut, currentTime, currentDate, tm_Year, week); // 显示时间界面 } delay(50);}/*******************时间界面显示****************/void show_time(uint16_t fg,uint16_t bg,const uint16_t* image[], String currentTime, String currentDate, int tm_Year,const char* week){ //tft.fillRect(10, 55, 64, 64, bg); tft.setSwapBytes(true); //使图片颜色由RGB->BGR tft.pushImage(10, 55, 64, 64, image[i]); delay(100); i+=1; if(i>8){i=0;} tft.drawFastHLine(10, 53, 108, tft.alphaBlend(0, bg, fg)); showtext(15,5,2,3,fg,bg,currentTime); showtext(75,60,1,2,fg,bg, String(tm_Year)); showtext(75,80,1,2,fg,bg, currentDate); showMyFonts(80, 100, week, TFT_GREEN);}/*******************天气界面显示****************/void show_weather(uint16_t fg,uint16_t bg){ tft.setSwapBytes(true); //使图片颜色由RGB->BGR    tft.pushImage(50,  6464, weather[ph]); showMyFonts(70, 20, now_address.c_str(), TFT_GREEN);    showMyFonts(9040, now_wea, TFT_GREEN); tft.pushImage(0, 65, 30, 30, temIcon); tft.pushImage(0, 95, 30, 30, humIcon); tft.pushImage(55, 65, 30, 30, rainIcon);    tft.pushImage(45953030, windIcon); showtext(25,75,1,1,fg,bg,now_high_tem + "/" + now_low_tem); showtext(85,75,1,1,fg,bg,now_rainfall +"mm"); showtext(25,105,1,1,fg,bg,now_hum+"%"); String now_wind = now_wind_direction + "风"; showMyFonts(75, 100, now_wind.c_str(), TFT_GREEN);}
/*******************整句字符串显示****************/void showtext(int16_t x,int16_t y,uint8_t font,uint8_t s,uint16_t fg,uint16_t bg,const String str){ //设置文本显示坐标,和文本的字体,默认以左上角为参考点, tft.setCursor(x, y, font); // 设置文本颜色为白色,文本背景黑色 tft.setTextColor(fg,bg); //设置文本大小,文本大小的范围是1-7的整数 tft.setTextSize(s); // 设置显示的文字,注意这里有个换行符 \n 产生的效果 tft.println(str);}
/*******************单个汉字显示****************/void showMyFont(int32_t x, int32_t y, const char c[3], uint32_t color) { for (int k = 0; k < 26; k++)// 根据字库的字数调节循环的次数 if (hanzi[k].Index[0] == c[0] && hanzi[k].Index[1] == c[1] && hanzi[k].Index[2] == c[2]) { tft.drawBitmap(x, y, hanzi[k].hz_Id, hanzi[k].hz_width, 16, color); }}/*******************整句汉字显示****************/void showMyFonts(int32_t x, int32_t y, const char str[], uint32_t color) { //显示整句汉字,字库比较简单,上下、左右输出是在函数内实现 int x0 = x; for (int i = 0; i < strlen(str); i += 3) { showMyFont(x0, y, str+i, color); x0 += 17; }}
程序中的天气信息获取采用当天+未来3天天气API,API如下,因为选用当天天气API无法获取风向,温湿度以及晴雨表。
https://api.seniverse.com/v3/weather/daily.json?key=SiFlIC-Dte98pIK7z&location=haerbin&language=zh-Hans&unit=c&start=0&days=5
解析出来的json数据如下,将获取的json数据格式修改添加到上面的程序当中,程序其余部分就是将时钟信息,天气信息进行中英文显示。

时钟信息界面和天气信息界面显示如下:

ESP32太空人天气时钟完结视频:

DQ笔记 记录自己学习的过程
评论
  • RGB灯光无法同步?细致的动态光效设定反而成为产品客诉来源!随着科技的进步和消费者需求变化,电脑接口设备单一功能性已无法满足市场需求,因此在产品上增加「动态光效」的形式便应运而生,藉此吸引消费者目光。这种RGB灯光效果,不仅能增强电脑周边产品的视觉吸引力,还能为用户提供个性化的体验,展现独特自我风格。如今,笔记本电脑、键盘、鼠标、鼠标垫、耳机、显示器等多种电脑接口设备多数已配备动态光效。这些设备的灯光效果会随着音乐节奏、游戏情节或使用者的设置而变化。想象一个画面,当一名游戏玩家,按下电源开关,整
    百佳泰测试实验室 2025-02-27 14:15 137浏览
  • 请移步 gitee 仓库 https://gitee.com/Newcapec_cn/LiteOS-M_V5.0.2-Release_STM32F103_CubeMX/blob/main/Docs/%E5%9F%BA%E4%BA%8ESTM32F103RCT6%E7%A7%BB%E6%A4%8DLiteOS-M-V5.0.2-Release.md基于STM32F103RCT6移植LiteOS-M-V5.0.2-Release下载源码kernel_liteos_m: OpenHarmon
    逮到一只程序猿 2025-02-27 08:56 195浏览
  • 应用趋势与客户需求,AI PC的未来展望随着人工智能(AI)技术的日益成熟,AI PC(人工智能个人电脑)逐渐成为消费者和企业工作中的重要工具。这类产品集成了最新的AI处理器,如NPU、CPU和GPU,并具备许多智能化功能,为用户带来更高效且直观的操作体验。AI PC的目标是提升工作和日常生活的效率,通过深度学习与自然语言处理等技术,实现更流畅的多任务处理、实时翻译、语音助手、图像生成等功能,满足现代用户对生产力和娱乐的双重需求。随着各行各业对数字转型需求的增长,AI PC也开始在各个领域中显示
    百佳泰测试实验室 2025-02-27 14:08 255浏览
  •         近日,广电计量在聚焦离子束(FIB)领域编写的专业著作《聚焦离子束:失效分析》正式出版,填补了国内聚焦离子束领域实践性专业书籍的空白,为该领域的技术发展与知识传播提供了重要助力。         随着芯片技术不断发展,芯片的集成度越来越高,结构也日益复杂。这使得传统的失效分析方法面临巨大挑战。FIB技术的出现,为芯片失效分析带来了新的解决方案。它能够在纳米尺度上对芯片进行精确加工和分析。当芯
    广电计量 2025-02-28 09:15 116浏览
  • 1,微软下载免费Visual Studio Code2,安装C/C++插件,如果无法直接点击下载, 可以选择手动install from VSIX:ms-vscode.cpptools-1.23.6@win32-x64.vsix3,安装C/C++编译器MniGW (MinGW在 Windows 环境下提供类似于 Unix/Linux 环境下的开发工具,使开发者能够轻松地在 Windows 上编写和编译 C、C++ 等程序.)4,C/C++插件扩展设置中添加Include Path 5,
    黎查 2025-02-28 14:39 140浏览
  • 在2024年的科技征程中,具身智能的发展已成为全球关注的焦点。从实验室到现实应用,这一领域正以前所未有的速度推进,改写着人类与机器的互动边界。这一年,我们见证了具身智能技术的突破与变革,它不仅落地各行各业,带来新的机遇,更在深刻影响着我们的生活方式和思维方式。随着相关技术的飞速发展,具身智能不再仅仅是一个技术概念,更像是一把神奇的钥匙。身后的众多行业,无论愿意与否,都像是被卷入一场伟大变革浪潮中的船只,注定要被这股汹涌的力量重塑航向。01为什么是具身智能?为什么在中国?最近,中国具身智能行业的进
    艾迈斯欧司朗 2025-02-28 15:45 221浏览
  • 振动样品磁强计是一种用于测量材料磁性的精密仪器,广泛应用于科研、工业检测等领域。然而,其测量准确度会受到多种因素的影响,下面我们将逐一分析这些因素。一、温度因素温度是影响振动样品磁强计测量准确度的重要因素之一。随着温度的变化,材料的磁性也会发生变化,从而影响测量结果的准确性。因此,在进行磁性测量时,应确保恒温环境,以减少温度波动对测量结果的影响。二、样品制备样品的制备过程同样会影响振动样品磁强计的测量准确度。样品的形状、尺寸和表面处理等因素都会对测量结果产生影响。为了确保测量准确度,应严格按照规
    锦正茂科技 2025-02-28 14:05 134浏览
  • 构建巨量的驾驶场景时,测试ADAS和AD系统面临着巨大挑战,如传统的实验设计(Design of Experiments, DoE)方法难以有效覆盖识别驾驶边缘场景案例,但这些边缘案例恰恰是进一步提升自动驾驶系统性能的关键。一、传统解决方案:静态DoE标准的DoE方案旨在系统性地探索场景的参数空间,从而确保能够实现完全的测试覆盖范围。但在边缘案例,比如暴露在潜在安全风险的场景或是ADAS系统性能极限场景时,DoE方案通常会失效,让我们看一些常见的DoE方案:1、网格搜索法(Grid)实现原理:将
    康谋 2025-02-27 10:00 252浏览
  •           近日受某专业机构邀请,参加了官方举办的《广东省科技创新条例》宣讲会。在与会之前,作为一名技术工作者一直认为技术的法例都是保密和侵权方面的,而潜意识中感觉法律有束缚创新工作的进行可能。通过一个上午学习新法,对广东省的科技创新有了新的认识。广东是改革的前沿阵地,是科技创新的沃土,企业是创新的主要个体。《广东省科技创新条例》是广东省为促进科技创新、推动高质量发展而制定的地方性法规,主要内容包括: 总则:明确立法目
    广州铁金刚 2025-02-28 10:14 103浏览
  • 美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?‌美国加州CEC能效认证与美国DOE能效认证在多个方面存在显著差异‌。认证范围和适用地区‌CEC能效认证‌:仅适用于在加利福尼亚州销售的电器产品。CEC认证的范围包括制冷设备、房间空调、中央空调、便携式空调、加热器、热水器、游泳池加热器、卫浴配件、光源、应急灯具、交通信号模块、灯具、洗碗机、洗衣机、干衣机、烹饪器具、电机和压缩机、变压器、外置电源、消费类电子设备
    张工nx808593 2025-02-27 18:04 120浏览
  • 更多生命体征指标风靡的背后都只有一个原因:更多人将健康排在人生第一顺位!“AGEs,也就是晚期糖基化终末产物,英文名Advanced Glycation End-products,是存在于我们体内的一种代谢产物” 艾迈斯欧司朗亚太区健康监测高级市场经理王亚琴说道,“相信业内的朋友都会有关注,最近该指标的热度很高,它可以用来评估人的生活方式是否健康。”据悉,AGEs是可穿戴健康监测领域的一个“萌新”指标,近来备受关注。如果站在学术角度来理解它,那么AGEs是在非酶促条件下,蛋白质、氨基酸
    艾迈斯欧司朗 2025-02-27 14:50 400浏览
  • 在物联网领域中,无线射频技术作为设备间通信的核心手段,已深度渗透工业自动化、智慧城市及智能家居等多元场景。然而,随着物联网设备接入规模的不断扩大,如何降低运维成本,提升通信数据的传输速度和响应时间,实现更广泛、更稳定的覆盖已成为当前亟待解决的系统性难题。SoC无线收发模块-RFM25A12在此背景下,华普微创新推出了一款高性能、远距离与高性价比的Sub-GHz无线SoC收发模块RFM25A12,旨在提升射频性能以满足行业中日益增长与复杂的设备互联需求。值得一提的是,RFM25A12还支持Wi-S
    华普微HOPERF 2025-02-28 09:06 143浏览
  • 一、VSM的基本原理震动样品磁强计(Vibrating Sample Magnetometer,简称VSM)是一种灵敏且高效的磁性测量仪器。其基本工作原理是利用震动样品在探测线圈中引起的变化磁场来产生感应电压,这个感应电压与样品的磁矩成正比。因此,通过测量这个感应电压,我们就能够精确地确定样品的磁矩。在VSM中,被测量的样品通常被固定在一个震动头上,并以一定的频率和振幅震动。这种震动在探测线圈中引起了变化的磁通量,从而产生了一个交流电信号。这个信号的幅度和样品的磁矩有着直接的关系。因此,通过仔细
    锦正茂科技 2025-02-28 13:30 100浏览
  • Matter 协议,原名 CHIP(Connected Home over IP),是由苹果、谷歌、亚马逊和三星等科技巨头联合ZigBee联盟(现连接标准联盟CSA)共同推出的一套基于IP协议的智能家居连接标准,旨在打破智能家居设备之间的 “语言障碍”,实现真正的互联互通。然而,目标与现实之间总有落差,前期阶段的Matter 协议由于设备支持类型有限、设备生态协同滞后以及设备通信协议割裂等原因,并未能彻底消除智能家居中的“设备孤岛”现象,但随着2025年的到来,这些现象都将得到完美的解决。近期,
    华普微HOPERF 2025-02-27 10:32 214浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦