zwave-js / node-zwave-js

Z-Wave driver written entirely in JavaScript/TypeScript
https://zwave-js.github.io/node-zwave-js/
MIT License
755 stars 613 forks source link

Support Leviton scene/zone controllers #2397

Open j9brown opened 3 years ago

j9brown commented 3 years ago

Is your feature request related to a problem? Please describe.

Now that OpenZWave is deprecated in Home Assistant, I've started looking at device support that I'll need to migrate over to node-zwave-js. This issue concerns Leviton devices (of which I have many) such as VRCS2, VRCS4, VRCZ2, VRCZ4, VRR15, VRS15, etc.

These devices use some custom and less common command classes for various features. OpenZWave never supported them but I was able to work around the limitations by sending raw Zwave commands and parsing responses (not ideal). I'd love to implement a better solution for node-zwave-js but need some guidance.

Features needed:

Describe the solution you'd like

I basically need some help to plan the changes needed to support these features. I'm happy to write the code or provide documentation or test cases to delegate to someone else more familiar with this project.

For LED setting, we'll need a custom command-class. How should vendor-specific classes be implemented?

For scene activations, we'll need some method to configure the device's scene groups and receive activations so that the button presses can be handled correctly. This setting uses a different set of messages from the usual configuration parameters or association groups so how should it work?

Describe alternatives you've considered

If there's a way to send/receive raw Zwave messages then I could keep using my own code which generates/parses them but it wouldn't be of much use to anyone else.

Additional context

Here are some technical details from a patch request I sent to OpenZwave but didn't commit (because it would have required deeper changes to the project to implement properly): https://github.com/j9brown/open-zwave/tree/master/config/leviton

I reverse engineered most of this using a Zniffer.

For example, this explains some quirks of VRCZ4.

<!-- Indicator Lights -->
  <!-- Use these messages to override the indicator lights.
       91 00 1D 0D 01 00 00 : Reset LEDs to locally controlled operation (default behavior).
       91 00 1D 0D 01 FF xx : Set LEDs by OR-ing together the following bit patterns.
         00000000: button 1 off
         00000001: button 1 green
         00010000: button 1 red
         00010001: button 1 amber
         00000000: button 2 off
         00000010: button 2 green
         00100000: button 2 red
         00100010: button 2 amber
         00000000: button 3 off
         00000100: button 3 green
         01000000: button 3 red
         01000100: button 3 amber
         00000000: button 4 off
         00001000: button 4 green
         10000000: button 4 red
         10001000: button 4 amber
  -->

  <!-- Scene Control -->
  <!-- Use these messages to assign scenes to the controller's buttons.
       When no scene is assigned (default behavior), the controller sends BASIC_SET messages
       to association groups 1 to 4 corresponding to the active button.
       When a scene is assigned, the controller sends scene activations and level change messages
       that offer richer control of the device's behavior.
       The controller has 8 scene groups:
         - Groups 1-4 are triggered when buttons 1-4 are toggled to the left side.
         - Groups 5-8 are triggered when buttons 1-4 are toggled to the right side.

       To configure the scenes, send SCENE_CONTROLLER_CONF_SET to associate scenes with
       each scene group.  The simplest solution is to assign scene groups 1-8 to scenes 1-8
       so they are in one-to-one correspondence using the following messages:
         2D 01 01 01 00 : Set scene group 1 to scene 1
         2D 01 02 02 00 : Set scene group 2 to scene 2
         2D 01 03 03 00 : Set scene group 3 to scene 3
         2D 01 04 04 00 : Set scene group 4 to scene 4
         2D 01 05 05 00 : Set scene group 5 to scene 5
         2D 01 06 06 00 : Set scene group 6 to scene 6
         2D 01 07 07 00 : Set scene group 7 to scene 7
         2D 01 08 08 00 : Set scene group 8 to scene 8

       Once this is done, the controller will send SCENE_ACTIVATION_SET to the devices
       in association groups 1-4 whenever their corresponding scenes are triggered.  To handle
       these messages centrally, make sure to associate the primary controller (node 1) with
       association groups 1-4.  The primary controller will then receive messages like this:
         2B 01 S# 00 : Sent by controller when scene S# is triggered

       When you press the up/down level below the scene buttons, the controller will send
       send SWITCH_MULTILEVEL_START_LEVEL_CHANGE and SWITCH_MULTILEVEL_STOP_LEVEL_CHANGE messages
       to the association group corresponding to the most recently activated scene.
         26 04 40 00 : Sent by controller when the down lever is pressed
         26 05       : Sent by controller when the down lever is released
         26 04 00 00 : Sent by controller when the up lever is pressed
         26 05       : Sent by controller when the up lever is released

       After a scene change, the controller sometimes sends SCENE_ACTUATOR_CONF_GET messages
       (2C 02 00) to query the scene configuration of the controlled devices.  The controlled
       devices should reply with SCENE_ACTUATOR_CONF_REPORT (2C 03 <sceneId> FF 00) to confirm
       the scene change.  Ignoring the message works too although the controller seems to ask
       several times after each scene change until it gets the expected reply.

       Scene messages interact with the indicator light change messages described above.
       Turning on and off button LEDs determines whether the controller considers the
       corresponding scenes to be active.
  -->
