Homeseer HS-WD200 Dimmer Button Mapping

No, log.debug (or .trace, .warn, .error, or .info) is probably the best tool we have to see what's happening when. During development, sometimes I'll use weird things (like log.error) just to get my attention more easily if I want to be sure to see something, then of course remove that line when I'm done. But no, no line-by-line debugger or anything (unless the code in question is just regular Groovy that doesn't depend on the Hubitat environment, of course, in which case you have more options).

I am in process of moving from ST and found the HE driver for WS200 a bit lacking. Your port from ST is great because that's what I was using there. Thanks for the work.

I was unable to get configuration to set local and remote ramps with your driver. I did some digging, looking at the return values for configure() using your driver on HE, and also the WS200 driver running on ST and found some differences. The format for the ramp parms differed between the two and on ST a lot of info is returned where on yours nothing is returned.

I got it working and thought I will post my changes.

I have been programing in one language or another for many years, but have done only a little in Groovy. I am used to a strong typed language and you will see that in my changes. I am sure that I did not implement them in the best way possible, that said it seems to work.

Sorry for the unformatted stuff below, please point me to how to edit post's. (edited to only show key changes)

Changes to configure()
...
// was commands<< setDimRatePrefs()
def commands = setDimRatePrefs()
commands << secure(zwave.switchMultilevelV1.switchMultilevelGet())
...

Changes to setDimRatePrefs()
...
// change from def to int
int localcontrolramprate = Math.max(Math.min(localcontrolramprate, 90), 0)

// changed from def to int
int remoteramprate = Math.max(Math.min(remotecontrolramprate, 90), 0)

Before I go ahead and start switching drivers around, does anyone who’s been working on this port know if the one driver will work unmodified for HomeSeer WD100+ and WS200+ models as well, since I have all three? And I miss the triple-tap functionality on some of my WD100+ dimmers that I used to have before I migrated from ST.

Also, has anyone made this available on GitHub or HPM? I’d feel better knowing that the most recent updates/fixes are included in code I retrieve that way than scanning through Community threads, even as great as they are for engendering this cooperative development work!

Guys, the driver seems to work, but it appears to break the Switch Dashboard app:

ERROR: Unsupported switches (missing setStatusLED/setIndicator command):

  • Hall (WD200+ Dimmer)

With debug turned on, all I get is:

[app:292] 2021-02-17 01:16:55.097 am [debug] Unsupported devices: [Hall]

or

[app:292] 2021-02-17 01:16:26.787 am [error] Hall is not a usable HomeSeer or Inovelli device (ID:311, Name:'HS-WD200+ Scene Capable Wall Dimmer' Type:'WD200+ Dimmer')

And yet I can see that setStatusLED() is in the code that I pasted in from above.

Any ideas?

Hmm, just noticed that using the code in post #42, (please confirm that is the code that is most current/should be working), that after testing with the driver’s manual setStatusLED function, (attempted to set LED 4 to Green), I now have a state variable “statusled{4} : 2” in addition to “statusled4: 0”.

Looks like a simple error, but before I attempt to debug code that’s probably already been fixed, can @ArchStanton or @bertabcd1234 which post or other repository contains the latest/best code?

Thanks

Guys,
As another thought, and a possible "simpler way" to address the multi-tap button problem, I'm currently working on a driver where I implement multi-tap in my drivers using a custom attribute

		attribute "multiTapButton", "number"	

