Skip to content

2026-10-12 美的空调联网改造:从 ESP32 到 ESP-01(ESP8266) ​

  • 数据时间:2026-10-12,Asia/Shanghai
  • 研究对象:美的空调联网改造与自研控制固件
  • 当前硬件:ESP-01(ESP8266),按 1 MiB Flash 预算维护
  • 当前进展:ESP32 固件稳定运行两个月后切换硬件,已完成 0.2.3.8A 固件下载,正在测试
  • 资料来源:作者运行记录、既有项目文章、当前源码与固件更新文档

ESP32 固件稳定运行了两个月后,我把这套美的空调控制系统切换到了 ESP-01(ESP8266)硬件。目前已经完成 0.2.3.8A 固件下载,测试仍在进行。项目的重点随之转向紧凑硬件上的持续运行、控制体验和更新恢复。

这套系统此前以 ER Midea Bridge 为名,记录在八月的架构文章中。当时,ESP32 承担协议探测与云端验证,ESP-01 系列是长期部署目标。两个月后的这次切换,把原先的硬件路线推进到了实际使用阶段,也让 1 MiB Flash、有限内存和单个硬件串口成为日常迭代中必须面对的条件。

两个月运行之后,切换到紧凑硬件 ​

项目最初要解决的未知数很多:空调主板的 UART 是否可用,哪些协议字段能被可靠读取,一条控制命令怎样确认执行,断网后设备会怎样恢复。ESP32 开发板提供了充足的 GPIO、内存和调试空间,方便把这些问题逐个拆开,也让协议观察和云端控制能够在同一套业务逻辑上验证。

两个月的稳定运行给了我继续推进硬件切换的基础。这段时间的运行经验来自 ESP32;切换后,长期观察的对象变成了 ESP-01。共享的协议和控制逻辑可以延续,供电、启动串口、网络重连时的内存峰值和实际安装条件,则需要在新硬件上继续观察。

ESP-01 是模块形态,ESP8266 是它使用的芯片平台。选择这块模块,延续了项目原先的紧凑安装方向:空调节点需要 UART、Wi-Fi 和主动建立的云连接,开发板上的大部分扩展接口在正常运行时没有用途。硬件收小之后,调试便利性有所下降,资源和故障信息就更需要通过遥测保留下来。

这次改造针对的空调是美的 KFR-26GW/BP2DN8Y-DH400(3),不带 M。硬件方案把空调侧的 5V 分成供电与通信两条路径:独立稳压电路为 ESP 提供 3.3V,两路电平转换处理主板与 ESP 的 UART 电平,双方共地。Wi-Fi 发送和 TLS 握手期间的供电波形,是新硬件观察的一部分;稳压器的标称输出能力之外,还需要关注线缆、连接点和模块附近的瞬态电压。

串口安排也不同。ESP32 验证时可以用 UART2 连接主板,同时保留 USB 调试输出;ESP-01 使用 UART0 的 GPIO3 接收、GPIO1 发送,这个串口承担正式空调通信,普通日志退出这条路径。GPIO1 上电时的启动输出、GPIO0/GPIO2 的启动电平,以及 EN/RST 的稳定状态,都会影响启动和主板通信。模块缩小以后,这些板级细节直接进入可靠性问题的范围。项目的硬件基线保留了供电、接线和启动条件。

维护范围也已经收敛。自 2026-10-11 起,空调节点只维护 A 固件,即 ESP-01/ESP-01S 的 ESP8266、1 MiB Flash 路径;ESP32 的 B 固件和 ESP8266 devkit 的 C 固件退出维护,源码及历史资料仍保留。独立 HomeKit Bridge 是另一个产品,继续使用自己的版本和工程边界。固件更新记录记录了这次调整。

控制架构延续,设备端承担明确的工作 ​

硬件切换后,系统仍沿用原有路径:空调主板通过 UART 与设备通信,设备主动连接 EMQX Serverless,Cloudflare Worker 和每设备 Durable Object 处理状态、命令与定时,浏览器通过同源控制台访问。家庭中无需额外运行 Home Assistant、MQTT Broker 或数据库服务器。

ESP-01 上保留的工作很具体:服务空调串口、维持 Wi-Fi 与 MQTT/TLS、检查命令、上报状态和运行信息,以及处理固件更新。网页、历史记录和命令协调留在云端。这种分工让设备的组成保持可控,也方便在硬件变化时延续同一套控制语义。