blhoward2 commented 3 years ago

Edit: Removing discussion of the scene configuration part because we support that CC already (with a bug). See below.

I'm actually impressed you figured out the button light piece. Mine were just frequently wrong.

blhoward2 commented 3 years ago

Also, node does support sending raw messages already. https://zwave-js.github.io/node-zwave-js/#/usage/custom

From that any UI could if it chose handle this.

And, as of a few days ago, zwavejs2mqtt allows you to send a custom driver message under the Advanced tab from which you could setup the scene events.

Screen Shot 2021-04-18 at 10 28 30 PM

I'll leave it to @AlCalzone to decide if we intend to offer custom command classes beyond that at the node-zwave-js level.

j9brown commented 3 years ago

Hmm, that's good. I noticed Home Assistant doesn't plumb that service through yet but that's fixable.

Does node-zwave-js also support receiving raw messages?

For OpenZWave I used the ugly but effective expedient of parsing the logs in real time! 🤣

On Sun, Apr 18, 2021 at 7:20 PM blhoward2 @.***> wrote:

Also, node does support sending raw messages already. https://zwave-js.github.io/node-zwave-js/#/usage/custom

From that any UI could if it chose handle this. I'll leave it to @AlCalzone https://github.com/AlCalzone to decide if we intend to offer custom command classes beyond that at the node-zwave-js level.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/zwave-js/node-zwave-js/issues/2397#issuecomment-822122543, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAY7BAGBO5HEQLGSPVWBVLTJOHPLANCNFSM43EUKB5A .

blhoward2 commented 3 years ago

@AlCalzone will need to comment on that. From the docs:

Sending unimplemented get-type commands does not actually make sense since the response will silently be dropped.

My guess is that it would be an easier sell to overcome that than creating and supporting completely custom command classes, especially in light of the need. Our analytics are still early stage but so far there is only one Leviton device on the list and it isn't one of these (DZ15S). And I expect the Zooz ZEN32 would cut even further into these devices. (I've replaced my VRC4's with them.)

HA did recently add a SERVICE ZWAVE_JS.SET_VALUE but I believe it only calls values setup already. It may be possible to expand that to include raw commands or create a new service. The dev_zwave channel on the HA discord would be a good place to take the devs temperature as to whether they'd merge such a PR.

j9brown commented 3 years ago

Actually it looks like that "better way" is pretty much what I have done.

I'd just like to make the configuration more systematic in some way so that other people don't have to jump through hoops to make this work. Back in the day, Vera configured these Leviton devices out of the box for scene support and even supported the quirky indicator LEDs.

It'd be neat if node-zwave-js provided an extensible way to configure and access device-specific functionality. For example, suppose that the device configuration files allowed developers to describe "services" for the device that could be enumerated and shown in a UI, similar to how other parameters are exposed.

Pseudo-code example:

services: [
  {
    name: "Configure scene button reports",
    commands: [
       { class: "scene_controller_conf", params: ... },
       { class: "scene_controller_conf", params: ... },
       ... 6 more of these ...
    ]
  }, {
  name: "Set indicators",
  parameters: ... define the leds and their colors ...
  commands: [
    { bytes: ... synthesize the message ... }
  ]}
]

On Sun, Apr 18, 2021 at 7:10 PM blhoward2 @.***> wrote:

So, there is a better way. You can configure those to send normal scene commands with a little work. https://blog.gruby.com/2019/01/04/setting-up-a-leviton-vrcz4-m0z-for-use-with-home-assistant/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/zwave-js/node-zwave-js/issues/2397#issuecomment-822119919, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAY7BDKFU3ELEZOEI6OA4DTJOGI3ANCNFSM43EUKB5A .

blhoward2 commented 3 years ago

Edit: Removing the scene configuration discussion to make this easier to follow.

As for the services idea, could you flesh out other circumstances where this may be helpful and have wider applicability? OZW became, in my view (and I think other's view), bloated and complex because of a lot of one-off quirks built into the code base. We try to live by a different mantra, including working with manufacturers to fix things when possible. What else are you envisioning? I get the configuring for scene events here but I'm unaware of any other device that needs a similar setup.

It's an interesting idea but it would be a fair bit of work for the UIs I suspect and UI space is at a premium.

blhoward2 commented 3 years ago

@robertsLando Thoughts from your end? An enumerated list of device-specific scripts (if you will) defined in the config files?

j9brown commented 3 years ago

Another example of weird stuff is my Intermatic spa controller. Some values need to be refreshed after setting them. The thermostats are also a little non-standard.

That said, the Leviton scene configuration behavior is technically an official command class in the spec so one could argue that it should be handled by the stack during device setup and/or presented to the user (just like associations).

But there's always a question of what trade-offs are appropriate for supporting rarely used features, "advanced" functionality, or quirky hardware.

Right now, when the stack doesn't know how to support some feature, responsibility falls on the user to set things up, perhaps after reading blog posts or doing some reverse engineering (hopefully not?). It's pretty tedious.

This seems like a problem that the device database can help users with in various ways either in machine readable form (such as by formally describing config params) or as a resource for finding relevant device specific documentation.

Personally, I'm biased towards encoding more information in a machine readable way, such as the quirky commands for setting LEDs. I don't know how common this is but it's probably not a singular occurrence. (I wonder if there's a good way to search for examples of folks sending raw zwave commands.)