This can be used in addition to the "legacy" methods of having capability PushableButton, HoldableButton, ReleaseableButton, and doubleTap. What I do is that, on a central scene event, I assign a decimal number like 1.1 or 2.3, where the first part is the button number, the second is the number of taps. The idea is that I can then create rule machine rules that trigger on the attribute change and compare to the expected value (i.e., if I'm looking for 4 taps on button #3, I look for the value 4.3. Here's the code to handle this (which I'll eventually release as a community driver). Using the decimal form makes the code device-independent as this easily extends to whatever number of buttons the device supports and is simple to understand. I had also considered using negative numbers for "special" meaning, like -4.1 to mean "button 4, hold", but I figured the hold and released were already handled using existing Capabilities and there wasn't much value in changing those.

In the sample code, below, I also include the possibility of using custom attributes

        attribute "buttonTripleTapped", "number"	
	attribute "buttonFourTaps", "number"	
	attribute "buttonFiveTaps", "number"	

which work more like the existing button Capabilities, But I think the better approach is the use of the multiTapButton attribute so there is only 1 attribute to have to consider in rule machine - thus, I may remove the triple / four / five from my final code.

///////////////////////////////////////////////////////////////////////////////////////////////
///////////////                  Central Scene Processing          ////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////

//The next two import lines usually would go at the very top of the .groovy driver file
import java.util.concurrent.* // Available (white-listed) concurrency classes: ConcurrentHashMap, ConcurrentLinkedQueue, Semaphore, SynchronousQueue
import groovy.transform.Field

// Use a concurrentHashMap to hold the last reported state. This is used for "held" state checking
// In a "held" state, the device will send "held down refresh" messages at either 200 mSecond or 55 second intervals.
// Hubitat should not generated repreated "held" messages in response to a refresh, so inhibit those
// Since the concurrentHashMap is @Field static -- its data structure is common to all devices using this
// Driver, therefore you have to key it using the device.deviceNetworkId to get the value for a particuarl device.
@Field static  ConcurrentHashMap centralSceneButtonState = new ConcurrentHashMap<String, String>()

String getCentralSceneButtonState(Integer button) { 
 	String key = "${device.deviceNetworkId}.Button.${button}"
	return centralSceneButtonState.get(key)
}

String setCentralSceneButtonState(Integer button, String state) {
 	String key = "${device.deviceNetworkId}.Button.${button}"
	centralSceneButtonState.put(key, state)
	return centralSceneButtonState.get(key)
}

void getCentralSceneInfo() {
	// Not currently used.
	sendToDevice(zwave.centralSceneV3.centralSceneSupportedGet() )
}

void zwaveEvent(hubitat.zwave.commands.centralscenev3.CentralSceneNotification cmd)
{

	// Check if central scene is already in a held state, if so, and you get another held message, its a refresh, so don't send a sendEvent
	if ((getCentralSceneButtonState(cmd.sceneNumber as Integer) == "held") && (cmd.keyAttributes == 2)) return

	// Central scene events should be sent with isStateChange:true since it is valid to send two of the same events in a row (except held, whcih is handled in previous line)
    Map event = [value:cmd.sceneNumber, type:"physical", unit:"button#", isStateChange:true]
	
	event.name = [	0:"pushed", 1:"released", 2:"held",  3:"doubleTapped", 
					4:"buttonTripleTapped", 5:"buttonFourTaps", 6:"buttonFiveTaps"].get(cmd.keyAttributes as Integer)
	
	String tapDescription = [	0:"Pushed", 1:"Released", 2:"Held",  3:"Double-Tapped", 
								4:"Three Taps", 5:"Four Taps", 6:"Five Taps"].get(cmd.keyAttributes as Integer)
    
	// Save the event name for event that is about to be sent using sendEvent. This is important for 'held' state refresh checking
	setCentralSceneButtonState(cmd.sceneNumber, event.name)	
	
	event.descriptionText="${device.displayName}: Button #${cmd.sceneNumber}: ${tapDescription}"

	if (device.hasAttribute( event.name )) sendEvent(event)
	
	// Next code is for the custom attribute "multiTapButton".
	Integer taps = [0:1, 3:2, 4:3, 5:4, 6:5].get(cmd.keyAttributes as Integer)
	if ( taps && device.hasAttribute("multiTapButton") )
	{
		event.name = "multiTapButton"
		event.unit = "Button #.Tap Count"
		event.value = ("${cmd.sceneNumber}.${taps}" as Float)
		sendEvent(event)		
	} 
}

Either approach (decimal notation or custom attributes) is cleaner than the ST-ported driver, which requires a mapping of Button 5 = Triple Tap Up and so on.

Regardless, I like the Switch Dashboard app so much that I consider implementing the setStatusLED() function a mandatory feature before I would switch to a new driver in production. Is this part of your plans?

FYI - I'm also not a fan of the ST-ported notation if just for the reason that it is harder to remember what the button number means. I just went back and updated my code to add device.hasAttribute("multiTapbutton") and device.hasAttribute(event.name) checking before sending the sendEvent. With this change, it now adapts to either (or both) approaches. I.e., if you use the existing capabilities which will work as expected. It also works if you add the custom attributes "buttonTripleTapped", "buttonFourTaps", "buttonFiveTaps", and finally you can use it with the "multiTapButton" attribute (which is my preferred approach).

Just tried the Release Candidate driver code on my HS-WD100+ and I'm practically giddy with the thought of getting my triple-taps functionality back that I had with ST.

Here's my device Events tab:

Name Value Unit Description Text Source Type Date
multiTapButton 1.3 Button #.Tap Count Office Ceiling: Button #1: Three Taps DEVICE physical 2021-02-22 04:57:44.018 PM EST
buttonTripleTapped 1 button# Office Ceiling: Button #1: Three Taps DEVICE physical 2021-02-22 04:57:44.017 PM EST
switch on Device turned on DEVICE digital 2021-02-22 04:57:30.218 PM EST
multiTapButton 1.2 Button #.Tap Count Office Ceiling: Button #1: Double-Tapped DEVICE physical 2021-02-22 04:57:30.147 PM EST
doubleTapped 1 button# Office Ceiling: Button #1: Double-Tapped DEVICE physical 2021-02-22 04:57:30.145 PM EST
switch off Device turned off DEVICE digital 2021-02-22 04:57:25.005 PM EST

Bravo!!!

And I just confirmed that the RM rule I used in lieu of the Button Controller built-in app works as well:

I used the prefix "RM Button Controller" to name the rule in RM to match the existing rules I have defined in the built-in Button Controller app, which still works without changes, so I don't have to redo all of those in RM:

Hopefully the Hubitat team will take on your suggestions and incorporate them into the built-in Apps.

Also happy to report that this works with my HS-WS200+ switches (not dimmers) as well. The appearance in the built-in Button Controller app, however, is a little different, since it reports as having 10 buttons.

If one cares to remember all the button number mappings, you can do everything in the built-in Button Controller App, but like you I prefer the sensible decimal notation in your custom capability.

Otherwise, the behaviour in RM is just like the dimmers (HS-WD100+).

Now, if you can just add in the setStatusLED() functions for the HS-WD200+ I'll be all set to replace the existing driver so I can still use your universal driver with the Switch Dashboard App!

Once again, keep up the good work!

I promised to try out a multi-endpoint device as well, and the only one I have is a Fibaro FGS-223 dual switch. It doesn't create the Child Devices upon initialization, however, like the community driver by @ericm Eric Maycock does. What should I be doing to set up your driver?

Here's the device page (multiple screenshots to capture it all):

I posted updated drivers this morning which should create the child devices upon first boot. If your existing driver already created child devices and their Device Network Id ends in "-ep001" or '-ep002" then the existing child devices will be used.

For more info, see: https://github.com/jvmahon/HubitatCustom

That's a leftover artifact from a prior driver. My driver wasn't resetting the "numberOfButtons" attribute, but it should, so I just updated my drivers to fix this. Latest beta version is 0.1.1

The WD200 uses zwave parameter settings to control the status LEDs. My drivers aren't written for any specific device, so they don't have a WD200 specific function to control the LEDs, but you can still do it -- to provide a "generic" way to handle these functions, my driver exposes a "setParameter" function which you can use in Rule Machine to set the status LEDs. See below for an example rule which sets parameter #13 to1 (which puts the LED's into "status" display mode), and then sets paramter #21 to 4 (which turns LED #1 to Magenta). Note that you access this as a custom action and when entering the parameters you have to enter two numbers, the parameter # and the new value. The pasted rule makes it seem like you can enter these as a comma-separated list, but actually, you enter the first parameter as a "numeric" type, then click a button to add another parameter to the rule where you enter the second parameter. Hope this helps!

Of course, as a Universal driver, you don't want the bloat that would come from adding "just one little customization for device X", with |X| approaching infinity over time.

Unless @MFornander wants to update his code, I will have to fork it and see if my (very) rusty programming skills are up to the task of leveraging your driver, which would make Mattias' extremely useful app available to a much wider range of devices.

You could add the customizations yourself as the code base makes it pretty easy.

For example, if you don't want to use the "setParameter" custom command as I've demonstrated, you could wrap setParameter as a new command. For the example shown, you could add the following in the preferences section:

command "setLed01ToMagenta"

And add a simple function in the body of the code

void setLed01ToMagenta() {
     setParameter(13, 1)
     setParameter(21, 4)

}

I changed back to your driver [Beta 0.1.1] and tested this with RM and a Custom Action to set parameters as per your example, and it worked. Was getting all set to set up all my rules in RM to mirror what I currently have going in the Switch Dashboard app, but then found basic taps and double-taps aren't working at all any more.

Here's the logs:

dev:3112021-03-14 03:52:54.810 pm infoHall was turned off [digital]

dev:3112021-03-14 03:52:54.803 pm debugdimmerEvents value: 87, type: digital

dev:3112021-03-14 03:52:54.794 pm infoBasicReport value: 87

dev:3112021-03-14 03:52:54.791 pm debugparse description: zw device: 09, command: 2003, payload: 57 63 84 , isMulticast: false

dev:3112021-03-14 03:52:53.940 pm infoHall button 2 was doubleTapped

dev:3112021-03-14 03:52:48.398 pm infoHall is 99% [digital]

dev:3112021-03-14 03:52:48.395 pm infoHall is on [digital]

dev:3112021-03-14 03:52:48.392 pm debugdimmerEvents value: 99, type: digital

dev:3112021-03-14 03:52:48.388 pm infoBasicReport value: 99

dev:3112021-03-14 03:52:48.383 pm debugparse description: zw device: 09, command: 2003, payload: 63 63 00 , isMulticast: false

dev:3112021-03-14 03:52:44.856 pm infoHall button 1 was doubleTapped

dev:3112021-03-14 03:52:38.909 pm infoHall was turned on [digital]

dev:3112021-03-14 03:52:38.906 pm debugdimmerEvents value: 6, type: digital

dev:3112021-03-14 03:52:38.904 pm infoBasicReport value: 6

dev:3112021-03-14 03:52:38.901 pm debugparse description: zw device: 09, command: 2003, payload: 06 63 A6 , isMulticast: false

dev:3112021-03-14 03:52:34.859 pm infoHall was turned off [digital]

dev:3112021-03-14 03:52:34.856 pm debugdimmerEvents value: 94, type: digital

dev:3112021-03-14 03:52:34.854 pm infoBasicReport value: 94

dev:3112021-03-14 03:52:34.851 pm debugparse description: zw device: 09, command: 2003, payload: 5E 63 7F , isMulticast: false

dev:3112021-03-14 03:52:29.651 pm infoHall is 99% [digital]

dev:3112021-03-14 03:52:29.636 pm infoHall is on [digital]

dev:3112021-03-14 03:52:29.633 pm debugdimmerEvents value: 99, type: digital

dev:3112021-03-14 03:52:29.629 pm infoBasicReport value: 99

dev:3112021-03-14 03:52:29.622 pm debugparse description: zw device: 09, command: 2003, payload: 63 63 00 , isMulticast: false

dev:3112021-03-14 03:52:29.449 pm debugrefresh

dev:3112021-03-14 03:52:29.407 pm warnconfigure...

dev:3112021-03-14 03:46:23.036 pm errorgroovy.lang.MissingMethodException: No signature of method: user_driver_jvm__Beta_0_1_1__Almost_Any_Dimmer_Z_wave_Plus_Dimmer_Driver_775.doubleTap() is applicable for argument types: (java.math.BigDecimal) values: [1] (doubleTap)

dev:3112021-03-14 03:46:13.561 pm errorgroovy.lang.MissingMethodException: No signature of method: user_driver_jvm__Beta_0_1_1__Almost_Any_Dimmer_Z_wave_Plus_Dimmer_Driver_775.doubleTap() is applicable for argument types: (java.math.BigDecimal) values: [2] (doubleTap)

dev:3112021-03-14 03:45:52.076 pm debugDevice Hall: In sendSupervised, Sending supervised command: 9F0301260163

dev:3112021-03-14 03:45:52.073 pm debugDevice Hall: Attempted to supervise a class 2601 which was previously rejected as not supervisable.

dev:3112021-03-14 03:45:30.469 pm debugDevice Hall: In sendSupervised, Sending supervised command: 9F0301260100

dev:3112021-03-14 03:45:30.464 pm debugDevice Hall: Attempted to supervise a class 2601 which was previously rejected as not supervisable.

dev:3112021-03-14 03:45:30.385 pm infoDevice Hall: Turning device to: Off.

It looks like a type mismatch or something. The log entries from 3:52pm onwards are after I changed back to the built-in driver for WD200. I included them for comparison purposes.

I Reset State and Initialize/Configure after each driver change, so it should be a clean state for either driver. The device is included as S2 Unauthenticated in case that matters.

Have any ideas, or do you need more info?

Try the version that's on my site as 0.1.2. Double taps are working on my WD200s, so this is odd. Did you reboot after switching to my driver?