外观
2026-08-14 ER Midea Bridge:不在家里运行服务器的美的空调控制桥
- 目标空调:美的
KFR-26GW/BP2DN8Y-DH400(3),不带M - 长期部署目标:ESP-01S,1 MiB Flash,配合现有 ESP-01 Adapter 5V 转换底座
- 验证平台:经典 ESP32,承担 RX-only、全双工协议探测、离线命令闭环和云端集成验证
- 云端路径:EMQX Serverless + Cloudflare Worker / Durable Object / Worker Static Assets / Access
- 产品原则:家中不运行 HASS、MQTT Broker、数据库或其他常驻服务器,设备只建立主动出站连接
- 固件更新:ESP8266 目标 A/C 与 ESP32 目标 B 分别走同目标、人工确认的 OTA,设备不主动检查更新
- HomeKit 边界:独立 ESP32/S2/S3 Bridge 在局域网提供 HAP,空调节点不监听局域网控制端口
我们实现了一套什么系统
ER Midea Bridge 把一台没有现代联网能力的美的空调变成可远程观察、控制和定时的设备。ESP 通过室内机 UART 读取主板状态,使用 MQTT/TLS 主动连接托管 Broker;浏览器控制页、状态历史、命令协调和定时任务全部运行在云端。家中无需公网 IP,也无需常驻树莓派、NAS 容器或 Home Assistant 主机。当前架构已从单一遥控链扩展到分目标 OTA 和独立 HomeKit Bridge,但这些能力仍共享“主板回读才是当前状态”的同一条权威边界。
除了远程遥控页面,项目还把“网页已经提交”“Broker 已经接收”“ESP 已经接受”“空调主板已经执行”拆成四个不同状态。只有主板后续报告与目标设定匹配时,命令才进入 applied。HTTP 202、MQTT publish 成功和页面动画只表示链路中的一个阶段,不代替主板执行证据。
代码基线 0b7b6f5 将四个产品版本分开管理:Worker 0.3.0,ESP8266 固件 0.2.0.2+A/C.<UTC>,ESP32 固件 0.2.1.5+B.<UTC>,HomeKit Bridge 0.1.0.1。版本号反映构建与发布边界;硬件支持等级仍以实际目标的分层验收为准。
| 能力 | 当前实现 |
|---|---|
| 状态读取 | 统一状态模型覆盖电源、模式、目标温度、风速、摆风、预设,以及室内/室外温度、湿度和功率的可空字段 |
| 远程控制 | 命令携带 boot_id、request_id 和有效期,经过严格字段、类型、组合与能力校验后才进入 UART |
| 最终确认 | accepted → applied / rejected / timeout 与主板回读关联;applied 携带对应 state_seq |
| 浏览器控制 | Vue 3 + Element Plus 的响应式 PWA,展示 reported state、短暂 desired overlay、运行反馈、历史图表与设备信息 |
| 云端定时 | 每设备 Durable Object 保存最多五项一次性任务,通过 Alarm 进入同一命令串行协调器 |
| 固件更新 | Worker 只在操作者确认后下发同目标、短有效期、非 retained 的 OTA 命令;ESP8266 与 ESP32 均有 trial/回滚路径 |
| HomeKit | 独立 Bridge 通过 LAN HAP 服务 Home App/Siri,直连 EMQX 读状态并发复合命令,不连接空调 UART |
| 安全边界 | 每设备独立 MQTT 凭据和主题 ACL;控制页与设备 API 由 Cloudflare Access 保护;空调节点没有入站 Web、Telnet 或 AP 配网入口 |
| 故障恢复 | 网络异常不改变空调状态;ESP8266 在持续离线且资源退化、UART 安全、启动时间与 RTC 重启预算同时满足时才受控重启 |
| 可观测性 | RSSI、堆与连续块低水位、连续栈、最大 tick 间隔、会话/发布/确认/恢复计数随 telemetry 上报 |
当前技术架构
flowchart LR Mainboard["美的室内机主板<br/>9600 8N1 UART"] <--> Device["ESP-01S<br/>1 MiB production"] Probe["经典 ESP32<br/>probe / cloud validation"] -. "分级验证同一协议与运行时" .-> Mainboard Device -->|"MQTT/TLS 1.2 出站"| EMQX["EMQX Serverless<br/>Broker / ACL / Rule"] Probe -->|"production composition"| EMQX Home["Home App / Siri"] <-->|"LAN HAP"| Bridge["ESP32/S2/S3<br/>HomeKit Bridge"] Bridge <-->|"MQTT/TLS"| EMQX EMQX -->|"四类上行 webhook"| Worker["Cloudflare Worker<br/>API / OTA / Static Assets"] Worker <--> DO["每设备 Durable Object<br/>SQLite / WebSocket / Alarm"] Worker -->|"HTTP API 发布命令与 Bridge 目录"| EMQX Browser["浏览器<br/>Vue 3 PWA"] <--> Worker Access["Cloudflare Access"] --> Browser Access --> Worker
ESP-01S 固件只关心四件事:持续服务 UART、维持 Wi-Fi 与 MQTT/TLS、执行严格命令合同、上报状态与健康数据。EMQX 负责设备与 Bridge 连接、ACL、retained 状态和消息转发;Worker 验证 webhook 与操作者身份;每台设备的 Durable Object 保存状态、历史、命令意图和定时任务。Vue 控制台已合并为同一 Worker 的 Static Assets,网页不保存 Broker 密钥。
空调节点始终只建立出站连接。云端发生故障时,ESP 继续处理主板 UART 和原装遥控器状态,空调不会因控制服务离线而自动改变设置。HomeKit Bridge 是唯一在家庭 LAN 监听 HAP 的组件,它不连接空调 UART,也不改变节点的网络信任边界。
路线如何一步步收敛
项目没有从一开始就写出当前架构。每一阶段先解决一个未知数,再删除已经失去价值的过渡实现。
| 阶段 | 路线 | 当时解决的问题 | 后续处理 |
|---|---|---|---|
| Phase 0–1 | ESP-01S + ESPHome/HASS 临时探测 | 快速生成 climate 实体、观察传感器、准备 RX-only 与双向 UART 抓取 | 只定位为实机探针,不进入正式系统;后来由 ESP32 原生探测栈取代 |
| Phase 2–3 | 自研 C++ 核心 + ESP8266 MQTT 固件 | 固定命令 schema、主板回读确认、故障隔离和 1 MiB 构建边界 | 成为两种 MCU 共用的长期核心 |
| Phase 4–9 | Mosquitto + 轻量 Go HTTPS 服务 | 用单文件静态服务验证完整自托管闭环,建立 API、控制页和跨语言合同测试 | 证明路线可行,但仍需管理 VPS、证书、容器与另一套状态实现 |
| Phase 10–15 | 引入 ESP32 / ESP-IDF | 用更安全、可观察的平台完成 RX-only、全双工、离线命令和云端 composition | ESP32 固定为验证平台,ESP8266 保持长期部署目标 |
| Phase 20–26 | 生产/探针拆分与代码收敛 | 移除 ESP8266 探针、ESPHome/HASS 资料和重复诊断;统一 C++/Go/前端合同 | 探针只在 ESP32,生产固件只保留必要路径 |
| Phase 27–32 | EMQX Serverless + Cloudflare | 将 Broker、状态、API、实时通信和前端迁入托管服务 | 完成线上 mock 双向 E2E、Durable Object 状态层与单 Worker 控制面 |
| 2026-08-07–08 | Worker Static Assets + HomeKit mainline | 删除独立 Pages 部署;把 HomeKit 作为独立 ESP-IDF Bridge 产品 | 网页/API 同源;Bridge 直连 EMQX,Worker 退出实时 HomeKit 关键路径 |
| 2026-08-09–10 | ESP32 OTA + ESP8266 RTOS SDK v3.4 | 建立分目标发布合同,将 ESP8266 生产路径迁入原生 UART/Wi-Fi/NVS/mbedTLS/ESP-MQTT | ESP32 保留 IDF 双分区回滚;ESP8266 形成 1 MiB 可链接基线 |
| 2026-08-11–13 | ESP8266 真 A/B OTA + 项目自有协议模块 | 将双槽构建、trial/confirm/回滚和固定内存 Midea 协议纳入同一验收链 | 软件/目标构建已通过;断电、WDT、双槽往返和长期运行仍待实机 |
这段迭代留下了三条稳定边界:美的协议与命令规则在共享 C++ core;UART、Wi-Fi、TLS、MQTT、boot 和构建差异留在 ESP8266/ESP32 adapter;云端与 HomeKit Bridge 只消费公开 MQTT 合同。服务端语言、前端框架或 MCU 可以继续变化,accepted/applied、启动绑定、期限、去重和主板回读语义不需要跟着重写。
为什么没有采用 ESPHome + HASS 作为正式路线
ESPHome 很适合项目最早期的未知数。几段 YAML 就能得到 UART、Midea climate 实体、加密 Native API 和 Home Assistant 页面;短期探测不需要先完成 MQTT 合同、控制 API和前端。项目 Phase 1 因此准备了 RX-only、正常控制与原始抓帧三种固件,以及只绑定本机回环地址的临时 HASS 容器。
正式产品的运行目标与这套组合不一致。典型 ESPHome + HASS 路线由 Home Assistant 通过 Native API 连接设备;ESPHome Native API 官方文档列出的主要客户端也包括 Home Assistant。这样做意味着家中需要一台长期在线的 HASS 主机,并承担存储、升级、备份、网络发现和故障恢复。我们的目标是通过手机或浏览器随时控制空调,同时不在家里维护服务器,因此没有把 HASS 纳入生产依赖。
还有一层更重要的产品语义。HASS climate 实体擅长表达目标状态,ER Midea Bridge 还需要表达一次命令从云端到主板的证据链、当前启动身份、短期有效期、重复请求、主板回读匹配和控制授权新鲜度。这些规则放在自有协议与控制面中更直接,也可以针对准确型号逐项收紧能力,而不把 YAML 中出现的实体自动视为主板已经支持。
ESPHome 不用 HASS:路线成立,为什么仍未选择
ESPHome MQTT 官方文档明确支持设备直接连接 MQTT Broker。关闭 Native API,或把其离线重启时间设为零,就可以在没有 HASS 的情况下运行;设备也可以通过自定义 topic 与外部服务交互。它确实满足“家中不运行 Home Assistant”这一条约束。
这条候选路线可以做成:
text
空调主板 → ESPHome Midea 组件 → MQTT/TLS → EMQX → Worker / Static Assets它的优势很清楚:UART、Wi-Fi、日志、配置生成和 Midea climate 组件已有框架支持,常见实体接入速度快;如果目标只是把标准 climate 状态发布到 Broker,再由通用平台消费,ESPHome 会减少大量固件工作。
ER Midea Bridge 的自定义部分已经超过框架能直接复用的部分。项目仍需在 ESPHome lambda、自定义组件或外部服务中实现以下内容:
- 与当前 Worker 完全一致的严格命令 schema、字段类型和组合限制;
boot_id启动绑定、可信时间、命令期限和有界request_id去重;accepted/applied/rejected/timeout及主板后续报告匹配;- retained 状态只作为缓存、实时 state/telemetry 才能恢复
control_ready的新鲜度规则; - 命令期间优先 UART、推迟阻塞式 TLS 重连,以及 ESP8266 的堆、连续块、连续栈与受控恢复策略;
- ESP32 RX-only、全双工原始帧观察和离线命令会话;
- ESP8266 与 ESP32 共用的协议 fixture、主机单元测试和 sanitizer 门禁。
| 比较项 | ESPHome + HASS | ESPHome + 直接 MQTT | 当前自研固件 + Serverless |
|---|---|---|---|
| 家中常驻服务器 | 需要 HASS | 不需要 | 不需要 |
| 首次做出 climate 实体 | 最快 | 快 | 较慢 |
| 自定义命令生命周期 | 需要额外实现 | 需要额外实现 | 已是 core 合同 |
| ESP32 原始探针与离线闭环 | 另建专用路径 | 另建专用路径 | 与生产 core 共用 |
| ESP8266 1 MiB 资源策略 | 受框架 composition 约束 | 受框架 composition 约束 | 固定存储与热路径可逐项控制 |
| 云端 UI 与状态协调 | HASS 提供 | 仍需自建 | Worker / DO / Static Assets 已完成 |
| 主板能力证据 | 实体易快速出现,仍需另做验证 | 同左 | 能力矩阵与命令 policy 直接相连 |
ESPHome 可以直接连接 MQTT。选择自研固件,是因为项目已经需要维护自己的云端、命令合同、硬件探针和验收体系;继续使用 ESPHome 会同时维护框架模型与自有模型,减少的主要是外围初始化代码。当前路线把复杂度集中在少量深模块里,ESP32 和 ESP8266 直接运行相同业务核心,长期边界更清晰。
从 Go 自托管服务转向纯 Serverless
Go 路线完成了什么
Phase 4 的 Go 控制服务是一条刻意保持简单的自托管路径:Mosquitto 负责 MQTT/TLS,约 7 MiB 的静态 Go 二进制在 scratch 容器中提供 HTTPS API 与嵌入式中文控制页;最新状态放在内存,服务重启后由 Broker retained state 恢复。它没有数据库、反向代理或 HASS,软件 E2E 已经证明 MQTT/TLS 上报、HTTPS 读取和 QoS 1 非 retained 命令可以闭环。
这条路线的优点是完全可控、依赖少、部署行为容易理解。代价也同样具体:需要一台持续在线的 VPS,维护 Mosquitto、容器、DNS、防火墙、私有 PKI、叶证书轮换、数据备份和服务升级;控制页与 API 跟随同一个二进制发布;复杂状态、历史、实时连接与定时任务会逐步把“轻量服务”扩展成长期运维对象。
迁移早期,Go 与 Cloudflare 两套控制面曾经并存并共享 MQTT 合同。这种双实现适合迁移验证,不适合作为长期基线:命令字段变化需要同步 C++、Go、Worker 和页面;线上问题还要先判断设备连接了哪一个 Broker、请求进入哪一个控制面。Serverless 链路完成真实 mock E2E 与 Access 迁移后,Go 服务在提交 e3ad589 中删除,自建 Mosquitto 缩回 TLS/ACL 冒烟工具。
Serverless 路线怎样分担状态
这里的“纯 Serverless”表示没有需要自行管理的家庭服务器或 VPS,生产链仍由两套托管服务组成:EMQX Cloud 管 MQTT,Cloudflare 管 HTTP、状态和页面。EMQX Serverless 官方文档提供托管 MQTT/TLS 入口;Cloudflare Durable Objects为每台设备提供单点协调、持久状态、WebSocket 和 Alarm。
| 层次 | 当前责任 | 从 Go/VPS 路线移走的工作 |
|---|---|---|
| EMQX Serverless | MQTT/TLS、设备认证、ACL、retained 状态、规则与 HTTP 动作 | Mosquitto 容器、Broker 端口和生产私有 PKI 运维 |
| Worker | Access JWT 复验、webhook schema、设备 API、EMQX 发布 | Go HTTPS 进程、TLS listener、Bearer token API |
| Durable Object | 每设备串行命令、reported/desired、历史、WebSocket、SQLite 与 Alarm | 内存状态扩展、数据库选型、调度器和并发协调 |
| Worker Static Assets | 与 API 同源的 Vue 控制台、PWA、响应式布局、图表与瞬时操作反馈 | 独立 Pages 项目和嵌入 Go 二进制的静态页面 |
| Cloudflare Access | 登录身份与 API 会话 | 自管登录入口与控制 token 生命周期 |
Serverless 带来的关键变化是发布与故障边界。前端、状态协调和固件保持独立版本,但控制台与 API 从同一 Worker 域名交付;浏览器不接触 EMQX 密钥;每台设备最多一个命令在途,手动操作和定时任务进入同一串行出口。投递结果未知或确认超时时,协调器停止当前意图及后续队列,不自动重放一条可能已经生效的空调命令。
HomeKit 接入为什么是独立 Bridge
HomeKit 要求家庭 LAN 内有一个常驻 HAP 端点,这与空调节点“只建立出站 TLS、不监听入站端口”的约束相冲。项目因此把 homekit-bridge-idf/ 作为独立产品:ESP32、ESP32-S2 或 ESP32-S3 运行 HAP 和 mDNS,空调节点继续保持原有固件和 UART 边界。
Bridge 使用自己的 MQTT/TLS 身份直连 EMQX,订阅已绑定设备的实时状态,并把 Home App 在 100 ms 窗口内的多字段写入合并为一条复合命令。Worker 只异步发布 retained 目录与绑定、镜像设备事件,不中转 HomeKit 实时操作。这样可以在 Worker 暂时不可用时保留 LAN 到 EMQX 的实时路径,同时仍由设备端执行 boot_id、过期、去重和单命令顺序规则。
Bridge 当前版本为 0.1.0.1,三个芯片目标只完成 build-supported 证据。Home App 配对、Siri、真实复合命令、断网恢复、资源峰值和长期运行必须按 ESP32/S2/S3 分别验收,不能由链接成功代替。
为什么先用 ESP32 验证,再转向 ESP8266
两块芯片承担不同角色:ESP32 提供观测和试错空间,ESP-01S 提供最终安装形态,因此从 ESP32 转向 ESP-01S 属于验证平台与部署平台的切换。
ESP32 适合把未知数逐个拆开
经典 ESP32 开发板有独立 USB 调试口、更多 GPIO、多个硬件 UART、4 MiB Flash 和更充足的内存。项目默认用 UART2 的 GPIO16/GPIO17 连接空调侧,同时保留 USB 串口输出结构化探针日志。验证过程可以严格分级:
probe-rx在软件中解除 TX 路由,实物上继续物理断开 TX,只观察主板数据;- 电平、共地、波特率和帧完整性稳定后进入
probe-duplex,先查询能力; - 通过 USB 控制台运行与 MQTT 相同的命令 JSON,离线完成
accepted → applied闭环; - 最后使用 ESP32
productioncomposition 验证 Wi-Fi、SNTP、MQTT/TLS 与云端全链路。
这套顺序把 UART、电气、协议、命令和云端拆成可单独观察的阶段。ESP32 的结果证明共享协议与业务路径,无法替代 ESP8266 的 mbedTLS 内存峰值、GPIO1 启动输出、1 MiB Flash、供电和长时间运行验收。
ESP-01S 对应真正的部署约束
最终设备只需要一个 UART、2.4 GHz Wi-Fi 和主动 MQTT/TLS。ESP-01S 尺寸小,现有库存与已经购入的 ESP-01 Adapter 5V 转换底座也使空调内部的紧凑安装更现实。选型围绕手头物料、安装形态和角色匹配展开,价格差异没有主导这次决定。
1 MiB 预算反过来约束了软件组成:固件没有文件系统、Web Server、HASS Native API、Telnet 或生产抓包日志;热路径使用固定容量帧、请求池与内联回调;TLS 重连受当前堆、最大连续块和连续栈门槛约束;协议抓包只留在 ESP32。当前 checkout 保留的两份 ESP-01S 槽专用 production 镜像均为 430,944 bytes,低于每槽 458,751 bytes 硬上限,并已链入 UART、Wi-Fi、mbedTLS、ESP-MQTT、OTA 与 trial 确认路径。这仍是构建证据,不是 ESP-01S 电气、断电或长期运行证据。
转换底座属于最终硬件验收的一部分。商品名称提供了 5V 输入和 ESP-01 插座这一设计线索;实际安装仍以测量为准,记录外部输入、ESP 插座 3.3V、两侧 UART 高电平、Wi-Fi/TLS 峰值期间电压和复位原因。它是否同时完成双向电平适配,也由实物电路与波形确认。
| 角色 | ESP32 | ESP-01S / ESP8266 |
|---|---|---|
| 项目定位 | 协议探针与完整云端验证平台 | 长期部署目标 |
| 串口 | UART2 接空调,USB 串口独立调试 | UART0 同时承担生产通信与早期配置 |
| 验证模式 | RX-only、probe-duplex、offline command、production | production |
| 资源目标 | 保持可观察性和集成覆盖 | 固定 1 MiB、双 448 KiB 应用槽、无文件系统、控制热路径固定容量 |
| 共同部分 | C++ core、MideaController、CommandPolicy、CloudProtocol、MqttContract | 同左 |
| OTA | IDF ota_0/ota_1 + pending verify/回滚,目标 B | 项目 bootloader + 无复制 A/B trial/confirm/回滚,目标 A/C |
| 独立验收 | GPIO、电平、ESP-IDF 网络栈与选定开发板 | Adapter 供电、GPIO1 启动输出、mbedTLS/OTA 峰值与 14 天耐久 |
1 MiB ESP8266 怎样完成真 A/B OTA
最早的 CopyOTA 思路会把新镜像下载到临时区,重启前再复制到固定运行位置。它有两个存储区域,但没有独立的 trial 启动、确认和自动回滚语义。当前实现在 1 MiB Flash 上固定两个 0x70000 应用槽:ota_0 从 0x10000 开始,ota_1 从 0x80000 开始。每个版本分别按所属 IROM 地址链接两份镜像,新固件直接在 inactive slot 运行,不做第二次 Flash 复制。
text
STABLE(old)
→ 下载并校验 inactive slot
→ PENDING(old, new)
→ bootloader 先持久化 TRIAL_STARTED,再启动 new
→ 本地自检通过:CONFIRMED(new)
→ 确认前复位、panic、WDT 或掉电:ROLLED_BACK(old)boot-control 使用两个 4 KiB 扇区保存带 generation 与 CRC32 的冗余记录,更新 metadata 时不先擦除唯一有效副本。trial 固件运行至少 15 秒,在 30 秒窗口内确认 Midea/Cloud task、堆、最大连续块、栈余量与 recovery watchdog 都处于本地可接受状态,才提交新槽。这个确认不等待 Wi-Fi、MQTT、NTP、Cloudflare 或空调应答,普通网络故障不会被当成坏固件。
ESP-01S 目标 A 与调试板目标 C 共享 ESP8266 修订号,但使用独立 stable channel,不能交叉升级。发布清单同时引用两份 slot-specific 制品;Worker 只向设备投影当次目标槽的固定下载路径。设备校验 target、version、长度、镜像格式和流式 SHA-256;项目依赖 R2/Worker 写权限、Cloudflare Access 与 TLS 建立来源信任,当前没有独立固件签名、Secure Boot 或 Flash 加密。
这条链目前已完成状态机、双槽构建、双制品发布、Worker 路由和回滚展示的软件/目标构建验证。仍需在 A/C 实板上分别做双槽启动、下载/写 Flash/首启三个断电窗口、panic/WDT、多次往返、UART/TLS 资源峰值和回滚 ACK 验收。软件门禁通过不等于这些实机门槛已完成。
我们怎样找到显示板上的飞线点位
CN22 接上适配器后,最早遇到的现象是两个候选信号脚都收不到数据。交换 RX/TX、改变监听方向也没有改变结果,适配器自身回环却能正常收发。这组现象只能说明串口工具和适配器具备基本收发能力,问题范围仍包括主板没有主动发帧、逻辑电平不匹配、CN22 没有接入实际 UART 网络,以及板型选配导致走线被断开。
点位来自一条逐段收敛的证据链:“串口现象缩小范围 → 观察空焊位 → 断电测通断 → 对比同系列板型 → 沿两条信号链继续追踪”。参考板照片负责解释空焊位对应的板型选配,万用表结果负责确定当前板子上的实际路径。
flowchart LR NoData["CN22 两个候选信号脚<br/>均无数据"] --> Adapter["适配器回环与串口参数<br/>确认基本收发能力"] Adapter --> Empty["发现 RJX1 / RJX2 / RJX3<br/>均为空焊位"] Empty --> Continuity["断电逐点测通断<br/>CN22 对 RJX 两侧"] Continuity --> FirstMap["CN22-2 → RJX1<br/>CN22-3 → RJX2"] FirstMap --> Variants["对比同系列显示板<br/>外接 CN22 / 板载 Wi-Fi 选配"] Variants --> SecondMap["继续追 R9B 网络<br/>RJX1 → R9B2<br/>RJX2 → R9B1"] SecondMap --> Route["形成两条完整候选路径<br/>并选择现成焊盘恢复"]
第一步:从“没有数据”转向检查 PCB 选配网络
最初的 RX-only 监听没有字节,交换信号脚后仍然如此。排查先确认适配器回环、9600 8N1 和候选输出电平,再观察显示板上与 CN22 相邻的器件位,暂时保留固件、针脚定义和 PCB 路由三类可能。此时发现 RJX1、RJX2、RJX3 都没有安装 0Ω 电阻或锡桥。
这组空焊位改变了排查方向:CN22 插座虽然存在,信号脚可能只到达选配焊盘的一侧,没有继续接入 IC02 周边的 UART 网络。三处焊盘的用途当时仍不清楚,可能分别属于 TX、RX、电源、使能或另一种模块选配,因此没有把三处一起短接。
第二步:用断电通断测量建立第一段路径
断开空调供电、ESP32 USB 和串口工具后,分别测量 CN22 第 2、3、4 脚到 RJX1/2/3 两端。为了避免“左、右”随着照片方向变化,现场把每个焊盘分成“靠 CN22/板边的一侧”和“靠 IC02/数码管的一侧”。
我们逐项记录的测量结果把两条信号线锁定为:
text
CN22 2脚 → RJX1 的 CN22 侧
CN22 3脚 → RJX2 的 CN22 侧当时 RJX1、RJX2 本身开路,所以两根线都在焊盘处终止。这可以解释为什么适配器连接正确、串口参数也合理,主板侧仍然没有形成完整收发路径。RJX3 没有进入这两条实测链路,因此继续保持空置。
第三步:用同系列板照片识别“板型选配”,不靠照片猜网络
随后对比了多个同系列美的显示/接收板照片。带外接 CN22 的参考板在 RJX1、RJX2 位置安装了 0Ω 链路,RJX3 保持空置;另一类板载 Wi-Fi 版本在同一区域使用不同的电阻选配。高分辨率板图还能看到 R9B1、R9B2、R9B4、R9B5、CN303、CN305 与 IC02 等丝印。
照片提供的是板型差异:同一 PCB 通过不同的 0Ω/电阻组合,把 UART 路由到外接 CN22 或板载 Wi-Fi 模块。它没有单独决定飞线位置;位置仍需回到当前板子的通断测量。
第四步:补上 RJX 与 IC02 之间缺失的 R9B 段
只恢复 RJX1/RJX2 仍不足以构成完整链路,因为我们继续发现参考板上的 R9B1/R9B2 在当前板上也没有安装。于是测量从 RJX 的 IC02 侧继续向 R9B1/R9B2 两端推进。
现场结果为:
text
R9B1 一侧 → RJX2 的 IC02 侧:导通
R9B2 一侧 → RJX1 的 IC02 侧:导通两次测量修正了最初按编号顺序配对的猜测。最终形成的两条候选信号路径是交叉编号:
text
CN22 2脚 → RJX1 → R9B2 → IC02
CN22 3脚 → RJX2 → R9B1 → IC02这也是飞线点位的来源。最终方案沿 PCB 已经预留的外接 CN22 选配链施工:补通 RJX1、RJX2、R9B1、R9B2 四个空焊位,保留 RJX3 开路;无需从 CN22 拉两根长线直接焊到 IC02 引脚。现成焊盘让两条路径可以分别测量、返工和检查,也保留了原板的布线方向。
| 现场线索 | 当时得到的结论 | 下一步动作 |
|---|---|---|
| 两个候选脚监听都无数据,适配器回环正常 | 交换 RX/TX 仍不足以解释现象 | 检查电平和 CN22 后方 PCB 路由 |
RJX1/2/3 均为空焊位 | CN22 可能是同板不同配置留下的接口 | 断电测 CN22 到每个 RJX 两侧的通断 |
CN22-2 → RJX1、CN22-3 → RJX2 | 两条 UART 候选线在 RJX 处被截断 | 对比外接 CN22 参考板,同时保持 RJX3 不动 |
参考板还有 R9B1/R9B2,当前板同样缺件 | 只补 RJX 可能仍到不了 IC02 | 继续测 RJX 到 R9B 两侧 |
RJX1 → R9B2、RJX2 → R9B1 | 得到两条交叉编号的完整候选路径 | 使用四个现成焊位恢复外接 CN22 选配链 |
飞线方案形成后,断电检查项目也随路径确定:CN22-2 应越过 RJX1 到达 R9B2 另一侧,CN22-3 应越过 RJX2 到达 R9B1 另一侧;第 2、3 脚之间保持不导通,5V 与 GND 保持不导通,两根信号也不应短接到电源或地。完成这些静态检查后,才恢复 CN22 3 → HW-580 RX、CN22 2 → HW-580 TX 并重新观察串口。
这次找点的关键经验是先找 PCB 自己留下的选配边界。相似板照片能揭示 BOM 变体,万用表能确认当前板的铜线实际去了哪里;两者相交后,飞线从“猜一对串口脚”变成“恢复原设计中的四段可测链路”。
固件内部如何同时服务两种芯片
共享层采用无平台依赖的 C++ core 保存稳定规则,硬件与网络实现通过窄 interface 接入,避免用大量 #ifdef 把两块芯片揉在一起。
| 模块 | 负责内容 | 平台边界 |
|---|---|---|
midea_protocol / MideaController | 固定容量帧、状态映射、命令发送与主板回读 | 共享有界 ByteStream;ESP8266 与 ESP32 分别提供原生 UART adapter |
CommandPolicy | 模式、温度、风速、预设组合与主板状态匹配 | 纯 C++,主机单测直接覆盖 |
CloudProtocol | MQTT 命令 JSON、期限、启动身份、状态/确认/遥测编码 | 不建立网络连接 |
MqttContract | topic、发布顺序、有界确认队列、状态与遥测生命周期 | 两个平台的 ESP-MQTT adapter 只实现 publication sink |
DeviceRuntime | UART 优先级、在途命令、网络重连时机 | 不解析 Midea 帧,也不手写 JSON |
RuntimeHealth / RecoveryWatchdog | 资源门、长期遥测与受控恢复判定 | ESP8266 adapter 执行 RTC 预算和实际重启 |
OtaContract / boot adapter | 共享 manifest、版本、SHA-256 与命令边界 | ESP8266 项目 boot-control;ESP32 使用 ESP-IDF OTA/回滚 API |
MideaFrameProbe / OfflineCommandSession | 原始帧观察与无云端命令闭环 | 只进入 ESP32 探针 composition |
美的协议实现已从外部子模块和构建期 overlay 迁入项目自有的 lib/midea_protocol。上游来源和最新审阅 commit 记录在 PROVENANCE.md,后续同步采用显式审阅和选择性移植,不再导入 Arduino/IDF 兼容层。完整帧固定 96 字节,一个在途请求与八个排队请求使用对象池,回调、定时器和状态监听也使用固定容量。动态帧字符串、通用 logger 和重复日志从 ESP8266 热路径移除,原始帧诊断集中到 ESP32 probe。
一条命令怎样到达空调主板
sequenceDiagram participant U as 控制页面 participant W as Worker / DO participant M as EMQX participant E as ESP participant A as 空调主板 U->>W: 提交设定 W->>W: Access、schema、在线新鲜度、串行意图 W->>M: QoS 1 非 retained command M->>E: MQTT command E->>E: boot_id / expires_at / request_id / policy E-->>M: accepted M-->>W: ack webhook E->>A: UART 命令 A-->>E: 后续状态报告 E->>E: 匹配设定与 state_seq E-->>M: applied + 新 state M-->>W: ack / state webhook W-->>U: WebSocket 更新 reported state
retained availability=online 只用于恢复上一次已知状态,不能单独开放控制。Worker 还要求 120 秒内出现相同 boot_id 的实时 state 或 telemetry。ESP 重启、命令过期、请求重复或设备只剩 Broker 缓存时,旧命令都无法再次执行。
下一步验收已经从“能否构建”转向实物故障注入
当前软件基线、已部署控制链路和一台真实目标的基本命令/回读闭环已有分层证据,经典 ESP32 production 也已在真实开发板烧录。剩余风险集中在每个实际目标的电气、更新恢复和长期运行,应按以下顺序继续:
- 在 ESP-01S 上记录实际芯片/Flash 身份、镜像 SHA-256、Adapter 输入与 3.3V 低水位、两侧 UART 高电平和 GPIO1 启动输出影响。
- 在目标 A/C 上分别完成
ota_0 ↔ ota_1往返,对下载、写 Flash、boot-control、trial 首启和确认前掉电注入故障,并核对 Workerrolled_back与同 release 抑制。 - 分别中断 Wi-Fi、DNS、NTP、MQTT、Worker 和空调,确认 UART 仍可服务且旧命令不重放;随后启动 ESP-01S 14 天耐久窗口。
- HomeKit Bridge 按 ESP32、S2、S3 分别完成配对、Siri、复合命令、断网恢复、资源余量和长期运行,三个 target 不互相代替。
实物验收会回答三个仍然开放的问题:ESP-01 Adapter 是否真正完成所需的供电与双向电平转换;trial 阶段的 WDT 是否能覆盖所有永久卡死类型;HomeKit Bridge 在三种无 PSRAM 目标上的 TLS/HAP 峰值是否仍保留足够堆、连续块和栈余量。这三项都需测量,无法从构建产物推导。
这条路线最终得到什么
ER Midea Bridge 的收敛方向可以概括为四次职责转移:ESPHome/HASS 把协议探索速度交给成熟框架;ESP32 把真实硬件未知数放到更安全的验证平台;Serverless 把服务器运维交给托管基础设施;独立 HomeKit Bridge 把 LAN HAP 入站能力与空调节点的出站安全模型分开。ESP-01S 上最终留下主板通信、可靠命令语义、受控出站云连接和可回滚更新。
Go 路线和 ESPHome 路线都完成了各自的任务。前者证明完整自托管闭环可以很小,后者证明 Midea 实体与探测流程可以快速建立;当前架构吸收了两者的结果,同时删除双控制面、独立 Pages 项目、家庭常驻服务器和生产探针。现有 ESP-01S 与 5V 转换底座让最终安装有了明确物料基础,ESP32 继续承担探测与云端验证责任,HomeKit Bridge 承担局域网入口,三者之间由同一套领域语义和 MQTT 合同连接。