Some of the setup I had to do for my system was pretty finicky. I was really glad to have the Zwave PC apps and a Zniffer on hand.

So...

I think what I'm really looking for is a single source of truth for device configuration and control.

Zwave devices have a lot of internal state. Getting these Leviton controllers to work required quite a few steps none of which were automated. After the fact, there wasn't any record of what changes were made or how to reproduce them. Just some docs and ad-hoc scripts I wrote for myself.

For robustness, I'd love a model where the user specified the intended goal state for device configuration and the stack made the necessary queries and settings to get there. Assuming all of those settings are machine readable. 😁

On Sun, Apr 18, 2021 at 8:31 PM blhoward2 @.***> wrote:

Yes, I meant rather than implementing a new command class. If you couldn't figure out (or sell AlCalzone) on the idea for the LEDs, users could still configure it for scene events. I realized after that you could probably figure it out to do it through zwavejs2mqtt. That was literally added on like Friday.

As for the services idea, could you flesh out other circumstances where this may be helpful and have wider applicability? OZW became, in our view, bloated and complex because of a lot of one-off quirks built into the code base. We try to live by a different mantra, including working with manufacturers to fix things when possible. What else are you envisioning? I get the configuring for scene events here but I'm unaware of any other device that needs a similar setup.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/zwave-js/node-zwave-js/issues/2397#issuecomment-822141761, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAY7BBHOCWJOT4A62EQZN3TJOPZZANCNFSM43EUKB5A .

blhoward2 commented 3 years ago

It looks like we claim support for scene controller configuration.

Screen Shot 2021-04-19 at 1 26 22 AM

I was able to set the first four scene IDs and I see them come through when I hit the button. I'm not sure what happened to the other four though.

