Z-wave config files for Inovelli LZW60 with Home Assistant docker

Get “Portainer” up and running. It will tell you with a nice pretty web GUI where your volumes are coming from.

Thanks heaps for that Jon, I really appreciate it. I’m running in Unraid, so do have quite a nice GUI for Docker, but maybe there is something that I’m missing. Is the config mapping the folder in which I would find configurations.yaml etc?

$ docker run --init -d --name="home-assistant" -e "TZ=Europe/London" -v /home/gerdesj/docker/test-ha:/config -p 8123:8123 homeassistant/home-assistant:latest

$ docker ps
CONTAINER ID        IMAGE                                 COMMAND             CREATED             STATUS              PORTS                    NAMES
da9f45714090        homeassistant/home-assistant:latest   "/init"             47 seconds ago      Up 45 seconds>8123/tcp   home-assistant

$ docker exec -it home-assistant  /bin/bash

Right, now we are talking!

# find / -name "*.xml"

and we get this path:


If you fiddle with files in there they will get overwritten on an update. Off the top of my head a docker-compose job might be a good idea because you could deploy your changes into the container. Failing that, for simplicity keep your changes available and re apply them when updating the container.

I’m running fishwaldo’s OZW 1.6 in a separate docker container on a Pi where my RaZberry hat is which is separate from Debian box running HA. That way I just re-pull to get the latest & greatest and not have to wait for HA to implement a newer rev.

docker_version  | 19.03.12
hassio  | true
host_os  | Debian GNU/Linux 10 (buster)
installation_type  | Home Assistant Supervised
docker pull openzwave/ozwdaemon:allinone-latest
docker run -d \
 --name ozwd \
 --restart=unless-stopped \
 --security-opt seccomp=unconfined \
 --device=/dev/ttyAMA0 \
 -v $PWD/ozw:/opt/ozw/config \
 -e MQTT_SERVER="" \
 -e MQTT_USERNAME="homeassistant" \
 -e MQTT_PASSWORD="Aighio8ooVa3xaif4aipha2gi..........ohmeiph8Ciuthu8ThieHoopie0uth" \
 -e USB_PATH=/dev/ttyAMA0 \
 -e OZW_NETWORK_KEY=0xBC,0x87,0xD5, , , , , , , , , , , ,0xF9,0xD6,0x17 \
 -p 1983:1983 \
 -p 5901:5901 \
 -p 7800:7800 \

Here is the inovelli “031E” section from my manufacturer_specific.xml:

  <Manufacturer id="031E" name="Inovelli">
    <Product type="0002" id="0001" name="LZW30-SN Switch Red Series" config="inovelli/lzw30-sn.xml"/>
    <Product type="0004" id="0001" name="LZW30 Switch" config="inovelli/lzw30.xml"/>
    <Product type="0001" id="0001" name="LZW31-SN Dimmer Red Series" config="inovelli/lzw31-sn.xml"/>
    <Product type="0003" id="0001" name="LZW31 Dimmer" config="inovelli/lzw31.xml"/>
    <Product type="0005" id="0001" name="LZW42 Multi-Color Bulb" config="inovelli/lzw42.xml"/>
    <Product type="0006" id="0001" name="LZW41 Multi-White Bulb" config="inovelli/lzw41.xml"/>
    <Product type="0007" id="0001" name="LZW40 Dimmable  Bulb" config="inovelli/lzw40.xml"/>
    <Product type="000d" id="0001" name="LZW60 4-in-1 Sensor" config="inovelli/lzw60.xml"/>
    <Product type="000e" id="0001" name="LZW36 Fan/Light Dimmer" config="inovelli/lzw36.xml"/>

Here is my inovelli/lzw60.xml:

