Skip to content


ZWaveJSController is the interface to Z-Wave JS. Currently, this Controller accesses Z-Wave JS through the zwave-js-server subsystem, which provides a WebSocket interface. This interface is provided when running either zwave-js-server or zwavejs2mqtt. Future versions of the controller will support direct serial/USB port control through the native library.


You will need to be running either zwave-js-server or zwavejs2mqtt. These subsystems are available on Github with complete instructions, so their installation will not be covered here.


If you don't have either installed, choose zwavejs2mqtt. It has some nice management tools that you will find handy.


zwavejs2mqtt and zwave-js-server open a port (3000) on which ZWaveJSController must connect. If you are using these tools as part of a Docker container or embedded install within HassOS, you will need to ensure that port 3000 is exported and accessible from outside these containers.

You will also need an Authorization Key to use ZWaveJSController. This is a temporary measure to limit the spread of its use to just those individuals participating in the evaluation and test phase. To get your Authorization Key, please PM (private message) your system's host public key to me on the Smart Home Community forums. Your host public key can be found on the About page in Reactor.

Supported Devices

Z-Wave JS has excellent device support, but like all Z-Wave systems, it doesn't perfectly support every possible thing that has ever been (or is currently) manufacturered. Z-Wave JS provides a searchable database where you can see if your device(s) is (are) supported. It should go without saying (but will be said anyway) that devices not supported by Z-Wave JS will not be supported by ZWaveJSController.


To configure an instance of ZWaveJSController:

  1. Make sure your ZWave-JS server instance (or zwavejs2mqtt) is running.
  2. If you are using zwavejs2mqtt, make sure WS Server is turned on in the Settings tab under Home Assistant. The setting of Disable MQTT Gateway does not matter to ZWaveJSController, nor does any other Home Assistant or MQTT setting.
  3. Open your reactor.yaml configuration file.
  4. In the controllers section, add the following template, substituting your site's IP address and Authorization Key:

    controllers:  # Don't add this line, it's just for indenting/placement reference
      - id: zwavejs
        implementation: ZWaveJSController
        enabled: true
          source: ws://  # modify the IP address as needed
          auth: >

    Remember that properly indenting using spaces (only) is vital to the integrity of YAML files. If you format your file incorrect, Reactor will not start. Make sure every line of the multi-line auth value is indented two spaces in from auth: > line above it, as shown.

  5. Restart Reactor.

  6. Connect to the Reactor UI using a browser.

You should be able to go to the Entities list in the Reactor UI and see at least the system entity for the controller instance. If your existing Z-Wave JS installation has configured devices, they should be visible as entities.

Entity Structure

Z-Wave devices are called nodes. A node can have one or more endpoints, which are effectively sub-units of the device.

Reactor maps one entity per endpoint, so a node with one endpoint (the most common scenario), will be represented by a single Reactor entity. If a node has additional endpoints, each endpoint will be represented by an additional entity.

Some command classes also require additional entities to represent properly. For example, the Central Scene command class, used by newer scene controllers, will typically represent scene notification value per button on the device. In this case, Reactor will create additional entities to represent each of the buttons. Currently, however, this is the only command class for which that is necessary.

As with other controllers, all values known for the node/endpoint will be published on the related entity. For recognized Z-Wave command classes and values, Reactor will use its native capabilities (e.g. power_switch, dimming, etc.); the rest are published in extended attributes. It is highly recommended you avoid direct use of the extended attributes in rule conditions. If you find you need something that Reactor is not providing in a native capability, open a post on the forums, describing the device in detail.

Setting Configuration Values

Some Z-Wave devices have configuration values that you can set. These can be set in one of two ways:

  1. Using the zwave_device.set_config action (preferred);
  2. Using the zwave_device.set_value action, specifying command class 112 (or the word "Configuration", the name of the command class), the configuration parameter number in the property field, empty propertyKey, and the value to be set (you can see why set_config is preferred).

You can set configuration values at any time. For some devices, this dynamically changes things like displayed LED colors or other "real time" parameters. These values are manufacturer- and device-dependent, so please refer to the device manufacturer's documentation for information.

The set_config action takes a bitmask argument that can be used to set or reset specific bits on a configuration value when needed. For some device configuration, this makes it easier to enable/disable specific features or behaviors controlled by individual bits in the value without disrupting other bits that control other things. If the bitmask is 0 or empty, the value given is set on the parameter and replaces the current value entirely. But, if bitmask is non-zero, only those bits having a 1 in their position of the bitmask are copied from the value onto the old value. For example, if the current value of a parameter is 13 (00001101b), and a value of 2 (00000010b) is given with a bitmask of 3 (00000011b), the parameter value written will be 14 (00001110b), because the bitmask only permits the lowest two bits to be written/copied. Turning a bit on can be accomplished by providing an identical value and bitmask with a 1 in the bit position; turning a bit off is accomplished with a value of 0 and a bitmask with a 1 in the bit position. For the techies, the specific statement used in establishing the new value is (roughly): newvalue = ( oldvalue & ~mask ) | ( value & mask ).


Some legacy Z-Wave devices do not support "instant status," so a manual change on the device (i.e. turn the switch on or off at the switch itself) does not send a message to the Z-Wave controller, and thus Z-Wave JS and Reactor cannot "see" the change. One way around this is polling the devices periodically, which requests a refresh of the data explicitly.


Polling can have a deleterious impact on mesh performance. Only poll those nodes that absolutely require it. Typically, these are just legacy Z-Wave nodes that do not support some form of instant status or hail when their state is changed manually (e.g. a switch operated by hand). Z-Wave Plus nodes do not usually require polling. Also, battery nodes will not be polled; they are refreshed during their wake-up intervals. Dead nodes are not polled (polling cannot be used to try to "reincarnate" them). Polling is also not a cure for an unstable or poor-quality mesh — in fact, it will likely make things much worse.

To configure a node for polling, add the following template to your ZWaveJSController config section (config line is shown for indenting reference only, do not include it when copy-pasting):

      poll_interval: 3600
      poll_frequency: 20
        - node: 30
          command_class: Binary Switch
        - entity: Upstairs Thermostat
          command_class: Thermostat Operating State
          interval: 120
        - entity: Upstairs Thermostat
          command_class: Thermostat Fan State
          interval: 120

The following is the meaning of each of the keys in this section:


Defines the default polling interval for all nodes to be polled (in seconds). If a node does not specify a different polling interval, this is how often (at the earliest) the node will be polled. The default polling interval is 3600 seconds (one hour).


The ZWaveJSController poller polls one eligible node at a time. To keep network traffic down, this is the minimum time between polls of eligible nodes. If 10 nodes are all due to be polled, it will take 10 × poll_frequency seconds (at least) to poll them all. The default frequency is 20 seconds.


Only specified nodes are polled, and this is the list. It is an array of objects, each of which must contain either a node key and node ID, or an entity key with an entity name or local ID (not a canonical ID). For each node, an optional interval may be specified to override the default. A command_class may be specified so that only that command class is refreshed, which can considerably reduce mesh traffic and is highly recommended. If command_class is not given, the entire node (all values) is refreshed. Note in the example/template that you can enter the same node/entity multiple times to poll multiple command classes. The known command classes are listed in Z-Wave JS.

Updated: 2022-Feb-19