小米(绿米)网关局域网通信协议中,网关采用UDP组播方式上报终端设备心跳及状态。目前家里有一些米家的设备,通过绿米的空调伴侣网关接入HA。由于docker对网络隔离,容器在桥接模式下是无法收到宿主机的组播包,查找过文档没找到能映射组播端口的方法。所以自从Home Assistant迁移到docker环境运行后,只能设置容器网络为host模式来解决这个问题,但一来容器间无法用容器名互访影响统一编排管理,二来容器共享主机网络也有一定安全隐患,所以做了这个,测试下来效果不错。
0. 插件说明
- 概述
- 原理很简单,在局域网主机使用agent采集UDP组播消息,封装为TCP发送给Home Assistant插件,插件再还原为UDP组播消息发送到容器本身网络空间。
- 小米(绿米)网关[UDP组播] —> 局域网主机(agent)[TCP] —> HA容器(本插件)[UDP组播] —> HA容器(xiaomi_aqara网关插件)
- 下载地址
1.环境
- Ubuntu 20.04(部署采集程序)
- Docker 19.03.15
- Home Assistant 2021.5.4
2.使用说明
2.1 启用Home Assistant插件
假设Home Assistant宿主机为192.168.1.100,映射服务端口为4321
- 下载HA插件,
xiaomi_gateway_proxy
目录放置在{HA配置目录}/custom_components/
下。 - HA配置启用xiaomi_gateway_proxy插件。
1
2
3# 在 configuration.yaml 添加
xiaomi_gateway_proxy:
port: 4321 # 通信端口,不指定默认4321 - docker宿主机将插件通信端口映射出来。
1
2# docker run方式,增加-p 参数
docker run -p 4321:4321/tcp [省略...]1
2
3
4
5
6
7# docker-compose方式,增加ports设置
[省略...]
services:
homeassistant:
[省略...]
ports:
- 4321:4321/tcp服务端口
插件作为服务端,需提供服务端口给采集程序连接。
2.2 部署采集程序
在和网关同一局域网的机器上部署,采集程序需要python环境运行,一般linux系统已经自带。如果使用windows部署,可编写bat放到计划任务启动执行,具体方法自行搜索。
下载
xiaomi_gateway_proxy_agent.py
,假设放置在/opt/homeassistant
下。启动采集程序,脚本目录、HA宿主机ip、HA插件服务映射端口根据实际调整
1
python3 /opt/homeassistant/xiaomi_gateway_proxy_agent.py --host 192.168.1.100 --port 4321 >/dev/null 2>&1 &
调试建议
可以不加
>/dev/null 2>&1 &
参数,在前台运行看下输出是否有异常。启用开机启动服务(有些linux已启用,可跳过该步骤)
1
2
3
4
5
6
7
8
9touch /etc/rc.local
chmod +x /etc/rc.local
cat /lib/systemd/system/rc-local.service | grep Install || \
cat >> /lib/systemd/system/rc-local.service << EOF
[Install]
WantedBy=multi-user.target
Alias=rc-local.service
EOF
systemctl enable rc-local.service开机启动
以上为Ubuntu配置方法,其它发行版本可能有差异,具体请自行搜索。
编辑/etc/rc.local添加启动脚本
1
2
3
4
5
6
7
8
9
10
11
# 脚本目录、HA宿主机ip、HA插件服务映射端口根据实际调整
# python2版本使用这个
# python /opt/homeassistant/xiaomi_gateway_proxy_agent.py --host 192.168.1.100 --port 4321 >/dev/null 2>&1 &
# python3版本使用这个
python3 /opt/homeassistant/xiaomi_gateway_proxy_agent.py --host 192.168.1.100 --port 4321 >/dev/null 2>&1 &
# 新建的文件不能忽略这个
exit 0
3. 小结
- HA的网关插件需要提取组播通信包的源IP信息,一开始使用udxpy作为采集客户端,发现无法传递源IP信息,所以写了python版本的采集程序。
- 设想过另一种解决方案是将宿主机和容器做IP隧道直接转发UDP组播,感觉实现比较复杂暂没深入研究。