<Product Revision="1" xmlns="https://github.com/OpenZWave/open-zwave">
    <MetaDataItem name="OzwInfoPage">http://www.openzwave.com/device-database/031E:000d:0001</MetaDataItem>
    <MetaDataItem name="ProductPic">images/inovelli/lzw60.png</MetaDataItem>
    <MetaDataItem id="0001" name="ZWProductPage" type="000d">https://products.z-wavealliance.org/products/3723</MetaDataItem>
    <MetaDataItem name="ProductPage">https://inovelli.com/shop/smart-sensors/z-wave-4-in-1-sensor/</MetaDataItem>
    <MetaDataItem name="ProductSupport">https://inovelli.com/shop/smart-sensors/z-wave-4-in-1-sensor/</MetaDataItem>
    <MetaDataItem name="ExclusionDescription">To Exclude your switch, put your HUB in exclusion mode and press the Sensor Button on the back of the device one (1) time.</MetaDataItem>
    <MetaDataItem id="0001" name="FrequencyName" type="000d">U.S. / Canada / Mexico</MetaDataItem>
    <MetaDataItem name="ProductManual">https://products.z-wavealliance.org/ProductManual/File?folder=&amp;filename=product_documents/3723/Inovelli%204-1%20Sensor%20Manual.pdf</MetaDataItem>
    <MetaDataItem name="Description">Control and Monitor Temperature, Light, Motion, and Humidity with the 4 in 1 Sensor.</MetaDataItem>
    <MetaDataItem name="Name">LZW60 4-in-1 Sensor</MetaDataItem>
    <MetaDataItem id="0001" name="Identifier" type="000d">LZW60</MetaDataItem>
    <MetaDataItem name="InclusionDescription">To include your switch, start the inclusion process on your HUB and Sensor Button on the back of the device one (1) time.</MetaDataItem>

      <Entry author="Eric Maycock - [email protected]" date="7 Nov 2019" revision="1">Initial Release</Entry>
  <!-- Configuration Parameters -->
  <CommandClass id="112">
    <Value genre="config" type="byte" size="1" index="10" label="Low Battery Power Level Alarm" min="10" max="50" value="10">
      Value at which the sensor reports low battery to the gateway
      Default: 10
    <Value genre="config" type="byte" size="1" index="12" label="PIR Sensitivity" min="0" max="10" value="8">
      Change the sensitivity of the PIR (Motion) Sensor
          0 = off, 1 = Low sensitivity, 10 = High sensitivity
      Default: 8
    <Value genre="config" type="short" size="2" index="13" label="PIR Trigger Time (seconds)" min="5" max="15300" value="30">
      The amount of seconds between motion detection (ie: the interval)
      Default: 30
    <Value genre="config" type="list" size="1" index="14" label="Basic Set Command Send after PIR Trigger" min="0" max="1" value="0">
      Should Basic Set Command be sent after PIR is triggered? This is used to turn other devices on/off when motion is detected.
      Default: No
          <Item value="0" label="No"/>
          <Item value="1" label="Yes"/>
    <Value genre="config" type="list" size="1" index="15" label="PIR Trigger Correspondence Action" min="0" max="1" value="0">
      Ability to reverse the Basic Set behavior for devices associated in group 2
      Default: ON when motion is tripped, OFF when motion stops
          <Item value="0" label="ON when motion is tripped, OFF when motion stops"/>
          <Item value="1" label="OFF when motion is tripped, ON when motion stops"/>
    <Value genre="config" type="int" size="4" index="101" label="Temperature Sensor Read Interval" min="0" max="2768400" value="7200">
      The interval in which the temperature sensor is checked, in seconds. Set to 0 to disable (Note: will be rounded to the nearest minute)
      Default: 7200 (2 hours)
    <Value genre="config" type="int" size="4" index="102" label="Humidity Sensor Read Interval" min="0" max="2768400" value="7200">
      The interval in which the humidity sensor is checked, in seconds. Set to 0 to disable (Note: will be rounded to the nearest minute)
      Default: 7200 (2 hours)
    <Value genre="config" type="int" size="4" index="103" label="Luminance Sensor Read Interval" min="0" max="2768400" value="7200">
      The interval in which the luminance sensor is checked, in seconds. Set to 0 to disable (Note: will be rounded to the nearest minute)
      Default: 7200 (2 hours)
    <Value genre="config" type="int" size="4" index="104" label="Battery Level Read Interval" min="0" max="2768400" value="86400">
      The interval in which the battery level is checked, in seconds. Set to 0 to disable (Note: will be rounded to the nearest minute)
      Default: 86400 (24 hours)
    <Value genre="config" type="list" size="1" index="110" label="Sensor Report Method" min="0" max="1" value="0">
      Sensor reports are only checked at the interval defined in parameters 101-104.  Should the sensor data always be reported, or only if the value has changed more than the threshold configured in parameters 111-114?
          Always: Send sensor data every interval, even if the value did not change.
          Threshold: Send sensor data on interval, but only if the value has changed by more than the defined threshold since the last report was sent.
          Default: Always
          <Item value="0" label="Always"/>
          <Item value="1" label="Threshold" />
    <Value genre="config" type="short" size="2" index="111" label="Temperature Threshold" min="1" max="500" value="10">
      Set the temperature threshold of the sensor.  If Sensor Report Method = "Threshold", the temperature change must exceed this value in order to be reported to the hub.
          Range: 1-500
          1 = 0.1 degrees Celcius, 500 = 50 degrees Celcuis
      Default: 10 (1 degree Celcuis)
    <Value genre="config" type="byte" size="1" index="112" label="Humidity Threshold" min="1" max="32" value="5">
      Set the humidity threshold of the sensor.  If Sensor Report Method = "Threshold", the humidity change must exceed this value in order to be reported to the hub.
          Range: 1-32, 1 = 1%, 32 = 32%
      Default: 5%
    <Value genre="config" type="short" size="2" index="113" label="Luminance Threshold" min="1" max="65528" value="150">
      Set the luminance threshold of the sensor (in lux).  If Sensor Report Method = "Threshold", the luminance change must exceed this value in order to be reported to the hub.
          Range: 1-65528
      Default: 150
    <Value genre="config" type="byte" size="1" index="114" label="Battery Threshold" min="1" max="100" value="10">
      Set the battery threshold of the sensor (percent).  If Sensor Report Method = "Threshold", the battery level change must exceed this value in order to be reported to the hub.
          Range: 1-100
      Default: 10

  <!-- Association Groups -->
  <CommandClass id="133">
    <Associations num_groups="2">
      <Group index="1" label="Lifeline" max_associations="5" />
      <Group index="2" label="PIR Trigger Basic Set" max_associations="5" />

