You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
5.1 KiB
107 lines
5.1 KiB
[Unit]
|
|
Description=Z-Wave JS UI - Z-Wave control panel and Z-Wave JS Server
|
|
Documentation=https://zwave-js.github.io/zwave-js-ui/
|
|
After=network.target var-lib-virtiofs-data.mount zwave-js-ui-init.service
|
|
Requires=var-lib-virtiofs-data.mount zwave-js-ui-init.service
|
|
|
|
# The Z-Wave controller, under the stable name a udev rule gives it. Without it
|
|
# there is nothing to talk to: the driver would retry forever and every entity
|
|
# of the household would sit unavailable, which is noise, not a service.
|
|
ConditionPathExists=/dev/zwave
|
|
|
|
# The security keys and the session secret are operator-provided: they are the
|
|
# identity of the Z-Wave network, not a setting. Starting without them would
|
|
# form a network whose keys nobody kept, and re-pairing every device by hand is
|
|
# the only way back from that.
|
|
ConditionPathExists=/etc/quadlets/zwave-js-ui/external-settings.json
|
|
ConditionPathExists=/etc/quadlets/zwave-js-ui/zwave-js-ui.env
|
|
|
|
# Start/stop this unit when the target is started/stopped
|
|
PartOf=zwave-js-ui.target
|
|
|
|
[Container]
|
|
ContainerName=zwave-js-ui
|
|
Image=zwave-js-ui.image
|
|
AutoUpdate=registry
|
|
|
|
# No need for root privileges: the image has no entrypoint script, it execs node
|
|
# straight away, and node binds 8091 and 3000 (both > 1024) as this user. It
|
|
# writes nothing outside STORE_DIR.
|
|
User=10035
|
|
Group=10000
|
|
|
|
# Network configuration (host networking is the convention across this repository)
|
|
Network=host
|
|
|
|
# The Z-Wave controller. /dev/zwave is a stable name a udev rule of the site
|
|
# gives to its controller, and the device node it points at has to be writable
|
|
# by GID 10000 -- see the README. Naming the device here rather than a
|
|
# /dev/serial/by-id/... path is what keeps this cookbook free of site values.
|
|
#
|
|
# The container path is spelled out, and it has to be: a udev SYMLINK is a
|
|
# symbolic link, and `--device /dev/zwave` alone hands the container the node
|
|
# under its RESOLVED name (/dev/ttyACM0), which is not the name ZWAVE_PORT
|
|
# below asks for. The symptom is a driver that never opens its port:
|
|
# "Failed to open the serial port: No such file or directory (ZW0100)".
|
|
AddDevice=/dev/zwave:/dev/zwave
|
|
|
|
# Everything the driver needs comes from the environment, so the settings this
|
|
# operator decided stay out of reach of the web interface (Z-Wave JS UI marks
|
|
# them "managed externally" and refuses to edit them):
|
|
# - ZWAVE_PORT forces the serial port AND enables the driver;
|
|
# - ZWAVE_EXTERNAL_SETTINGS holds the security keys and the Z-Wave JS Server
|
|
# settings Home Assistant connects to;
|
|
# - STORE_DIR moves the store off the image and onto the precious-data mount.
|
|
Environment=ZWAVE_PORT=/dev/zwave
|
|
Environment=ZWAVE_EXTERNAL_SETTINGS=/etc/quadlets/zwave-js-ui/external-settings.json
|
|
Environment=STORE_DIR=/var/lib/virtiofs/data/zwave-js-ui
|
|
|
|
# SESSION_SECRET and the initial administrator credentials (site secrets).
|
|
EnvironmentFile=/etc/quadlets/zwave-js-ui/zwave-js-ui.env
|
|
|
|
# Configuration (read-only): the ONE file the container reads, at the same path
|
|
# inside and outside so that ZWAVE_EXTERNAL_SETTINGS names one path only.
|
|
#
|
|
# Never mount the whole /etc/quadlets/zwave-js-ui directory here. ":Z" relabels
|
|
# what it mounts to container_file_t, recursively and on disk, and init.sh lives
|
|
# in that directory: systemd can no longer execute it, so
|
|
# zwave-js-ui-init.service fails 203/EXEC at every boot after the first start of
|
|
# this container, and the Requires= above then keeps the container down with it.
|
|
# A machine that survived its install stops surviving a reboot.
|
|
#
|
|
# ConditionPathExists on this file above is also what keeps podman from creating
|
|
# a DIRECTORY at this path when the operator has not provided the file.
|
|
Volume=/etc/quadlets/zwave-js-ui/external-settings.json:/etc/quadlets/zwave-js-ui/external-settings.json:ro,Z
|
|
|
|
# Precious data: the store holds the node names, the associations, the NVM
|
|
# backups of the controller and the users of the web interface. It lives on the
|
|
# virtiofs mount so the host's ZFS snapshots and backups pick it up.
|
|
Volume=/var/lib/virtiofs/data/zwave-js-ui:/var/lib/virtiofs/data/zwave-js-ui:z
|
|
|
|
# Health check: /health is 200 only once the driver is connected to the
|
|
# controller AND the MQTT gateway is either connected or explicitly disabled
|
|
# (which is what the packaged initial-settings.json does). A radio head whose
|
|
# driver is down serves nothing, so that is the right thing to probe. The image
|
|
# has no curl; busybox wget exits non-zero on 500, which is all that is needed.
|
|
#
|
|
# The Accept header is what makes the probe a probe. A request that accepts HTML
|
|
# -- which includes one with no Accept header at all -- is taken by the
|
|
# single-page-application fallback and answered with a 301 to /health/ and then
|
|
# the web interface itself, 200, driver or no driver. The probe would pass
|
|
# forever. Asking for text/plain is what reaches the endpoint.
|
|
HealthCmd=wget -q -O /dev/null --header="Accept: text/plain" http://127.0.0.1:8091/health
|
|
HealthInterval=30s
|
|
HealthTimeout=10s
|
|
# First start downloads the device configuration database into the store, which
|
|
# takes a minute or so before the driver even opens the port.
|
|
HealthStartPeriod=180s
|
|
HealthRetries=5
|
|
|
|
[Service]
|
|
Restart=always
|
|
RestartSec=10
|
|
TimeoutStartSec=300
|
|
TimeoutStopSec=60
|
|
|
|
[Install]
|
|
WantedBy=zwave-js-ui.target
|
|
|