OpenZWave / Zwave2Mqtt

Fully configurable Zwave to MQTT gateway and Control Panel using NodeJS and Vue
MIT License
354 stars 93 forks source link
control-panel gateway groups hacktoberfest iot mqtt mqttjs nodejs open-zwave openzwave ozwcp ozwcp-replacement scene scenes vue vuetify zwave zwave-network zwave2mqtt

Zwave To MQTT

GitHub package.json version PRs Welcome MadeWithVueJs.com shield MIT Licence ci Docker Build GitHub All Releases Coverage Status Known Vulnerabilities Dependencies Status devDependencies Status Total alerts Language grade: JavaScript

Join channel

Buy Me A Coffee

dockeri.co

OpenZWave TO MQTT

Fully configurable Zwave to MQTT Gateway and Control Panel.

THIS PROJECT IS UNMAINTAINED. PLEASE CONSIDER MOVING TO Zwavejs

!! ATTENTION

After a discussion with Openzwave maintainer all issues related to OZW 1.4 will be ignored and automatically closed as it isn't supported anymore, please use OZW 1.6+

đź“– Table of contents

:electric_plug: Installation

DOCKER :tada: way

# Using volumes as persistence
docker run --rm -it -p 8091:8091 --device=/dev/ttyACM0 --mount source=zwave2mqtt,target=/usr/src/app/store robertslando/zwave2mqtt:latest

# Using local folder as persistence
mkdir store
docker run --rm -it -p 8091:8091 --device=/dev/ttyACM0 -v $(pwd)/store:/usr/src/app/store robertslando/zwave2mqtt:latest

# As a service
wget https://raw.githubusercontent.com/openzwave/zwave2mqtt/master/docker/docker-compose.yml
docker-compose up

Replace /dev/ttyACM0 with your serial device

For more info about docker check here

Kubernetes way

kubectl apply -k https://raw.githubusercontent.com/OpenZWave/Zwave2Mqtt/master/kustomization.yaml

You will almost certainly need to instead use this as a base, and then layer on top patches or resource customizations to your needs or just copy all the resources from the kubernetes resources directory of this repo

