
1. 项目缘起为什么需要一个本地化的降雨预报设备几年前我在一个信号不太稳定的山区小屋里住过一阵子。那段时间我每天都要反复刷新手机上的天气App就为了看一眼未来几天的降雨预报好安排晾晒衣物或者出门徒步。但问题来了山里的网络时好时坏有时候加载个预报图要等半天更别提那些App里夹杂的广告和无关信息了。当时我就想如果能有一个设备像挂在墙上的日历一样安安静静地显示未来几天的天气不用联网刷新不用手动操作看一眼就知道那该多方便。这个想法一直没落地直到我接触了ESP32和电子墨水屏。ESP32这颗芯片的强大之处在于它内置了Wi-Fi可以轻松地从网络上获取数据但功耗控制得又很好非常适合这种间歇性工作的设备。而电子墨水屏也就是E-Paper它的显示特性简直是为这个场景量身定做的只在刷新内容时才耗电显示静态画面时零功耗这意味着设备可以做到极低的待机功耗用一块小电池就能撑很久。把这两者结合起来一个能够自动获取、显示未来五天降雨预报的“智能挂件”就有了硬件基础。这个DIY项目的核心价值就是打造一个完全属于你自己的、离线可读的天气信息终端。它不依赖手机不占用你的注意力只是在你需要的时候提供最干净、最核心的降雨信息。无论是放在玄关出门前看一眼还是挂在阳台规划晾晒甚至作为工作室里一个有趣的科技装饰都非常实用。接下来我会从硬件选型、软件架构、数据获取与解析再到最终的组装调试完整地拆解这个项目的每一个环节并分享我在制作过程中踩过的坑和总结的经验。2. 核心硬件选型与电路设计思路硬件是整个项目的骨架选型直接决定了设备的稳定性、功耗和最终体验。这里没有“最好”的方案只有“最适合”当前需求的组合。我的核心诉求是低功耗、显示清晰、开发简便、成本可控。2.1 主控芯片为什么是ESP32在微控制器领域可选方案很多比如经典的Arduino UnoATmega328P、功能更强的ESP8266或者更省电的STM32系列。我最终选择ESP32-S3主要基于以下几点考量第一双核处理器与充足的存储。ESP32-S3拥有240MHz的双核Xtensa处理器性能对于处理网络请求和解析JSON天气数据绰绰有余。更重要的是它通常内置4MB或以上的Flash存储这允许我们存储复杂的图形字体、甚至缓存多天的天气图标而无需外置SD卡简化了电路设计。第二集成的Wi-Fi与蓝牙。这是实现自动获取天气数据的关键。相比需要额外模块的方案内置Wi-Fi节省了空间和功耗。ESP32的深度睡眠模式Deep Sleep配合Wi-Fi的间歇性连接是实现超长待机的技术基础。在深度睡眠下整机电流可以降到10微安级别只有实时时钟RTC和部分内存保持供电等待定时唤醒。第三丰富的外设与成熟的生态。ESP32支持SPI、I2C、UART等多种通信协议方便连接屏幕和各种传感器。其Arduino核心及乐鑫官方的ESP-IDF开发框架拥有海量的社区资源和库支持遇到问题很容易找到解决方案极大降低了开发门槛。注意市面上ESP32型号繁多对于本项目推荐选择带有外部天线接口的型号如ESP32-S3-DevKitC-1以获得更稳定的Wi-Fi信号。如果追求极致紧凑也可以选择ESP32-S3-MINI这类模组但需要自行设计PCB和天线。2.2 显示模块电子墨水屏的选型要点电子墨水屏的选择是项目的门面直接影响显示效果和功耗。我选择了一款7.5英寸、800x480分辨率的黑白三色黑、白、红屏幕。以下是选型时的几个关键决策点尺寸与分辨率7.5英寸是一个折中的选择。足够大能在一定距离外清晰看清五天的预报信息又不会太大导致功耗和成本急剧上升。800x480的分辨率足以显示文字和简单的图标细节表现良好。色彩黑白红三色屏比纯黑白屏贵一些但带来的价值提升是显著的。我们可以用红色来高亮显示“大雨”或“暴雨”预警让重要信息一目了然。从用户体验角度看这一点点成本增加是完全值得的。驱动接口与刷新速度大部分E-Paper屏幕使用SPI接口驱动。需要关注两个参数一是全局刷新时间二是局部刷新能力。全局刷新全屏清空再绘制通常需要2-3秒期间屏幕会闪烁。局部刷新只更新变化的部分更快且无闪烁但对驱动IC和代码有要求。我选择的这款屏幕支持局部刷新这对于只更新某一天温度或图标的情况非常友好体验更流畅。功耗考量E-Paper只在刷新瞬间功耗较高约几十毫安静态显示时为零。因此整体功耗取决于我们刷新的频率。计划每天定时如早晚各一次获取数据并刷新那么平均功耗会非常低。2.3 电源管理实现“续航数月”的关键目标是让设备摆脱电源线的束缚因此电池供电和高效的电源管理电路至关重要。电池选择我选用了一块容量为2000mAh的3.7V锂聚合物电池。选择理由如下首先电压与ESP32的工作电压3.3V匹配只需一个简单的低压差稳压器LDO或更高效的DC-DC降压模块即可。其次软包电池体积相对小巧易于集成。2000mAh的容量假设设备每天唤醒2次每次工作Wi-Fi连接、数据处理、屏幕刷新耗时约30秒工作电流约150mA深度睡眠电流10μA简单估算续航可达数月。充电与管理为了方便我直接选用了集成充电管理如TP4056和升压输出至5V或3.3V的模块。这样只需一个Micro-USB或Type-C接口就能为电池充电同时模块能提供稳定的3.3V输出给ESP32和屏幕。这种模块化设计避免了自行设计充放电电路的复杂性可靠性更高。ESP32的省电配置在软件层面我们需要充分利用ESP32的睡眠模式。代码逻辑将是设备唤醒 - 连接Wi-Fi - 获取天气数据 - 处理数据并刷新屏幕 - 进入深度睡眠 - 等待定时器唤醒例如12小时后。这里的关键是在进入深度睡眠前要确保Wi-Fi已断开所有外设如屏幕已进入最低功耗状态。一个常见的坑是屏幕的SPI引脚如果保持上拉可能会产生微小的漏电流需要在代码中将其设置为输入模式或拉低。3. 软件架构与核心代码逻辑剖析软件是项目的灵魂它需要可靠地执行“获取-解析-显示”这个核心循环并优雅地处理各种异常情况。整个程序将基于Arduino框架开发结构清晰便于理解和修改。3.1 整体工作流程设计程序的主循环非常简单因为大部分时间芯片都在睡觉。一次完整的工作流程如下上电/唤醒初始化从深度睡眠中唤醒后首先初始化串口用于调试、文件系统用于存储配置、以及屏幕驱动。读取配置从非易失性存储NVS或文件中读取Wi-Fi的SSID、密码、以及天气API的请求地址和密钥。避免将敏感信息硬编码在代码中。连接Wi-Fi尝试连接预设的Wi-Fi网络。这里必须加入超时和重试机制。例如尝试连接30秒每5秒输出一次状态。如果失败则让屏幕显示“网络连接失败”的提示信息然后延长睡眠时间如10分钟后重试而不是陷入死循环。获取天气数据使用HTTP客户端如HTTPClient库向天气API发送GET请求。这里需要设置合理的超时时间如10秒并检查HTTP响应码是否为200成功。解析数据天气API通常返回JSON格式的数据。我们需要使用ArduinoJson库来解析这个JSON。核心任务是提取未来五天或七天的日期、白天/夜晚的天气状况代码、最高/最低温度、降水概率等关键字段。处理与格式化将解析出的天气代码如“04”表示阴天映射到我们预先设计好的图标上。将温度、降水概率等数字格式化成适合显示的字符串如“25°C”, “60%”。计算布局确定每个元素日期、图标、温度、降水在屏幕上的坐标位置。刷新屏幕如果是首次运行或需要全屏清空则执行一次全局刷新。通常我们采用局部刷新来更新数据区域。先绘制一个白色的矩形覆盖旧的数据区域然后再绘制新的文字和图标。这比全局刷新快得多且无闪烁。进入深度睡眠调用esp_deep_sleep_start()函数并传入睡眠时间微秒。例如esp_deep_sleep(12 * 3600 * 1000000ULL)表示睡眠12小时。在睡眠前务必关闭Wi-Fi (WiFi.disconnect(true),WiFi.mode(WIFI_OFF))。3.2 天气数据源的选择与API集成免费且稳定的天气数据源是这个项目能持续运行的基础。国内开发者常用的有心知天气、和风天气HeWeather等。我以和风天气为例因为它提供清晰的免费层级和API文档。API申请与配置注册和风天气开发者账号创建一个项目获得一个Key。查阅其“7天天气预报”API文档。我们需要的是一个返回未来几天预报的接口例如https://devapi.qweather.com/v7/weather/7d?locationYOUR_LOCATION_IDkeyYOUR_KEY。location参数需要城市的地理位置ID。你可以在其城市搜索API中用城市名搜索到对应的id。切记不要直接在代码中暴露你的API Key。最佳实践是将其存储在ESP32的NVS或SPIFFS文件系统中首次配置时通过串口或Web配网页面写入。JSON数据解析示例 假设API返回的JSON中daily数组包含了每天的预报。我们需要解析类似下面的结构{ code: 200, daily: [ { fxDate: 2023-10-27, textDay: 多云, iconDay: 101, tempMax: 22, tempMin: 15, precip: 0.0 }, // ... 更多天的数据 ] }使用ArduinoJson库解析的代码片段如下#include ArduinoJson.h DynamicJsonDocument doc(4096); // 根据返回数据大小调整 deserializeJson(doc, httpResponse); if (doc[code] 200) { JsonArray daily doc[daily]; for (int i 0; i 5; i) { // 只取前五天 String date daily[i][fxDate]; // 2023-10-27 String dayText daily[i][textDay]; // 多云 String dayIconCode daily[i][iconDay]; // 101 int tempMax daily[i][tempMax].asint(); int tempMin daily[i][tempMin].asint(); float precip daily[i][precip].asfloat(); // 将 iconCode (如101) 映射到具体的图标文件名或绘制函数 // 格式化温度字符串 // 存储到用于显示的数据结构中 } }3.3 图形界面绘制与局部刷新策略绘制界面是让数据变得直观的关键。我们使用GxEPD2库来驱动电子墨水屏它是一个功能强大且维护积极的库支持多种屏幕型号和局部刷新。设计布局 在纸上或绘图软件中先规划好布局。一个简单的五天预报布局可以是水平排列五列每列包含顶部日期如“10/27”或“周五”。中部天气图标用drawBitmap函数绘制。中下部最高温/最低温如“22/15°C”。底部降水概率如“30%”用红色字体显示。图标处理 天气图标需要事先准备好。可以从开源天气图标库中获取将其转换为单色位图数组。由于E-Paper是黑白的图标需要处理成1位色深每个像素1位的XBM格式或直接是字节数组。可以使用在线转换工具或Image2CPP这样的软件来转换。将不同天气代码如“101”对应晴“104”对应阴映射到不同的图标数组。局部刷新实现GxEPD2库为支持局部刷新的屏幕提供了setPartialWindow和nextPage的机制。核心思想是只更新屏幕上发生变化的一个矩形区域而不是全屏。// 假设屏幕对象为 display display.setPartialWindow(column_x, column_y, column_width, column_height); // 设置要更新的区域 display.firstPage(); // 开始局部刷新 do { // 在这个区域内先画一个白色矩形覆盖旧内容 display.fillRect(column_x, column_y, column_width, column_height, GxEPD_WHITE); // 然后绘制新的日期、图标、温度、降水概率 display.setCursor(text_x, text_y); display.print(new_date); // ... 绘制其他元素 } while (display.nextPage()); // 完成局部刷新局部刷新能大幅提升刷新速度可能从2秒缩短到0.5秒并彻底消除全屏闪烁体验提升巨大。4. 组装、调试与功耗优化实战当所有代码就绪后真正的挑战才刚刚开始把分散的模块变成一台稳定可靠的设备。这个阶段会暴露设计时未曾考虑到的问题。4.1 硬件焊接与组装注意事项焊接和组装看似简单但细节决定成败。ESP32开发板与屏幕的连接通常使用杜邦线或排针焊接。务必对照屏幕和ESP32的引脚定义图正确连接SPI总线CLK, MOSI, MISO, CS、数据/命令选择引脚DC、复位引脚RST和忙信号引脚BUSY。接错线是导致屏幕白屏或不工作的最常见原因。一个建议是先在面包板上把所有线路接好测试功能正常后再进行焊接。电源连接确保电池、充电升压模块、ESP32和屏幕的电源地GND连接在一起形成共同的地参考点。电源线VCC要足够粗或使用多根并联特别是在屏幕刷新瞬间电流需求较大线阻过大会导致电压跌落可能引起ESP32意外复位。结构固定与绝缘如果使用3D打印外壳要留出足够的空间放置电池和电路并考虑散热虽然本项目发热不大。确保所有裸露的焊点和导线都有绝缘保护防止短路。屏幕排线要固定好避免频繁弯折导致断裂。4.2 软件调试与故障排查即使代码逻辑正确在实际硬件上也可能遇到各种问题。Wi-Fi连接不稳定这是户外或复杂环境中的常见问题。除了在代码中加入重试逻辑还可以尝试在WiFi.begin()后增加一个短暂的延迟再检查连接状态。如果信号弱可以尝试降低Wi-Fi的连接速率通过WiFi.setTxPower()设置有时稳定性比速度更重要。在代码中记录每次连接成功或失败的信息到NVS如果连续多次失败可以尝试重启ESP32或切换到备份的Wi-Fi配置如果有的话。天气API请求失败首先用串口监视器打印出完整的HTTP请求URL和返回的状态码、响应体。检查API Key是否过期、请求次数是否超限免费API通常有每日次数限制。其次考虑网络时间同步NTP。有些API服务器会校验请求时间如果设备时间偏差太大可能会被拒绝。在连接Wi-Fi后先使用configTime()函数同步网络时间。屏幕显示异常如果出现残影、刷新不全或乱码检查电源电压。在屏幕刷新时用万用表测量供电电压是否稳定在3.3V。如果跌落严重说明电源带载能力不足需要更换更大电流的LDO或电池。检查SPI时钟频率。过高的SPI速度可能导致数据传输出错。尝试在初始化屏幕时降低SPI频率。确保在每次刷新前都正确调用了display.init()或display.wakeup()对于某些驱动库。深度睡眠后屏幕也需要被重新初始化。4.3 功耗测量与续航优化技巧功耗优化是让设备从“能用”到“好用”的关键一步。你需要一个万用表切换到微安档μA串联在电池和电路板之间进行测量。测量各阶段电流深度睡眠电流理想情况应在10-50μA之间。如果过高检查所有GPIO引脚的状态。将未使用的引脚设置为INPUT_PULLUP或INPUT_PULLDOWN避免浮空。特别检查连接屏幕的引脚在睡眠前将其设置为输入模式。Wi-Fi连接与数据获取电流此时电流峰值可能达到150-200mA。关注这个阶段的持续时间优化代码以减少连接和数据传输时间。例如使用更高效的JSON解析库只请求必要的数据字段如果API支持。屏幕刷新电流全局刷新时电流峰值最高可能超过200mA但持续时间很短1-3秒。局部刷新电流较低。优化策略调整唤醒间隔如果不是特别需要不必每12小时更新一次。可以改为每天更新一次24小时甚至根据降水概率动态调整如果未来几天都无雨可以延长睡眠时间。优化网络交互如果天气API支持使用gzip压缩传输数据减少数据传输量。使用更快的DNS服务器。降低CPU频率在不需要高性能处理时可以调用setCpuFrequencyMhz()降低ESP32的主频例如降到80MHz能有效降低工作电流。使用更高效的睡眠模式除了深度睡眠ESP32还有轻度睡眠Light Sleep等模式。如果业务逻辑允许在睡眠中保持Wi-Fi连接通过Beacon监听可以进一步减少重连时间但功耗会高于深度睡眠。本项目对实时性要求不高深度睡眠是最佳选择。经过上述优化我的设备在每天刷新两次的情况下实测平均电流约20μA2000mAh电池的理论续航超过一年。当然实际续航会因网络信号强度、环境温度等因素有所缩短但维持数月是完全可以期待的。5. 功能扩展与个性化定制思路基础的五天降雨预报实现后这个开源硬件平台还有巨大的潜力可以挖掘。你可以根据自己的需求和兴趣把它改造成一个功能更丰富的环境信息站。增加传感器实现本地微气候监测ESP32的GPIO和ADC可以轻松连接各种传感器。例如接入一个BME280传感器就可以在屏幕上同时显示室内的温湿度、气压数据。接入一个光敏电阻就能感知环境光照。这些本地数据与网络预报相结合能提供更全面的环境信息。例如显示“预报今日有雨当前室内湿度已达85%建议关闭窗户”。设计更丰富的显示主题与布局目前的界面以信息清晰为主但美观性还有提升空间。你可以设计不同的主题比如简约风、拟物风、甚至像素艺术风。利用E-Paper三色的特点设计更生动的图标。布局也可以变化比如采用垂直列表、中心辐射状排列等。GxEPD2库支持绘制直线、矩形、圆形和位图给了你足够的创作空间。开发Web配置界面告别硬编码每次修改Wi-Fi密码或城市位置都要重新刷写固件太麻烦了。可以开发一个简单的Web服务器配网页面。当设备首次启动或长按某个按钮时ESP32会进入AP模式手机连接上它的热点后打开浏览器就能访问一个配置页面输入新的Wi-Fi信息和城市ID。配置信息会保存到NVS中。这利用了ESP32的Wi-Fi和Web服务器能力是提升产品化体验的重要一步。接入其他数据源除了天气你也可以让它显示其他信息。例如通过请求公共API显示空气质量指数AQI、股市指数、或者你关注的GitHub仓库的star数。只需要修改数据获取和解析部分的代码并在显示布局上做好规划。一个设备多种用途。这个DIY项目从想法到实现贯穿了硬件选型、嵌入式编程、网络通信、电源管理和用户界面设计等多个环节。它不仅仅是一个显示天气的工具更是一个学习物联网开发全流程的绝佳实践。当你看到自己亲手制作的设备安静地挂在墙上可靠地提供着所需的信息时那种成就感和实用性是购买任何成品都无法替代的。希望这份详细的拆解能帮助你少走弯路成功打造出属于自己的智能天气站。如果在制作过程中遇到任何具体问题不妨多查阅相关芯片的数据手册和库的文档社区的智慧总是能给你带来惊喜。