01:27:51.054 SERIAL « 0x010d00a800015e042b01030000c2ea (15 bytes)
01:27:51.057 CNTRLR [Node 094] [!] [Scene Activation] sceneId: 3 [Endpoint 0]
01:27:51.059 CNTRLR [Node 094] [~] [Scene Activation] dimmingDuration: {"value":0,"un [Endpoint 0]
it":"seconds"} => {"value":0,"unit":"seconds"}
01:27:51.062 SERIAL » [ACK] (0x06)
01:27:51.069 DRIVER « [Node 094] [REQ] [BridgeApplicationCommand]
└─[SceneActivationCCSet]
scene id: 3
dimming duration: [Duration: 0 seconds]
01:27:53.077 SERIAL « 0x01150049845e0f020100852d7c778273867291ef2b2caa (23 bytes)
01:27:53.079 SERIAL » [ACK] (0x06)
blhoward2 commented 3 years ago

@AlCalzone I'm unclear why we only query four scene IDs when there are eight. Where does it get four from...the fact there are four association groups? It should query double that number as each group has two scene IDs for on/off.

01:32:14.439 CNTRLR [Node 094] SceneControllerConfigurationCC: doing a complete interview...
01:32:14.439 CNTRLR » [Node 094] querying scene configuration for association group #1...
01:32:14.441 SERIAL » 0x010f00a9015e032d020125000000001618 (17 bytes)
01:32:14.441 DRIVER » [Node 094] [REQ] [SendDataBridge]
│ source node id: 1
│ transmit options: 0x25
│ route: 0, 0, 0, 0
│ callback id: 22
└─[SceneControllerConfigurationCCGet]
group id: 1
01:32:14.447 SERIAL « [ACK] (0x06)
01:32:14.448 SERIAL « 0x010401a90152 (6 bytes)
01:32:14.448 SERIAL » [ACK] (0x06)
01:32:14.449 DRIVER « [RES] [SendDataBridge]
was sent: true
01:32:14.462 SERIAL « 0x011800a91600000100bf7f7f7f7f0101030000000002010000e6 (26 bytes)
01:32:14.463 SERIAL » [ACK] (0x06)
01:32:14.464 DRIVER « [REQ] [SendDataBridge]
callback id: 22
transmit status: OK
01:32:14.493 SERIAL « 0x010e00a800015e052d0301010000c0ed (16 bytes)
01:32:14.496 CNTRLR [Node 094] [Scene Controller Configuration] sceneId[1]: metadata [Endpoint 0]
updated
01:32:14.498 CNTRLR [Node 094] [Scene Controller Configuration] dimmingDuration[1]: m [Endpoint 0]
etadata updated
01:32:14.499 CNTRLR [Node 094] [+] [Scene Controller Configuration] sceneId[1]: 1 [Endpoint 0]
01:32:14.501 CNTRLR [Node 094] [+] [Scene Controller Configuration] dimmingDuration[1 [Endpoint 0]
]: {"value":0,"unit":"seconds"}
01:32:14.504 SERIAL » [ACK] (0x06)
01:32:14.508 DRIVER « [Node 094] [REQ] [BridgeApplicationCommand]
└─[SceneControllerConfigurationCCReport]
group id: 1
scene id: 1
dimming duration: [Duration: 0 seconds]
01:32:14.512 CNTRLR « [Node 094] received scene configuration for association group #1:
scene ID: 1
dimming duration: [Duration: 0 seconds]
01:32:14.512 CNTRLR » [Node 094] querying scene configuration for association group #2...
01:32:14.518 SERIAL » 0x010f00a9015e032d02022500000000171a (17 bytes)
01:32:14.519 DRIVER » [Node 094] [REQ] [SendDataBridge]
│ source node id: 1
│ transmit options: 0x25
│ route: 0, 0, 0, 0
│ callback id: 23
└─[SceneControllerConfigurationCCGet]
group id: 2
01:32:14.526 SERIAL « [ACK] (0x06)
01:32:14.529 SERIAL « 0x010401a90152 (6 bytes)
01:32:14.529 SERIAL » [ACK] (0x06)
01:32:14.531 DRIVER « [RES] [SendDataBridge]
was sent: true
01:32:14.541 SERIAL « 0x011800a91700000100bf7f7f7f7f0101030000000002010000e7 (26 bytes)
01:32:14.542 SERIAL » [ACK] (0x06)
01:32:14.542 DRIVER « [REQ] [SendDataBridge]
callback id: 23
transmit status: OK
01:32:14.576 SERIAL « 0x010e00a800015e052d0302020000bf92 (16 bytes)
01:32:14.577 CNTRLR [Node 094] [Scene Controller Configuration] sceneId[2]: metadata [Endpoint 0]
updated
01:32:14.578 CNTRLR [Node 094] [Scene Controller Configuration] dimmingDuration[2]: m [Endpoint 0]
etadata updated
01:32:14.578 CNTRLR [Node 094] [+] [Scene Controller Configuration] sceneId[2]: 2 [Endpoint 0]
01:32:14.578 CNTRLR [Node 094] [+] [Scene Controller Configuration] dimmingDuration[2 [Endpoint 0]
]: {"value":0,"unit":"seconds"}
01:32:14.579 SERIAL » [ACK] (0x06)
01:32:14.581 DRIVER « [Node 094] [REQ] [BridgeApplicationCommand]
└─[SceneControllerConfigurationCCReport]
group id: 2
scene id: 2
dimming duration: [Duration: 0 seconds]
01:32:14.582 CNTRLR « [Node 094] received scene configuration for association group #2:
scene ID: 2
dimming duration: [Duration: 0 seconds]
01:32:14.582 CNTRLR » [Node 094] querying scene configuration for association group #3...
01:32:14.584 SERIAL » 0x010f00a9015e032d020325000000001814 (17 bytes)
01:32:14.584 DRIVER » [Node 094] [REQ] [SendDataBridge]
│ source node id: 1
│ transmit options: 0x25
│ route: 0, 0, 0, 0
│ callback id: 24
└─[SceneControllerConfigurationCCGet]
group id: 3
01:32:14.598 SERIAL « [ACK] (0x06)
01:32:14.599 SERIAL « 0x010401a90152 (6 bytes)
01:32:14.599 SERIAL » [ACK] (0x06)
01:32:14.600 DRIVER « [RES] [SendDataBridge]
was sent: true
01:32:14.605 SERIAL « 0x011800a91800000100c07f7f7f7f010103000000000201000097 (26 bytes)
01:32:14.606 SERIAL » [ACK] (0x06)
01:32:14.606 DRIVER « [REQ] [SendDataBridge]
callback id: 24
transmit status: OK
01:32:14.636 SERIAL « 0x010e00a800015e052d0303030000c0ed (16 bytes)
01:32:14.638 CNTRLR [Node 094] [Scene Controller Configuration] sceneId[3]: metadata [Endpoint 0]
updated
01:32:14.652 CNTRLR [Node 094] [Scene Controller Configuration] dimmingDuration[3]: m [Endpoint 0]
etadata updated
01:32:14.654 CNTRLR [Node 094] [+] [Scene Controller Configuration] sceneId[3]: 3 [Endpoint 0]
01:32:14.655 CNTRLR [Node 094] [+] [Scene Controller Configuration] dimmingDuration[3 [Endpoint 0]
]: {"value":0,"unit":"seconds"}
01:32:14.656 SERIAL » [ACK] (0x06)
01:32:14.660 DRIVER « [Node 094] [REQ] [BridgeApplicationCommand]
└─[SceneControllerConfigurationCCReport]
group id: 3
scene id: 3
dimming duration: [Duration: 0 seconds]
01:32:14.661 CNTRLR « [Node 094] received scene configuration for association group #3:
scene ID: 3
dimming duration: [Duration: 0 seconds]
01:32:14.661 CNTRLR » [Node 094] querying scene configuration for association group #4...
01:32:14.663 SERIAL » 0x010f00a9015e032d020425000000001912 (17 bytes)
01:32:14.663 DRIVER » [Node 094] [REQ] [SendDataBridge]
│ source node id: 1
│ transmit options: 0x25
│ route: 0, 0, 0, 0
│ callback id: 25
└─[SceneControllerConfigurationCCGet]
group id: 4
01:32:14.670 SERIAL « [ACK] (0x06)
01:32:14.670 SERIAL « 0x010401a90152 (6 bytes)
01:32:14.670 SERIAL » [ACK] (0x06)
01:32:14.671 DRIVER « [RES] [SendDataBridge]
was sent: true
01:32:14.687 SERIAL « 0x011800a91900000100c07f7f7f7f010103000000000201000096 (26 bytes)
01:32:14.687 SERIAL » [ACK] (0x06)
01:32:14.688 DRIVER « [REQ] [SendDataBridge]
callback id: 25
transmit status: OK
01:32:14.718 SERIAL « 0x010e00a800015e052d0304040000c0ed (16 bytes)
01:32:14.719 CNTRLR [Node 094] [Scene Controller Configuration] sceneId[4]: metadata [Endpoint 0]
updated
01:32:14.719 CNTRLR [Node 094] [Scene Controller Configuration] dimmingDuration[4]: m [Endpoint 0]
etadata updated
01:32:14.720 CNTRLR [Node 094] [+] [Scene Controller Configuration] sceneId[4]: 4 [Endpoint 0]
01:32:14.720 CNTRLR [Node 094] [+] [Scene Controller Configuration] dimmingDuration[4 [Endpoint 0]
]: {"value":0,"unit":"seconds"}
01:32:14.721 SERIAL » [ACK] (0x06)
01:32:14.722 DRIVER « [Node 094] [REQ] [BridgeApplicationCommand]
└─[SceneControllerConfigurationCCReport]
group id: 4
scene id: 4
dimming duration: [Duration: 0 seconds]
01:32:14.723 CNTRLR « [Node 094] received scene configuration for association group #4:
scene ID: 4
dimming duration: [Duration: 0 seconds]
01:32:14.723 CNTRLR [Node 094] [+] [Scene Controller Configuration] interv [Endpoint 0] [internal]
iewComplete: true
01:32:14.723 CNTRLR [Node 094] Interview stage completed: CommandClasses
robertsLando commented 3 years ago

An enumerated list of device-specific scripts (if you will) defined in the config files?

Would be ok for me!

AlCalzone commented 3 years ago

For LED setting, we'll need a custom command-class. How should vendor-specific classes be implemented?

If you're willing to do the work, you can take a look at how we're handling the Fibaro CC, which is also based on Manufacturer Proprietary CC (0x91): https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ManufacturerProprietaryCC.ts https://github.com/zwave-js/node-zwave-js/tree/master/packages/zwave-js/src/lib/commandclass/manufacturerProprietary

That technically is an official CC, but the official part is just the framework for manufacturer specific implementations. Since every manufacturer is free to do their own thing within the framework, I think it is hardly feasibly to do that all in configuration.


I'm unclear why we only query four scene IDs when there are eight.

Straight from the Z-Wave specs:

The Scene Controller Configuration Command Class is used to configure nodes launching scenes using their association groups. [...] The grouping identifier values MUST be a sequence starting from 1. The Association Supported Groupings Get Command may be used to request the number of groupings that a node supports.

So, yeah... The device supports 4 association groups, so zwave-js queries 4 scene groups. There's currently no way to detect that there are in fact 8 groups. We'd need a compat flag for this.


Does node-zwave-js also support receiving raw messages?

This is probably unnecessary if you implement the proprietary Leviton CC, but you could do this with https://zwave-js.github.io/node-zwave-js/#/api/driver?id=registerrequesthandler and provide a custom implementation that inspects the received message if it is the one you're looking for. Disclaimer: I have never used that for CCs, only some unsolicited controller messages.


As for the services idea: I can see where this is coming from, but IMO that belongs in a higher layer than the driver.

sarahmva commented 3 years ago

Leviton Scene Controllers have been part of my system since the beginning. Maybe I can provide some information how I use LED's and the different colors:

I use the scene button to control two different scenes, not like the traditional "on/off". At the moment I have configured the scene controller for 6 scenes and an on/off for a fan.

For the scenes I use the LED colors to indicate which scene is running: left: green, right: orange, both scenes: red, no scene off.

For the last toggle: LED is green when operated manually, orange when running on schedule and red if fan operation is blocked (e.g. due to AC running)

I basically use them as status indicator. Currently in Vera but I am starting to move all the devices to Home Assistant.

One other thing I like about the Leviton Scene controllers is the ability to use the bottom paddle to change brightness level on scenes / associated devices. I think Vera converts a lot of the scenes in associations.

pletch commented 3 years ago

@j9brown, are you working on the required modifications for implementing LED color control on the VRCS / VRCZ scene controllers?

I recently moved all of my kit from Vera to ZwaveJS except for one VRCS4 device. I am using some custom LUA scripting on the Vera to fire off a Home Assistant web hook that will manage states of my home theater equipment and set the color of the associated scene button depending on the status of the equipment. Since there appears to be no way to control the button LED or even detect scene controller button presses in Home Assistant with the VRCS devices, I have left this scene controller as my lone device on the Vera for now.

Would you mind sharing some of the details on how you have set things up to detect scene button presses and achieved control of the LED color via custom scripting? I am happy enough to use a python script or otherwise to replicate the desired functionality until it is properly exposed in the Zwave-JS driver.

j9brown commented 3 years ago

Hi Tim, I've been busy with other projects so I haven't done any work on this yet. I mostly wanted to confirm that there would be a plausible path for me to move to Zwave-JS once I'm ready to invest the effort. ;)

This part of my home automation system is currently implemented using Home Assistant and Node RED together with Zwave2MQTT. It relies on being able to inject and receive raw Zwave messages because Zwave2MQTT doesn't support the necessary command classes. Zwave2MQTT supports sending raw Zwave messages by sending a properly formatted MQTT message to the correct endpoint. Unfortunately, it doesn't support receiving raw Zwave messages but it does dump all received Zwave messages to its log. So I wrote some hacky code to parse the log in real-time and decode the messages. Surprisingly, it's been quite reliable!

Anyhow, the situation with Zwave-JS seems a little different at this point.

1) I don't think it's possible to inject raw Zwave messages from Home Assistant right now. At least, I wasn't able to find a suitable API wired up to Zwave-JS through a Home Assistant service at the time I last checked. So setting LEDs isn't possible yet. (Note that a better solution would be to implement a custom command class for indicators in Zwave-JS itself anyhow.)

