I’m a relatively lightweight user of Home Assistant and Z-Wave devices, at least compared to some who have dozens, if not hundreds, of devices and automations. Regardless, I do own about half a dozen Z-Wave devices, and I need to control them somehow. I’ve chosen to control them via Home Assistant and Z-Wave JS UI.
This is my thirteenth post documenting images I use at home. You can also read about how I run the Unifi controller, how I run Plex, how I update DuckDNS, how I run Duplicacy., how I run Heimdall, how I run Librespeed, how I run Home Assistant, how I run NetBox, how I run Scrutiny, how I run OpenVSCode Server, how I run QDirStat, and how I run WireGuard.
About Z-Wave JS UI
Z-Wave JS UI is a “full featured Z-Wave Control Panel and MQTT Gateway.” In my case, I run it alongside Home Assistant so I can manually or automatically control my Z-Wave devices. (In particular, I use a combination of controlling devices both via Home Assistant directly, as well as HomeKit via Home Assistant.)
It may be worth noting that this project was renamed Z-Wave JS UI the day before I started drafting this post. Apparently, the prior name was confusing and misleading to a lot of folks, myself included. So the first order of business was to update my docker-compose.yml
file to swap out a few names. Anyway, I point this out in case you run across the old name (which I will not name here, in the interest of helping the old name die out sooner).
Running via docker-compose
I run all of my containers via docker-copmose
. Here are the relevant sections of my docker-compose.yml
file:
networks:
home-assistant-zwave-js-ui:
name: home-assistant-zwave-js-ui
services:
home-assistant:
container_name: home-assistant
image: lscr.io/linuxserver/homeassistant:2022.9.6-ls97
network_mode: host
restart: unless-stopped
depends_on:
- home-assistant-zwave-js-ui
env_file:
- ./common.env
- ./secret.env
volumes:
- ${SERVICE_DATA_DIR}/home-assistant:/config
home-assistant-zwave-js-ui:
container_name: home-assistant-zwave-js-ui
image: zwavejs/zwave-js-ui:8.0.0
restart: unless-stopped
user: ${PUID}:${PGID}
devices:
- /dev/aeotec-zwave-stick:/dev/zwave
env_file:
- ./common.env
- ./secret.env
networks:
- home-assistant-zwave-js-ui
ports:
- 3002:3000
- 8091:8091
volumes:
- ${SERVICE_DATA_DIR}/home-assistant-zwave-js-ui:/usr/src/app/store
First, I create an explicitly-named network for Z-Wave JS UI to use. This helps ensure services are isolated and avoids the automatic names docker-compose
generates. The names aren’t bad, but I like the explicit names better. Note that I don’t create an explicitly named network for Home Assistant as it uses host networking instead of a bridge.
Then, the first stanza of the services
key specifies the basic container configuration: a name, image to use, and restart policy. It also includes a user
configuration to set the container’s user as the non-root user I use for all my containers. This isn’t strictly necessary, but I like how it runs the container as a regular user and not root. It also helps keep file ownership sane.
Next, the devices
section exposes my Aeotec Z-Wave stick into the container as /dev/zwave
. This gets Z-Wave JS UI access to the physical hardware it needs to communicate on the Z-Wave network.
In my prior post about Home Assistant, the device was passed directly to the Home Assistant container. In the intervening time since I made that post, Z-Wave functionality was split out of Home Assistant proper; the current recommendation is to use a separate container like Z-Wave JS UI. Hence the device
section moving from one container to another.
The env_file
section brings in environment variables used commonly across my containers. This includes the SERVICE_DATA_DIR
variable used further down the configuration.
Two external ports are mapped into the container: 3002 is mapped to 3000 and 8091 is mapped to 8091. Port 8091 is used to connect to the web application from a browser. There’s no difference in port numbers here, so it isn’t particularly interesting.
Port 3000, on the other hand, is more interesting. Because I have other containers running on my system, ports 3000 and 3001 are already in use. Thus I needed to present port 3000 as port 3002 on the host. This isn’t hard, but it’s mildly annoying, as Home Assistant then needs its Z-Wave JS configuration updated to also use port 3002. Thankfully that’s pretty easy to configure within Home Assistant.
Lastly, I have one volume mapping: /usr/src/app/store
within the container is mapped to the directory on my host filesystem with all of my persistent data across all containers. I use an environment variable SERVICE_DATA_DIR
to specify where that persistent configuration lives. The environment variable helps by cutting down on duplication in my broader docker-compose.yml
file.
The container is now ready for you to boot it up via docker-compose up
.
Final setup steps
Once you’ve booted the container, you can connect to its web interface in a browser on port 8091. From there, you can configure your particular Z-Wave network and devices.
You’ll also need to go into Z-Wave JS configuration within Home Assistant and update it to connect to port 3002 instead of 3000, or whatever the port number on your host is.
I can’t get more detailed in terms of configuration at this point, since every network is unique. Good luck!
Run Z-Wave JS User Interface via Docker Image
Though it was mildly obnoxious when Home Assistant deprecated the built-in Z-Wave support, I’m glad it was. Z-Wave JS UI has been a much friendlier and more effective interface to the Z-Wave network than the old support was. Thanks to the Z-Wave JS UI team for publishing such a handy tool.