固件内部采用 ESP8266 RTOS SDK v3.4。串口协议任务负责 UART、主板命令和响应,云任务负责 Wi-Fi、MQTT 与状态发布,独立恢复任务观察任务心跳和离线状态。任务之间用有界队列交换命令、状态和确认,网络任务不直接操作主板协议对象。

ESP8266 是单核芯片,任务拆分的价值在于所有权明确、调度可控。DNS、TLS 和网络等待留在串口任务之外;新的 MQTT/TLS 重连还要避开在途控制命令,并取得近期的 UART 安全窗口。共享的协议解析和命令策略继续保持平台无关,ESP32 与 ESP8266 分别提供硬件适配。这样能复用已经验证过的控制规则,同时为新平台单独处理资源与时序。

普通状态控制仍经过主板回读确认。页面提交设定后,系统先记录控制意图,设备接受命令,再等待空调主板报告与目标匹配,最终进入 applied。网络投递、设备接受和主板执行各有自己的阶段,页面反馈也围绕这些阶段组织。云连接异常期间,设备继续处理空调 UART,原装遥控器的操作仍由主板状态回读体现。

1 MiB Flash 怎样容纳双槽更新 ​

ESP-01 的 1 MiB Flash 要同时保存启动程序、分区表、设备配置、启动控制记录和两个应用槽。当前布局中,ota_0 位于 0x10000,ota_1 位于 0x80000,每槽容量为 0x70000,即 448 KiB。设备配置存放在 NVS,应用更新写入另一个槽,保留正在运行的旧镜像。

两个槽位使用分别链接的固件:业务代码和完整版本相同,执行地址不同。新镜像写入目标槽后直接从该槽运行,省去了复制回固定运行位置的过程。发布和下载都需要保留两个槽位的制品,设备根据当前运行槽选择对应镜像。

开发构建记录中的 0.2.3.8A 两槽镜像各为 422,032 字节,距每槽镜像硬上限各剩 36,719 字节。每槽预留 16 KiB 是项目的建议值,分区大小仍是严格限制。继续增加功能时,需要同时计算两个槽的预算,避免把首次串口安装时能容纳的大小误用为后续 OTA 的预算。双槽 OTA 设计记录了分区、镜像与启动规则。

Flash 容量之外,还有运行内存的约束。可用堆表示剩余内存总量,最大连续块表示一次分配能够取得的最大空间;长时间分配和释放后,两者可能有不同走势。TLS 需要容纳较大的接收缓冲,因此固件同时观察这两个指标和任务栈余量。镜像能装进 Flash 之后,网络握手与持续运行仍有各自的资源预算。

最近的迭代集中在资源与实际操作 ​

ESP8266 的 1 MiB Flash 要同时容纳网络栈、TLS、MQTT、空调协议和双槽更新。近期的工作因此包含固件精简:减少不必要的诊断文本,删除重复或已经失去用途的遥测字段,并移除 B5 主板能力查询路径。必要的断言、命令校验和回读确认仍然保留。

能力查询移除后,控制项改由每设备配置定义。温度范围、步进、模式、风速、摆风和附加功能由同一份配置约束,页面、手动命令和定时请求使用一致的规则。默认展示完整协议控制,具体设备不支持的功能可以显式关闭或收窄。这让控制入口的可用性更容易管理,实际效果仍由对应的主板响应确认。

控制台也逐步贴近日常使用。风速、摆风等入口保持可见,暂时不支持调温的模式会禁用温度控件并说明原因;点击后先给即时反馈,等待较长时才提示相关控件。固件把持续回读不匹配和缺少有效回读分开,分别表达为“设置未生效”和“未确认”,结果未知时通过刷新核实,不自动重复发送。

屏显控制有单独的处理方式:当前回读无法可靠提供屏显开关状态,页面使用“切换屏显”按钮,将其作为一次动作处理,不根据当前电源状态推定屏显状态,也不自动重试。这种处理保留了功能入口,同时避免把不可依赖的状态值带入后续操作。

页面现有的环境与运行历史也承担了不同用途。环境记录展示温度等已上报数值,运行记录保留可用堆、最大连续内存块、剩余栈、Tick 间隔、Wi-Fi/MQTT 和恢复相关指标。前者服务日常观察,后者帮助排查 ESP-01 上的资源退化和连接问题。功率卡片与功率历史目前默认隐藏。上述行为可在当前控制台文档中逐项核对。

