Para seguir el proceso de migración de mi Home Lab desde una pequeña Raspberry Pi 4 a un OptiPlex 7050 ejecutando Proxmox ahora le toca el turno a Zigbee2MQTT, un bridge entre los dispositivos Zigbee y MQTT que no necesita acceso a un cloud propietario para funcionar.
En esta ocasion, en lugar de realizar la instalación de Zigbee2MQTT en Docker, se utilizará un contenedor ligero LXC de Proxmox con Debian 12.
Creación del LXC
Este bridge Zigbee con Zigbee2MQTT se ejecutará sobre un LXC creado desde la Shell del servidor Proxmox mediante los Proxmox VE Helper-Scripts:
mkdir -p ~/tteck && cd ~/tteck
wget -nv https://github.com/tteck/Proxmox/raw/main/ct/zigbee2mqtt.sh
# Revisar el script ;-)
bash mqtt.sh
Al ejecutar el script anterior, aparecerá el asistente de instalación:
- This will create a New Zigbee2MQTT LXC. Proceed?
Yes
- Use Default Settings?
Advanced
- To make a selection, use the Spacebar.
Ok
- If the default Linux distribution is not adhered to, script support will be discontinued (debian 12).
Ok
- Choose Distribution: debian
- Choose version: 12 Bookworm
- Choose Type: 1 Unprivileged
- Set Root Password (needed for root ssh access): xxxxxxxx
- Verify Root Password: xxxxxxxx
- Set Container ID: 309
- Set Hostname: zigbee2mqtt
- Set Disk Size in GB: 4
- Allocate CPU Cores: 2
- Allocate RAM in MiB: 1024
- Set a Bridge: vmbr0
- Set a Static IPv4 CIDR Address (/24): 192.168.1.86/24
- Set gateway IP address: 192.168.1.1
- Set APT-Cacher IP (leave blank for default):
- Disable IPv6:
Yes
- Set Interface MTU Size (leave blank for default):
- Set a DNS Search Doamin (leave blank for HOST): home
- Set a DNS Server IP (leave blank for HOST): 192.168.1.81,192.168.1.82
- Set a MAC Address (leave blank for default):
- Set a Vlan (leave blank for default):
- Enable Root SSH Access?
No
- Enable Verbose Mode?
Yes
- Ready to create Zigbee2MQTT LXC?
Yes
Deshabilitar IPv6 implica añadir la siguiente configuración al LXC: net.ipv6.conf.all.disable_ipv6 = 1
Durante la clonación del repositorio de Zigbee2MQTT, el script preguntará si se quiere cambiar a la rama Edge/dev y la respuesta será N
para utilizar la rama estable:
✓ Set up Zigbee2MQTT Repository
Switch to Edge/dev branch? (y/N) N
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it.
Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
npm warn deprecated @humanwhocodes/config-array@0.11.14: Use @eslint/config-array instead
npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
added 798 packages, and audited 799 packages in 13s
87 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
npm notice
npm notice New patch version of npm available! 10.8.1 -> 10.8.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.2
npm notice To update run: npm install -g npm@10.8.2
npm notice
✓ Installed Zigbee2MQTT
/Created symlink /etc/systemd/system/multi-user.target.wants/zigbee2mqtt.service → /etc/systemd/system/zigbee2mqtt.service.
✓ Created Service
Los mensajes de error de NPM son debidos a dependencias indirectas según se explica en la issue 23238 del proyecto.
Antes de poner en marcha el LXC, se pueden deshabilitar un par de opciones que no son necesarias para el funcionamiento de MQTT y que han sido añadidas por el script ejecutado anteriormente:
- Expandir el centro de datos (Datacenter)
- Expandir el servidor (node):
pve
- Seleccionar el contenedor (container):
308 (mqtt)
- Seleccionar la opción Options
- Editar los siguientes valores:
- Features:
- Desmarcar la opción keyctl
- Desmarcar la opción Nesting
- Features:
Al deshabilitar nesting en un LXC Debian 12, el acceso a la Console del LXC es unos segundos más lento.
En este punto se puede conectar, en un puerto USB del servidor Proxmox, un adaptador Zigbee que hará las funciones de coordinador de la red Zigbee.
En mi caso usaré un SONOFF ZigBee 3.0 USB Dongle Plus que se puede comprar fácilmente en AliExpress.
Para identificar el dispositivo que se ha conectado se puede utilizar el comando ls -l /dev/serial/by-id
tal como se muestra a continuación:
root@pve:~# ls -l /dev/serial/by-id/
lrwxrwxrwx 1 root root 13 Jul 24 23:18 usb-Silicon_Labs_Sonoff_Zigbee_3.0_USB_Dongle_Plus_0001-if00-port0 -> ../../ttyUSB0
root@pve:~# ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 Jul 24 23:18 /dev/ttyUSB0
Para realizar el passthrough del dispositivo USB al contenedor LXC hay que editar su fichero de configuración /etc/pve/lxc/309.conf
y añadir las siguientes líneas:
lxc.cgroup2.devices.allow: c 188:* rwm
lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir
lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
A continuación, se reinicia el LXC mediante el comando pct reboot 309
desde la Shell de Proxmox o usando el botón Reboot
desde la interfaz gráfica del propio LXC.
Configuración del LXC
Al no haber habilitado el acceso para el usuario root
mediante SSH, se puede acceder al LXC utilizando el botón Console
desde la configuración del propio LXC.
Una vez dentro del LXC, se procederá a realizar una configuración similar a la realizada durante la instalación de Zigbee2MQTT en Docker.
El primer paso será modificar el fichero de configuración /opt/zigbee2mqtt/data/configuration.yaml
para añadir los mismos parámetros del entorno de producción actual en Docker.
Para ello, se hace una copia de seguridad del fichero actual, se copia el fichero de configuración desde la Raspberry y se modifica el fichero usando el editor nano
:
cd /opt/zigbee2mqtt/data
mv configuration.yaml configuration.original
scp pi@pi:/home/pi/volumes/zigbee2mqtt/configuration.yaml configuration.pi
nano configuration.yaml
El contenido final del fichero de configuración configuration.yaml
será parecido al siguiente:
homeassistant: true
permit_join: false
mqtt:
base_topic: zigbee2mqtt
server: mqtt://192.168.1.85
user: admin
password: xxxxxxxx
serial:
port: /dev/serial/by-id/usb-Silicon_Labs_Sonoff_Zigbee_3.0_USB_Dongle_Plus_0001-if00-port0
frontend:
auth_token: xxxxxxxx
advanced:
homeassistant_legacy_entity_attributes: false
legacy_api: false
legacy_availability_payload: false
network_key:
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
- xxx
device_options:
legacy: false
devices:
'0x0000000000000000':
friendly_name: sensor_temperatura
temperature_precision: 1
humidity_precision: 1
'0x0000000000000000':
friendly_name: sensor_apertura
[...]
ota:
ikea_ota_use_test_url: false
disable_automatic_update_check: true
En el fichero anterior se han ocultado los valores sensibles como la contraseña de MQTT, la contraseña del frontend de Zigbee2MQTT, la clave de la red Zigbee o los dispositivos Zigbee existentes en la misma.
A continuación se copian algunos ficheros que contienen el estado actual de la red Zigbee:
scp pi@pi:/home/pi/volumes/zigbee2mqtt/database.db .
scp pi@pi:/home/pi/volumes/zigbee2mqtt/coordinator_backup.json .
scp pi@pi:/home/pi/volumes/zigbee2mqtt/state.json .
Finalmente, se puede poner en marcha Zigbee2MQTT usando el comando npm start
desde el directorio del proyecto
cd /opt/zigbee2mqtt && npm start
Si aparece algún error indicando que no se puede acceder al dispositivo /dev/ttyUSB0
es debido a los permisos de usuario/grupo en Proxmox y en LXC.
Para que el usuario root
del LXC pueda acceder a /dev/ttyUSB0
es necesario cambiar el propietario en Proxmox usando el siguiente comando:
# Desde Proxmox
chown 100000:100000 /dev/ttyUSB0
Antes de ejecutar este comando, los permisos eran los siguientes:
# En Proxmox
root@pve:~# ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 Jul 24 23:18 /dev/ttyUSB0
# En el LXC
root@zigbee2mqtt:~# ls -l /dev/ttyUSB0
crw-rw---- 1 nobody nogroup 188, 0 Jul 24 23:18 /dev/ttyUSB0
Después de ejecutar el comando chown
, los permisos quedan de la siguiente manera:
# En Proxmox
root@pve:~# ls -l /dev/ttyUSB0
crw-rw---- 1 100000 100000 188, 0 Jul 24 23:18 /dev/ttyUSB0
# En el LXC
root@zigbee2mqtt:~# ls -l /dev/ttyUSB0
crw-rw---- 1 root root 188, 0 Jul 24 23:18 /dev/ttyUSB0
Al reiniciar Proxmox se recrean todos los dispositivos en /dev
y esto hace que se pierdan los permisos del dispositivo /dev/ttyUSB0
. Para evitarlo es necesario añadir una regla de udev
tal como se explica a continuación.
Se utiliza el comando lsusb -v
para localizar el idVendor
y el idProduct
del dongle de SONOFF:
[...]
idVendor 0x10c4 Silicon Labs
idProduct 0xea60 CP210x UART Bridge
iManufacturer 1 Silicon Labs
iProduct 2 Sonoff Zigbee 3.0 USB Dongle Plus
[...]
A continuación se edita el fichero /etc/udev/rules.d/99-usb-serial.rules
y se añade la siguiente línea:
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="0660", OWNER="100000", GROUP="100000"
Finalmente, se recargan y se aplican las reglas:
udevadm control --reload-rules
udevadm trigger
Frontend
El acceso al frontend de Zigbee2MQTT mediante la URL http://192.168.1.86:8080 debería funcionar correctamente usando la misma contraseña del entorno anterior.
Integración con Home Assistant
La integración con Home Assistant a través de MQTT Discovery también debería funcionar correctamente gracias a la configuración copiada desde el entorno anterior.
Actualizar
La actualización de Zigbee2MQTT en LXC es algo más complicada que en Docker (donde únicamente hay que parar el Docker, borrarlo y volver a ejecutarlo mediante docker compose
):
# Parar Zigbee2MQTT y acceder a su directorio
systemctl stop zigbee2mqtt
cd /opt/zigbee2mqtt
# Backup configuration
cp -R data /root/zigbee2mqtt_backup
# Update
git pull
npm ci
# Restore configuration
cp -R /root/zigbee2mqtt_backup/* data
rm -rf /root/zigbee2mqtt_backup
# Start Zigbee2MQTT
systemctl start zigbee2mqtt
Referencias
Historial de cambios
- 2024-07-24: Documento inicial
- 2024-07-27: Se añade fichero de configuración
- 2024-07-28: Regla de
udev
para permisos /dev/ttyUSB0