Hope that helps!

Thanks for the tip!!! Got “Portainer” up and running! It’s great!!

I finally now understand what -v $PWD/ozw:/opt/ozw/config \ actually means/does!
I was also able to fix my time/timezone inside the container via

mv /etc/localtime /etc/localtime.backup
ln -s /usr/share/zoneinfo/PST8PDT /etc/localtime

and in figuring out the above, I think I can add -e TZ=America/Vancouver \ to my docker run command so I should not have to fix it in future…

Thanks both, Daniel is it straightforward to get an external Openzwave running with HA docker? Slightly worried about destroying my config!

In retrospect I would say It is straightforward however at 3 am and xx # beers I cannot guarantee my response is coherent! If you understand my above docker pull / docker run commands then it should be painless… Lemme know if you have trouble or need clarification of anything. I’ve done lots of reading and experimenting to get to where I am and am willing to help shortcut the learning process.
I did change my run command (-v $PWD/OZW:/opt/ozw/config \ & added the TZ variable) to my liking:

docker run -d \
 --name ozw \
 --restart=unless-stopped \
 --security-opt seccomp=unconfined \
 --device=/dev/ttyAMA0 \
 -v /opt/ozw/config:/opt/ozw/config \
 -e TZ=America/Vancouver \
 -e MQTT_SERVER="" \
 -e MQTT_USERNAME="homeassistant" \
 -e MQTT_PASSWORD="Aighio8 . . . . Hoopie0uth" \
 -e USB_PATH=/dev/ttyAMA0 \
 -e OZW_NETWORK_KEY=0xBC,..,0xD5,..,0x51,..,0xA7,..,0x05,..,0xEA,..,0xBC,..,0xD6,.. \
 -p 1983:1983 \
 -p 5901:5901 \
 -p 7800:7800 \

Tip: Doing -v /etc/localtime:/etc/localtime:ro will import the hosts timezone automagicly for you :wink:
The ‘ro’ is read only so the container doesn’t try to change the host’s timezone on you.

