家里的开关没有预留零线又不想用那种24小时通电的单火线开关, 遂想起用那种简单的舵机按压开关的"手指机器人"来控制灯光. 但是某宝上这种东西如果带接入米家功能的话, 需要100多, 拼夕夕上也得大几十上百. 花这个钱整个这种东西还不如换个智能开关了, 不理解这些卖家是怎么个定价逻辑.😒既然这么贵还不如自制
在拼夕夕上能找到的这种"关灯神器"最便宜的是红外遥控控制的, 只需要不到10块钱. 那么只需要把这个红外遥控接入home assistant, 那它不就有了嘛!
在网上搜了搜, 发现有B站UP主在专栏里推荐了一款廉价的基于ESP8266的红外控制器欧瑞博 CT30W, 只需要8块钱! 去咸鱼上可以找到8块钱一个的, 付运费的话15块左右, 或者买5个包邮. 这样总体上这套方案只需要20块钱左右即可. 然后开始改装
拆机
这个玩意的卡扣确实挺紧的, 拆开肯定要破坏掉外观了. 我是用刀片和螺丝刀配合把它打开的.
- 先在外观上找到充电口, 然后在充电口垂直的地方, 也就是图中绿色的地方, 用刀把那个地方的底座削出来一条稍大一些的缝.
- 然后把平头螺丝刀捅进去开始撬. 图中绿色那个卡扣是一个口字形的, 只要一字螺丝刀插到那个口里面去, 这个玩意基本上就撬开了.
编程
我是用的这篇博客的作者的代码进行了二次修改. 这位作者的代码是一个空调控制器, 基本上把里面的控制组件删掉, 只留一个switch
组件就可以了. 但是我这边是双控开关, 所以我还加了一个"反向"开关, 用来切换旋转的方向.
红外协议
因为源代码是一个空调控制器, 作者直接使用了IRremoteESP8266
库中的空调控制协议. 但是我这个是一个不知道什么私有协议的DIY控制器, 所以需要dump出来遥控器的红外信号.
原代码里面打印红外信号的代码如下所示, 它打印出来的东西我是没看懂, 所以还得改一改.
```c++ decode_results results; if (id(ir_dump_pin).state && id(irrecv)->decode(&results)) { if (results.overflow) ESP_LOGW("ir_dump", "Buffer is full"); ESP_LOGI("ir_dump", "%s", resultToTimingInfo(&results).c_str()); }
查一查`decode_results`[^1] 的函数定义,
```c++
union {
struct {
uint64_t value
uint32_t address
uint32_t command
}
uint8_t state [kStateSizeMax]
};
可以看到解码出的红外信号里有一个value
字段. 将这一字段输出来查看红外的信号值.
interval:
- interval: 100ms
then:
- lambda: |-
decode_results results;
if (id(ir_dump_pin).state && id(irrecv)->decode(&results)) {
if (results.overflow) ESP_LOGW("ir_dump", "Buffer is full");
ESP_LOGI("ir_dump", "-> value = %s addr = %d command = %d decode_type = %d", uint64ToString(results.value, HEX), results.address, results.command, results.decode_type);
}
按照文章里介绍的编译方式编译固件, 然后给红外控制器刷写固件. 之后按住电源插口旁边的按钮, 将红外遥控器对准红外接收管并一一按下按钮, 可以看到它打印出了红外的值和解码的协议类型.
# on按钮
value = FF906F addr = 1242 command = 1 decode_type = 3
# off按钮
value = FF807FF addr = 1242 command = 1 decode_type = 3
查阅IRremoteESP8266的文档和源代码, 可以看到decode_type
值为3时对应的是NEC协议. 之后使用sendNEC
函数发送这两个值即可模拟两个按钮了
#.....
on_boot:
priority: -100
then:
- lambda: |-
id(ac) = new IRsend(id(ir_send_pin));
id(ac)->begin();
#.....
globals:
- id: ac
type: IRsend *
restore_value: no
initial_value: "NULL"
#.....
button:
- platform: template
name: Rotate Right
id: clockwise
# friendly_name: 顺时针转动
# Optional variables:
icon: "mdi:rotate-right"
web_server:
sorting_weight: 0
on_press:
- lambda: |-
if (id(ac)) {
// id(ac)->on();
id(ac)->sendNEC(0xFF807FUL);
}
- platform: template
name: Rotate Left
id: anticlockwise
# friendly_name : 逆时针转动
# Optional variables:
icon: "mdi:rotate-left"
web_server:
sorting_weight: 1
on_press:
- lambda: |-
if (id(ac)) {
// id(ac)->on();
id(ac)->sendNEC(0xFF906FUL);
}
这两个按钮是调试用的. 为了实用还是做一个"开关"组件, 分别为开关组件的"开"和"关"绑定两个值即可.
展望
这个红外控制器还有几个悬空的GPIO引脚. 也许可以通过飞线的方式把这几个引脚接到射频模块上, 打造成一个集红外和射频为一身的"全能遥控器".
如果能实现的话再继续更新吧.