可以使用官方的Zigbee2MQTT Docker镜像在Docker容器中运行Zigbee2MQTT。
此镜像支持以下架构:386、amd64、arm/v6、arm/v7、arm64。由于Zigbee2MQTT镜像已列出清单,因此Docker会自动检测架构并拉取正确的镜像。
首先,根据此处的说明确定适配器的位置。
重要提示:使用Raspberry Pi吗?确保查看Raspberry Pi用户的注意事项。
创建初始配置
导航到存储Zigbee2MQTT数据的目录,并执行以下命令:
wget https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/master/data/configuration.yaml -P data
现在,根据此处的说明配置MQTT服务器和适配器位置。
运行容器
执行以下命令,更新--device参数以匹配适配器的位置。
$ docker run \
--name zigbee2mqtt \
--restart=unless-stopped \
--device=/dev/serial/by-id/usb-Texas_Instruments_TI_CC2531_USB_CDC___0X00124B0018ED3DDF-if00:/dev/ttyACM0 \
-p 8080:8080 \
-v $(pwd)/data:/app/data \
-v /run/udev:/run/udev:ro \
-e TZ=Europe/Amsterdam \
koenkk/zigbee2mqtt
参数解释:
--name zigbee2mqtt
:容器名称--restart=unless-stopped
:在启动时自动启动并在崩溃后重启--device=/dev/serial/by-id/...
:适配器位置(例如CC2531)。-v $(pwd)/data:/app/data
:Zigbee2MQTT存储配置的目录-v /run/udev:/run/udev:ro
:仅用于自动检测端口和某些适配器,如ConBee-e TZ=Europe/Amsterdam
:配置时区-p 8080:8080
:从Docker容器内部到主机的端口转发(用于前端)
提示:
如果在同一主机上运行MQTT服务器(localhost),则可以使用docker0桥的IP建立连接:server: mqtt://172.17.0.1
。
无根容器
为了提高部署的安全性,您可能希望以非root用户身份运行Zigbee2MQTT。
确定可以访问适配器的组(例如在Ubuntu中,可能会分配给dialout)。更新ttyACM0以匹配您的适配器位置。
如果您想使用当前用户运行Zigbee2MQTT,请找到uid(用户ID)和gid(组ID)。
启动docker容器后,更新设备、用户(uid:gid)和group-add。
更新
要更新到最新的Docker镜像:
docker pull koenkk/zigbee2mqtt:latest
docker rm -f zigbee2mqtt
然后按照上面的说明再次运行容器。
标签
以下标签可用:
- 最新发布版本:latest
- 基于dev分支的最新开发版本:latest-dev
- 特定发布版本,例如:1.7.0
Docker Compose
Docker Compose文件的示例:
version: '3.8'
services:
zigbee2mqtt:
container_name: zigbee2mqtt
image: koenkk/zigbee2mqtt
...
Raspberry Pi用户的注意事项
如果您正在运行Raspbian Buster(而不是Bullseye!)(通过执行grep "PRETTY_NAME" /etc/os-release找出),则需要安装libseccomp2。
对于Raspberry Pi 1和零用户:Docker中有一个错误会选择错误的图像架构。在执行docker run之前,使用docker pull koenkk/zigbee2mqtt --platform linux/arm/v6
拉取正确的镜像。
Docker Stack设备映射
此内容仅与 Docker Stack 有关。
在 swarm 模式下部署堆栈时,Docker stack 不支持使用 --devices 选项进行设备映射。为此,我们有两种解决方案。这两种方法的起点都是将设备绑定为卷。
自动设备映射 cgroup v1 和 v2
启用 Docker Stacks 上的设备的最简单解决方案是 allfro 设备映射管理器 docker 映像。这个容器有一个小程序,可以读取其自身主机上的所有卷挂载,识别设备,然后修改主机上的权限,允许容器使用它们。与其他解决方案不同,这适用于两个版本的 cgroups。
这个容器必须直接部署到 docker,而不是通过堆栈。可以通过创建一个特权服务的堆栈来绕过这个问题,该服务作为代理启动实际的设备映射容器。
version: "3.8"
services:
dmm:
image: docker
entrypoint: docker
restart: unless-stopped
privileged: true
command: |
run
-i
--rm
--privileged
--cgroupns=host
--pid=host
--userns=host
-v /sys:/host/sys
-v /var/run/docker.sock:/var/run/docker.sock
-v /dev:/dev
ghcr.io/allfro/allfro/device-mapping-manager:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
mode: global
手动 cgroup v1
可以通过手动设置正确的权限来进行规避。此解决方案基于在 "service create" 上添加设备支持的解决方案,所有的荣誉都归给他。
此解决方案只适用于 cgroup v1,许多新的发行版上都没有启用此功能。
识别串行适配器 使用以下命令识别串行适配器:
sudo lsusb -v
UDEV 规则
为串行适配器创建一个新的 udev 规则,idVendor 和 idProduct 必须与 lsusb 命令的值相等。下面的规则创建了 /dev/zigbee-serial 设备:
echo "SUBSYSTEM==\"tty\", ATTRS{idVendor}==\"0451\", ATTRS{idProduct}==\"16a8\", SYMLINK+=\"zigbee-serial\", RUN+=\"/usr/local/bin/docker-setup-zigbee-serial.sh\"" | sudo tee /etc/udev/rules.d/99-zigbee-serial.rules
使用以下命令重新加载新创建的规则:
sudo udevadm control --reload-rules
创建 docker-setup-zigbee-serial.sh:
sudo nano /usr/local/bin/docker-setup-zigbee-serial.sh
复制以下内容:
#!/bin/bash
USBDEV=`readlink -f /dev/zigbee-serial`
read minor major < <(stat -c '%T %t' $USBDEV)
if [[ -z $minor || -z $major ]]; then
echo 'Device not found'
exit
fi
dminor=$((0x${minor}))
dmajor=$((0x${major}))
CID=`docker ps -a --no-trunc | grep koenkk/zigbee2mqtt | head -1 | awk '{print $1}'`
if [[ -z $CID ]]; then
echo 'CID not found'
exit
fi
echo 'Setting permissions'
echo "c $dmajor:$dminor rwm" > /sys/fs/cgroup/devices/docker/$CID/devices.allow
设置权限:
sudo chmod 744 /usr/local/bin/docker-setup-zigbee-serial.sh
创建 docker-event-listener.sh:
sudo nano /usr/local/bin/docker-event-listener.sh
复制以下内容:
#!/bin/bash
docker events --filter 'event=start'| \
while read line; do
/usr/local/bin/docker-setup-zigbee-serial.sh
done
设置权限:
sudo chmod 744 /usr/local/bin/docker-event-listener.sh
创建 docker-event-listener.service:
sudo nano /etc/systemd/system/docker-event-listener.service
复制以下内容:
[Unit]
Description=Docker Event Listener for Zigbee serial adapter
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=root
ExecStart=/bin/bash /usr/local/bin/docker-event-listener.sh
[Install]
WantedBy=multi-user.target
设置权限:
sudo chmod 744 /etc/systemd/system/docker-event-listener.service
重新加载守护程序:
sudo systemctl daemon-reload
启动 Docker 事件监听器:
sudo systemctl start docker-event-listener.service
查看 Docker 事件监听器状态:
sudo systemctl status docker-event-listener.service
启用 Docker 事件监听器:
sudo systemctl enable docker-event-listener.service
验证并部署 Zigbee2MQTT 堆栈:
现在重新连接串行适配器。使用以下命令验证:
ls -al /dev/zigbee-serial
以下是 docker-stack-zigbee2mqtt.yml 的示例:
version: "3.7"
services:
zigbee2mqtt:
image: koenkk/zigbee2mqtt:latest-dev
environment:
- TZ=Europe/Amsterdam
volumes:
- /mnt/docker-cluster/zigbee2mqtt/data:/app/data
- /dev/zigbee-serial:/dev/zigbee-serial
networks:
- proxy_traefik-net
deploy:
placement:
constraints: [node.hostname == rpi-3]
replicas: 1
networks:
proxy_traefik-net:
external: true
在上述示例中,proxy_traefik-net 是连接到 mqtt 代理的网络。约束确保 Docker 只部署到这个 (rpi-3) 节点,串行适配器连接到这个节点。卷绑定 /mnt/docker-cluster/zigbee2mqtt/data 是 zigbee2mqtt 的持久目录,
/dev/zigbee-serial 是 zigbee2mqtt 的串行适配器。
部署堆栈:
docker stack deploy -c docker-stack-zigbee2mqtt.yml zigbee2mqtt
遵循以上步骤应该允许你在 swarm 模式下通过 docker stack 部署 zigbee2mqtt,同时解决了 zigbee 串行适配器权限问题。
故障排查
即使按照上述方法操作,也可能会出现容器无法正确启动,并在服务的日志中显示 "Operation not permitted" 的消息:
错误:尝试打开串行端口时发生错误 'Error: Error: Operation not permitted, cannot open /dev/zigbee-serial'
这是因为使用了 cgroupv2 而不是 cgroupv1,而 docker/containerd 并不完全支持 cgroupv2。要从 cgroupv2 切换到 cgroupv1,你需要在 grub cmdline 中添加 systemd.unified_cgroup_hierarchy=false。例如,在 Raspberry Pi 4 上使用 Raspian Bullseye,你可以在 /boot/cmdline.txt 文件的行末添加它:
[…] rootfstype=ext4 fsck.repair=yes rootwait cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 systemd.unified_cgroup_hierarchy=false
Docker 在 Synology DSM 7.0 上的应用
注意:这可能不适用于所有 Zigbee 控制器,但已在 CC2531 上进行了测试。
从 Disk Station Manager 版本 7 开始,Synology 移除了对像 Zigbee 控制器这样的 USB 设备的内置支持。但你可以通过执行以下命令作为 root 用户来将 USB 支持安装到 Linux 内核。
modprobe usbserial
modprobe ftdi_sio
modprobe cdc-acm
执行上述命令后,可能需要拔出 Zigbee 控制器并重新插入 USB 端口。
你可能还需要基于你的 USB Zigbee 控制器设置的其他驱动程序,例如,默认情况下不包括 CH341 模块。你可以从 jadahl.com 的页面下载预编译的模块 - 根据 NAS CPU 架构选择模块目录(DS218+ -> INTEL Celeron J3355 -> Apollo Lake)。
cd /lib/modules
wget http://www.jadahl.com/iperf-arp-scan/DSM_7.0/apollolake/ch341.ko
insmod /lib/modules/ch341.ko
你还可以创建一个启动任务来执行上述命令:
- 创建一个包含三个 modprobe 命令的可执行脚本文件。
- 使用 DSM 的控制面板 -> 任务调度器 -> 创建 -> 触发任务 -> 用户定义脚本,并设置:用户:root,事件:启动,并在任务设置下执行可执行文件的 bash 命令。