2) I think Zwave-JS parses Scene Activation commands and Multi-Level Switch changes unlike OpenZWave. So I don't think it'll be necessary to parse raw Zwave messages. I think that these messages might show up as value changes with command class 43 and 38 respectively.

So here's what you can do:

  1. Use SCENE_CONTROLLER_CONF_SET to set up all of the 8 scene groups described at the beginning of this thread. I did this manually with the Zwave PC Controller program but perhaps there's a better way in Zwave-JS now.

  2. Try pressing buttons on your scene/zone controller. Look to see if Zwave-JS emits value change events with command class 43 command 1 (2B 01). The value associated with this event will tell you which scene group was activated and that will tell you which button was pressed. If this works as I hope it does, then you should be able to write some automation code to handle these value change events and do stuff as desired.

Good luck! Jeff.

On Fri, Jun 11, 2021 at 10:43 AM Tim @.***> wrote:

@j9brown https://github.com/j9brown, are you working on the required modifications for implementing LED color control on the VRCS / VRCZ scene controllers?

I recently moved all of my kit from Vera to ZwaveJS except for one VRCS4 device. I am using some custom LUA scripting on the Vera to fire off a Home Assistant web hook that will manage states of my home theater equipment and set the color of the associated scene button depending on the status of the equipment. Since there appears to be no way to control the button LED or even detect scene controller button presses in Home Assistant with the VRCS devices, I have left this scene controller as my lone device on the Vera for now.

