
搞太阳能气象站这个项目我最想吐槽的不是传感器也不是固件而是供电。很多玩家第一步就去挑温湿度传感器、买风杯、看雨量计最后才想起来太阳能板和电池要配多大的结果装起来才发现不是板子带不动就是电池两天饿死。其实整个项目里最该先动手算的是功耗账后面所有选型都围着这个数字转。这篇文章就把我从零搭建一台太阳能气象站的完整过程讲透功耗怎么估算、传感器怎么选、充电和稳压电路怎么搭、固件怎么写才能把深度睡眠做到位还有外壳防潮和现场校准这些只会在实战中碰到的坑。如果你正打算做一台放室外长期跑的自动气象站或者已经做了一台但续航始终不理想这篇能帮你省掉好几轮返工。1. 算清功耗定下太阳能板和电池容量1.1 别被峰值电流误导要按“唤醒周期”来算很多人算功耗时喜欢把所有器件的正常工作电流加起来比如ESP32跑起来算150mA传感器算几mA然后乘个24小时得出来的数字大到吓人于是直接买了一块10W的太阳能板。这种做法忽略了一件事气象站绝大多数时间不是在“工作”而是在睡觉。我做的这台站是每10分钟唤醒一次完成测量、传输然后继续深度睡眠。这个工作模式决定了功耗必须分成三段来算深度睡眠电流、唤醒采集电流、Wi-Fi发送电流各自乘上对应的时间占比。我实测的ESP32模块数据大概是这样状态电流占一天时间比例深度睡眠25-40µA99.85%唤醒采集传感器读取本地处理40-80mA0.1%Wi-Fi 发送120-180mA0.05%以每10分钟唤醒一次计算一天醒144次。每次采集处理约10秒其中Wi-Fi发送阶段约3到5秒。我按保守值算一下采集能耗60mA × 10秒 × 144次 86400mA·s 24mAh发送能耗150mA × 5秒 × 144次 108000mA·s 30mAh睡眠能耗30µA × 24小时 0.72mAh合计大约每天55mAh考虑到稳压器转换效率我按60到70mAh做设计余量。这颗数字才是后面所有选型的起点比“平均电流”靠谱得多。1.2 太阳能板和电池容量的实际配置有了每天约60mAh的耗电我们再来看太阳能。锂电池按3.7V折算每天消耗的能量约0.22Wh。太阳能板的发电量不能光看标称功率。市面的6V、3W小板在标准光照条件下1000W/m²满发才有3W但真实户外有云层、太阳角度、温度损耗一般只能按等效峰值日照4小时、系统效率60%来估算。那么一块3W板一天大概能发3W × 4小时 × 0.6 7.2Wh这个量是设备日耗电的30倍以上听起来夸张但太阳能供电最怕的不是晴天而是连续阴雨天。我最终定下的配置是6V/3W太阳能板加2600mAh锂电池电池总能量约9.6Wh。按每天0.22Wh消耗即便完全不充电电池也能撑40天左右。这个余量看着很大但考虑到冬天的低日照、电池老化、太阳能板表面积灰实际冗余并没有想象中充裕。如果你在南方多雨或者冬季雾霾重的地区我建议直接上5W板加3400mAh电池成本差别不大但续航安全感完全不一样。1.3 阴天余量怎么判断判断太阳能系统靠不靠谱经验法则是系统能在“连续7天没有有效日照”的情况下照常运行。为什么是7天因为大部分地区超过7天连续阴雨的情况很少而且阴天往往不是完全无光6V板子在云层下依然能输出一点涓流只是不足以进入正常充电状态但足以维持系统运行。我实际测试过一块3W太阳能板在阴天多云的户外交出大约0.2到0.5W这个功率虽然充不满电池但能抵消一部分消耗。真正要防的是冬天太阳高度角低、日照时间短加上太阳能板被雪覆盖或长期积灰这些情况叠加起来才会真正威胁到供电稳定。2. 传感器选型什么钱该花什么是冤枉钱2.1 温度湿度气压DHT11真的别用新手常犯的错是图便宜选DHT11。这个传感器做室内温度监测勉强能用但放到室外气象站就有两个硬伤湿度精度只有±5%RH而且在高湿度环境下读数会明显漂移另外它的功耗控制不如新一代数字传感器也没有气压测量能力。我最终用的是BME280因为它在同一个芯片里集成了温度、湿度、气压三个参数功耗极低支持forced mode测量一次后自动回到睡眠状态非常适合电池供电场景。几个主流传感器的对比我整理成了表格型号温度精度湿度精度气压休眠电流接口DHT11±2°C±5%RH无无法休眠单总线AHT20±0.3°C±2%RH无1µAI2CSHT30±0.2°C±2%RH无0.4µAI2CBME280±0.5°C±3%RH±1hPa1µAI2C/SPIBMP388±0.3°C无±0.5hPa0.8µAI2C/SPI如果你对温度和湿度精度要求更高SHT30配BMP388也是经典组合但价格会上去一些。我自己的建议是第一台站用BME280就够了这几个参数一个不少而且驱动库很成熟。一个常被忽略的细节是BME280有两个I2C地址0x76和0x77取决于SDO引脚接法。买模块回来先确认用的是哪个地址有些模块把SDO默认接地地址是0x76有些默认接VCC是0x77。如果你在总线上还挂了其他传感器地址冲突排查会花不少时间。2.2 风速风向霍尔开关比干簧管省心风速传感器的核心是风杯转动时产生脉冲MCU通过统计单位时间内的脉冲数换算成风速。市面常见的有干簧管和霍尔开关两种输出我强烈建议选霍尔版本。干簧管是机械触点风杯转快了会有触点抖动每次抖动都会产生额外的脉冲MCU如果没有做去抖实测风速会明显偏高。霍尔开关没有机械触点输出的是干净的数字电平信号接上拉电阻后直接进MCU的GPIO或脉冲计数器不用考虑抖动问题。风向传感器常见的是电位器输出模拟电压或者角度编码器输出数字角度。这里最容易踩的坑是风向平均值的算法。假设10分钟内采样了10次风向其中9次是350°一次是10°真实平均风向应该是355°左右但如果你直接把10个数加起来除以10会得出一个完全不合理的角度。正确做法是把每个风向角拆成sin和cos分量再平均double sumX 0, sumY 0; for (int i 0; i sampleCount; i) { double rad windDir[i] * PI / 180.0; sumX cos(rad); sumY sin(rad); } double avgDir atan2(sumY, sumX) * 180.0 / PI; if (avgDir 0) avgDir 360.0;这段代码我实际跑了一年风向数据一致性很好不会再出现350度和10度平均出180度这种荒唐结果。2.3 雨量计翻斗式是主流防溅设计别忽视雨量计一般用翻斗式雨从集雨口落入两个小斗积满一定量后翻斗翻转一次输出一个脉冲代表某一固定降雨量常见规格是0.2mm/斗。买成品比自己做的精度稳定但不管哪种安装时要注意防溅。雨滴落进集雨口时可能会溅出来导致计量偏小狂风暴雨时更明显。我在雨量计周围加了一圈锯齿状的挡风圈实测下来大雨时计数偏差明显改善。雨量计要水平安装距离地面0.5米以上周围不要有遮挡物。3. 供电系统锂电充电、稳压和电池保护3.1 充电板选型TP4056、CN3065还是CN3791这是很多人直接照抄别人电路图的地方也是翻车最多的地方。TP4056是最常见的锂电池充电模块最大充电电流1A价格便宜适合5V USB输入。但它的设计并不是为太阳能板优化的输入电压一旦低于某个阈值就开始反复重启。太阳能板在阴天或部分遮挡时输出电压会跌到4.5V以下这时候TP4056就会进入“刚启动就欠压欠压后重启”的死循环导致充电效率非常低。我实测下来的经验是晴天、太阳直射时TP4056搭配6V板子勉强能用但阴天或树影遮挡时充电表现很不稳定。如果你坚持用TP4056最好在太阳能板输出端加一个稳压模块把电压稳定到5V同时保证输出电流足够。但这样又多了一级转换白白浪费一些能量。更推荐的做法是用专门为太阳能充电设计的CN3065它内置了类似最大功率点跟踪的逻辑虽然精度比不上专业MPPT控制器但对3W以内的太阳能板已经足够。如果想上更大功率的板子比如10W以上那就用CN3791这种开关型充电管理方案外围电路相对复杂但效率更高也更稳定。3.2 稳压器和静态电流是隐形杀手我之前用过一个现成的ESP32开发板接上锂电池后发现续航只有两三天百思不得其解。后来用万用表一测发现板载的AMS1117稳压器静态电流有5mA左右。5mA放到这个系统里是什么概念它比整个ESP32深度睡眠电流30µA高了一百多倍电池每天光给稳压器“空转”就要消耗120mAh比传感器和主控加起来还多。所以做长期太阳能方案不要用便宜的现成开发板直接供电至少要把板载的AMS1117替换掉或者选静态电流在10µA以下的低压差稳压器比如MCP1700实测静态电流只有几微安。如果想让睡眠电流做到极致可以选带使能引脚的DCDC降压芯片比如TPS62130休眠时直接把输出关掉只保留RTC唤醒电路供电这样整个系统的睡眠电流能压到10µA以下。3.3 电池电压采样要在唤醒后立刻读电池电压是判断系统供电状况的唯一依据固件里必须定期读取。方法是用两个等值电阻比如100k/100k把电池电压分压到ESP32的ADC输入引脚再通过ADC采样计算。需要注意的是采样时序有讲究。ESP32从深度睡眠唤醒后如果马上连着Wi-Fi开始发送数据电流瞬间冲到150mA以上电池内阻会导致电压跌落0.2到0.3V。如果你在这个阶段读取ADC得到的电压会远低于实际值甚至可能误判为“电池没电了”触发低电量保护。正确做法是唤醒后立刻读取电池电压然后再开启Wi-Fi或执行耗电操作。如果电压低于3.3V直接重新进入深度睡眠等待太阳能板充电恢复。4. 固件与功耗控制深度睡眠、唤醒和数据回传4.1 ESP32深度睡眠与唤醒周期ESP32自带的RTC定时器唤醒足够满足气象站需求不需要额外接外部RTC芯片。配置深度睡眠非常简单esp_sleep_enable_timer_wakeup(600 * 1000000ULL); // 10分钟 esp_deep_sleep_start();唤醒后第一件事是确保Wi-Fi和蓝牙都处于关闭或已停止状态减少不必要的外设功耗btStop(); esp_wifi_stop(); esp_bt_controller_disable();另一个容易漏掉的细节是深度睡眠期间GPIO引脚的电平状态。有些传感器或外部上拉电阻会在睡眠时持续漏电哪怕只有几十微安放在“微安级”睡眠目标里也是很大的占比。我建议在休眠前把所有不需要的外部传感器电源引脚置为低电平或者用MOS管做负载开关只在唤醒采集时给传感器供电。4.2 测量与发送的代码结构固件整体逻辑不复杂唤醒 → 读电池电压 → 读传感器 → 读取风速风向计数 → 发送数据 → 进入睡眠。我这里给一个最常用的HTTP POST示例发送JSON数据到本地服务器或云平台#include WiFi.h #include HTTPClient.h const char* ssid your_wifi; const char* password your_password; const char* serverUrl http://192.168.1.10:8086/write?dbweather; void postWeather(float temp, float hum, float pressure, float windSpeed, float windDir) { WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(100); } HTTPClient http; http.begin(serverUrl); http.addHeader(Content-Type, text/plain); String postBody weather,siteroof temp String(temp, 1) ,hum String(hum, 1) ,pressure String(pressure, 1) ,wind String(windSpeed, 1); int httpCode http.POST(postBody); http.end(); WiFi.disconnect(); }这段代码的关键点是数据发送完成后要主动WiFi.disconnect()否则Wi-Fi模块还会持续扫描信号影响睡眠电流。4.3 如何持续统计风速而不增加功耗很多人会问10分钟唤醒一次风速怎么测那10秒内的风速窗口太短根本代表不了10分钟的平均风速更捕捉不到阵风。解决思路有两个。第一个是用ESP32的ULP协处理器它可以在深度睡眠状态下继续运行简单的程序统计GPIO脉冲数不唤醒主CPU。ULP的代码需要单独编写和加载稍微有点学习成本但确实是最省电的方案。第二个更简单粗暴用独立的小低功耗MCU比如ATtiny在睡眠模式下用引脚中断计数然后通过I2C或UART把计数结果传给ESP32。考虑到大多数人不想在固件上花太多时间我建议先用主CPU定期采样每10分钟唤醒后以1秒间隔连续采样10次风速用这10个值估算平均风速和阵风。精度肯定不如专业站但作为家用和种植参考足够了。4.4 数据存储与NTP时间同步如果现场网络不稳定数据发送失败后不要无限重试否则电量会很快耗尽。我的做法是数据先存到ESP32的Flash或EEPROM最多保留最近100条记录下次唤醒时如果网络恢复就补传。重试逻辑控制在每次唤醒最多尝试1次避免反复重连消耗电量。时间戳方面ESP32自带RTC在深度睡眠期间能保持时间但断电重启后需要重新同步。我的做法是每次开机后从NTP服务器同步一次时间如果同步失败就用本地维护的计数时间暂时顶上。5. 通信方案怎么选Wi-Fi、LoRa还是本地MQTT5.1 Wi-Fi成本最低但要做好断线处理家里架站首选Wi-Fi因为不需要额外买网关直接把数据POST到本地服务器或者云端即可。需要注意的点是Wi-Fi重连是个功耗黑洞。我见过不少人的固件逻辑是“连不上Wi-Fi就循环重试”结果电池可能几小时就耗尽。正确做法是设置一个超时上限比如10秒内连不上就放弃本次发送保存数据进入睡眠。这样即使断网一整天也不会因为重连把电量耗光。5.2 LoRa适合远距离部署如果站点放在没有Wi-Fi的农田或山坡LoRa是更好的选择。典型方案是ESP32配合433MHz的SX1276或SX1268模块使用RadioLib库开发非常方便。LoRa发射时峰值电流也不低但因为发送时间极短整体平均功耗通常只有Wi-Fi方案的十分之一。代价是接收端必须有一个LoRa网关。网关可以做成一个始终在线的树莓派加LoRa模块也可以直接买商用网关。数据先到网关再转发到MQTT或云端服务。5.3 本地MQTT加数据库数据才不会丢无论用Wi-Fi还是LoRa我都建议先把数据发到本地的MQTT代理比如Mosquitto或者用Home Assistant自带的MQTT Broker。再通过Telegraf或Node-RED把数据写入InfluxDB最后用Grafana做可视化。这套链路的好处是数据在本地就有一份完整备份公网服务偶尔抽风不影响数据积累。MQTT发布数据的代码用PubSubClient库核心逻辑#include PubSubClient.h WiFiClient espClient; PubSubClient mqtt(espClient); void sendData() { char payload[128]; snprintf(payload, sizeof(payload), {\temp\:%.1f,\hum\:%.1f,\press\:%.1f}, temp, hum, pressure); mqtt.publish(home/weather/outdoor, payload); }我在本地跑了一套InfluxDB加Grafana已经连续记录了大半年的气象数据回头看历史曲线特别有成就感这些数据可以帮你在当地判断什么时候适合播种、要不要提前给露台植物遮阴。6. 外壳和机械设计防潮比防水更关键6.1 温度传感器的防辐射罩不能省温度传感器如果直接暴露在阳光下日间读数会明显偏高因为传感器外壳吸收了太阳辐射热。这就是为什么专业气象站要把温度传感器放在百叶箱或者防辐射罩里。DIY防辐射罩的做法是用白色塑料片做成多层环状结构上下开口让空气自然流通同时阻挡阳光直射传感器。网上有成品防辐射罩也有3D打印模型。关键参数是外层必须用白色反光材料至少双层结构层与层之间留一定间隙保证内部通风。我实测过没有防辐射罩的传感器在晴天午后读数能比真气温高3到5°C加了防辐射罩后误差缩小到0.5°C以内。6.2 电子舱的防潮和“呼吸”这个是所有室外项目里最容易被低估的环节。完全密封的电子舱在早晚温差大的时候内部会结露水珠一旦凝结在主板上轻则测量漂移重则直接短路烧板。我的处理方式是用IP65或IP67的防水接线盒进口孔用防水电缆接头盒子内部放一小包硅胶干燥剂每季度换一次在盒子底部开一个小泄压孔然后用Gore-Tex防水透气膜贴住让盒子能“呼吸”有水汽也能排出去而不是凝在电路上主板的裸露焊点可以用三防漆刷一层防潮防腐这些步骤看着不起眼但我见过太多DIY项目因为没做防潮用了两个月就开始出现随机重启、数据错乱。6.3 太阳能板、电池和传感器的相对位置太阳能板工作时的表面温度可能超过50°C如果直接贴在气象站外壳上会加热整个机箱影响温度湿度传感器读数。我专门做过对比实验太阳能板紧贴外壳时白叶箱内部温度最高能高出正常值2°C以上。所以太阳能板一定要独立支架安装离站体至少30厘米而且朝向要根据你所在的纬度调整北半球一般朝正南倾角约等于当地纬度。电池也尽量避免暴晒尤其是锂电池长期处在60°C以上的环境中会加速老化容量衰减得很快。我建议把电池放在电子舱的底部或者是站体的北侧阴影区不要让阳光直射到电池表面。安装高度方面家用气象站的风杯至少离地2米温度湿度传感器离地1.5到2米雨量计离地0.5米以上。还要注意远离空调外机、墙壁排风口和任何会产生局部热源或乱流的地方。7. 现场部署与校准把数据做到能信而不是能亮7.1 湿度校准用饱和盐法BME280这类传感器出厂时虽然做了标定但湿度传感器在长期使用后可能漂移。想让湿度数据更可靠可以用饱和盐法在校准。原理是在密封罐里放入某种盐的饱和溶液在一定温度下容器内的空气相对湿度会稳定在一个已知值。比如氯化钠饱和溶液在20到25°C下大约维持75.5%RH氯化镁饱和溶液的湿度大约是33%RH硫酸钾饱和溶液大约是97.6%RH。操作方法是把传感器悬在饱和盐水的上方密封容器等待30分钟以上记录传感器读数然后对比已知湿度值做偏移修正。我实测这样做之后湿度数据能稳定在±3%RH以内。7.2 雨量计标定注射器法是基本功雨量计出厂时标定了每斗对应的降雨量但安装后最好自己复核一次。以集雨口直径160mm、每斗0.2mm为例集雨口面积约201cm²每斗对应的水量是0.02cm × 201cm² 4.02ml。用注射器慢慢滴入4ml水翻斗应该正好翻转一次。如果翻斗提前或延后说明内部配置有偏差需要调整翻斗上的调节螺丝。速度不能太快倒水太猛会导致翻斗还没完全复位就被强行拨动测出来的值会偏高。7.3 现场数据对比和长期巡检设备上线后不要只是看着它“出数”就完事。第一个月最好每天把站点的数据跟附近的气象站或机场天气报告对比一轮。重点看几个指标日最高气温、日最低气温、雨后累计雨量、夜间的风速曲线。如果日最高温和周边站点差得太多问题大概率在防辐射罩如果夜间风速经常异常地偏向某一个固定方向检查风杯是不是