Home Assistant Remote Radio
One of the challenges of running Home Assistant in a virtualized environment is the access to hardware radios. Home Assistant ultimately needs to bridge a ton of home automation networks, and most of these require some sort of USB / Serial dongle. You could have all of your dongles in your server closet and pass them through to the VM/container, but then you can’t migrate it across hosts. You could have one dongle for each host, I guess, but that doesn’t work for Z-wave where the entire network is stored on the dongle. Plus, the server closet probably isn’t a great place for the one radio anyway. So, I’m showing you how I use a Raspberry Pi to run my Zwave and Zigbee radios, remotely, for Home Assistant. This keeps the core Home Assistant setup flexible in where it can run on the network, and also lets me run multiple remote radios without resorting to weird tricks in HA OS.
Contents⌗
Video⌗
Base OS⌗
I’ve chosen to install Raspberry Pi OS Lite, a variant of Debian Bookworm. I’m using the ARM 64-bit builds for Raspberry Pi 3. The Lite version just lacks the UI, which is fine since I’m never going to plug in a display.
As far as I know, all of this should work fine on Debian Bookworm as well, if you want to use a mini PC.
Don’t forget to run OS update as well:
apt update
apt full-upgrade -y
I also dropped my SSH public key into ~/.ssh/authorized_keys
(the file does not exist by default) to avoid password logins.
I disabled IPv4 on my setup (nmcli connection modify 'Wired connection 1' ipv4.method disable
), and put the IPv6 address in DNS where it belongs. You are of course free to do other things, such as instlaling avahi-daemon for mdns, for example.
PBS Backups⌗
I backup everything to Proxmox Backup Server, so I need to install the client to backup this host.
If you’re running on an ARM device you can get deb packages from https://github.com/wofferl/proxmox-backup-arm64 (you only need the client deb, not all of them)
If you are running on x86 you can use Proxmox’s client-only repository instead.
In any case, install PBS Client from packages.
Here’s my backup script (/etc/systemd/system/backup.service
):
[Unit]
Description=Run Backup to Proxmox Backup Server
After=network-online.target
[Service]
#TLS fingerprint if cert is self-signed
Environment=PBS_FINGERPRINT=your_fingerptint
#Your API key here
Environment=PBS_PASSWORD=api_key_here
#Use your user @ realm ! api key name @ hostname : repository
Environment=PBS_REPOSITORY=user@pbs!apikey@localhost:backup
Type=oneshot
#Backup the root fs. This will not backup any other mount points, only the mount point which mounts /
#You can add more pxars if you want more mount points
#--change-detection-mode=metadata is optional, but I prefer it
ExecStart=proxmox-backup-client backup root.pxar:/ --change-detection-mode=metadata
[Install]
WantedBy=default.target
I also have a backup timer (/etc/systemd/system/backup.timer
):
[Unit]
Description=Backup System Daily
RefuseManualStart=no
RefuseManualStop=no
[Timer]
#Run 540 seconds after boot for the first time
#OnBootSec=540
#Run at 7pm
OnCalendar=*-*-* 19:00:00
Unit=backup.service
[Install]
WantedBy=timers.target
Then a quick systemctl daemon-reload
and sytemctl enable backup.timer
is all you need. When the timer fires, it will trigger the service, which will run a single backup. Since it runs every day at 7pm, it will do one backup per day.
ZwaveJS UI⌗
I previously used Snap packages but I really hated working with them, so I am now using the NPN (nodeJS package manager) version combined with a systemd service script.
Install:
#Node 22 (seems like a reasonable choice)
curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
sudo -E bash nodesource_setup.sh
#Install it from packages
sudo apt install nodejs -y
#Since we used apt here, we can run `apt upgrade -y` to upgrade Node minor versions
#Install zwave js ui
sudo npm install -g zwave-js-ui
#Create directory
mkdir -p /var/zwavejs
Service (/etc/systemd/system/zwavejs.service
):
[Unit]
Description=Z-Wave Network Manager
After=network-online.target
[Service]
#ZwaveJS binary
ExecStart=/usr/bin/zwave-js-ui
#Storage location
Environment=STORE_DIR=/var/zwavejs
#Config location
Environment=ZWAVEJS_EXTERNAL_CONFIG=/var/zwavejs/.config-db
[Install]
WantedBy=default.target
Then it’s just a systemctl daemon-reload
and systemctl enable --now zwavejs
.
In my case, this would immediately cause the Pi to lock up due to underpower, so …. that’s fun? I was hoping to migrate my old Zwave network, but I bought a new dongle and moved on to re-pairing everything. Zwave stores everything within the chipset, and being a proprietary standard with a single vendor, there are no hardware options other than Silicon Labs. On the plus side, compatibility between devices is excellent, but the downside is it isn’t as easy for ZwaveJS to store the network config in a place I can back it up.
Zigbee2MQTT⌗
This one is also written in NodeJS, so we again need to make sure NodeJS is installed and ready to go (skip this if you already did ZwaveJS):
Install NodeJS:
#Node 22 (ZwaveJS is using 18 in their docker images I think?)
curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
sudo -E bash nodesource_setup.sh
#Install it from packages
sudo apt install nodejs -y
#Since we used apt here, we can run `apt upgrade -y` to upgrade Node minor versions
Now, we can install Zigbee2MQTT from source:
#Need git and friends
sudo apt install git
# Create a directory
sudo mkdir /opt/zigbee2mqtt
sudo chown -R ${USER}: /opt/zigbee2mqtt
#Checkout into directory
git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
#Install depends
cd /opt/zigbee2mqtt
npm ci
#Build
npm run build
Service (/etc/systemd/system/zigbee2mqtt.service
):
[Unit]
Description=Zigbee 2 MQTT
After=network-online.target
[Service]
#Node binary
ExecStart=/usr/bin/node index.js
#Location
WorkingDirectory=/opt/zigbee2mqtt
[Install]
WantedBy=default.target
Then it’s just a systemctl daemon-reload
and systemctl enable --now zigbee2mqtt
(these may need sudo fyi).
After that, we need to set a few things in the configuration.yaml, so edit data/configuration.yaml
(it’s in /opt/zigbee2mqtt/data/configuration.yaml). You can also copy the example (configuration.example.yaml
).
Things you should do:
- Set
homeassistant
totrue
- Set
permit_join
tofalse
(you can re-enable it from the UI) - Set your MQTT broker server, username, and password
- Set the location of your serial port (please use the one in
/dev/serial/by-id/
instead of/dev/ttyUSBX
in case your devices change) - Add
frontend: true
to run the web UI
You can access the web ui on port 8080 to configure it.
For reference, here is my configuration (redacted) for reference:
homeassistant: true
frontend: true
mqtt:
base_topic: zigbee2mqtt
#MQTT User Information Here
server: mqtt://telstar.palnet.net
serial:
port: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0
advanced:
homeassistant_legacy_entity_attributes: false
legacy_api: false
legacy_availability_payload: false
#PAN ID, etc. removed
#Devices removed
RTL-433⌗
Previous Project Entry Here When I previously set this up I had to compile it from source. Now, it’s included in the Pi repos directly, so no need to do that.
apt install rtl-433 -y
Not to revisit that previous entry too much, here’s my service file (/etc/systemd/rtl433.service
):
[Unit]
Description=rtl_433 SDR Receiver Daemon
After=network-online.target
[Service]
ExecStart=/usr/bin/rtl_433 -C si -F "mqtt://<broker>:1883,user=<user>,pass=<pass>"
Restart=always
[Install]
WantedBy=multi-user.target
Then it’s just a systemctl daemon-reload
and systemctl enable --now rtl433
.
Updates⌗
Managing software updates can be a full-time task, so here are the update commands for everything:
apt update && apt upgrade -y
to update the base Debian system and Node.JSnpm update zwave-js-ui && systemctl restart zwavejs
to update ZwaveJS UI itself- There are no updates for my UPS daemon
- Zigbee2MQTT needs a bit more:
#cd to the directory
cd /opt/zigbee2mqtt
#Pull update from Git
git pull
#Make depend
npm ci
#Make
npm run build
#Restart service
systemctl restart zigbee2mqtt