Would you mind sharing some of the details on how you have set things up to detect scene button presses and achieved control of the LED color via custom scripting? I am happy enough to use a python script or otherwise to replicate the desired functionality until it is properly exposed in the Zwave-JS driver.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/zwave-js/node-zwave-js/issues/2397#issuecomment-859739886, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAY7BAOYYGBHNEZ66ZP4TLTSJDLNANCNFSM43EUKB5A .

blhoward2 commented 3 years ago

You may still be able to send a raw message by using zwavejs2mqtt and turning on mqtt to do so. You can turn the api on without using mqtt discovery. The driver supports raw messages and zjs2mqtt does in the UI but I've never checked via mqtt itself.

https://zwave-js.github.io/zwavejs2mqtt/#/guide/mqtt

pletch commented 3 years ago

I have started to revisit this and am thoroughly confused on how to implement the actual syntax of the raw command in Zwave-JS required for setting the button led color on my VRCS4.

I already have a simple python based websockets client working which will connect and pass commands to zwavejs-server. I would like to now use the client in a script to set the colors on these buttons.

The command class detail provided here for the ManufacturerProprietaryCC https://www.silabs.com/documents/login/miscellaneous/SDS13781-Z-Wave-Application-Command-Class-Specification.pdf provides details for the data payload framing for this class.

