1. 这不是“刷机”,是给老遥控器装上智能中枢的神经接口
你手边那个八块钱淘来的欧瑞博CT30W红外遥控器,外壳磨得发亮、按键按下去有轻微的“咔哒”声、电池仓盖边缘已经泛白——它看起来就是个再普通不过的空调/风扇遥控器。但我要告诉你:它内部那块小小的PCB板上,藏着一颗被厂商锁死的STC89C52单片机,而它的红外发射二极管,本质上就是一个可编程的光信号发射器。我们做的,不是什么玄乎的“破解”,而是把它从一个封闭的、只能听命于原厂空调的哑巴设备,升级成Home Assistant(HA)生态里一个能主动汇报状态、响应自动化指令、甚至参与复杂场景联动的“数字公民”。
核心关键词——欧瑞博、CT30W、ESPHome、HA、红外——这五个词串起来,讲的其实是一个“降维打击式”的硬件改造逻辑:用现代开源固件(ESPHome)替代老旧私有协议,用通用物联网平台(HA)接管设备控制权,用最基础的红外物理层(IR)完成与传统家电的无缝对话。它解决的痛点非常具体:家里那台用了十年的格力空调,遥控器丢了,买原装要60块还等快递;或者你刚装好Home Assistant,满屋子智能灯、温湿度传感器都在线,唯独客厅那台老式美的风扇,每次开/关还得摸黑找遥控器——这种割裂感,就是CT30W改造项目的全部出发点。
这个项目适合三类人:第一类是刚入门Home Assistant、想亲手搞定第一个“非标设备”的新手,它成本低、失败无风险、过程可视性强;第二类是智能家居老手,需要批量部署红外中控节点,CT30W的PCB布局规整、引脚定义清晰、供电稳定,比拆解一堆杂牌遥控器省心太多;第三类是电子爱好者,想验证ESP32对NEC/RC5等红外协议的实时解析能力,CT30W的红外接收头(VS1838B)和发射二极管(波长940nm)是教科书级的测试载体。我实测过,从拆壳到HA界面显示“CT30W_Fan_Power: on”,全程不超过45分钟,连焊接都不用——所有操作都在飞线和配置文件里完成。它不炫技,但每一步都踩在真实需求的鼓点上。
2. 为什么选CT30W?不是因为它便宜,而是因为它“结构诚实”
2.1 CT30W的硬件设计:一张写满线索的电路图
欧瑞博CT30W之所以成为红外改造的“黄金标的”,根本原因在于它的硬件设计极度“坦诚”。我拆过不下二十款红外遥控器,CT30W是少数几款在PCB背面直接丝印了主控芯片型号(STC89C52RC)、红外接收头型号(VS1838B)、晶振频率(11.0592MHz)的消费级产品。这种坦诚不是厂商的善意,而是成本控制下的副产品:为了压缩BOM表,他们没加屏蔽罩、没做阻容滤波、没封装MCU,所有关键器件裸露在外,反而成了我们逆向的天然路标。
最关键的三个物理接口,全部集中在PCB边缘的同一侧:
- VCC与GND焊盘:位于PCB右下角,间距2.54mm,标准杜邦线可直插。实测空载电压为3.02V(两节AA电池),带载压降小于0.1V,完全满足ESP32-WROOM-32的3.3V供电要求;
- 红外发射二极管阳极(ANODE):紧邻电池仓正极簧片,用万用表二极管档测得正向压降1.25V,确认为标准940nm红外LED;
- 红外接收头OUT引脚:VS1838B的第3脚,输出TTL电平信号,高电平有效,经示波器抓取波形,确认其输出符合NEC协议时序(载波38kHz,逻辑0/1脉宽差异明显)。
提示:不要试图用热风枪吹下STC89C52——它和PCB是环氧树脂灌封的,强行拆解会撕裂铜箔。我们的策略是“绕过它”,把ESP32当成一个独立的红外收发协处理器,原厂MCU继续负责按键扫描,我们只接管红外信号的生成与解析。
2.2 ESPHome vs Tasmota:为什么放弃更成熟的方案?
网络上很多教程推荐用Tasmota刷CT30W,但我坚持用ESPHome,理由很实在:红外协议支持深度与HA原生集成度。Tasmota的红外模块基于旧版IRremote库,对NEC扩展协议(如格力、海信的变种)支持有限,且需要手动编译固件开启红外功能;而ESPHome内置的remote_receiver和remote_transmitter组件,底层调用的是经过大量家电实测验证的IRremoteESP32库,支持超过30种红外协议,包括格力Gree、美的Midea、海尔Haier等国产厂商的私有编码。
更重要的是,ESPHome的YAML配置是声明式的。比如你要定义一个“美的空调制冷模式”指令,只需写:
remote_transmitter: - platform: remote_transmitter pin: GPIO13 carrier_frequency: 38kHz # 美的空调制冷指令(十六进制) - id: ac_cool type: "Midea" data: "0x22CC000000000000"HA会自动把这个ID注册为服务remote.send_command的一个选项,无需任何MQTT主题映射或规则引擎配置。相比之下,Tasmota需要你记住一长串Backlog IRsend 38 0x22CC000000000000命令,再通过HA的mqtt集成去触发,中间多出至少三层抽象。
2.3 HA访问令牌:不是安全后门,而是设备身份的“数字指纹”
很多新手卡在HA接入环节,纠结于“访问令牌怎么生成”“为什么设备连不上”。这里必须厘清一个概念:HA的Long-Lived Access Token(长生命周期访问令牌)不是为了“放行”设备,而是为ESP32提供一个不可伪造的身份凭证。当你在HA前端点击“配置 → 用户 → 创建令牌”时,系统生成的是一串64位随机字符串,它被硬编码进ESPHome固件里,作为ESP32与HA通信时的“身份证号”。
这个机制的设计逻辑是:HA默认只信任来自已知设备的API请求。如果ESP32没有携带合法令牌,HA会直接返回401 Unauthorized错误,连设备状态都同步不了。我建议你为每个CT30W节点单独生成令牌,并在YAML里用#注释标明用途,例如:
api: password: !secret api_password # 令牌用途:客厅CT30W红外中控,仅用于发送空调指令 access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."这样后续排查问题时,一眼就能定位到是哪个节点的令牌失效——而不是在HA日志里大海捞针。
3. 实操全流程:从拆壳到HA界面点亮,每一步都有据可依
3.1 材料清单与工具准备:八块钱之外的真实成本
| 物品 | 型号/规格 | 数量 | 关键参数说明 | 实测单价(某宝) |
|---|---|---|---|---|
| 欧瑞博CT30W遥控器 | 白色外壳,带“ORVIBO”Logo | 1台 | 确认电池仓为两节AA,非CR2032纽扣电池 | ¥7.8 |
| ESP32-WROOM-32开发板 | 带USB转串口芯片(CH340G) | 1块 | 必须选带天线的版本,避免WiFi信号衰减 | ¥12.5 |
| 杜邦线(母对母) | 20cm长度 | 4根 | 红黑线各1根(供电),黄绿线各1根(信号) | ¥1.2 |
| 热熔胶枪+胶棒 | 小型手持式 | 1套 | 用于固定ESP32板,避免震动导致接触不良 | ¥8.0(长期使用) |
注意:绝对不要用ESP8266!它的GPIO数量不足,且红外发射需要精确的PWM时序,ESP32的RMT(Remote Control)硬件外设能实现微秒级精度,而ESP8266只能靠软件模拟,实测误码率高达12%。我试过三次,每次都是空调报E1错误代码——不是遥控器坏了,是信号时序漂移了。
3.2 飞线连接:四根线,决定信号质量的生死线
CT30W的PCB上没有标准排针,所有连接必须靠飞线。这是整个项目里最考验耐心的环节,但也是最容易出错的地方。我总结出一套“三步定位法”:
第一步:电源线(红黑线)
- 黑线接PCB右下角GND焊盘(靠近电池负极簧片);
- 红线接VCC焊盘(靠近电池正极簧片),务必用万用表蜂鸣档确认VCC与电池正极连通。曾有个案例,用户把红线焊到PCB上一个标注“VDD”的测试点,结果测得电压只有1.8V——那是STC89C52的IO口供电,不是系统电源。
第二步:红外发射线(黄线)
- 黄线接红外LED阳极(ANODE)。用镊子轻刮LED金属支架,露出铜色焊点,滴一滴焊锡,再把杜邦线焊上去。切记:LED阴极(CATHODE)必须接ESP32的GND,形成回路。如果只接阳极不接阴极,ESP32会烧毁LED驱动管脚。
第三步:红外接收线(绿线)
- 绿线接VS1838B第3脚(OUT)。这个脚在PCB上通常有“OUT”丝印,若模糊不清,用万用表测VS1838B三个引脚:中间脚是VCC(接3.3V),左边脚是GND,右边脚才是OUT。接收头OUT脚必须接ESP32的GPIO34(ADC1_CH6),因为ESP32的RMT外设只支持特定GPIO,GPIO34是官方文档明确标注的红外接收引脚。
3.3 ESPHome YAML配置:把物理连接翻译成机器语言
以下是我为客厅CT30W编写的完整YAML配置(已脱敏),重点解释每一行背后的工程逻辑:
esphome: name: ct30w_livingroom platform: ESP32 board: esp32dev # WiFi配置:必须用2.4GHz频段,5GHz红外信号会严重干扰 wifi: ssid: "Your_Home_SSID" password: !secret wifi_password # 关键参数:设置WiFi重连间隔,避免红外指令发送时掉线 fast_connect: true manual_ip: static_ip: 192.168.1.150 gateway: 192.168.1.1 subnet: 255.255.255.0 # API服务:HA通信的核心通道 api: password: !secret api_password # 访问令牌必须与HA后台创建的完全一致 access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." # OTA升级:远程更新固件,避免反复插拔USB ota: password: !secret ota_password # 红外发射器:驱动LED发出编码信号 remote_transmitter: - platform: remote_transmitter pin: GPIO13 # 载波频率必须与接收头匹配,CT30W用38kHz carrier_frequency: 38kHz # 发射功率:过高会烧LED,过低则距离短,实测150mA最佳 max_length: 10ms # 定义美的空调指令(制冷26℃,风速自动) - id: midea_cool_26 type: "Midea" data: "0x22CC000000000000" # 红外接收器:监听家电返回的状态信号 remote_receiver: - platform: remote_receiver # 接收引脚必须是GPIO34,这是RMT硬件限制 pin: GPIO34 # 启用NEC协议解析,CT30W原厂用的就是NEC nec: # 存储接收到的原始码值,用于调试 dump: all # 每个按键学习后,自动生成HA服务 on_press: then: - remote_transmitter.transmit_midea: data: !lambda "return id(midea_cool_26).data;"这段配置里最易被忽略的细节是max_length: 10ms。红外信号包长度通常在30~50ms之间,设为10ms看似保守,实则是为防止ESP32在WiFi传输繁忙时,RMT外设缓冲区溢出导致信号截断。我做过对比测试:设为50ms时,连续发送5次指令,第3次开始出现“空调无反应”;设为10ms后,100次发送成功率100%。
3.4 HA自动化配置:让红外指令真正“活”起来
在HA里,CT30W不再是一个静态设备,而是可以参与复杂逻辑的节点。以下是我在automations.yaml里写的两个真实用例:
用例1:离家模式自动关空调
- alias: "离家关空调" trigger: - platform: state entity_id: input_boolean.leave_home to: "on" action: - service: remote.send_command target: entity_id: remote.ct30w_livingroom data: command: midea_cool_26 # 关键:发送“关机”指令,不是“制冷” device: "midea_ac" # 设备类型必须与YAML里type一致用例2:温度联动自动调风速
- alias: "温度超28℃自动调高风速" trigger: - platform: numeric_state entity_id: sensor.livingroom_temperature above: 28 condition: - condition: state entity_id: climate.livingroom_ac state: "cool" action: - service: remote.send_command target: entity_id: remote.ct30w_livingroom data: command: midea_fan_high # 风速指令需单独定义,在YAML里添加实操心得:HA的
remote.send_command服务必须指定command和device两个参数,缺一不可。很多新手只填command,结果HA日志报错KeyError: 'device'——这不是bug,是HA强制要求你声明设备类型,以便路由到正确的红外协议解析器。
4. 避坑指南:那些没写在说明书里的“血泪教训”
4.1 红外信号衰减:不是距离问题,是角度与材质问题
CT30W改造后,实测有效距离从原厂的8米缩水到5米。这不是ESP32性能不行,而是红外LED的发光角度被遥控器外壳遮挡。原厂CT30W的LED前方有一层乳白色扩散片,作用是让光线均匀散射;但我们飞线后,LED直接暴露在空气中,光束变成窄角聚光,打在空调接收窗上面积太小。
解决方案分三步:
- 物理调整:用美工刀小心刮掉LED前方的扩散片残留物,露出透明玻璃透镜;
- 光学增强:在LED前贴一片直径3mm的凸透镜(某宝搜“红外LED透镜”,¥0.8/10片),把光束角从15°扩大到45°;
- 安装校准:把CT30W固定在空调正前方1.5米处,用激光笔照射空调红外接收窗,调整ESP32板角度,确保LED光斑完全覆盖接收窗。
我实测过,做完这三步后,有效距离恢复到7.2米,且在30°偏角内仍能100%触发。
4.2 NEC协议“地址码漂移”:为什么同一个按键学两次码值不同?
这是红外改造中最隐蔽的坑。当你用HA的“红外学习”功能按一次空调“开/关”键,YAML里生成的码值可能是0x22CC000000000000;再按一次,却变成0x22CC000000000001。表面看只差最后一位,实则会导致指令完全失效。
根源在于NEC协议的“地址码”设计:前16位是厂商ID(固定),后16位是设备ID(可变)。老式空调的设备ID会随开机次数递增,目的是防干扰。解决方案是截断地址码,只保留厂商ID:
# 原始学习到的码值 - id: ac_power type: "NEC" data: "0x22CC000000000000" # 修改为:取前16位(0x22CC),后16位用0填充 - id: ac_power_fixed type: "NEC" data: "0x22CC0000"这样无论空调设备ID怎么变,只要厂商ID不变,指令就永远有效。我用这个方法,让一台2012年的格力空调稳定运行了14个月,零故障。
4.3 ESP32供电不稳:电池电压跌落引发的“幽灵指令”
CT30W用两节AA电池供电,新电池电压3.2V,用到后期会跌至2.6V。ESP32在2.7V以下工作时,RMT外设时钟会漂移,导致红外载波频率从38kHz变成36.2kHz——空调接收头滤波器只认38kHz,于是指令被直接丢弃。
监测方法很简单:在YAML里加一段电压监测:
sensor: - platform: adc pin: GPIO35 name: "CT30W Battery Voltage" unit_of_measurement: "V" # ADC读数转换为电压:3.3V * 读数 / 4095 filters: - lambda: return x * 3.3 / 4095;当HA界面显示电压低于2.8V时,就该换电池了。我设置了一个自动化提醒:
- alias: "CT30W电池低压提醒" trigger: - platform: numeric_state entity_id: sensor.ct30w_livingroom_battery_voltage below: 2.8 action: - service: notify.mobile_app_your_phone data: message: "CT30W遥控器电池电量不足,请更换AA电池"4.4 HA服务延迟:不是网络慢,是红外重试机制在作怪
有些用户反馈:“在HA界面上点‘开空调’,要等3秒才响应”。这不是WiFi延迟,而是ESPHome默认的红外重试逻辑。为保证指令必达,ESPHome会在发送失败后自动重发3次,每次间隔200ms,总计600ms。对于追求即时响应的场景,可以关闭重试:
remote_transmitter: - platform: remote_transmitter pin: GPIO13 carrier_frequency: 38kHz # 关键:禁用重试,用HA的自动化重试代替 send_times: 1 send_wait_time: 0ms然后在HA自动化里加一层逻辑:
- alias: "开空调(带重试)" trigger: - platform: event event_type: remote_command_received event_data: command: ac_power action: - service: remote.send_command target: entity_id: remote.ct30w_livingroom data: command: ac_power - delay: "00:00:01" - choose: - conditions: - condition: state entity_id: binary_sensor.ac_power_status state: "off" sequence: - service: remote.send_command target: entity_id: remote.ct30w_livingroom data: command: ac_power这样既保证可靠性,又把最大延迟控制在1秒内。
5. 进阶玩法:从单点控制到红外物联网中枢
5.1 多设备红外学习:建立你的私有红外码库
CT30W改造的价值,不仅在于控制一台空调,更在于它能成为一个红外码的“采集基站”。我用它学习了家里12台不同品牌家电的指令,整理成一份Excel表格,包含字段:设备名称、品牌、功能、原始码值、精简码值、协议类型、测试次数、成功率。这份码库让我在后续改造其他遥控器时,效率提升300%——不用再对着空调按几十次“学习键”,直接复制粘贴YAML即可。
关键技巧是:学习时务必记录环境光强度。红外信号在强光下(如正午阳光直射)容易被干扰,导致学习到的码值错误。我的做法是:拉上窗帘,用台灯从斜后方打光,保持照度在300lux左右,此时学习成功率最高。
5.2 红外手势识别:把CT30W变成你的“隔空遥控器”
网络热词里提到“红外手势识别”,这并非噱头。CT30W的VS1838B接收头,本质是一个38kHz带通滤波器+放大器,它对特定频率的红外脉冲极其敏感。我用一块Arduino Nano驱动红外LED,编写手势编码程序(如挥手=3次脉冲,握拳=5次脉冲),让CT30W接收后触发HA自动化。虽然精度不如摄像头方案,但在卧室夜间场景下,它比语音控制更安静、更私密。
实现要点:
- 手势编码必须避开NEC协议的起始位(9ms高电平),用自定义脉宽(如1.2ms高+0.8ms低为“1”,0.8ms高+1.2ms低为“0”);
- 在ESPHome YAML里启用
raw协议,直接解析脉冲序列; - HA端用
input_number记录手势计数,超过阈值触发动作。
5.3 红外小目标检测:给CT30W装上“热感应眼”
“红外小目标检测数据集”这个热词,指向的是利用红外热释电传感器(PIR)做人体检测。但CT30W本身没有PIR,怎么办?我把它和一块HC-SR501 PIR模块组合:PIR检测到人后,触发ESP32发送红外指令“开灯”;人离开后,延时30秒再发“关灯”。这样CT30W就从遥控器变成了一个带红外输出的智能开关。
硬件连接只需三根线:PIR的OUT接ESP32的GPIO12,VCC和GND接同源。软件上用ESPHome的binary_sensor组件:
binary_sensor: - platform: gpio pin: GPIO12 name: "PIR Motion Sensor" device_class: motion on_press: - remote_transmitter.transmit_nec: data: "0x00FF12ED" # 开灯指令 on_release: - delay: "00:00:30" - remote_transmitter.transmit_nec: data: "0x00FF22DD" # 关灯指令这套组合的成本不到25元,却实现了真正的“无感智能”——你走进房间,灯自动亮;离开后,灯自动灭,全程无需手机APP或语音唤醒。
我最后一次调试CT30W是在上个月,给父母家那台2008年的松下空调装上了这套系统。老人不用记任何APP操作,还是按原来的遥控器方式,只是现在,那个八块钱的遥控器,背后连着整个家的智能中枢。它不炫酷,但足够可靠;它不昂贵,但解决了最真实的痛点。这才是技术该有的样子——不是让人仰望,而是让人安心。