这一轮还调整了遥测接收规则。固件和 Worker 分别迭代,诊断字段会增加或精简;如果服务器要求每份报告都具有一模一样的完整字段,一个缺失或不认识的诊断项就可能使整份有效心跳被丢弃。现在 Worker 强制校验 schema 和 boot_id,对其余诊断字段逐项提取可用值,忽略未知项或类型不适用的项。历史中的缺测保存为 NULL,保留“没有测到”的含义,不用零或旧读数填补。

控制命令继续严格检查身份、期限、字段与组合。开放控制还需要当前启动的有效主板状态和最近 120 秒的实时证据。遥测兼容性的调整因此集中在诊断数据接收,控制授权和执行确认仍由各自的条件决定。具体配置与心跳规则见按设备配置说明。

断网恢复要处理连接与任务的实际状态 ​

近期一项修复处理了 MQTT 客户端的生命周期。应用为了安排 UART 安全窗口而关闭 SDK 自动重连后,SDK 的等待任务可能退出;此时反复调用重连接口,无法让已经停止的任务继续工作。0.2.1.3A 调整了这条路径,保留应用显式唤醒重连的方式,并区分首次启动、重连和停止后重新启动。重试退避从 5 秒起步,最长到 5 分钟,减少持续故障时的重复连接开销。

连接恢复还要处理“看起来在线”的情况。当前遥测使用 QoS 1,固件观察 Broker 的 PUBACK;持续 90 秒没有确认,就清除连接就绪状态并重新连接。连接请求本身超时后,也会停止客户端并安排重新启动。这样,运行状态包含了对 Broker 响应的观察,排查时可以区分成功写入 socket 和收到服务端确认。

独立恢复任务负责处理云任务或串口任务心跳停滞,以及长时间离线的情况。恢复原因与连续次数存放在 RTC 用户内存中,最多允许三次连续恢复,健康在线 24 小时后重置额度。恢复策略同时考虑命令和 OTA 状态,底层看门狗覆盖调度或中断停滞。次数预算使持续故障保持可观察,避免设备在同一种错误下反复重启。

对当前测试来说,需要跟踪一条完整时间线:网络何时中断,是否重新取得 IP,MQTT 是否建立会话,Broker 是否返回确认,状态上报是否恢复,以及期间空调串口是否继续更新。某个计数增加只是这条时间线上的一个节点。当前恢复实现可在云任务源码中核对。

0.2.3.8A 把下载来源交给更新命令 ​

0.2.3.8A 的主要变化是 OTA 下载方式。此前 A 固件依赖固定下载入口,新版本改由更新命令提供清单 URL 和授权类型,支持局域网 HTTP/HTTPS、域名或 IPv4、自定义端口与查询参数。清单包含两个槽位的镜像信息,设备选择非活动槽下载并写入。

这给测试增加了一条更直接的路径:在设备能够访问的电脑上提供清单和双槽镜像,再通过控制台指定下载链接。局域网文件传输可以避开公网下载路径,但更新命令的下发与结果上报仍使用 Worker/MQTT。下载来源与控制链路因此可以分别排查。

这一变化与近期遇到的问题有关。前面的下载实现存在两个具体边界:HTTP 响应可能带很长的 Cookie 等头部字段;HTTPS 服务端可能发送 16 KiB 的 TLS record,而旧接收上限只有 4 KiB。服务器返回 HTTP 200 后,设备仍可能在解析响应头或接收加密数据时失败。

修复后的 HTTP 头采用流式解析,跳过无用字段值;TLS 接收上限提升为 16 KiB,下载数据缓冲仍保持 1 KiB。为了给较大的 TLS 缓冲留空间,OTA 准备先停止 MQTT、释放原有 TLS 连接,随后检查至少 32 KiB 可用堆和 18 KiB 最大连续块。这些入场条件把资源不足提前变成可报告的失败,后续分配与传输仍由实际下载结果检验。

发布记录中的公网 SDK 模拟后来仍出现连接 EOF 或正文无进展超时。指定链接和局域网下载为测试提供了另一条可观察路径;公网传输的表现仍需单独跟踪。局域网测试可以先观察解析、校验和写入,再与公网场景对照,缩小问题所在的范围。