Thanks! I’ve updated my docker cheatsheet and will use that on my next update.
HA Supervisor is logging in UTC. Would I make the same change for it or does it always log in UTC?

Same tweak should work there as well.

I edited /usr/sbin/hassio-supervisor which is launched by the systemd service hassio-supervisor.service and added -v /etc/localtime:/etc/localtime:ro \ and restarted the service but hassio failed to initialize. So I reverted my change, rebooted, connected to the container using portainer and issued the following:
cat /usr/sbin/zoneinfo/Canada/Pacific > /etc/localtime and ‘date’ was then correct. I restarted the service, reconnected to the container and ‘date’ is still correct. I’ll re-try the -v option…maybe I had a typo in it???

TBH I’ve never started a Docker manually, but I’m learning a lot here! I wonder if a sneaky pip upgrade of openzwave in the Home Assistant docker would have the desired effect…

Ah, now I see that the openzwave implementation is a special Home Assistant package :confused:

I just verified from my docker compose:

    container_name: home-assistant
    restart: unless-stopped
    image: homeassistant/home-assistant:beta
      - "mariadb"
      - /home/docker/home-assistant:/config
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    network_mode: host
    privileged: true

-v /etc/localtime:/etc/localtime:ro should work

I used this link to install hass and I have a systemd service:

Description=Hass.io supervisor
After=docker.service dbus.socket

ExecStartPre=-/usr/bin/docker stop hassio_supervisor
ExecStop=-/usr/bin/docker stop hassio_supervisor



#!/usr/bin/env bash
set -e

# Load configs

SUPERVISOR="$(jq --raw-output '.supervisor' ${CONFIG_FILE})"
HOMEASSISTANT="$(jq --raw-output '.homeassistant' ${CONFIG_FILE})"
DATA="$(jq --raw-output '.data // "/usr/share/hassio"' ${CONFIG_FILE})"

# AppArmor Support
if command -v apparmor_parser > /dev/null 2>&1 && grep hassio-supervisor /sys/kernel/security/apparmor/profiles > /dev/null 2>&1; then
    APPARMOR="--security-opt apparmor=hassio-supervisor"
    APPARMOR="--security-opt apparmor:unconfined"

# Init supervisor
HASSIO_IMAGE_ID=$(docker inspect --format='{{.Id}}' "${SUPERVISOR}")
HASSIO_CONTAINER_ID=$(docker inspect --format='{{.Image}}' hassio_supervisor || echo "")

runSupervisor() {
    docker rm --force hassio_supervisor || true

    # shellcheck disable=SC2086
    docker run --name hassio_supervisor \
        --privileged \
        $APPARMOR \
        --security-opt seccomp=unconfined \
        -v /run/docker.sock:/run/docker.sock \
        -v /run/dbus:/run/dbus \
        -v "${HASSIO_DATA}":/data \
        -e TZ=America/Vancouver \
        -e SUPERVISOR_NAME=hassio_supervisor \
# Run supervisor
mkdir -p "${HASSIO_DATA}"
([ "${HASSIO_IMAGE_ID}" = "${HASSIO_CONTAINER_ID}" ] && docker start --attach hassio_supervisor) || runSupervisor
[email protected]:~# 

but there’s no TZ variable set inside the container:


The ‘cat … > /etc/localtime’ is sticking so I’m good.


As I’m sure you’re aware, but for the benefit of other readers who might see this, you need:

Supervisor, Add-on: Mosquitto Broker
Configuration, Integration: MQTT Mosquitto Broker
Configuration, Integration: OpenZWave (beta)
and one piece left…

  1. Supervisor, Add-on: OpenZWave (which lags behind the latest OpenZWave 1.6)
  2. Your own docker container with OpenZwave 1.6

I’m not sure if you can go option 1 and somehow upgrade it to openzwave:latest or not…

I’m not particularly aware haha.

So if I perform those steps, my Zwave devices will appear to HA as MQTT devices?

No, they appear as OpenZWave devices. MQTT is the middleman between the OpenZWave 1.6 (add-on/separate docker container) and the OpenZWave (beta) integration.

Very interesting, maybe I’m getting closer to comprehension.

I have been using the Zwave integration, maybe I should be trying to use this Openzwave beta integration

It is the way of the future…