极米投影仪遥控协议浅析

起源

家里有台极米(XGIMI)Z6X投影仪,需求其实很简单,就是平常需要开关机的时候,老是去找遥控器很烦。 所以就想通过语音或者什么去方便的操控他。因为用的苹果手机,自然的思路就是“捷径”,但是发现极米的遥控协议颇为复杂。一番折腾终于实现,这里分享一下。

关机

关机的话,网上搜到的资料相当完善了,简单来说就是投影仪在Wifi上兼听UDP 16735端口,可以通过直接向该端口发送“KEYPRESSES:116”来实现和遥控板电源键的相同效果。当然KEYPRESSES后面还可以跟其他代码,实现遥控器上几乎所有按键,但是我也没用到。

开机

开机就没这么简单,主要原因是设备处于关闭状态时,Wifi断联,并能通过UDP来开机。大致的解决思路有两种,一种是,每次关机都使用”关光机“选项,只关闭投影灯泡,不关闭计算机。但是这种模式需要改变自己的习惯,如果顺手用遥控器关了,就打不开,很不方便。

另一种方式就是直接模拟遥控器的信号。一番搜索了解到,遥控器采用的是直接低功耗蓝牙(BLE)广播的方式,唤醒投影仪,接下来要做的,就是抓到这个蓝牙包,然后用树莓派重放。

抓包

抓包我试了两种方式,感觉结合起来会更好用。一是一个叫nRF Connect的iOS app(Android好像也有),他可以抓取到周围的广播包,界面很友好,但是提取包内容不太方便。 还有一个就是用树莓派(或者电脑也行)的蓝牙模块,使用Python的bleak包,抓包。需要注意的是,BLE广播可能是出于低功耗的考虑,是个很直接的广播,除非用很专业的设备,否则单次广播被抓到的概率并不高,需要多次尝试。我大概抓了10次左右,才拿到了正确的包。同时也需要一些基本的BLE广播包的知识,来筛选包的内容。

重放

重放就像对简单了,用btmgmt来设置广播。之前也尝试了hcitool和hciconfig,但是不太成功。简单用Rust写了个REST service,方便捷径调用。我是把它运行在树莓派上的,然后手机只要调用树莓派就行,UDP的功能也由树莓派代劳。相关代码共享在Github上。

BLE协议分析

我实际抓取到的BLE包格式大概是 0201060303121813FF460002675544332211FFFFFF77889900AABB的样子 简单介绍下BLE的广播包内容。每个BLE广播包最长只能有31个字节,可以包含若干段,称为AD(Advertising Data),每段两字节段头,包括一字节的长度,一字节的类型。后面跟着具体的数据 简单分析一下可以分成三段 02 01 06 数据2字节长,01代表Flag,包含设备特性,06是具体内容

03 03 1218 数据3字节长,03代表Service UUID List,表示设备支持那些服务,后面的1218代表HIC,也就是鼠标键盘一类的输入输出设备

13 FF 4600 02 675544332211 FFFFFF 77889900AABB 数据13字节长,FF代表厂商自定义的数据,也就是没有明确的文档告诉我们他代表什么,可以知道的是4600代表硬件厂商,nRF。 02不确定。 后面的675544332211与投影仪的无线MAC高度相似,但是67那一位加了了1。也就是说如果投影仪无线MAC是11:22:33:44:55:66,那么BLE中这段就是675544332211。 后面FFFFFF似乎是固定的,留作扩展? 77889900AABB内容也不明。

另一个有意思的内容是,这个遥控器实际上会在开机时先广播上面的广播包,然后几秒钟之后,有会把自己当做一个正常BLE设备,广播自己的名字等参数。感觉广播部分纯粹是为了触发开机。然后后面的包则跟投影仪正常链接,可能其他案件是通过BLE连接后的单播实现的,并不是每个按钮都会广播。也因为这个,抓包就更难一点,有可能抓到的是后面建立BLE连接的包,需要注意区分。

总结

这一通设置结束之后,就使用捷径配合Siri实现语音开关投影仪了,实在是方便太多了。