
简介这是一份基于ESP8266的智能热泵控制系统完整源码包面向嵌入式开发者、物联网爱好者和智能家居项目实践者。系统集成了WiFi通信、MQTT消息收发、Web交互界面、WiFi配置管理以及OTA远程固件升级适合作为接入Home Assistant等平台的参考实现也可用于学习ESP8266网络编程与设备远程维护兼顾功能完整性与代码可读性。资源共15个文件包含6个C源文件、3个头文件以及README、PlatformIO配置、原理图等辅助材料结构清晰覆盖核心逻辑、Web服务、MQTT和WiFi配置模块压缩包约579KB轻量易部署。已有53人学习浏览源码可在PlatformIO环境直接编译烧录并结合项目说明快速理解从设备注册、状态上报到远程控制命令处理的完整链路。对希望掌握ESP8266MQTTWebServer综合开发或需要一套可扩展热泵控制框架的读者具备不错的参考与复用价值。 直接做这套基于ESP8266的智能热泵控制系统其实是我个人捣鼓很久的一个项目。当时家里装了一台空气能热泵热水器原厂控制面板功能太死板只能设定固定温度和定时想远程看水温、回家前提前启动加热基本没戏。后来一查热泵主机控制逻辑也不算复杂核心就是根据水温控制压缩机启停于是决定用ESP8266自己做一套控制系统顺便把源码整理出来分享。这个项目适合谁如果你是搞嵌入式的小伙伴想练手WiFi控制、传感器采集、继电器驱动这一整套物联网闭环或者家里正好有热泵、电热水器想改成智能控制这套代码可以直接拿过去抄作业。整个系统成本也就三四十块钱比买成品智能插座加温度计组合靠谱得多。1. 项目整体思路与系统架构1.1 为什么是ESP8266而不是其它方案选型的时候我其实纠结过几套方案STM32加蓝牙模块、树莓派加继电器、ESP32、ESP8266。后来综合比较ESP8266是最适合的。首先是价格一块ESP8266开发板裸板几块钱带USB转串口的NodeMCU板子也就十几块相比STM32需要额外买WiFi芯片比如ESP8285或AT指令模块成本低得多。其次是生态Arduino框架下ESP8266的开发资料非常多库函数齐全网上能搜到的项目案例数以万计。还有个关键原因热泵控制对实时性要求没那么苛刻。压缩机启动是个秒级动作水温变化以分钟甚至小时计ESP8266的主频80MHz虽然不算高但处理这种低频控制场景绰绰有余。相比之下ESP32在这个项目里有点性能过剩而且功耗也高一些。1.2 系统功能拆解与整体流程这套系统实现的功能对照着热泵主机的实际工作逻辑来拆水温实时采集热泵系统里最关键的是水箱温度用DS18B20防水探头插在水箱测温管里精度正负0.5摄氏度完全够用。温度显示与设定用0.96寸OLED显示屏实时显示当前水温、设定温度、工作状态。继电器控制压缩机通过一个5V继电器模块控制热泵主机的电源通断达到设定温度就断电停压缩机低于回差温度重新上电启动。远程监控与控制手机连上局域网或者通过公网MQTT服务器随时查看水温状态远程调整目标温度。本地按键交互两个物理按键一个调高温度一个调低温度方便家里老人不依赖手机也能操作。整体数据流是这样的DS18B20采集水温ESP8266读取数据后做滤波和格式化一方面送OLED显示另一方面与设定温度比较通过PID或回差逻辑决定继电器开关状态同时通过WiFi建立到MQTT服务器的长连接周期上报状态数据接收手机端下发的控制指令。1.3 源码目录结构与核心模块压缩包里我做了比较清晰的目录划分方便你直接找到需要的部分smart_heatpump/ ├── smart_heatpump.ino # 主程序入口 ├── config.h # 全局配置WiFi、MQTT、引脚定义 ├── temperature.h/.cpp # DS18B20采集模块 ├── relay_control.h/.cpp # 继电器控制模块 ├── display.h/.cpp # OLED显示模块 ├── button.h/.cpp # 按键处理模块 ├── mqtt_handler.h/.cpp # MQTT通信模块 └── README.md # 接线说明和配置指南这里要说明的是很多人拿到源码喜欢直接往Arduino IDE里灌结果一堆头文件找不到。分包编译是必须的.ino文件所在的文件夹名字必须和.ino文件名保持一致而且所有.h和.cpp文件放在同一个文件夹里编译时Arduino IDE才会自动识别。2. 核心源码解析与关键实现2.1 WiFi连接与断线重连机制WiFi连接这块我踩过的坑比想象中多。ESP8266的WiFi库看着简单但实际使用中你会发现如果路由器信号不稳定或者密码错误它会一直卡在连接状态WiFi.status()迟迟不返回WL_CONNECTED。我的处理方式是加了一个重连计数器和状态机#include ESP8266WiFi.h bool connectWiFi() { int retryCount 0; WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() ! WL_CONNECTED retryCount 30) { delay(500); retryCount; } if (WiFi.status() WL_CONNECTED) { Serial.println([WiFi] Connected, IP: WiFi.localIP().toString()); return true; } else { Serial.println([WiFi] Connection failed, retry later.); return false; } }注意一个细节ESP8266的WiFi.begin()是非阻塞的它启动连接过程后立即返回状态变化是异步的。所以必须用轮询方式等待。30次重试每次500毫秒总共15秒超时这个时间窗口基本覆盖了路由器DHCP分配IP所需的时间。还有一个重要操作是设置WiFi.setSleepMode(WIFI_NONE)关掉ESP8266的省电模式。ESP8266默认的modem sleep会导致WiFi传输延迟骤增甚至MQTT心跳包超时断开对实时控制场景来说非常致命。代价是功耗从几毫安涨到70毫安左右但控温系统是长期接电源的这点功耗无所谓。2.2 温度采集与多点滤波算法DS18B20是单总线协议数据线同时传输时钟和数据时序要求比较严格。用OneWire库和DallasTemperature库可以省去底层时序的麻烦但读取速度有个问题每次转换温度需要750毫秒12位精度如果你有多路传感器串行读取会非常耗时。我的方案是在主循环里用非阻塞方式轮询#include OneWire.h #include DallasTemperature.h #define ONE_WIRE_BUS D4 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(oneWire); float readCurrentTemp() { sensors.requestTemperatures(); float tempC sensors.getTempCByIndex(0); if (tempC DEVICE_DISCONNECTED_C) { Serial.println([Sensor] DS18B20 disconnected!); return lastValidTemp; } // 简单滑动滤波去除抖动 filteredTemp filteredTemp * 0.8 tempC * 0.2; lastValidTemp filteredTemp; return filteredTemp; }需要注意的点是DS18B20在长线传输时容易受到干扰尤其是和继电器控制线绑在一起走线时继电器吸合瞬间的电磁脉冲会导致温度读数跳变到85℃或者-127℃。我实测定下来传感器线最好用屏蔽双绞线屏蔽层单端接地而且尽量远离220V交流线。滑动滤波系数0.8和0.2是我实际调出来的兼顾了响应速度和稳定性。滤波系数如果太小比如0.95对0.05温度变化响应会非常滞后热泵压缩机启停判断就会迟钝可能导致水温过冲。这个系数在传感器数据变化频繁的场景需要根据实际情况重新整定。2.3 温度控制逻辑回差控制与防频繁启停热泵压缩机最怕频繁启停。压缩机启动电流大频繁启停会导致电机过热、寿命缩短甚至烧毁启动电容。所以控制逻辑里绝对不能简单地“低于设定温度就启动到了就停止”必须加入回差控制。回差控制的原理很简单设定目标温度28℃回差温度3℃那么水温降到25℃时才启动压缩机升到28℃时停止。这样压缩机每次运行至少能把水温提升3℃避免临界温度附近的反复震荡。void updateRelay(boolean relayStatus, float currentTemp, float targetTemp) { const float hysteresis 3.0; if (!relayStatus currentTemp (targetTemp - hysteresis)) { relayStatus true; digitalWrite(RELAY_PIN, HIGH); Serial.println([Control] Relay ON - Compressor start.); } if (relayStatus currentTemp targetTemp) { relayStatus false; digitalWrite(RELAY_PIN, LOW); Serial.println([Control] Relay OFF - Compressor stop.); } }这里有个细节继电器模块的触发逻辑分高电平触发和低电平触发代码里必须和实际硬件一致。我用的模块是低电平触发所以代码里relayStatus为true时digitalWrite(RELAY_PIN, LOW)。如果你买的是高电平触发的模块一定要把HIGH和LOW反过来这个粗心导致我debug了一个小时才找到原因。2.4 MQTT通信协议封装与JSON解析远程控制是本项目的亮点。考虑到局域网内HTTP请求轮询太浪费资源我选择了MQTT协议基于发布/订阅模式非常契合设备状态上报和指令下发场景。MQTT的核心概念是主题Topic。我定义了两类主题smart_heatpump/status设备向服务器发布状态信息载荷是JSON格式字符串频率为每30秒一次。smart_heatpump/set设备订阅服务器的指令主题手机端控制温度就向这个主题发布JSON数据。MQTT客户端用PubSubClient库这个库在ESP8266上跑得很稳。关键配置是设置keepalive心跳间隔为30秒这样理论上断线检测最长需要约45秒2倍心跳间隔配合重连机制可以实现自动恢复。#include PubSubClient.h void mqttCallback(char* topic, byte* payload, unsigned int length) { String message ; for (int i 0; i length; i) { message (char)payload[i]; } if (String(topic) smart_heatpump/set) { // 解析JSON指令 DynamicJsonDocument doc(256); DeserializationError error deserializeJson(doc, message); if (!error doc.containsKey(target_temp)) { targetTemp doc[target_temp].asfloat(); EEPROM.write(0, targetTemp); EEPROM.commit(); } } }JSON解析我用的是ArduinoJson库版本6.x。注意几个坑一是DynamicJsonDocument要分配足够的内存但也不能太大ESP8266的堆内存总共也就80KB可用一个256字节的JSON文档就够了二是deserializeJson返回的DeserializationError必须检查否则你解析乱数据时会得到一堆垃圾值。3. 硬件选型与接线实操3.1 关键元器件清单这套系统用到的元器件不多但每个都有讲究元件型号/规格数量选型理由主控板NodeMCU V3 (ESP8266)1内置USB转串口直接烧录方便温度传感器DS18B20防水探头1测温范围宽防水封装适合水箱继电器模块5V 1路低电平触发1控制热泵电源通断隔离控制信号显示屏0.96寸 I2C OLED1功耗低显示清晰I2C省引脚降压模块AC-DC 220V转5V 2A1长期稳定供电带过载保护按键轻触开关2本地温度调节电阻10k欧姆1DS18B20上拉电阻信号稳定接线端子5.08mm间距若干强电连接可靠方便维护这里重点说下电源。很多新手做ESP8266项目直接用USB供电但继电器模块拉合瞬间电流尖峰很大通过USB口供电容易导致ESP8266复位重启表现为控制过程中系统突然重启保护机制完全没有作用。我的做法是用一个220V转5V 2AAC-DC降压模块单独供电。5V输出分两路一路直接给继电器模块供电另一路经过AMS1117-3.3降成3.3V给NodeMCU的VIN引脚供电。这种方案下继电器大电流波动不会直接干扰到ESP8266的3.3V电源轨系统稳定性明显提升。3.2 接线方案与信号隔离接线其实不复杂但有几个位置必须细心处理。先看引脚分配NodeMCU引脚 连接设备 D1 (GPIO5) OLED SCL D2 (GPIO4) OLED SDA D3 (GPIO0) 按键1温度 D4 (GPIO2) 按键2温度- D5 (GPIO14) DS18B20 DATA D6 (GPIO12) 继电器模块IN VIN (5V) OLED VCC、继电器VCC 3V3 传感器VCC GND 所有设备GND继电器模块的控制信号GND必须和ESP8266的GND共地否则逻辑电平参考基准不一致继电器无法可靠触发。这个问题在独立供电方案中尤其容易出现接完线务必用万用表确认两路GND导通。强电部分继电器触点串联在热泵主机的火线上零线直连。这里必须注意继电器只是控制通断不具备漏电保护功能所以热泵的供电回路中一定要保留原有的空气开关或漏电保护器。安全是底线不能省。4. 固件编译与烧录全流程4.1 开发环境配置推荐用Arduino IDE加ESP8266开发板包操作门槛最低。打开IDE在“文件-首选项-附加开发板管理器网址”里填入http://arduino.esp8266.com/stable/package_esp8266com_index.json然后在“工具-开发板-开发板管理器”里搜索esp8266安装最新版本。这一步如果网络慢可以挂镜像源否则下载几十MB的包很容易超时失败。安装完成后在“工具-开发板”里选择NodeMCU 1.0 (ESP-12E Module)。烧录参数我建议CPU频率160MHz比默认80MHz快一倍JSON解析和MQTT收发更流畅。Flash大小4M (3M SPIFFS)默认即可。Upload speed115200不需要加快到921600提高烧录成功率。4.2 固件烧录与启动日志解读NodeMCU板子自带USB转串口驱动通常是CH340GWindows上自动识别。烧录前先拔掉D3和D4上连接的按键线因为GPIO0和GPIO2在烧录时是高电平还是低电平的状态会影响进入烧录模式。具体做法按住开发板上的FLASH按键不放插上USB线过两秒再松开FLASH按键然后点击Arduino IDE的“上传”按钮。如果时序错乱Serial Monitor会一直刷“warning: espcomm_sync failed”重复尝试就好。烧录完成后打开串口监视器波特率设9600正常情况下应该看到启动日志[WiFi] Connected, IP: 192.168.1.123 [Sensor] DS18B20 init success, address: 28FF6D4B2E17... [Control] Relay OFF - Compressor stop. [MQTT] Connected to broker, state: 0看到这四行日志基本说明系统核心链路已经通了。如果卡在WiFi连接这一步优先排查密码是否包含特殊字符导致转义问题ESP8266的WiFi.begin对包含引号或反斜杠的密码处理有坑建议用不含特殊字符的密码测试。4.3 参数调优与现场调试系统跑通后就是调参数。个人经验是水温回差设为3℃到5℃。回差太小压缩机会在设定点附近频繁启动电费飙升还伤设备回差太大水温波动明显洗澡体验差。还要注意MQTT的心跳保活机制。如果家用的WiFi路由器开启了AP隔离或客户端隔离功能设备之间无法互通手机App可能连不上MQTT服务器但设备本身能连外网。排查时先确认手机和设备是否在同一网段能否互相ping通。5. 常见问题与排查技巧实录5.1 典型故障速查表我梳理了几个高频问题每个都是实打实踩过的坑现象可能原因排查方法上电后OLED无显示I2C地址不对或接线错误用I2C扫描代码查地址常见是0x3C或0x3DDS18B20读数85℃传感器未接好或线序错误检查数据线上拉电阻确认VCC和GND没接反继电器乱跳控制逻辑滤波不够增强软件滤波确认回差设置合理手机远程没反应MQTT断开或IP变化串口看MQTT状态码检查路由器DHCP静态绑定WiFi频繁掉线电源纹波干扰或信号弱加1000uF电解电容到VIN调整天线方向水温显示不变传感器位置没泡到水里确认探头在水箱测温盲区外5.2 防灰防潮与长期稳定性热泵机组通常装在室外或者半开放空间环境湿度大。PCB板裸露使用几个月就容易出问题。建议买一个ABS防水接线盒把控制板、继电器模块和电源模块全部装进去进出线口用防水接头锁紧。内部走线也要注意强弱电分离220V线束和信号线保持3厘米以上的距离交叉处用扎带固定避免摩擦。我实测下来做好物理隔离后系统的故障率下降了一半以上。另一个容易忽略的点是看门狗。ESP8266在异常情况下会死机比如WiFi协议栈卡死或者堆内存耗尽。代码里我加了一段硬件看门狗喂狗逻辑ESP.wdtDisable(); ESP.wdtEnable(3000);主循环里每次循环至少执行一次ESP.wdtFeed()这样即使某段代码阻塞超过3秒系统也会自动重启恢复。这个机制在远程无人值守场景下是保命功能绝对要加上。5.3 离线状态下的控制策略优化如果家里WiFi断了或者MQTT服务器挂了系统就完全失控了吗不会。我的代码里设计了一个降级模式当WiFi重连超过15秒还没成功就切换到纯本地逻辑模式。在这个模式下按键调温度和回差控制依然完全独立运行只是不更新远程状态。这个设计思路很重要。智能硬件的本质是以前的嵌入式系统加上了网络能力但网络只是辅助手段核心控制逻辑绝不能依赖网络。网络恢复后系统会自动重连MQTT并补发一条最新的状态快照保证云端和本地状态最终一致。我自己在实际使用中有个体会这套系统最爽的不是远程开关而是回家前用手机把水温从40℃调高到55℃到家马上能洗个热水澡。当时做这个项目的初衷就是为了这个场景后期加的按键、屏幕等都是为了让家里的老人不必依赖手机也能操作。后来有一次我给朋友装了第二套发现在断电重启后原设定值会被固定值覆盖查了半天原来是EEPROM参数在初始化时被重新写入固件默认值。这个坑我写了很长的注释放在config.h里提醒看代码的兄弟注意。如果你也想复刻这个项目我建议第一步先把硬件按接线图搭好烧录一个最简单的Blink样例确认开发板硬件没问题再烧录完整代码。如果直接烧录全套代码出了问题排查范围会比较广反而容易劝退。整个过程大概需要一个下午做成功后你会发现智能家居其实没有想象中那么神秘核心不过就是传感器加控制逻辑加网络通信这三件套。本文还有配套的精品资源点击获取