Based on the detail provided by @j9brown at the beginning this issue, a data payload of: 91 00 1D 0D 01 FF 00 will set the LEDs to off on all four buttons.
91 = command class 00 = manf ID 1 1D = manf ID 2 0D = Data 1 01 = Data 2 FF = Data 3 00 = Data 4

I have spent quite a bit of time and cannot figure out the syntax that I should use to pass a custom command to set this value on node 33 in my setup via the ZwaveJS websocket server. Can someone more versed in this possible provide a hint?

If this is not possible via websockets, what would the corresponding command look like if sent via mqtt to the zwavejs2mqtt api?

blhoward2 commented 3 years ago

I don't know the specific command, but it's likely easier to test in zwavejs2mqtt. It has a place to run raw JavaScript commands to the stick so you're removing a lot of middleware until you figure it out.

kpine commented 3 years ago

The Javascript "console" in zwavejs2mqtt is a great place to test out stuff like this, so I second the recommendation.

For the websocket server you should be able to use the endpoint.invoke_cc_api command with the Manufacturer Proprietary CC API.

I would try something like:

{
  "messageId": "invoke-mfg-prop-cc-set",
  "command": "endpoint.invoke_cc_api",
  "nodeId": 33,
  "endpoint": 0,
  "commandClass": 145, // command class = 0x91
  "methodName": "sendData",
  "args": [
    29, // manufacturerId = 0x001D
    [13, 1, 255, 0] // data = 0D 01 FF 00
  ]
}

What I'm not sure about is the data argument which is a Buffer type... will a JSON array convert to a Buffer?

MQTT has the equivalent sendCommand topic.

pletch commented 3 years ago

Thank you @kpine! Your suggestion is exactly where I ended up last evening and you precisely identified the remaining issue. After trying many iterations and a fair bit of googling, I don't think there is a way to serialize a byte object to JSON via python json.dumps() which will successfully pass into ZwaveJS.

ZwaveJS is receiving the command but complains as follows: 2021-08-21 00:02:59.736 ERROR ZWAVE-SERVER: Z-Wave error Message dropped because of an unexpected error: The "list[1]" argument must be an instance of Buffer or Uint8Array. Received an instance of Array TypeError [ERR_INVALID_ARG_TYPE]: The "list[1]" argument must be an instance of Buffer or Uint8Array. Received an instance of Array at Function.concat (buffer.js:574:13)at ManufacturerProprietaryCC.serialize (/home/homeassistant/Packages/zwavejs2mqtt/node_modules/zwavejs/src/lib/commandclass/ManufacturerProprietaryCC.ts:197:25)...............

I suspect that for this to work, ZwaveJS has to be modified. Fixed in zwave-js-server 1.10.3.

Ikcelaks commented 3 years ago

3354 adds the compat flag that these devices need to see all 8 scene groups.

pmoneill commented 3 years ago

I would really appreciate any support for a Leviton VRCZ4-M0Z 4-button scene controller in the Z-Wave JS implementation in Home Assistant. I can add the device but the HA device configuration page does not give any way to associate other entities with any of the 4 buttons like I could with the old HA Classic Z-Wave driver.

blhoward2 commented 3 years ago

HA doesn't yet let you manage associations for any devices. You need to use zwavejs2mqtt to do so. It's just waiting on UI support on their end.

pmoneill commented 3 years ago

blhaoward2, Thanks for the clarification. I'm running the HA Z-Wave JS integrations with the Z-Wave JS add-on that it installed. I am concerned that addin zwavejs2mqtt will create a conflict. What is the proper configuration?

blhoward2 commented 3 years ago

You can't run both addons but they both run the same driver in the background. You stop the zwavejs addon, start the zwavejs2mqtt addon, and reconfigure the zwavejs integration to uncheck the box so it doesn't reinstall the original one. No need to rename or anything so long as you don't remove the integration itself.

dlasher commented 2 years ago

I would really appreciate any support for a Leviton VRCZ4-M0Z 4-button scene controller in the Z-Wave JS implementation in Home Assistant. I can add the device but the HA device configuration page does not give any way to associate other entities with any of the 4 buttons like I could with the old HA Classic Z-Wave driver.

I would completely agree. There are quite a few of us trying to migrate away from Cloud-Based solutions like SmartThings, and have a non-small number of the Leviton Scene controllers installed. (6 here myself) - would appreciate them functioning, at least as "push button, be able to trigger action"... Color buttons would be a bonus later. :)

AlCalzone commented 2 years ago

@dlasher You'll have to request support in the https://github.com/home-assistant/core repository. The driver (node-zwave-js) has had association support for a long time, but it needs to be implemented by applications aswell.

As for the proprietary CC support: This is non-trivial without having a device to test with. Most other CCs have specs to implement against, this one doesn't. Anyone with some programming skills and a Leviton device will have to step up for this.

dra2885 commented 2 years ago

