A minimal docker container for zwave-js-server. This container provides a usable zwave-js-server and nothing else. The zwave-js-server is a websocket application that hosts the Z-Wave JS driver software.
For a more functional application that also provides the zwave-js-server, use Z-Wave JS UI instead.
Z-Wave JS (the driver) stores information about the Z-Wave network in a set of cache files. When the server restarts, the driver loads the network information from the cache. Without this information the network will not be fully usable right away. Therefore it is very important that the cache files are persisted between container restarts.
The docker run
examples below use an environment file to provide all of the Z-Wave network keys.
$ cat .env
S2_ACCESS_CONTROL_KEY=7764841BC794A54442E324682A550CEF
S2_AUTHENTICATED_KEY=66EA86F088FFD6D7497E0B32BC0C8B99
S2_UNAUTHENTICATED_KEY=2FAB1A27E19AE9C7CC6D18ACEB90C357
S0_LEGACY_KEY=17DFB0C1BED4CABFF54E4B5375E257B3
# Create a persistent volume for the driver cache
$ docker volume create zjs-storage
# starts the server and uses the volume as the persistent cache directory
$ docker run -d -p 3000:3000 --name=zjs -v zjs-storage:/cache --env-file=.env --device "/dev/serial/by-id/usb-0658_0200-if00:/dev/zwave" kpine/zwave-js-server:latest
# starts the server and uses a local folder as the persisent cache directory
$ docker run -d -p 3000:3000 --name=zjs -v "$PWD/cache:/cache" --env-file=.env --device "/dev/serial/by-id/usb-0658_0200-if00:/dev/zwave" kpine/zwave-js-server:latest
Docker Compose is a simple way to maintain a container configuration.
Example of a minimal docker-compose.yaml
file:
services:
zjs:
container_name: zjs
image: kpine/zwave-js-server:latest
restart: unless-stopped
environment:
S2_ACCESS_CONTROL_KEY: "7764841BC794A54442E324682A550CEF"
S2_AUTHENTICATED_KEY: "66EA86F088FFD6D7497E0B32BC0C8B99"
S2_UNAUTHENTICATED_KEY: "2FAB1A27E19AE9C7CC6D18ACEB90C357"
S0_LEGACY_KEY: "17DFB0C1BED4CABFF54E4B5375E257B3"
devices:
- "/dev/serial/by-id/usb-0658_0200-if00:/dev/zwave"
volumes:
- ./cache:/cache
ports:
- "3000:3000"
LOGTOFILE
: Set this totrue
to configure the driver to log to a file.LOGFILENAME
: Set this to configure the driver log filename (only used whenLOGTOFILE
istrue
). The default is/logs/zwave_%DATE%.log
. Note that the driver will automatically rotate the log files using a date based scheme.LOGLEVEL
: Set this to configure the driver log level.S2_ACCESS_CONTROL_KEY
: The network key for the S2 Access Control security class.S2_AUTHENTICATED_KEY
: The network key for the S2 Authenticated security class.S2_UNAUTHENTICATED_KEY
: The network key for the S2 Unauthenticated security class.S0_LEGACY_KEY
: The network key for the S0 (Legacy) security class.USB_PATH
: The device path of the Z-Wave USB controller. Defaults to/dev/zwave
. Use of this variable is unnecessary if the controller device path is mapped from the host as/dev/zwave
.FIRMWARE_UPDATE_API_KEY
: The API key used to access the Z-Wave JS Firmware Update Service. By default, no key is configured. Usually it is not necessary to configure this, unless you are a commercial user. See the Firmware Update API Key section for details.ENABLE_DNS_SD
: Set this totrue
to enable DNS Service Discovery. The default is disabled. Enabling this only works if you are using host networking.
/cache
- The driver cache directory. A volume or bind mount should be mapped to this directory to persist the network information between container restarts./cache/config
- The driver device configuration priority directory. Used to load your custom device configuration files. The directory is automatically created if/cache
is a named volume, otherwise it must be created manually or mapped as a volume/bind mount./logs
- When logging to file is enabled, this is the directory where the driver log file is written to. Assign a volume or bind mount to this directory to access and save the log files outside of the container.
3000
- The zwave-js-server websocket port. External applications, such as Home Assistant, must be able to connect to this port to interact with the server.
All network keys must specified as 16-byte hexadecimal strings (32 characters). A simple way to generate a random network key is with the following command:
$ < /dev/urandom tr -dc A-F0-9 | head -c32 ; echo
8387D66323E8209C58B0C317FD1F4251
All keys should be unique; sharing keys between multiple security classes is a security risk. See the Z-Wave JS Key management docs for further details.
At a minimum, the S0 (Legacy) network key is required, otherwise the zwave-js-server will fail to start. The S2 keys are optional but highly recommended. If unspecified, S2 inclusion will not be available.
Instead of using the USB_PATH
environment variable, map the USB controller device path to the container's default of /dev/zwave
.
Use the /cache/config
directory to easily test new device configuration files or modifications to existing ones. The files located in this directory will supplement or override the embedded device configuration database. When the container is restarted the driver logs will indicate which file was loaded:
2021-06-19T06:19:18.506Z CNTRLR [Node 007] Embedded device config loaded
2021-06-19T06:21:43.793Z CNTRLR [Node 008] User-provided device config loaded
Z-Wave JS performs a soft-reset (restart) of the Z-Wave controller during startup, and during certain operations such as NVM backups and restores. The soft-reset can result in a USB disconnect for some Z-Wave controllers, which may cause problems with certain container runtimes or host configurations. If you observe that Z-Wave JS has trouble finding the USB device, you may try opting out of this functionality by setting the ZWAVEJS_DISABLE_SOFT_RESET
environment variable, or setting the enableSoftReset
driver option to false
. For more details, see the softReset
documentation.
Z-Wave JS uses directories as lock files to prevent the cache files from being modified by multiple concurrent processes; this helps prevent against cache corruption. These directories are located in the cache directory, next to the actual cache files. The locking technique updates the mtime
(Modified time) of the lock file every ~1 second. If your storage media is sensitive to frequent writes, such as an SD card, you may want to relocate the lock files to another directory, such as a tmpfs. To relocate the cache files, set the ZWAVEJS_LOCK_DIRECTORY
environment variable to an alternate path, preferably some kind of tmpfs on the host. Here is an extract of a compose file:
services:
zjs:
environment:
ZWAVEJS_LOCK_DIRECTORY: "/run/lock/zwave-js"
volumes:
- /run/lock/zwave-js:/run/lock/zwave-js
The environment variable tells Z-Wave JS to store the lock files in the directory /run/lock/zwave-js
. The volume entry maps the hosts /run/lock/zwave-js
directory, which is a tmpfs, to the container directory with the same name. The end result is that the lock files created in the container are located in the tmpfs of the host. The path /run/lock
is usually mounted as a tmpfs. Another candidate might be /tmp/zwave-js
.
Note that locating the locks in a central place on the host ensures that multiple containers with the same configuration will be aware of the locks. However, if Z-Wave JS is run in another instance without the same lock directory configuration, it will not see the locks and this will bypass the lock protections, allowing for the chance that the cache will be corrupted. When the locks are located in the default location, all instances of Z-Wave JS using the default configuration will see the locks. So use this feature with care.
Z-Wave JS has an online web service that provides information about firmware updates for your devices. Use of this service requires an API key. The Z-Wave JS organization has provided this project with its own key. This key is only valid when used for non-commercial purposes, and is not permitted for commercial usage. If you are a commercial organization using this application, you must request and configure your own key.
If you are using the Z-Wave integration with Home Assistant, you do not need to enable or install an API key. The integration provides the key when accessing the firmware update APIs. This is true for any client application that makes use of the firmware update APIs with its own keys.
If you use a client that does not support its own API key, and you are a non-commercial user, you can enable the built-in key by setting the FIRMWARE_UPDATE_API_KEY
to -
. By doing so you agree that you are not a commercial user.
If you have your own key, i.e. you are a commercial user, you can set FIRMWARE_UPDATE_API_KEY
to that key.
If the FIRMWARE_UPDATE_API_KEY
environment variable is empty (the default), no API key will be configured. In that case a client application would be responsible for setting it, otherwise the firmware update service may not be functional or incur more restrictive rate-limiting.