背景
小米空调伴侣可以控制家里的空调。通过米家 APP 开关和设置,也可以在上面设置定时。在南方湿冷的冬天,早上起床前自动把房间的空调开起来,床再也不会赖着我了。有很长的一段时间,我是这么用的。但是有几次出门,完全不记得空调会自动开。于是回家后发现空调一直开着…。于是就有了这篇博客的内容。能不能只有我在家的时候空调才自动开?
思路和实现
研究了一下,米家 APP 原生提供的功能似乎无法满足这个需求。不通过米家 APP 能不能做到呢?把这个拆分为两个问题:
- 怎么控制空调?
- 如何判断我在不在家?
如何控制空调
首先想到的是通过小爱同学,可以录好“小爱同学,开空调”,“小爱同学,关空调”这类音频。通过播放音频触发小爱同学来控制。也可以写一段代码来给空调伴侣发送开机命令。考虑到语音控制的准确性,另外突然播放一段音频可能也挺奇怪的。还是决定通过代码来控制。最后选择用 python-miio 来实现。
想要通过 miIO 协议来控制米家设备,需要先获取到设备的 ip 和 token。这个脚本可以从小米服务获取账号下所有设备的 token 等信息。
1 | $ curl -LO https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor/raw/master/token_extractor.py |
获取到空调伴侣的 ip 和 token 之后,就可以通过 miIO 来控制设备(见文末代码)。
如何判断我在不在家
最简单的办法可能就是通过判断自己的手机有没有连接家里的 WI-FI。想到可以 ping 手机的 IP,最后看退出状态码是不是 0。
1 | $ ping -c 3 192.168.2.146 |
-c
参数指定发送 n 个包以后退出。
最终这个效果不是特别好,手机会休眠,休眠以后 ping 可能会失败。特别是早上还没醒,手机可能处于待机状态。ping 可能会失败。既然 ping 不行,就通过路由器的 API 来查询连接的设备吧。不同路由器的接口不同,以家里的小米路由器为例,刷了 openwrt 系统。通过浏览器的开发者工具,来查看路由管理页面的网络请求信息。发现 openwrt 通过一个 /cgi-bin/luci
接口查询设备信息,也包括已经连接到路由器的设备。拿到连接设备列表以后,根据手机的 MAC 地址判断是否在连接设备列表中,就可以知道我是不是在家里了。
1 | def get_devices(): |
定时任务
完成脚本以后,在家里的服务器上,配置一个 cron job。每天早上 06:30 尝试开启空调。同样脚本也实现了当我不在家才关空调的功能。设置一个每天上午 10:00 尝试关空调的任务。
1 | 30 06 * * * /home/eirture/scripts/acpartner/main.py on |
总结
最终通过 miIO 协议发送命令给小米空调伴侣来控制空调。通过查询路由器已连接设备列表中是否有我的手机,来判断我是否在家。cron job 定时尝试开关空调。通过一端时间的使用,感觉还不错。不用担心忘记关空调了。
附上完整的代码: