想起上次做光感+人体感应自动控灯的时候,用aqara无线开关(贴墙式)控灯遇到个小坑:像zigbee墙壁开关,接入空调伴侣后,HA会实例化switch.wall_switch_xxxxxxxx,但没找到无线开关。于是又苦逼去读代码了,还算顺利解决,惯例把解决过程理一理做个总结分享下。
1.环境
- Ubuntu18.04 + HA 0.71.0
- aqara空调伴侣升级版(网关)
- aqara无线开关(贴墙式)
- python模块目录,即/srv/homeassistant/homeassistant_venv/lib/python3.6/site-packages/,后面用{[python模块目录]}代替。
2.过程
Step1
首先查看看HA日志,发现有错误信息:
ERROR (SyncWorker_8) [xiaomi_gateway] Unsupported device found! Please create an issue at https://github.com/Danielhiversen/PyXiaomiGateway/issues and provide the following data: {‘cmd’: ‘read_rsp’, ‘model’: ‘sensor_86sw1’,……
明显是说不支持sensor_86sw1的类型,还注意信息中的“[xiaomi_gateway]”说明是xiaomi_gateway模块。找到{[python模块目录]}/xiaomi_gateway/init.py,可以看到支持的设备类型是在device_types = {}中定义的,我们把sensor_86sw1、sensor_86sw2(双键开关)加进去。
1 | #……省略……# |
Step2
xiaomi_gateway模块只是完成把设备信息和网关关联起来,正式的创建设备是在{[python模块目录]}/homeassistant/components/binary_sensor/xiaomi_aqara.py中实现的。所以打开看里面代码可以看到无线开关是在elif model in [‘86sw1’, ‘sensor_86sw1.aq1’]、elif model in [‘86sw2’, ‘sensor_86sw2.aq1’]里面的,确是没有“sensor_86sw1”,那继续添加。
Tips
单键开关是实例化一个XiaomiButton的,双开关是实例化成三个XiaomiButton的(一个同时按双键触发)。
1 | #……省略……# |
1 | #……省略……# |
1 | ……省略…… |
3.小结
最后简单介绍下我所理解的网关工作流程吧,相关的工作是由{[python模块目录]}/homeassistant/components/xiaomi_aqara.py来完成的。
1)读取配置文件xiaomi_aqara:的信息,初始化网关发现对象XiaomiGatewayDiscovery({[python模块目录]}/xiaomi_gateway/init.py),注意HA也用了全局变量hass.data[PY_XIAOMI_GATEWAY]存储所找到的网关,后续注册设备会用到。
1 | xiaomi = hass.data[PY_XIAOMI_GATEWAY] = XiaomiGatewayDiscovery( |
2)通过udp通信发现、注册网关,同时读取网关的设备列表。这时候,网关对象已经存有设备信息,供后续不同组件(component)注册设备使用。
1 | xiaomi.discover_gateways() |
3)监听udp通信端口,网关接收到数据包会调用push_data()进行解析,再根据数据包中设备sid调用相应设备所定义的push_data()实现对应设备的回调处理。设备的push_data()会再调用parse_data()(不同的设备会定义不同的方法)来更新数据、调用parse_voltage(通用)来更新电量,最后调用async_schedule_update_ha_state()更新状态。这部分是实现和设备的通信。
1 | xiaomi.listen() |
4)调用不同组件(component)的setup_platform注册设备。(好像是通过discovery.load_platform()触发EVENT_PLATFORM_DISCOVERED事件,后续HA自行处理,具体会处理我也没了解。)
1 | for component in ['binary_sensor', 'sensor', 'switch', 'light', 'cover', 'lock']: |