用ESP32给电热水器加装物联网远程控制:从硬件选型到固件设计全攻略

📅 2026/8/27 6:37:44
用ESP32给电热水器加装物联网远程控制:从硬件选型到固件设计全攻略
今年冬天我家的储水式电热水器把我整不会了。每天早上出门前想着“开一会儿就关”结果到晚上回家一摸水是温的人是冷的等它重新加热到能洗澡的温度差不多要一个小时。更让我难受的是电费单热水器一天到晚插着电保温功率看着不高一个月累积下来多出好几十块。后来我做了个决定给它加一套物联网控制模块让它连上家里的WiFi用手机和电脑远程控制加热。这个项目做完我手里多了一台名副其实的Net-Connected Wireless Water Heater——热水器本体没换但“无线”和“联网”两个词都落实了。这个项目适合谁如果你家里有储水式电热水器又不想花大几千换所谓“智能热水器”同时你愿意动动手、接接线那么这篇文章基本就是给你写的。即使你之前只玩过Arduino、没碰过220V强电也完全可以从方案层面先看懂整个架构再决定做到哪一步。下面我把从需求拆解、硬件选型、电路接线、固件逻辑到远程控制链路和实测数据的完整过程都整理出来照着做不敢保证零翻车但至少能让你少走一半弯路。1. 一个被“保温电费”逼出来的联网改造项目1.1 需求拆解我到底需要热水的什么“权限”先别急着买模块把需求列清楚比什么都重要。我给自己理了四条最核心的需求。第一远程开关。下班前用手机打开加热到家就能洗澡白天家里没人确保热水器处于断电状态不白白保温耗电。第二定时策略。工作日早晨固定加热20分钟晚上回家前再加热一次周末不启用早晨时段。第三温度可视。我不想只看到“开”和“关”我还想知道当前水温否则远程开了跟没开一样纯粹碰运气。第四意外保护。任何时候水温超过安全上限设备必须能自动断电不能依赖我一个人盯着手机。这四条需求决定了项目的技术方向需要一个能联网的控制器、一个能切换220V回路的开关元件以及一个能放入水中或贴附在管道上测温的传感器。至于“智能”到什么程度语音控制、App推送、用电统计属于锦上添花后头再说。1.2 为什么没有直接买成品智能热水器我也认真看过市面上所谓的“智能热水器”。带WiFi的型号普遍比同容量普通款贵800到1500元而且它们的智能功能大多数还是靠一个App控制开关和定时有的还要连厂商自己的云平台一旦厂商服务器出问题或者你换了网络环境设备就变成“聋子耳朵”。更别说家里的旧热水器还能用只是为了一个远程开关把它整个换掉既不环保也不划算。再算一笔账我自己攒一个控制方案核心硬件成本加在一起一百块出头外壳和线材算上也不到两百。如果你家里已经有ESP32或者ESP8266开发板成本能压到七八十块。这个差价足够说明问题了。所以我的结论很明确热水器本身不需要换缺的只是一套让它“上网”的控制装置。改造成本低、可玩性高、坏了还能随时拆掉还原这才是DIY的意义。2. 硬件组合ESP32、继电器与防水温度探头2.1 主控ESP32在处理功率开关时的角色主控我选了ESP32开发板也就是带WiFi和蓝牙双模的MCU。为什么不用更便宜的ESP8266因为ESP8266只有2.4GHz WiFi没有蓝牙而且ADC只有一个GPIO也少。这个项目里我需要读取温度、控制继电器、上报状态GPIO数量和ADC需求倒是不多但ESP32的稳定性更好WiFi连上之后不容易掉线还支持将来做OTA升级。一句话多花十块钱省掉后面一堆麻烦。ESP32在整套系统里的角色很清晰它不直接接220V所有强电都由继电器或接触器承担。它只负责两件小事——用GPIO输出高低电平来触发继电器通断以及通过单总线读取温度传感器的数据。你千万别指望MCU引脚去驱动大功率负载那是纯粹的火灾隐患。2.2 开关负载继电器、接触器与固态继电器怎么选热水器的加热功率一般在1500W到3000W之间220V交流电下对应电流大约7到14A。这个电流级别普通小继电器根本扛不住。市面上几块钱一个的5V迷你继电器标称10A那指的是纯阻性负载短时间通断热水器这种长时间连续工作的场景我建议至少选额定电流20A以上的继电器最好是30A留足余量。我最终用的是5V线圈的30A继电器模块但这个模块有个坑它的线圈驱动电流大约70mA左右ESP32的GPIO输出能力虽然能到40mA但并不足以在一个引脚上直接驱动继电器模块。解决办法有两条一是买“3.3V-5V电平转换”的继电器模块模块自带三极管放大二是像我这样在中间加一级2N7000 MOSFET或者ULN2003达林顿管来驱动。我选择的是ULN2003一个芯片管四路后续还能扩展控制其他负载。如果你想减少触点火花和机械寿命问题可以考虑用固态继电器SSR尤其是带过零触发的型号。但固态继电器在大电流下发热严重必须配散热片而且存在一定的导通压降散热条件不好的环境不建议自己焊。我用机械继电器用了大半年开关次数累计不过几百次完全在寿命范围内所以普通家庭用高质量机械继电器足够。2.3 温度测量DS18B20防水探头的安装方式水温测量我选了DS18B20防水探头这是DIY圈子里非常成熟的方案。它测温范围-55℃到125℃精度正负0.5℃采用1-Wire协议只需要一根数据线而且多个传感器还能挂在同一根总线上。对热水器来说这个量程和精度都够用。探头有两种装法。第一种是把探头直接伸进热水器进出水管的内部比如从泄压阀管道插进去测量实际水温。这种最准但安装需要拆管而且要处理好密封漏水就麻烦了。第二种是把探头贴在热水器出水管的管壁上外面用导热硅胶和保温棉包住测量管壁温度。这种安装简单安全不破坏水路但温度滞后比较明显后面我会讲到怎么用温度偏移来补偿。我两种都试过最终选择了第二种贴在出水口管道的上端。理由很简单不用关总水阀、不用拆卸任何管路操作风险低。就算测量温度比真实水温低个两三度我只要把目标温度往上调三度实际洗澡体验完全一致。2.4 外壳、电源与线材准备控制器不能裸露着直接塞墙角必须装进绝缘外壳。我买了一个标准明装塑料防水盒尺寸大概15cm乘10cm乘6cm里面放ESP32、电源模块和继电器模块盒侧面的孔位用来出220V进线、220V出线和低压信号线。外壳不要选金属的否则WiFi信号会被屏蔽成一个“铁皮罐头”除非你愿意在外面再拖一根天线。电源方面ESP32需要稳定的5V供电。我试过从热水器内部取电但那意味着控制盒也得跟着拆机走线危险系数高也失去了“独立控制盒随时可拆”的优势。更推荐的方案是控制盒单独用一个5V/1A的USB电源适配器供电跟220V主回路完全隔离。虽然这样等于多占用一个插座但安全性和易维护性都高很多。线材上面220V主回路用至少1.5平方毫米的铜芯线最好2.5平方别图省事用细线。低压信号线用普通的杜邦线就能跑但要注意跟强电线保持距离至少分开5厘米别捆在一起否则继电器通断瞬间的电磁干扰会影响温度传感器的读数。3. 接线与安全先学会拒绝“开热”再谈智能控制3.1 强电与弱电分离的接线思路这个项目最核心的一条红线就是强电和弱电必须分开走。我的控制盒内部是这样组织的220V进线先经过一个保险管再进入继电器模块的公共触点从常开触点引出去接插座插座上插热水器的插头。继电器线圈的5V低压侧由USB电源适配器供电和220V侧没有电气连接只通过继电器内部的机械触点去控制通断。接线顺序也有讲究。先把弱电部分全部调通ESP32刷好固件、继电器模块的测试代码跑通、温度探头读数正常再动220V强电。接线时务必先断开总闸用验电笔确认没有电了再操作。接线完成后别急着通电先用万用表通断档检查一遍线路确认火线零线没有接反公共端和常开常闭端没有搞混然后再上电。这里要特别提醒如果你对220V强电操作没有信心完全可以做“半成品”——只做ESP32控制板、继电器模块和温度探头然后让有经验的电工师傅帮忙完成强电接线部分。自己动手的精神值得鼓励但命只有一条。3.2 温度探头装在哪个位置最准温度探头的位置直接决定远程控制好不好用。我一开始图省事把DS18B20贴在热水器外壳外面结果读数始终稳定在25摄氏度左右——那测的是环境温度跟水箱内部的水温毫无关系。后来又改成贴在进出水管的保温层外头读数依旧慢半拍温差大概能差到五六度。最后确定的方案是把探头贴在热水器冷水进水管的弯头表面用导热硅胶均匀涂抹贴合面再用隔热棉把探头和管道一起包裹住减少环境温度对管壁温度的影响。为什么选进水管而不是出水管因为进水管直接连着水箱底部的冷水区水温上升时会慢一点但变化趋势更线性用来判断“加热到没到目标”更稳定。贴出水管响应快但会受到自来水管道温度干扰冬天尤其明显读数忽高忽低。温度采样频率设置为5秒一次不要在每次采样后立刻决定继电器通断。我写了一个简单的滤波逻辑连续读取5次去掉最大值和最小值取中间三个值的平均数作为当前温度。这个处理能滤掉继电器吸合瞬间产生的干扰毛刺实测下来读数平滑很多。3.3 物理备份与漏电保护智能设备再智能也总会有断电、死机、固件崩溃的时候。热水器这种每天都要用的设备绝不能做成“控制器坏了就不能洗澡”。所以我在控制盒旁边保留了一个机械开关这个开关直接串在热水器主回路线路上不经过任何电子元器件。使用规则很简单日常使用远程控制时机械开关保持闭合由继电器模块控制加热通断如果控制器出问题了直接把机械开关断开再把热水器插头插回墙上的备用插座热水器就恢复成原始的机械加热状态。这个备份设计听起来平平无奇但在我实际使用中救过我一次——有一回ESP32突然死机WiFi怎么都不连我就是靠这个机械开关撑过了三天没有被迫洗冷水澡。还有两个安全件不能省一是漏电保护热水器本身如果带漏保是最好不带的话控制盒前端最好接一个带漏电保护的插头或者直接在控制盒内串一个漏保断路器。二是地线热水器三脚插头的接地脚必须可靠接地。这个项目所有智能控制都建立在“漏电还能保命”的前提下别把DIY的想象力用在这些底线问题上。4. 固件逻辑温控、命令与掉线自恢复的三层设计4.1 上电状态与继电器误触发问题固件里第一个要处理的坑就是上电瞬间的误动作。很多继电器模块上电时如果控制引脚默认是高电平会瞬间吸合一下导致热水器在没人操作的情况下突然开始加热。这个问题在ESP32上非常容易踩因为某些GPIO在芯片复位阶段会短暂输出不确定电平。我做了三层防护。第一层硬件上选择“低电平触发”的继电器模块这意味着GPIO输出低电平时继电器吸合上电时GPIO默认状态由外部下拉电阻强制拉到低电平。第二层固件启动时先把继电器控制引脚设置为OUTPUT并输出高电平即断开状态初始化完成后再开始网络连接。第三层代码里用一个全局布尔变量记录加热开关状态任何逻辑执行前都要先检查这个状态不允许出现“状态没有更新但继电器却动作”的情况。三层防护下来我反复断电重启了几十次继电器再也没有出现上电误开的情况。这个测试非常重要别觉得麻烦至少做十次断电重启再接入真实热水器。4.2 温控逻辑的代码骨架温控逻辑并不复杂核心就是一个带滞回区间的比较器避免设置温度的临界点上继电器反复高低切换。比如我想让水温维持在50摄氏度就设置一个2摄氏度的回差温度低于48摄氏度时接通加热温度达到52摄氏度时断开加热。这段区间既保证了洗澡水温足够热又不会让继电器每分钟都在通断寿命影响小得多。代码骨架大概长这样基于Arduino框架加PubSubClient#include WiFi.h #include PubSubClient.h #include OneWire.h #include DallasTemperature.h #define RELAY_PIN 26 #define ONEWIRE_PIN 4 OneWire oneWire(ONEWIRE_PIN); DallasTemperature sensors(oneWire); WiFiClient espClient; PubSubClient mqtt(espClient); const float TARGET_TEMP 50.0; const float HYSTERESIS 2.0; float currentTemp 25.0; bool heaterState false; bool remoteOverride false; float readAverageTemp() { float temps[5]; sensors.requestTemperatures(); for (int i 0; i 5; i) { temps[i] sensors.getTempCByIndex(0); delay(250); } // 简单排序后去极值取中间三值平均 for (int i 0; i 4; i) { for (int j i 1; j 5; j) { if (temps[j] temps[i]) { float t temps[i]; temps[i] temps[j]; temps[j] t; } } } return (temps[1] temps[2] temps[3]) / 3.0; } void controlHeater() { if (remoteOverride) { return; // 远程手动控制时跳过自动温控 } if (currentTemp (TARGET_TEMP - HYSTERESIS) !heaterState) { heaterState true; digitalWrite(RELAY_PIN, LOW); // 继电器吸合接通加热 } else if (currentTemp (TARGET_TEMP HYSTERESIS) heaterState) { heaterState false; digitalWrite(RELAY_PIN, HIGH); // 断开加热 } }实际项目中还要把远程命令解析、MQTT主题订阅和看门狗喂狗都加进去但核心骨架就是这样一个简单的逻辑。注意一点加热过程中温度采样不要卡在readTemp函数里太久否则会影响MQTT消息的及时处理我一般把温度读取和网络发送都放在主循环里每次循环控制在200毫秒以内。4.3 掉线之后怎么办本地策略这是整个固件里最容易被忽略、但实际最影响体验的部分WiFi断了、MQTT服务器连不上热水器该怎么办最简单粗暴的做法是断线就停止加热但这意味着你在外面访问不了家里热水器也一直处于“罢工”状态。更糟糕的做法是断线后继续保持当前状态不管了万一当时正在加热断线期间温度到极限了还在加热怎么办我的策略是分三层。第一层WiFi断开后ESP32每5秒尝试重连重连成功之前不处理任何远程命令第二层MQTT连接断开后自动温控逻辑降级为本地运行也就是继续按照预设在固件里的目标和回差控制加热这确保没有网络也能维持热水器的基础功能第三层断线时间超过30分钟且当前水温超过85摄氏度无条件强制断开继电器这是纯粹的安全兜底只在极异常情况下触发。这个“断线降级”的设计非常关键。它意味着这台热水器虽然联网但联网只是锦上添花最基础的温控能力永远保留在本地不至于因为路由器重启或者运营商网络抖动就让全家洗不上热水澡。5. 控制端与联网链路局域网服务搭配手机App5.1 MQTT主题约定与消息格式控制端和固件的通信我选了MQTT而不是简单的HTTP接口。原因是MQTT保持长连接继电器状态和温度变化可以主动推送不用手机端频繁轮询实时性也更好。主题设计我单独说一下因为后面扩展功能都靠它。我用三层主题结构water_heater/status设备上线、掉线、温度、加热状态等状态信息采用JSON格式上报water_heater/cmd手机端发送控制命令比如{cmd:set_power,value:1}water_heater/telemetry定时上报温度数据和设备运行时间用于后续数据统计为啥不把所有数据都混在一个主题里因为不同消费者关注不同数据。比如Home Assistant只需要订阅status主题就能展示开关状态和温度而如果你后续想接入数据可视化平台telemetry主题里塞的连续流式数据会更合适。我在固件里用ArduinoJson库拼接和解析JSON注意串口输出调试信息时不要和MQTT消息混在一行否则解析容易出问题。5.2 局域网状态面板局域网内控制最简单的方案就是手机装一个MQTT客户端App订阅status主题往cmd主题发命令。我用过好几个App比如MQTT Dash配置简单但界面要自己拼适合喜欢折腾的人。如果你更习惯图形化界面可以搭建Home Assistant并通过MQTT集成把它和热水器关联起来Home Assistant会自动生成一个“entity”显示温度并且可以直接用开关卡片控制。我自己的使用习惯是局域网内用Home Assistant面板出门在外用手机上的MQTT Dash快速查看。为什么不把Home Assistant面板直接暴露到外网因为任何暴露到公网的服务都需要HTTPS和访问控制配置不当就是给黑客送后门处理起来不比DIY热水器省心。5.3 外网访问与云端IoT平台外网访问的安全做法我踩过坑之后总结出两个相对靠谱的方向。第一如果你自己有一台云服务器或者NAS可以在那上面跑一个加密的MQTT Broker比如EMQX开TLSESP32连接时启用TLS证书校验。这样做的好处是密钥在自己手里数据链路全程加密但证书管理和设备端内存占用都要考虑ESP32跑TLS需要一定Flash资源好在4MB版本足够。第二使用商业IoT云平台比如在固件SDK里封装好的物联网平台。很多平台自带设备认证、数据上行下发、OTA固件升级等功能虽然在国内使用需要实名和合规配置但稳定性和安全性比自己搭建公网监听端口高得多。这个方案尤其适合你希望在外面随时控制、又不想折腾公网IP和TLS证书的场景。我的选择是折中平时用局域网Home Assistant出差前临时用云服务器上的加密MQTT Broker控制。热水器毕竟不像智能门锁那样高频率使用不需要24小时把所有控制通道都暴露在外网按需开放反而更安全。6. 实测数据、翻车记录和可以继续折腾的方向6.1 一个月的温度曲线与耗电记录把整套系统稳定运行了一个月之后我从MQTT telemetry里导出数据整理了几条有意思的结论。我家的热水器是60L容量、2000W加热功率。在环境温度15摄氏度左右时从28摄氏度加热到50摄氏度大约需要38分钟耗电约1.26千瓦时。保温情况下水温从50摄氏度自然回落到40摄氏度大约需要5到6个小时平均每小时温降两摄氏度。改用远程控制策略之前热水器常年保持50摄氏度保温状态一天保温和保温补偿耗电加起来大概2.2千瓦时改用“提前一小时定时加热 平时断电”的策略后每天实际耗电降到1.3千瓦时左右省了差不多四成。这个数字仅供参考因为各家热水器保温性能、环境温度差异非常大。但如果你想复现类似的能耗统计建议在固件里记录继电器吸合时长然后结合额定功率估算耗电量。误差虽然比不上工业级电表但用来判断省电趋势已经够了。6.2 踩坑记录测温滞后、继电器粘连、WiFi屏蔽这个项目看起来简单实际翻车的地方不少。第一个坑是测温滞后。贴在管壁上的DS18B20读数比水箱内部真实水温慢大约5到10分钟导致加热过程中继电器提前断开水温始终差那么一点。解决方法是把目标温度从47摄氏度调到50摄氏度相当于补偿3摄氏度左右的滞后差实测洗澡体感温度正好。第二个坑是继电器触点问题。便宜的30A继电器模块在热水中频繁通断时触点表面会逐渐积碳严重时有粘连风险。我用了一个多月后发现继电器关闭后热水器偶尔还在通电万用表一量才知道触点在断开位置依然导通。虽然频率很低但这件事足够吓人。后来我换成了品牌继电器同时把温控回差从1摄氏度改成2摄氏度明显降低了通断频率。如果你的热水器功率超过3000W直接考虑加交流接触器别再为难小继电器。第三个坑是WiFi信号被遮蔽。控制盒放在热水器旁边的角落热水器本身就是一大块金属加上墙壁和管道的遮挡ESP32的WiFi信号经常只有两格偶尔还会断线。我把天线位置从控制盒内部引到外壳外头方向朝向客厅信号从两格变成满格。如果你用的是没有外置天线接口的ESP32开发板可以考虑换一个带IPEX天线座子的开发板效果立竿见影。还有一个小坑是DS18B20探头线材的抗弯折能力。探头线比较细长期贴着热水器管路弯来弯去很容易断芯断芯之后温度读数会变成-127摄氏度或者85摄氏度之类的异常值。好在这种故障非常明显固件里加一个读数合理性判断比如温度在0到100之间才有效否则按上次有效值处理就能避免把异常温度当成真实温度触发保护。6.3 后续可以继续折腾的方向这个项目的可扩展性很好我这半年已经在规划下一步了。首先是OTA固件升级利用云IoT平台的远程升级通道修复固件里的温控算法不用每次拔ESP32下来插电脑线刷。其次是水位检测在热水器进水管或出水管上增加一个压力传感器粗略估算剩余热水量做到“洗澡洗一半发现水凉了”的预警。还可以接入电价策略把定时加热时段跟峰谷电价联动比如半夜低谷电价时提前加热到目标温度白天断电保温。如果你懒得自己从零写固件也可以考虑直接用ESPHome方案把上面的继电器和DS18B20配置写进YAMLHome Assistant会自动识别为恒温器控制器逻辑一样开发量会小很多。这个项目的乐趣并不在于“我写完了一段代码”而在于看着热水器在手机屏幕上跳动的温度曲线你心里清楚这台平平无奇的老旧电器正在用一种更聪明的节奏运作。最后再啰嗦一句我建议所有做这个项目的人在正式接入220V之前花一晚上把强电接线反复检查三遍并让家里懂电的长辈或专业电工看一眼。我见过太多DIY翻车的案例原因往往不是电子部分而是强电接线的粗心。这项目能给你省电费、带来动手的成就感但它首先是台热水器安全永远排在智能前面。