老空调没有Wi-Fi,遥控器还总找不到,这事本身不算大,但搁在夏天就挺烦人。我前前后后折腾了一个星期,用一块ESP8266加一个几毛钱的红外发射管,把家里的美的空调接进了Home Assistant。手机随手一点就能开关机、调温度,设置里的自动化还能根据温湿度传感器自动把空调调到合适的温度。这套东西做完之后我再也没找过遥控器,今天就把从红外协议拆解到HA集成的完整过程写出来,给准备给老空调“联网”的朋友一个参考。
这个项目最核心的难点不在ESP8266,也不在Home Assistant,而在中间那段红外协议解析。很多人卡在这一步就放弃了,其实只要弄懂美的红外的帧结构,后面全是水到渠成的事。我尽量把每一步都写清楚,包括我自己踩过的坑,让你能少走点弯路。
1. 项目整体设计与方案选型
1.1 为什么选择ESP8266而不是其他方案
做空调联网控制,市面上能抄的近道不少,但每一条都有坑。
先看Wi-Fi智能插座。这个方案只能给空调断电上电,问题是空调通电之后并不会自动开机,遥控器在待机状态下需要红外信号才能唤醒。所以插座方案只能配合“通电自启”的空调机型用,很多老空调根本不支持,而且这样强行断电对压缩机也有损伤,制冷系统高压侧直接停机,次数多了容易出故障。
再看成品空调伴侣。这类产品本质就是一个带红外的Wi-Fi网关,体验确实不错,但有两个问题:一个是贵,一个是不开放。像美的自己的“美居”系列也不是所有老机型都支持,第三方兼容方案又经常出现码库缺失、控制失灵的情况。
所以最可控的路就是自己做:ESP8266负责联网和逻辑处理,红外发射管负责把控制指令发出去。ESP8266选它的原因很简单,便宜、社区资料多、Arduino和ESPHome生态都成熟,NodeMCU开发板十几块钱就能买到。ESP32虽然性能更强,但干这活儿属于性能过剩,价格还贵出一截,没必要。
1.2 方案整体链路与关键决策
整个系统的数据流是这样的:
手机 / Home Assistant通过MQTT或本地API下发指令给ESP8266,ESP8266内部把指令翻译成对应的红外码,通过GPIO驱动红外发射管发出38kHz载波信号,空调接收到信号后执行对应操作。
这里有一个关键决策:红外码怎么来。市面上很多现成库号称内置了几万条空调码,但我实测下来,对美的老机型兼容性非常一般,有时候看起来码是对的,空调就是不理你。所以我选择了“先抓码、后解析”的路线。
具体来说,就是用一个红外接收头把原装遥控器的信号录下来,分析出协议格式,再把格式转化成可编程的帧结构。这样做的优点是完全适配你自己的空调型号,不用猜、不用试错,缺点是前期要多花一两个小时抓码和分析。
还有个决定是通信协议。我一开始用的是MQTT自写固件,调试起来很灵活,但后来发现ESPHome对红外发射的支持已经很成熟,配置化程度高,省去了大量重复造轮子的工作。所以最终固件部分我用了ESPHome,HA集成直接走原生API。后面正文里两条路线都会写到,你可以根据自己的偏好选。
2. 美的空调红外协议深度解析
2.1 载波、时序与NEC协议变种
红外遥控本质是让红外发光管以一定频率闪烁,接收端通过检测闪烁频率和持续时间来还原数据。绝大多数空调遥控器用的载波频率是38kHz,也就是每秒闪烁38000次。为什么是38kHz?因为红外接收头(比如常见的VS1838B)内部集成了一组带通滤波器,只对38kHz左右的信号敏感,能有效滤掉阳光、白炽灯这些红外干扰源。
载波之上是数据调制。通信协议上,美的空调用的是NEC协议的变种。标准NEC协议数据帧是32位,包含地址码、地址反码、命令码、命令反码。它的时序特征是:
- 引导码:9ms高电平 + 4.5ms低电平,用来告诉接收端“我要开始发数据了”
- 逻辑1:560us高电平 + 1690us低电平
- 逻辑0:560us高电平 + 560us低电平
- 帧结束:560us高电平
美的在NEC基础上做了改动,数据帧不是32位,而是48位,也就是6个字节。部分机型甚至有两段帧,中间带较长的间隔。我第一次用逻辑分析仪抓到的波形和标准NEC一比,心里就大概有数了:协议底子是NEC,数据位长度变了,有效载荷结构也是美的自定义的。
2.2 48位数据帧结构拆解
我抓的是自家一台老款美的挂机遥控器发出的码,拆解后的帧结构大概是这样的(注:不同批次、不同型号的美的空调编码可能存在差异,务必用自己的遥控器抓码验证,下文数值是示例参考):
一帧8字节(部分机型6字节,但结构逻辑类似),发送顺序采用LSB First,也就是一个字节内低位先发。典型的一帧数据如下:
| 字节 | 含义 | 示例值 | 说明 |
|---|---|---|---|
| Byte 0 | 帧头/厂商码 | 0xAA | 固定值,用于识别厂商 |
| Byte 1 | 开关+模式 | 0x24 | 高位是开关,中位是模式 |
| Byte 2 | 温度+风速 | 0x60 | 高4位是温度,低4位是风速 |
| Byte 3 | 保留/功能 | 0x00 | 部分机型这里是定时等扩展位 |
| Byte 4 | 摆风/扫风 | 0x41 | 控制上下摆风和左右摆风 |
| Byte 5 | 校验/固定值 | 0x00 | 有的机型是校验和,有的固定不变 |
模式和风速编码规则如下(示例):
| 功能 | 选项 | 编码 |
|---|---|---|
| 模式 | 自动 | 0x00 |
| 模式 | 制冷 | 0x10 |
| 模式 | 除湿 | 0x20 |
| 模式 | 制热 | 0x30 |
| 模式 | 送风 | 0x40 |
| 风速 | 自动 | 0x00 |
| 风速 | 低风 | 0x01 |
| 风速 | 中风 | 0x02 |
| 风速 | 高风 | 0x03 |
温度编码相对直观,一般是“设定温度减去基准值”。美的很多机型基准是17℃(也有16℃或18℃),比如26℃对应0x09,30℃对应0x0D。这个基准值可以通过抓码对比几组不同温度的遥控信号推算出来,比如我抓到的26℃对应0x09,27℃对应0x0A,那基准就是17℃没跑了。
2.3 用红外接收头抓码验证协议
光看协议表格还不够,关键是要自己抓到一组真实数据做验证。抓码需要的硬件非常简单:一个VS1838B红外接收头,三个引脚分别是VCC(接3.3V或5V)、GND、OUT(信号输出,接ESP8266的某个GPIO)。
我用Arduino框架写了一段简单的脉宽采集程序,原理就是不断读取引脚电平变化时间,把高电平和低电平的持续时间记录下来,然后通过串口打印出来。核心代码如下:
#define IR_PIN 14 void setup() { Serial.begin(115200); pinMode(IR_PIN, INPUT); attachInterrupt(digitalPinToInterrupt(IR_PIN), handleInterrupt, CHANGE); } volatile unsigned long lastTime = 0; volatile bool printing = false; void handleInterrupt() { if (printing) return; unsigned long now = micros(); unsigned long duration = now - lastTime; lastTime = now; Serial.print(duration); Serial.print(","); } void loop() { if (Serial.available()) { char c = Serial.read(); if (c == 's') { printing = false; lastTime = micros(); Serial.println("START"); } if (c == 'e') { printing = true; Serial.println(); Serial.println("END"); } } }这个程序的逻辑很简单:电平每次跳变都会触发中断,记录下上一次跳变到这次跳变的时间间隔,也就是当前电平的持续时间。串口输出的就是一串以微秒为单位的电平脉宽序列。
拿到原始脉宽之后,我用Python脚本快速把数据转换成0和1的序列。判断规则是:脉宽在560us附近的高电平记作一个数据位,随后跟着的低电平如果也是560us左右就是逻辑0,如果低电平持续到1690us左右就是逻辑1。把连续的数据位按8位一组切分,就能还原出每一帧的字节内容。
这里有个小技巧:抓码时最好把遥控器对准接收头,距离控制在10到30厘米,环境中不要有强红外干扰源,比如阳光直射或白炽灯。多按几次同一按键,对比几组数据是否一致,能有效排除偶然的抓取错误。
3. 硬件搭建与电路连接
3.1 元器件清单与选购建议
这个项目的硬件成本非常低,如果手头有现成的核心板,总花费可以控制在20元以内。我用到的元器件清单如下:
| 元器件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| ESP8266开发板 | NodeMCU或Wemos D1 mini | 1 | 选带USB口方便烧录 |
| 红外发射管 | 940nm,5mm直插 | 1 | 必须选红外波段,不能拿普通LED |
| 红外接收头 | VS1838B | 1 | 抓码和调试用 |
| NPN三极管 | S8050或2N3904 | 1 | 放大驱动电流 |
| 电阻 | 1kΩ、100Ω各一只 | 2 | 基极限流和发射管限流 |
| 面包板/洞洞板 | 通用 | 1 | 前期调试推荐面包板 |
这里特别提醒一句:红外发射管必须选940nm波段的。有些商家把普通的紫光LED也标成“红外”,买回来你肉眼能看到微微的光,但空调根本收不到。判断方法很简单:用手机摄像头对着发射管,按下发射时屏幕上能看到明显的白色或淡紫色光点,那就是正常的红外光。因为手机摄像头传感器能感知红外波段,人眼却不敏感。
3.2 红外发射电路设计要点
ESP8266的GPIO输出能力有限,直接推红外发射管的话,实测距离通常只有半米左右,放在空调附近勉强能用,但如果想嵌入式安装到天花板或者墙壁开关盒里,信号衰减就很明显。所以我加了S8050三极管做电流放大,电路结构如下:
GPIO4引脚通过1kΩ电阻连接到S8050基极,S8050集电极接红外发射管负极(阴极),发射管正极(阳极)通过100Ω限流电阻接5V,S8050发射极接地。GPIO为高电平时,三极管导通,红外管以接近满额电流工作,发射距离可以提升到8米甚至更远,视具体发射管功率而定。
电路连接注意两点。第一,限流电阻的阻值决定发射管工作电流,5V供电下100Ω大概能让电流稳定在30到40mA,对普通小功率红外管来说比较安全。如果嫌距离还不够,可以换1W以上的大功率红外管,但那时候就要重新计算限流电阻了。第二,三极管基极电阻不能省,它是用来限制基极电流的,省掉的话三极管可能进入过饱和状态,反复开关容易损坏GPIO口。
还有个GPIO选择问题。ESP8266的GPIO0、GPIO2、GPIO15在启动时分别有特殊作用,GPIO0和GPIO2在上电时如果被拉低会导致ESP8266进入烧录模式,GPIO15必须保持低电平才能正常启动。所以红外发射这类对时序没有严格要求的信号,我建议优先选GPIO4或GPIO5,这两个引脚在启动阶段没有特殊要求,而且没有默认占用,接线方便。
3.3 供电与布局的实战心得
整个系统供电我建议直接用一个5V/1A以上的USB充电头带。ESP8266的板载稳压芯片会把5V转成3.3V给芯片供电,而红外发射管直接吃5V,这样电压裕量比较充足。
实测下来有个坑:如果供电用的是电脑USB口,可能会因为瞬间电流需求导致电压跌落,ESP8266当场重启或者Wi-Fi掉线。我曾经为了图省事用充电宝供电,结果空调一开机(红外连续发码几毫秒),ESP8266就重启,折腾了一上午才定位到问题。后来换了一个质量正常的5V/1A充电头,问题彻底消失。
布局方面,如果是要长期使用,不建议用面包板,震动和氧化都会引起接触不良。我最终把电路焊在了一块2cm×4cm的洞洞板上,用一个塑料外壳装起来,贴在空调侧面进风口附近的墙体上。注意不要让红外发射管正对空调的金属外壳,红外会被金属反射损耗;尽量让发射管朝向空调室内机的接收窗口位置,一般在右下角面板后面。
4. 固件开发:从抓码到发码
4.1 用IRremote库还是自己写时序
Arduino生态有两个常用红外库:IRremote和IRMP。IRremote对NEC协议的解析非常完善,支持接收和发送。但美的空调这种48位自定义帧,IRremote默认的decode结果里只会显示一个原始RAW数据数组,直接用它来“回放”没问题,要在逻辑层面修改温度字段就绕远了。
我最终的方案是:抓码阶段用IRremote库快速拿到RAW数据,发送阶段自己写一个简短的NEC发送函数。这样既能验证码值,又能灵活构建自定义帧。
4.2 发送48位自制帧的核心函数
自己写发送函数其实并不复杂。核心就是根据NEC的时序,把每一个bit变成对应的高电平和低电平组合,最后通过GPIO控制红外管通断。发送逻辑如下:
#define IR_LED_PIN 4 void sendIRBit(bool bit) { digitalWrite(IR_LED_PIN, HIGH); delayMicroseconds(560); digitalWrite(IR_LED_PIN, LOW); if (bit) { delayMicroseconds(1690); // 逻辑1:长低电平 } else { delayMicroseconds(560); // 逻辑0:短低电平 } } void sendMideaFrame(uint8_t data[], int len) { // 发送引导码:9ms高电平 + 4.5ms低电平 digitalWrite(IR_LED_PIN, HIGH); delayMicroseconds(9000); digitalWrite(IR_LED_PIN, LOW); delayMicroseconds(4500); // 逐字节发送,LSB first for (int i = 0; i < len; i++) { for (int j = 0; j < 8; j++) { bool bit = (data[i] >> j) & 0x01; sendIRBit(bit); } } // 结束位:一个短高电平 digitalWrite(IR_LED_PIN, HIGH); delayMicroseconds(560); digitalWrite(IR_LED_PIN, LOW); }这个函数是按流传的NEC时序写的,在多个美的机型上验证过。使用方法是先把帧装进一个数组,再调用sendMideaFrame。举个例子,假设我需要发“开机、制冷、26℃、自动风速”这条指令,帧字节是{0xAA, 0x24, 0x60, 0x00, 0x41, 0x00},调用方式如下:
uint8_t acOnCool26[] = {0xAA, 0x24, 0x60, 0x00, 0x41, 0x00}; sendMideaFrame(acOnCool26, 6);4.3 温度字段的动态构建
空调控制不可能只发一组固定码,所以需要写一个帧构建函数,根据参数动态拼字节。温度编码逻辑我在2.2节已经讲过,是“设定温度减基准值”,基准值需要用抓码结果确定。以我自己的机器为例,26℃对应0x09,27℃对应0x0A,基准就是17℃。动态构建函数可以写成这样:
uint8_t buildMideaFrame(uint8_t mode, uint8_t fan, uint8_t tempC, bool powerOn) { uint8_t data[6] = {0}; data[0] = 0xAA; // 固定帧头 // 高4位是开关信号,低5位是模式 data[1] = (powerOn ? 0x80 : 0x00) | (mode & 0x0F); // 温度基准是17℃,低4位是风速 data[2] = ((tempC - 17) << 4) | (fan & 0x0F); data[3] = 0x00; // 保留 data[4] = 0x41; // 摆风等固定值 data[5] = 0x00; // 部分机型校验 return data[6]; // 为了方便说明,简化了返回方式,实际建议用指针或引用 }实际工程中更好的做法是把数据存在一个全局数组里,函数内部逐位修改,再通过发送函数发出去。这里只是展示一个逻辑,帮助理解帧结构。
我踩过的一个坑是:模式字段和开关字段在不同机型上的位置可能不一样。有些机型开关是单独的bit,有些机型模式字段的高四位就是开关,还有一部分机型制热或者除湿模式下会有额外的防冷风字节。所以,千万不要默认所有美的空调的帧结构都和我的一样,一定要拿自己的遥控器抓几组不同状态下的码,做一下对比分析再写入逻辑。
4.4 MQTT通信与串口调试
固件只负责发红外还不够,它需要接收来自Home Assistant的控制指令。最简单的方案是通过MQTT。ESP8266连接Wi-Fi后,订阅一个主题,比如home/AC/set,收到消息后解析JSON,提取温度、模式、风速等字段,然后调用sendMideaFrame发送红外码。用ArduinoJson库解析JSON非常方便:
#include <ArduinoJson.h> #include <PubSubClient.h> void callback(char* topic, byte* payload, unsigned int length) { StaticJsonDocument<128> doc; deserializeJson(doc, payload, length); uint8_t mode = doc["mode"] | 0; uint8_t fan = doc["fan"] | 0; uint8_t temp = doc["temp"] | 26; bool power = doc["power"] | true; // 构建帧并发送 uint8_t frame[] = {0xAA, 0x24, 0x60, 0x00, 0x41, 0x00}; frame[1] = (power ? 0x80 : 0x00) | (mode & 0x0F); frame[2] = ((temp - 17) << 4) | (fan & 0x0F); sendMideaFrame(frame, 6); }串口调试也非常重要。我习惯在每条指令处理后往串口打印一份十六进制帧数据,比如发送之前打印“SEND: AA 24 60 00 41 00”,这样如果空调没反应,能首先确认固件这边生成的码有没有问题,不用每次都把矛头指向硬件。
5. Home Assistant集成实践
5.1 用ESPHome替代自写固件
我起初是用Arduino + MQTT自写固件接到HA的,功能没问题,但HA侧要做一堆template switch和自动化。后来发现ESPHome对红外发射的场景支持得非常好,而且和HA原生集成,状态同步和重连逻辑都省了,于是就把固件整体换成了ESPHome。
ESPHome里使用红外发射只需要两步。第一步定义remote_transmitter,指定GPIO引脚和载波占空比:
remote_transmitter: pin: GPIO4 carrier_duty_percent: 100%carrier_duty_percent控制红外载波的占空比,100%意味着载波全开,发射功率最大。有的接收头对占空比敏感,如果距离近但信号不稳,可以试着调整这个参数,常见值有50%和100%。
第二步就是通过按钮或脚本触发红外码。ESPHome的remote_transmitter组件支持transmit_raw动作,可以直接把抓码得到的脉宽数组填进去。我之前抓到的开机制冷26℃的脉宽数组,在ESPHome里配置成按钮是这样:
button: - platform: template name: "AC Power On Cool 26" on_press: - remote_transmitter.transmit_raw: carrier_frequency: 38kHz code: [8950, -4450, 550, -550, 550, -1650, 550, -550, ...]transmit_raw的code数组是成对出现的,正值代表高电平持续时间(微秒),负值代表低电平持续时间。用IRremote库抓到的RAW结果可以直接复制到这里,非常方便。
5.2 HA自动化与温度联动
按钮这种单体控制方式只能手动点,要真正实现“温度联动”,需要在Home Assistant里做自动化。我这里的方法是用input_number创建“目标温度”,再用自动化监听目标温度变化,变化时调用ESPHome实体发送对应温度的帧。
具体来说,HA侧新建一个input_number:
input_number: ac_target_temp: name: 空调目标温度 min: 17 max: 30 step: 1 unit_of_measurement: "°C"然后创建一个automation,监听这个input_number的变化。一旦变化,根据当前设定模式、风速和新的目标温度,组合出对应的红外码并触发发送。由于ESPHome已经内置了所有温度档位的码值raw数组,我直接在automation里用choose匹配温度值,对应触发不同的ESPHome按钮实体。
这里有个更聪明的做法:如果不想在ESPHome里写一大堆按钮,可以把码值用script的形式保存在HA里,在自动化里直接调用script,脚本再通过mqtt或者ESPHome的native API发送。这样HA就是唯一的逻辑层,ESP8266只需要做“收到指令就发红外”这一件事,维护起来更清晰。
我自己最后采用的是:HA侧写了一个Python脚本(用HA的python_script集成),输入参数是温度、模式、风速、开关,脚本内部拼出帧字节数组,然后调用ESPHome的raw发送服务。好处是拼帧逻辑集中在HA里,空调品牌换了或者码库更新,只改一个脚本就够了。
5.3 单向控制的现实问题与解决方案
红外控制是单向的,也就是说ESP8266把码发出去了,空调到底有没有执行,我们是不知道的。空调的显示屏上显示26℃,但实际室温可能是30℃,这是所有红外方案都绕不开的物理限制。
解决思路是把“期望状态”和“实际状态”分开管理。HA里所有空调相关的实体,比如开关、目标温度、模式,都是“期望状态”。当自动化触发设置温度后,HA侧相应实体立即更新,后续所有联动都基于这个期望状态。至于实际室温,则通过一个独立的温湿度传感器来感知。
我在客厅放了一个基于zigbee的温湿度计,然后写了一条自动化:当室温高于目标温度2℃且空调处于制冷模式时,把目标温度调低1℃。实测下来,整个房间的温度波动能控制在±1℃以内,比原来用遥控器手动调的体验好太多。
另外一个常见问题是:空调关机状态和待机状态的码可能不同。美的部分机型的关机码是一段独立的48位帧,不能简单用开机帧关掉某个位来模拟。这个必须在抓码阶段就另外抓关机键的码,单独存储、单独发送,否则会出现“按了关机但空调还在吹风”的诡异情况。
6. 常见问题与排查实录
6.1 空调完全没反应怎么排查
这是新手最常遇到的问题。我的排查顺序是:先确认红外管是否真的发光(手机摄像头看),再看RAW数据是否完整,最后查载波频率。
红外管不发光,基本就是接线问题或者GPIO引脚定义错了。这个时候先用一个最简单的Blink程序控制GPIO4闪起来,用万用表量引脚电压,排除代码问题之后再把发射管接上。
红外管发光但空调没反应,最可能是码值不对或者载波频率不对。载波频率可以在代码里设置成36kHz、38kHz、40kHz分别试一下,有些老的接收头对33.3kHz也有响应。我试过一台老机子对38kHz完全无视,换成36kHz就好了,所以这个参数值得多试几个。
最后还要检查帧末尾的结束位。NEC标准的结束位是一个560us高电平,但部分美的是发送完最后一帧后还会跟一个额外的低电平脉冲。如果抓码时没抓到完整帧,可以试试在RAW序列后面追加一个560us高电平再补一个几毫秒的低电平。
6.2 红外发射距离不够怎么办
距离不够几乎全是驱动电路的问题。GPIO直接驱动的话,发射管电流通常只有几毫安,红外光功率太低。加了S8050放大之后,电流能到30至40毫安,距离立刻提升。如果还不够,可以考虑两个办法:一是用两个红外发射管串联,配一个更小的限流电阻,增加总光功率;二是在发射管前面加一个半球形的透明树脂透镜,聚光效果对距离提升非常明显。
另外要注意发射管和接收头的角度问题。红外接收头有一个接收角度范围,通常在15到30度左右。发射管正对接收头的时候效果最好,偏一点就会明显衰减。实际安装时,可以用一个小万向支架或者热熔胶固定发射管,现场调节角度,直到空调能稳定响应为止。
6.3 抓码数据不稳定、时有时无
抓码时数据不稳定,大部分情况是环境红外干扰,或者接收头距离太远信号太弱。我把接收头用热缩管套住,只留正面进光,干扰就小了很多。另外,抓码时接收头离遥控器保持10到20厘米,不要贴着,太近反而会因为信号饱和导致脉宽失真。
还有一个容易忽略的点:很多遥控器按键有长按连续发送机制。按一下,遥控器会发送2到3遍同样的帧。抓码时如果没注意,会把连发的间隙也一起记录下来。我的处理方法是,抓码串口输出后,对比脉冲间隔,如果遇到超过10ms的空隙,就认为是两帧之间的分界,只保留第一帧的完整数据。
6.4 ESP8266发码时死机或重启
这个问题的根源几乎都是供电不足或电磁干扰。红外发射管瞬时电流比较大,如果ESP8266和发射管共用同一个3.3V稳压器,发码瞬间电压被拉低,芯片就会重启。
解决方案是:红外发射管供电直接从5V输入取,不经过板载稳压;ESP8266的3.3V只供芯片自身。5V入口加一个100uF以上的电解电容,用来吸收瞬时电流。我用的是470uF电容,实测发码瞬间电压跌落控制在0.1V以内,再没出现过重启。
如果ESP8266频繁重启的同时Wi-Fi信号也不稳定,大概率是供电问题叠加了Wi-Fi启动电流。这时候可以检查一下USB线质量,劣质数据线内阻大,供电本来就弱,再加上红外瞬态电流就直接崩了。我之前遇到的一个重启问题,最后换了一根短粗的USB线就好了,和固件一点关系都没有。
6.5 状态同步和使用中的实用建议
Home Assistant里如果做了很多自动化,状态同步的坑主要出在“手动按遥控器”这件事上。你用手机把空调设成了26℃,转头又拿起遥控器调成了22℃,HA里的目标温度实体还显示26℃,后续的自动化就会基于错误的状态执行。
解决思路有两个。一是物理隔离:把遥控器收起来,家里统一用HA或者手机控制。二是增加一个红外接收头,让ESP8266实时监听遥控器发出的码,解析后反向更新HA状态。第二种方案实现起来比较复杂,因为监听前后可能需要区分自己发出的码和遥控器发出的码,但如果你家里有其他人习惯使用遥控器,这可能是唯一妥善的办法。
我实际采用的办法比较简单粗暴:保留遥控器,但空调的自动温度调节只基于真实室温传感器,不依赖HA里的目标温度。这样即使状态不一致,自动化的核心逻辑也不会跑偏。
7. 写在最后的一点体会
这套ESP8266红外控制方案做完,最大的收获不是省了遥控器的钱,而是理解了一件事:老设备联网,真正的门槛往往在“翻译设备语言”这一步。红外协议看起来复杂,实际拆开之后就是一连串精确计时的高电平和低电平,就像摩尔斯电码一样。一旦把协议弄明白了,你能做的事情就远远不止控制空调——电视、风扇、投影仪、电动窗帘,凡是手里有红外遥控器的东西,都可以用这套逻辑接进Home Assistant。
个人建议,如果你准备动手做,第一步一定是先抓码,不要急着画板、写HA自动化。用面包板加杜邦线把接收头和发射头搭出来,花半天把遥控器所有按键的码抓全、整理成表,这比后面任何一步都重要。码值准了,后面全是顺水推舟的事。
最后再分享一个小技巧:抓码表格建议直接用CSV文件记录,字段包含按键名、模式、温度、风速、RAW数组。后面写HA脚本的时候,直接读取CSV就能动态生成按钮和脚本,不用在代码里硬编码每一个码值。这个习惯帮我省了不少维护的功夫,你大概率也用得上。