Writing Technical guide

Technology · 4 min read

How I Connected a ZWA-2 to Home Assistant on My Ugreen NAS

My working setup for a Home Assistant Connect ZWA-2 on a Ugreen NAS, using Docker and Z-Wave JS UI.

In this article3 sections

I run Home Assistant alongside Docker services on a Ugreen NAS. To add Z-Wave, I connected a Home Assistant Connect ZWA-2 to the NAS and let Z-Wave JS UI bridge the USB controller back to Home Assistant over WebSocket. This is the setup that worked.

Hardware Setup

The Connect ZWA-2 is the first Z-Wave product in Home Assistant’s Connect line. The “2” refers to the second-generation technology platform, not a previous ZWA-1 model.

Prerequisites: Ugreen NAS with Docker installed, SSH access to your NAS, Home Assistant Connect ZWA-2 USB stick, and a USB extension cable (recommended for better signal).

Connect the hardware: Plug the ZWA-2 into the NAS. A USB extension cable helps — it positions the stick away from interference.

Identify the device path: SSH into your NAS and locate your Z-Wave device with ls /dev/serial/by-id/. You should see something like usb-Nabu_Casa_ZWA-XXXXXXXXXX-if00. This is your device identifier.

Create persistent storage: Run mkdir -p /volume1/docker/zwave-store. This directory stores your Z-Wave network config, device database, and security keys. Without it, you lose everything on container restart.

Run the Docker container:

docker run --rm -it \
  -p 127.0.0.1:8091:8091 -p 127.0.0.1:3000:3000 \
  --device=/dev/serial/by-id/usb-Nabu_Casa_ZWA-XXXXXXXXXX-if00:/dev/zwave \
  -v /volume1/docker/zwave-store:/usr/src/app/store \
  zwavejs/zwave-js-ui:latest

These example mappings bind only to the NAS loopback interface. Port 8091 serves the Z-Wave JS UI web interface. Port 3000 runs the WebSocket server for Home Assistant. The device mapping connects the physical USB to /dev/zwave inside the container.

Software Configuration

Access the web interface: Use an SSH tunnel, ssh -L 8091:127.0.0.1:8091 user@example.local, then open http://localhost:8091/ on your computer. In Settings → Z-Wave, set Serial Port to /dev/zwave and click Save.

Protect the network keys Generate security keys: Navigate to Settings → Z-Wave → Security Keys and click Generate for each key type (S0, S2 Access Control, S2 Authenticated, S2 Unauthenticated). Save these keys securely—you’ll need them to re-pair devices if you rebuild the container. Without these keys, secure devices cannot be added to your network.

Set RF region: Go to Settings → Z-Wave → RF Manager and set RF Region to your location (USA, EU, ANZ, etc.). Wrong region means communication failures and potential regulatory violations.

Set the RF region before pairing Setting the wrong RF region is not just a configuration error. A controller and device using different regional frequencies may fail to communicate or pair at all. Use the region supported by the devices and permitted where you operate them.

Connect to Home Assistant: In Z-Wave JS UI, go to Settings → Home Assistant and enable WS Server. The loopback mapping above works for a Home Assistant process sharing the host network. For a separate container, use a private Docker network and the Z-Wave container name; its own localhost is not the NAS. If Home Assistant runs on another machine, bind port 3000 to a trusted LAN interface and restrict access to that machine. Do not expose the UI or WebSocket server publicly. See the Z-Wave JS UI Docker setup. In Home Assistant, go to Settings → Devices & Services, add the Z-Wave JS integration, and enter that URL.

Pair Z-Wave devices: In Z-Wave JS UI, click Control Panel → Add Node (or Include), then follow your device’s pairing instructions (usually triple-press a button). Paired devices appear in Home Assistant automatically.

What I Back Up

Back up the controller state Without backups, you’ll need to re-pair all devices if the container is lost.

Backup strategy: Back up security keys (Settings → Z-Wave → Security Keys, export as JSON), the entire /volume1/docker/zwave-store directory, and your Home Assistant config. Stop the service before copying its store so the backup is consistent. Use private permissions, for example umask 077, before creating the archive. It contains network security keys: encrypt it before moving it off the NAS and never publish its contents.

Common issues:

Device not found: Check if USB device is visible with ls -la /dev/serial/by-id/ and review kernel logs with dmesg | tail -n 50.

Permission denied: The container needs access to the USB device. Check the mapped device and the container user’s access to it. Grant only the required device permissions; --privileged grants much broader host access and is not a routine repair.

Controller offline: Verify serial port setting is /dev/zwave, check container logs with docker logs <container-id>, restart container, or check USB cable connection.

Home Assistant can’t connect: Verify WebSocket server is enabled in Z-Wave JS UI, check firewall rules on NAS allow port 3000, confirm Home Assistant can reach NAS IP, and try ws:// instead of wss:// for local network.

Once the WebSocket connection was up, paired devices appeared in Home Assistant without any extra bridge code. Z-Wave JS UI owns the controller and mesh; Home Assistant stays focused on the automations. The part I do not leave to chance is the store directory and its security keys.

I later found the same ownership problem in Thread border routers, except Thread hides the competing networks more effectively than Z-Wave does.

Was this useful?

What was missing?

Thanks for the feedback.