I've gotten two Leviton VRCZ4s to work in my instance of HA Container + zwavejs2mqtt after a ton of trial-and-error. I use the Z-wave JS integration in HA rather than MQTT for z-wave devices .. someone smarter than me can hopefully figure out how to apply this to an MQTT use-case.

Here's a summary of the steps I took.

  1. In the control panel for zwavejs2mqtt, go to the scene controller configuration section for the VRCZ4 node you want to work with. Set a value from 1-8 for each associated scene ID. You'll need to make an API call for each value (click the little envelope).

    image
  2. I then setup the dev tools in HA to listen for zwave_js_value_notification and started pressing buttons. Here's an example of the output for one of the button presses.

{
    "event_type": "zwave_js_value_notification",
    "data": {
        "domain": "zwave_js",
        "node_id": 40,
        "home_id": XXXXXXXXXXXX,
        "endpoint": 0,
        "device_id": "f9d0bb43cac374e433f2b0efa692490b",
        "command_class": 43,
        "command_class_name": "Scene Activation",
        "label": "Scene ID",
        "property": "sceneId",
        "property_name": "sceneId",
        "property_key": null,
        "property_key_name": null,
        "value": 1,
        "value_raw": 1
    },
    "origin": "LOCAL",
    "time_fired": "2022-01-26T04:03:55.053569+00:00",
    "context": {
        "id": "830a5db7de03696630d49700f2b27cc1",
        "parent_id": null,
        "user_id": null
    }
}
  1. The two key pieces of data are the node_id (which you obviously already know) and the value_raw. The value_raw will be different for each button you press and correspond to the values you set in step 1. Each paddle will have two values (i.e., they are two buttons).

  2. Now you can create automations by listening to the zwave_js_value_notification event type for these two pieces of data. For example:

    - id: 'Set lights for dinner'
    alias: Set lights for dinner
    trigger:
    - platform: event
      event_type: zwave_js_value_notification
      event_data:
        node_id: 40
        value_raw: 1

I'm not sure how to set the LEDs for different states, but at least the above will get your switches functioning inside of HA. I'm sure there is a way to actually tie these to switches in HA, too .. I'm just using them as physical triggers for scenes and routines, so that hasn't been as important to me.

If all you want to do is associate other z-wave devices to the buttons, you can do that in the group tab in zwavejs2mqtt. I haven't figured out a way to do that inside HA, though I haven't really felt the need to.

AlCalzone commented 2 years ago

FWIW, https://github.com/zwave-js/node-zwave-js/pull/4701 makes it less messy to define new proprietary CC implementations

alexeip0 commented 6 months ago

In case someone is still looking for a solution. I have pretty much all of the feature I used to have with Vera working with Home Assistant (LED propagation, intensity buttons, etc) and way more reliably than with Vera.

I posted all the code and instructions here: https://github.com/alexeip0/vrcz4_updater/

The only feature that is still missing is supporting direct association between VRCZ4s and loads, i.e. right now it has to go through HA, so if HA is down - controllers are effectively dead. With Vera only LED propagation would stop working if Vera was down, so I'm pretty sure they used direct association.

I believe the same can be achieved with HA if we had ability to trigger off of this event:

2024-05-16T07:06:37.496Z SERIAL « 0x0115004984050f020100852d7c778273867291ef2b2cf1                    (23 bytes)
2024-05-16T07:06:37.498Z SERIAL » [ACK]                                                                   (0x06)
2024-05-16T07:06:37.500Z DRIVER « [Node 005] [REQ] [ApplicationUpdateRequest] payload: 0x050f020100852d7c778273867291ef2b2c
2024-05-16T07:06:37.501Z CNTRLR « [Node 005] Received updated node info
2024-05-16T07:06:37.502Z CNTRLR   [Node 005] Node does not send unsolicited updates; refreshing actuator and sensor values...

HA observes it when a controller button is pressed, even if controllers are configured for direct association to other loads. The event is always the same, so it doesn't tell you which button was pressed, but the scripts' logic can be changed to deal with that by refreshing loads.

AlCalzone commented 6 months ago

Thanks for investigating. I've opened a feature request for that. Makes sense to support this IMO.

j9brown commented 6 months ago

Fwiw, I use the indicators of my controllers differently. When my script receives a button press event, it activates the next scene in a programmed sequence and lights up the button with a color that indicates the currently active scene (green -> amber -> red). I don’t use direct associations to define these scenes because they involve non-Zwave devices so my script handles all of the activation logic by way of Home Assistant. It works well for me.

Anyhow, it sounds like adding an optional feature to manage the LED states automatically could be useful for some folks. I’d still want to continue driving the LEDs with my own logic to avoid any interference.

Incidentally, I believe the Leviton controllers are designed to automatically update the LED states to their controlled loads themselves when they receive scene change reports from those loads but the mechanism isn’t reliable or supported by all devices. You can see this mechanism in action with associations for load loads (particularly VRCS2 with its built-in relays).