NodeJS or PKG version

  1. Firstly you need to install the Open-Zwave library on your system.

    cd ~
    git clone https://github.com/OpenZWave/open-zwave.git
    cd open-zwave && make && sudo make install
    sudo ldconfig
    export LD_LIBRARY_PATH=/usr/local/lib64
    sudo sed -i '$a LD_LIBRARY_PATH=/usr/local/lib64' /etc/environment

    For Raspberry check here

  2. Test the library: go to openzwave directory cd openzwave-* and run the command

    MinOZW /dev/ttyACM0

    replace /dev/ttyACM0 with the USB port where your controller is connected

  3. Now you can use the packaged version (you don't need NodeJS/npm installed) or clone this repo and build the project:

    • For the packaged version:

      cd ~
      mkdir Zwave2Mqtt
      cd Zwave2Mqtt
      # download latest version
      curl -s https://api.github.com/repos/OpenZWave/Zwave2Mqtt/releases/latest  \
      | grep "browser_download_url.*zip" \
      | cut -d : -f 2,3 \
      | tr -d \" \
      | wget -i -
      unzip zwave2mqtt-v*.zip
      ./zwave2mqtt
    • If you want to compile last code from github:

      git clone https://github.com/OpenZWave/Zwave2Mqtt
      cd Zwave2Mqtt
      npm install
      npm run build
      npm start
  4. Open the browser http://localhost:8091

Reverse Proxy Setup

If you need to setup ZWave To MQTT behind a reverse proxy that needs a subpath to work, take a look at the reverse proxy configuraiton docs.

:nerd_face: Development

Developers who wants to debug the application have to open 2 terminals.

In first terminal run npm run dev to start webpack-dev for front-end developing and hot reloading at http://localhost:8092 (THE PORT FOR DEVELOPING IS 8092)

In the second terminal run npm run dev:server to start the backend server with inspect and auto restart features (if you don't have nodemon installed: npm install -g nodemon)

To package the application run npm run pkg command and follow the steps

Developing against a different backend

By default running npm run dev:server will proxy the reequests to a backend listening on localhost on port 8091.

If you want to run the development frontend against a different backend you have the following environment variables that you can use to redirect to a different backend:

:wrench: Usage

Firstly you need to open the browser at the link http://localhost:8091 and edit the settings for Zwave, MQTT and the Gateway.

Zwave

Zwave settings:

MQTT

Mqtt settings:

Gateway

Gateway settings:

Once finished press SAVE and gateway will start Zwave Network Scan, than go to 'Control Panel' section and wait until the scan is completed to check discovered devices and manage them.

Settings, scenes and Zwave configuration are stored in JSON/xml files under project store folder that you can easily import/export for backup purposes.

Special topics

<mqtt_prefix>/<?node_location>/<node_name>/status

<mqtt_prefix>/<?node_location>/<node_name>/event

OZW 1.4:

<mqtt_prefix>/<?node_location>/<node_name>/scene/event (value will be the scene event code)

OZW 1.6: In OZW 1.6 scenes are treated like a valueID (so the topic depends on gateway configuration). For example if the command class is 91 (central_scene) and gateway uses valueid topics

<mqtt_prefix>/<?node_location>/<node_name>/91/1/1 (value published in payload will depend on gateway payload type)

Gateway values table

The Gateway values table can be used with all gateway types to customize specific values topic for each device type found in the network and do some operations with them. Each value has this properties:

:file_folder: Nodes Management

Add a node

To add a node using the UI select the controller Action Add Node (inclusion), click send (:airplane:) button to enable the inclusion mode in your controller and enable the inclusion mode in your device to. Controller status will be waiting when inclusion has been successfully enabled on the controller and completed when the node has been successfully added. Wait few seconds and your node will be visible in the table once ready.

Remove a node

To add a node using the UI select the controller Action Remove Node (exclusion), click send (:airplane:) button to enable the exclusion mode in your controller and enable the exclusion mode in your device to. Controller status will be waiting when exclusion has been successfully enabled on the controller and completed when the node has been successfully removed. Wait few seconds and your node will be removed from the table.

Replace failed node

To replace a failed node from the UI you have to use the command Replace Failed Node, if everything is ok the controller will start inclusion mode and status will be Waiting, now enable inclusion on your device to add it to the network by replacing the failed one.

Remove a failed node

If a node is missing or marked as dead. There is a way to cleanup the controller by executing Remove Failed Node. This will forcebly delete the node from the controller. It can only succeed if:

Alive and Sleeping nodes cannot be deleted.

:star: Features

:robot: Home Assistant integration (BETA)

At least Home Assistant >= 0.84 is required!

The easiest way to integrate Zwave2Mqtt with Home Assistant is by using MQTT discovery. This allows Zwave2Mqtt to automatically add devices to Home Assistant. To enable this feature remember to set the flag Hass Discovery in Gateway settings configuration.

ATTENTION: Hass updates often break Zwave2Mqtt device discovery. For this reason Zwave2Mqtt will try to be always compatible with latest hass version. Check the changelog before update!

To achieve the best possible integration (including MQTT discovery):

NB: Starting from version 4.0.0 the default Birth/Will topic is homeassistant/status in order to reflect defaults birth/will of Hass 0.113 th

mqtt:
  discovery: true
  discovery_prefix: <your_discovery_prefix>
  broker: [YOUR MQTT BROKER] # Remove if you want to use builtin-in MQTT broker
  birth_message:
    topic: 'hass/status' # or homeassistant/status if z2m version >= 4.0.0
    payload: 'online'
  will_message:
    topic: 'hass/status' # or homeassistant/status if z2m version >= 4.0.0
    payload: 'offline'

Mind you that if you want to use the embedded broker of Home Assistant you have to follow this guide.

Zwave2Mqtt is expecting Home Assistant to send it's birth/will messages to hass/status (or homeassistant/status if z2m version >= 4.0.0). Be sure to add this to your configuration.yaml if you want Zwave2Mqtt to resend the cached values when Home Assistant restarts.

Zwave2Mqtt try to do its best to guess how to map devices from Zwave to HASS. At the moment it try to guess the device to generate based on zwave values command classes, index and units of the value. When the discovered device doesn't fit your needs you can you can set custom a device_class to values using Gateway value table.

Components management

To see the components that have been discovered by Zwave2Mqtt go to Control Panel UI, select a Node from the Nodes table then select the Node tab from tabs menu at the bottom of Nodes table. Now at the Bottom of the page, after Node values section you can find a new section called Home Assistant - Devices. Here you will see a table with all devices created for the selected node.

Hass Devices

ATTENTION Once edited the devices will loose all their customizations after a restart. To prevent this you can store the node hassDevices by pressing STORE button at the top of hass devices table. By pressing it the hassDevices will be stored in nodes.json file that can be imported/exported easily from control panel UI at the top of nodes table.

Rediscover Node

If you update node name/location you have to also rediscover values of this node as they may have wrong topics. To do this press on REDISCOVER NODE green button on top of Home Assistant - Devices table (check previous picture)

Edit existing component

If you select a device it's configuration will be displayed as a JSON object on the right. With the selected device you can edit it and send some actions:

Add new component

If no device is selected you can manually insert a device JSON configuration. If the configuration is valid you can press the button Add to add it to devices. If the process complete successfully the device will be added to the Hass Devices table and you can now select it from the table and press on Rediscover to discover your custom device

Custom Components

At the moment auto discovery just creates components like sensor, cover binary_sensor and switch. For more complex components like climate and fan you need to provide a configuration. Components configurations are stored in hass/devices.js file. Here are contained all components that Zwave2MQTT needs to create for each Zwave device type. The key is the Zwave device unique id (<manufacturerid>-<productid>-<producttype>) the value is an array with all HASS components to create for that Zwave Device.

UPDATE: Starting from version 2.0.7 you can specify your custom devices configuration inside store/customDevices(.js|.json) file. This allows users that use Docker to create their custom hass devices configuration without the need to build a new container. If using .json format Zwave2Mqtt will watch for file changes and automatically load new components on runtime without need to restart the application.

ONCE YOU SUCCESSFULLY INTEGRATE NEW COMPONENTS PLEASE SEND A PR!

Identify the Device id

Starting from version 2.2.0 device id is shown on node tab of control panel before the inputs for update the node name and locations.

Before version 2.2.0 you can get the device id in this ways:

First (and easier) option is to add a random value in gateway values table for the desired device, the device id will be visible in first column of the table (Devices) between square brackets [<deviceID>] Device Name

Second option would be to retrieve it from here. Each device has Manufacturerid, product id and a product type in HEX format and needs to be converted in decimal:

<Manufacturer id="019b" name="ThermoFloor AS">
    <Product config="thermofloor/heatit021.xml" id="0001" name="Heatit Thermostat TF 021" type="0001"/>
    <Product config="thermofloor/heatit056.xml" id="0202" name="Heatit Thermostat TF 056" type="0003"/>
    <Product config="thermofloor/heatit-zdim.xml" id="2200" name="Heatit ZDim" type="0003"/>
</Manufacturer>

In this example, if we have choose Heatit Thermostat TF 056:

So in decimal format will become: 411-514-3. This is the device id of Heatit Thermostat TF 056

Thermostats

{
    "411-1-1":[
        { // Heatit Thermostat TF 021 (ThermoFloor AS)
            "type": "climate",
            "object_id": "thermostat",
            "values": ["64-1-0", "49-1-1", "67-1-1", "67-1-2"],
            "mode_map": {"off": "Off", "heat": "Heat (Default)", "cool": "Cool"},
            "setpoint_topic": { "Heat (Default)": "67-1-1", "Cool": "67-1-2" },
            "default_setpoint": "67-1-1",
            "discovery_payload": {
                "min_temp": 15,
                "max_temp": 30,
                "modes": ["off", "heat", "cool"],
                "mode_state_topic": "64-1-0",
                "mode_command_topic": true,
                "current_temperature_topic": "49-1-1",
                "current_temperature_template": "{{ value_json.value }}",
                "temperature_state_template": "{{ value_json.value }}",
                "temperature_command_topic": true
            }
        }
    ]
}

Thermostats are most complex components to create, in this device example the setpoint topic changes based on the mode selected. Zwave2Mqtt handles the mode changes by updating the device discovery payload to match the correct setpoint based on the mode selected.

Fans

{ // GE 1724 Dimmer
    "type": "fan",
    "object_id": "dimmer",
    "values": ["38-1-0"],
    "discovery_payload": {
        "command_topic": "38-1-0",
        "speed_command_topic": "38-1-0",
        "speed_state_topic": "38-1-0",
        "state_topic": "38-1-0",
        "speeds": ["off", "low", "medium", "high"],
        "payload_low_speed": 24,
        "payload_medium_speed": 50,
        "payload_high_speed": 99,
        "payload_off": 0,
        "payload_on": 99,
        "state_value_template": "{% if (value_json.value | int) == 0 %} 0 {% else %} 99 {% endif %}",
        "speed_value_template": "{% if (value_json.value | int) == 25 %} 24 {% elif (value_json.value | int) == 51 %} 50 {% elif (value_json.value | int) == 99 %} 99 {% else %} 0 {% endif %}"
    }
}

Thermostats with Fans

The main template is like the thermostat template. The things to add are:

{ // GoControl GC-TBZ48 (Linear Nortek Security Control LLC)
    "type": "climate",
    "object_id": "thermostat",
    "values": [
        "49-1-1",
        "64-1-0",
        "66-1-0", // <-- add fan values
        "67-1-1",
        "67-1-2",
        "68-1-0" // <-- add fan values
    ],
    "fan_mode_map": { // <-- add fan modes map
        "on": "On",
        "auto": "Auto"
    },
    "mode_map": {
        "off": "Off",
        "heat": "Heat",
        "cool": "Cool",
        "auto": "Auto"
    },
    "setpoint_topic": {
        "Heat": "67-1-1",
        "Cool": "67-1-2"
    },
    "default_setpoint": "67-1-1",
    "discovery_payload": {
        "min_temp": 60,
        "max_temp": 85,
        "modes": [
            "off",
            "heat",
            "cool",
            "auto"
        ],
        "fan_modes": [ // <-- add fan supported modes
            "on",
            "auto"
        ],
        "action_topic": "66-1-0",
        "mode_state_topic": "64-1-0",
        "mode_command_topic": true,
        "current_temperature_topic": "49-1-1",
        "current_temperature_template": "{{ value_json.value }}",
        "temperature_state_template": "{{ value_json.value }}",
        "temperature_low_command_topic": true,
        "temperature_low_state_template": "{{ value_json.value }}",
        "temperature_high_command_topic": true,
        "temperature_high_state_template": "{{ value_json.value }}",
        "fan_mode_command_topic": true,
        "fan_mode_state_topic": "68-1-0" // <-- add fan state topic
    }
}

:gift: MQTT APIs

You have full access to all Openzwave-Shared APIs (and more) by simply using MQTT.

Zwave Events

If Send Zwave Events flag of Gateway settings section is enabled all Zwave events are published to MQTT. Here you can find a list with all available events

Topic

<mqtt_prefix>/_EVENTS_/ZWAVE_GATEWAY-<mqtt_name>/<event name>

Payload

{
  "data": [ "1.4.3319" ] // an array containing all args in order
}

Example

Topic

zwave2mqtt/_EVENTS/ZWAVE_GATEWAY-z2m/node_ready

Payload

{
  "data": [
    1,
    {
      "manufacturer": "AEON Labs",
      "manufacturerid": "0x0086",
      "product": "ZW090 Z-Stick Gen5 EU",
      "producttype": "0x0001",
      "productid": "0x005a",
      "type": "Static PC Controller",
      "name": "",
      "loc": ""
    }
  ]
}

Zwave APIs

To call a Zwave API you just need to publish a JSON object like:

{
  "args": [2, 1]
}

Where args is an array with the args used to call the api, the topic is:

<mqtt_prefix>/_CLIENTS/ZWAVE_GATEWAY-<mqtt_name>/api/<api_name>/set

The result will be published on the same topic without /set

Example: If I publish the previous json object to the topic

zwave/_CLIENTS/ZWAVE_GATEWAY-office/api/getAssociations/set

I will get this response (in the same topic without the suffix /set):

{
  "success": true,
  "message": "Success zwave api call",
  "result": [1]
}

result will contain the value returned from the API. In this example I will get an array with all node IDs that are associated to the group 1 (lifeline) of node 2.

Custom APIs

There are some custom apis that can be called that are not part of Zwave Client:

Set values

To write a value using MQTT you just need to send the value to set in the same topic where the value updates are published by adding the suffix /set to the topic (READONLY VALUES CANNOT BE WRITE).

Example with gateway configured with named topics:

If I publish the value 25.5 (also a payload with a JSON object with the value in value property is accepted) to the topic

zwave/office/nodeID_4/thermostat_setpoint/heating/set

I will set the Heating setpoint of the node with id 4 located in the office to 25.5. To check if the value has been successfully write just check when the value changes on the topic:

zwave/office/nodeID_4/thermostat_setpoint/heating

Broadcast

You can send broadcast values to all values with a specific suffix in the network.

Broadcast API is accessible from:

<mqtt_prefix>/_CLIENTS/ZWAVE_GATEWAY-<mqtt_name>/broadcast/<value_topic_suffix>/set

It works like the set value API without the node name and location properties. If the API is correctly called the same payload of the request will be published to the topic without /set suffix.

Example of broadcast command (gateway configured as named topics):

zwave/_CLIENTS/ZWAVE_GATEWAY-test/broadcast/thermostat_setpoint/heating/set

Payload: 25.5

All nodes with command class thermostat_setpoint and value heating will be set to 25.5 and I will get the same value on the topic:

zwave/_CLIENTS/ZWAVE_GATEWAY-test/broadcast/thermostat_setpoint/heating

:camera: Screenshots

Settings

OpenZWave

Control Panel

Control Panel

Groups associations

Groups

Scenes

Scenes

Mesh

Mesh

Debug

Debug

Health check endpoints

/health: Returns 200 if both mqtt and zwave client are connected, 500 otherwise /health/mqtt: Returns 200 if mqtt client is connected, 500 otherwise /health/zwave: Returns 200 if zwave client is connected, 500 otherwise

Remember to add the header: Accept: text/plain to your request.

Example: curl localhost:8091/health/zwave -H "Accept: text/plain"

Environment variables

Note: Each one of the following environment variables corresponds to their respective options in the UI settings and options saved in the UI take presence over these environment variables.

:question: FAQ

A: Why when I add a value to Gateway values table I don't see all my devices?

B: When adding values to the gateway values table it shows JUST ONE DEVICE FOR EACH TYPE. This is to make it easier and faster to setup your network as if you have a network with lot devices (light, light dimmers for example) you just need to add the values you want to bridge to mqtt (for a light it will always be just the switch to turn it on/off for exmple without all configuration values) and it will bridge those values for all the devices of that type (without configure the values one by one).

A: My device is X and has been discovered as Y, why?

B: Hass Discovery is not easy, zwave have many different devices with different values. To try to understand how to discover a specific value I have used this file that shows what kind of value is expeted based on value class and index. Unfortunally not all devices respect this specifications so for those cases I have created Hass Devices table where you can manually fix the discovery payload and than save it to make it persistent. I have also created a file /hass/devices.js where I place all devices specific values configuration, your contribution is needed there, so submit a PR with your files specification to help it grow.

:pray: Thanks

Thanks to this people for help with issues tracking and contributions:

:pencil: TODOs

:bowtie: Author

Daniel Lando

Support me on Patreon :heart: