Dimmer duration seemingly not working on Zwave Devices When using Generic Z-Wave Smart Dimmer driver

Maybe it is just me, or maybe I'm going crazy - all possible things.

On my C-8 ( I have various zwave devices using the "Generic Z-Wave Smart Dimmer" driver.

If I start with a level of say 25, and go to the device detail page and enter a level of 99 with duration of 300, I would expect it to gradually increase brightness over 5 minutes. What actually happens is the level immediately goes to 99.

I also turned debug logging on, and see nothing in the logs when doing a level change (but I do see other commands like on/off). So I have no idea what it is doing.

Example, I turned the lamp off, then after 1s did a level change (99, 30s) to turn it on.... Nothing in the logs on the level change until the level was reported back some time later.

Using my custom "GE Z-Wave Plus Dimmer" driver, it fades on a level change as expected, so it seems like a driver issue more than a platform issue (?).

The zwave spec only allows for up to 254 for the duration, and it is broken down such that 0-127 is in seconds, and 128-254 is in minutes where 128 = 1 minute.

Here is my notes on it and the code the converts it in my setLevel commands. I am just converting anything above 120 (2 minutes) over to minutes. This might result in a decimal, I am dealing with that later in the code but you could also wrap that calculation in a Math.round()

	// Duration Encoding:
	// 0x01..0x7F 1 second (0x01) to 127 seconds (0x7F) in 1 second resolution.
	// 0x80..0xFE 1 minute (0x80) to 127 minutes (0xFE) in 1 minute resolution.
	// 0xFF Factory default duration.

	//Convert seconds to minutes above 120s
	if (duration > 120) duration = (duration / 60) + 127

The Zooz ZEN7x switches support the proper spec, the older ZEN2x do not, and count everything as seconds. I use it on one switch (ZEN72) for my bedroom lights to ramp up over 5 minutes and it works great.

1 Like

It does the same thing if I enter 30 (for example) as well. Really ANY duration value does not work on the "Generic Z-Wave Smart Dimmer" for me.

As it works fine in my custom driver, I have to deduce there is an issue with the in-box driver.

I do the same math you do for durations in some of my drivers. As you mention, not all devices respect/use it properly though. GE has a few quirky ones just like Zooz does.

Ok missed that part I just saw the 300 and went ah ha I know whats wrong!

Looking at the logs it appears the driver is possibly using the Basic command class, I can double check but I doubt it supports duration. It would probably have to use SwitchMultiLevel to get the duration. The Basic class would give broader support on many devices.

It is possible it is sending the correct class though, and the device responds with the Basic class, no way to tell what it is sending unless you zniffer the traffic, that I know of.


The device does send a basic report on its own, I see it when doing level changes via switchMultilevelSet too.

I have a zniffer, just too lazy to drag it out since switching to my custom driver fixed it (on this GE device).

To your point, since it isn't logging the command, can't tell exactly what it is doing without sniffing.

FYI @bcopeland

You can specify a value with Basic Set, I think the Zooz devices will take it and set the level.

This is why I hate using the generic system drivers and just find or make my own for most devices. Biggest plus factor for me is if something is going wrong I can look at the driver code.

1 Like

You can definitely set a value with BasicSet - you just shouldn't. :wink:

(joking of course... For a multilevel device though, really one should use a switchMultilevelSet in my novice opinion)

If you are not using the +127 converting for the duration to minutes on your driver you should try it out and see if it works on GE. It gives a nice smooth fade instead of faking it with the hub functions that step it up.

1 Like

I will. I know it works on the motion dimmer GE device as I've done 20 minute fades before in the device.

Looks like I didn't add the conversion in this particular driver though.

I'll go add it in and see. If I remember correctly it will work without the conversion if you do a .format on it, as it will convert the duration.

So when you use your driver, does the device automatically respond with the multiLevel class or Basic? If it responds with multiLevel the generic driver is most definitely sending a Basic command.

Undocumented secret features.... I never use the .format() because I never actually knew what the heck it did besides convert it, which happens anyway somehow it seems. Works without it, why bother using it. Now I am going to have to check that out.

I was wrong, the device does not automatically send a Basic Report. So that must be something Hubitat is going in their generic driver.

The way I do it in my driver is send a switchMultilevelSet and then after the duration + 1s send a switchMultilevelGet to ensure I get a fresh value.

I knew I had this discussion before - not that it goes into gory technical detail though, so it doesn't answer if a 2s complement conversion is being done there or elsewhere. I thought all zwave values specified were 2s complemented though (could be wrong on that).

Sounds like the format() just passes it as a string instead of the entire command class, so yeah probably not a bad idea to use that. Now to test your theory on the duration encoding. Especially since in most of my drivers it gets passed between 3 functions before it hits the secure encap function.

1 Like

Does not look format does anything special with the duration

200 = 0xC8
If it was converting it, 200 is around 3 minutes, which would be 130 or 0x82


If you send something over the limit of 255 it looks like it converts to hex and chops it to the last byte, so 258 becomes 2 seconds, which I tested and it did fade in 2 seconds.


1 Like

Side note.... a change like this, if I were to add .format() to everything, I have to touch and check a whole bunch of drivers. I have seriously been considering doing a library for common stuff which is probably over 50% of the code on the drivers I do.

Any thoughts on that? I feel like it would make my life easier for maintaining. But updates to users not so much. I would either have to include the library as a bundle in every single HPM package, which I only have 5 so not terrible. But if I update it, people would get 5 updates from all 5 packages, for the same file, not sure how that would work even. OR, I could do it as a separate package, but then lots of people will NOT get that package first, and then complain they cant install the driver from HPM.... its a lose lose for the users.

Hmm... I could just make it required in every package, but never bump the versions. Then make a separate package just for the library where I could bump the version to push updates....

You're right. I just tried it too. Guess I need to go back and change my setLevel coding on all my drivers. lol

I've thought about that too, but it seems to be more trouble than I'm willing to deal with once you factor in distribution and updates to the shared library.

That said, I might just be lazy / not thinking it all the way through.

1 Like

What would be really awesome is if multiple people teamed up and make a super zwave library so making a full driver is easier.

I have this scanner tool I have worked on and it scans the parameters and presents them to the user based on what the device reports. I have this grand idea where you could switch to this scanner tool. Scan the settings, then switch back to a universal-ish driver for the type of device it is. It would read the stored settings and poof you have a customized driver for that device. I would also have an export/import function on the scanner so you could write a formatted text file (JSON maybe?) and then import it for the settings if the scan wont work or gives garbage descriptions, etc...

It would be awesome.... keep telling myself I am going to work on it.

Question... That can make a decimal value (obviously), but the command class expects a short. Do you rely on the casting to take care of it, or massage the decimal away elsewhere?

The system will accept the decimal without dying/throwing an error, so it works either way. I was just curious.

I have a range validation function I pass it through after that, to make sure people don't do stupid stuff, and it also converts whatever you send it to an integer.

Could just wrap the whole thing with Math.round() though.

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.