更新保护继续保留:镜像长度和 SHA-256 校验、槽位及存储格式检查、试启动确认和回滚;一次 OTA 最长 10 分钟,连续 30 秒没有进展就结束,正常失败后释放下载资源并恢复 MQTT。错误信息也细分到连接、TLS、响应头和正文阶段,正文超时会带上已经读取的字节数,便于定位停在了哪里。

下载信任方式也发生了实质变化。0.2.3.8A 的 OTA HTTPS 关闭了服务端证书验证,MQTT 仍保留证书验证;更新信任经认证下发的命令和指定下载服务器。清单中的 SHA-256 用于检查镜像与清单是否一致,服务器身份与发布者认证需要由其他机制保证。Cloudflare Access 凭据只发送到 HTTPS 同来源。这个取舍扩大了下载来源的适用范围,也要求清单和服务器保持可信。具体规则见指定链接与局域网 OTA 文档。

更新后的试启动与回滚 ​

镜像下载完成后,设备继续检查长度、散列和槽位信息,保存本次更新记录,再把新槽标为待启动。启动程序在跳入新镜像前先持久化试启动状态,随后由新应用检查本地任务、调度间隔和资源余量。连续健康观察至少 15 秒,确认截止时间为 30 秒;本地确认不等待 Wi-Fi、MQTT 或云服务恢复,避免将普通网络故障判定为固件启动失败。

启动控制记录使用两个扇区,每份带 CRC 和代数标记;提交新记录时保留另一份有效记录。下载或写入非活动槽期间失败,旧槽继续保留;新应用确认前再次复位,启动程序则回到旧槽。永久挂死时需要看门狗产生复位才能进入这条回滚路径;新槽已确认之后出现的故障,则由正常运行中的恢复机制处理。

云端有自己的成功判定:新 boot_id、目标版本和 ota_confirmed=true 必须同时出现。设备回滚后,上报失败目标和原因,同一设备对同一 release 的重复升级会被抑制。页面因此能够把本地试启动、最终确认和回滚结果联系起来,保留失败版本的信息。

新下载协议也带来安装条件:旧 A 客户端需要先通过串口安装 0.2.3.8A 基线,后续才能使用 schema 2 更新命令。OTA 只比较第四段修订号,同修订号换一个构建 hash 不会触发升级。这些条件影响后续测试安排,尤其是在反复验证同一版固件或跨旧布局迁移时。

当前进展与仍在测试的部分 ​

我已经完成 0.2.3.8A 固件下载,当前处于测试阶段。同期仓库发布记录仍将它列为未发布的源码版本,记录中的 A stable 为 0.2.3.7+A.7062d162。测试版进展和正式发布状态各自保留,后续随实际结果更新。

下载实现已有本机 HTTP 和自签 HTTPS 的完整下载、双槽模拟写入与试启动测试记录。这些测试使用实际下载代码,Flash、NVS 和任务环境为模拟;ESP-01 上的真实写入、启动和恢复表现仍在后续测试范围内。

后续测试的重点是实际使用中的几条路径:控制后主板如何响应,网络断开后是否恢复,下载失败后控制链路能否继续工作,以及更新后的试启动和回滚是否按预期完成。问题出现时,版本、复位原因、资源低水位和发生场景比单独的“在线”状态更有用。

长期观察还需要区分持续运行与恢复后的运行。新启动身份和运行时间可以标出复位发生点,连接会话与恢复计数帮助还原原因,内存低水位则用于观察握手和重连期间的峰值。若某个问题只在断网、待机或连续操作后出现,就需要保留对应场景,修复后再观察这条路径。两个月的 ESP32 使用经验已经成为切换前的基础,ESP-01 上的运行结果正在继续积累。

入冬后,迭代频率可能下降 ​

随着天气进入冬季,我预计项目的迭代频率可能下降。后续更新会更多地取决于实际使用和测试中暴露的问题,现阶段仍围绕 ESP-01(ESP8266)上的 0.2.3.8A 测试推进。

对这套空调控制系统来说,持续使用本身会提供新的信息:偶发断线后的恢复、长时间运行后的资源变化,以及不同操作场景下的主板响应。版本更新的节奏可以放慢,这些观察仍能帮助判断哪些地方需要继续修复。

资料来源 ​