把一个传统空调接进网页,听起来像是给旧设备加一层智能家居。这个项目的实现其实更窄:ESP8266 自己开一个 Wi-Fi 热点,网页发出几个 HTTP 请求,固件把状态编码成美的空调能理解的红外脉冲。它没有云端账号,也没有复杂的家庭网络配置,所有链路都停留在一块小开发板附近。
我更喜欢从这条短链路看它,而不是从“智能”两个字看它。问题一旦被缩小,网络、状态、协议和硬件之间的关系就能逐个核对;某一步没有反应,也能知道应该回到哪一层。
先让网络退到设备旁边
仓库使用 ESP8266 的 AP 模式,设备自己提供热点。DNSServer 把连接进来的域名请求引向本地地址,ESP8266WebServer 提供网页和控制接口。手机连上热点后可以打开本地页面,即使没有家庭路由器和外网,控制路径也仍然存在。
这是一种很朴素的取舍。接入家里的 Wi-Fi,当然可以让设备出现在更多场景里,但也会引入密码、配网、路由器隔离和网络变化。这个项目只服务于近距离控制,AP 模式已经足够。先把依赖删到最低,调试时面对的变量也会少很多。
页面发送的不是一个按钮
网页上的开关、温度、模式、风速和睡眠操作,最后都会回到一份状态。固件用几个变量保存开关状态、温度索引、模式索引、风速索引和睡眠状态;每个接口更新其中一项后,再用 buildStateString() 返回完整状态。
这个返回值很重要。前端显示的是设备刚刚确认过的状态,而不是“按钮已经被点击”的猜测。对一个只服务于单个设备的小网页来说,完整状态字符串已经够用,不需要为了看起来实时就先引入 WebSocket 或复杂的状态管理库。
状态也给故障排查留出了顺序:请求有没有到达,参数有没有被处理,状态变量有没有改变,红外发送函数有没有被调用,最后才检查发射管方向和距离。每一层都能单独观察,问题就不会全部变成“网页点了没反应”。
红外信号有自己的语法
红外发射不是把 GPIO 拉高就结束。仓库里把美的协议拆成三个字节:A 是固定用户码,B 表示风速或特殊功能,C 由模式和温度组合得到。固件再把这三个字节转换为红外脉冲,并按项目约定发送双帧。
这层编码把网页上的词汇翻译成设备能理解的格式。温度不是直接传一个数字,模式也不是字符串;它们要先查表,再组合成协议字段。关机还有独立的负载,不能和普通状态更新共用同一条假设。
协议表越具体,越应该同时写出不确定的部分。仓库给睡眠模式的字节留了占位值 0xCE,要求使用真实遥控器重新捕获后替换。这个说明比“睡眠模式已支持”更有价值,因为它告诉后来的人,哪一段仍然没有被当前设备证明。
同样的边界也适用于型号。代码和 README 针对特定的美的协议做了实现,并不代表所有品牌、所有型号都能收到同样的帧。把一次设备上的成功扩大成通用兼容,会让故障排查从协议差异退化成猜测。
loop() 保持轻一点
固件的主循环只负责处理 Web 请求和 DNS 请求,没有把耗时工作塞进 loop()。各个处理函数完成参数更新、红外发送和状态回写,职责比较短。这样的代码看起来没有太多技巧,却让检查路径变得直接:页面请求、路由、状态、编码、发射,按顺序往回走就能找到断点。
网页端也保留了错误显示。如果请求失败,页面会把 HTTP 错误写到调试区域,而不是静默地保持旧状态。它不能替代串口日志和示波器,但至少让“浏览器没有收到响应”和“空调没有识别红外帧”不再混在一起。
能力范围要写在项目里
这个实现没有 MQTT、远程控制和断电恢复,也没有证明睡眠指令适配所有手里的遥控器。它只完成了一条近距离的本地链路:连热点、打开页面、提交状态、发出红外帧。剩下的功能可以继续做,但不能在已有代码上自动推导出已经完成。
我越来越愿意把这种边界写进项目说明。小设备的价值不在于拥有一张很长的路线图,而在于每一个已经完成的动作都能回到代码和硬件上核对。先让一个 HTTP 请求稳定地变成一串脉冲,再决定是否需要更大的系统,通常比一开始接入所有平台更容易走完。
这个仓库最后留下的经验也很具体:先把网络依赖缩小,再把状态写清楚,接着把协议字段和未验证的占位符标出来。硬件项目并不因为体积小就少了工程问题,只是它把这些问题放得更近,近到每一行代码都能对应一次按键和一次闪烁。