Homeseer HS-WD200 Dimmer Button Mapping

Hi All,
I installed this dimmer switch and works as expected. I also have the StatusLed working as I want. There are many topics on this device but I could not find an answer/solution for my issue.

My question is about the functions of physically multi-pressing the on/off paddles (3-tap-, 4-tap, 5-tap). I am using the recommended "HomeSeer WD-200 Dimmer" Device Type and can see the functions for double-tap, flash, hold, on/off, push, release, set level, set status LED, start level change. Reading some documentation I think the push function is somehow related but I do not seem to get the correlation between the physical paddle presses and the virtual push function.

For example, these are two logs I get for both:
Virtual 4-push function
image

Physical 3-tap of the off paddle

My device shows the latest firmware and currently running HE version 2.2.3.148.

Any help is appreciated,
Bill

Are you using Hubitat's built-in driver? None of those support multi-taps beyond double taps for any "Scene"/button device I know of. For this device, the up paddle is button 1, the down paddle is button 2, and you should get pushed, held, released, and double-tapped events for each corresponding to the real-world actions. For anything more than that, you'll need a custom driver.

Yes, I am using the built in driver called "HomeSeer WD-200 Dimmer". I figured since HE has its own built-in driver it would have its functionality. The multi-taps do register in the logs so I thought I was doing something wrong.

I see, I remember seeing a driver from CodaHQ but it has been withdrawn and I cannot find. Are there other drivers out there that you know of? Have searched but not found any.

I guess my other choice is reinstalling in ST and using HubConnect.

Figured I'd ask around to see what my options were,
Thanks,

I'm not able to find a community driver that is still available, though I think that one was released under an open license, so if anyone still happens to have a copy, it's possible they could share it. (If I am wrong, then nevermind with that idea!) Alternatively, if HomeSeer or a community member has created a SmartThings DTH, those are usually pretty easy to port, though there will be some modification needed for the button events since Hubitat handles those a bit differently. HubConnect would certainly work too, though I personally wouldn't want to put any cloud but especially ST's in the middle of this. :slight_smile:

As for the native drivers, Hubitat has commented things that make me assume they aren't interested in supporting anything more than double taps, with paraphrased rationales being things like "if we implement quintuple-tappable, where does it stop?", "can people really remember what all those taps do?", and similar. There would certainly be some workaround (likely button-number awkwardness) required with their current button model, but most community drivers have found good workarounds, and there's nothing technically preventing the events from being parsed and used somehow. If this is important to you, I'd consider sharing your feedback with them. In the meantime, and possibly forever, a custom driver is what you'll need.

1 Like

Thank you for the reply and information.

I get it, "how many button combinations is enough?" If my son can memorize 20+ button combinations on his game controller, I think we can remember 4, lol.

I guess I can keep looking around to see if the custom driver is out there still. I am not tech savvy when it comes to porting as I have never done it. This is the custom device handler for ST.

/**

  • HomeSeer HS-WD200+
  • Copyright 2018 HomeSeer
  • Modified from the work by DarwinsDen device handler for the WD100 version 1.03
  • Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  • in compliance with the License. You may obtain a copy of the License at:
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  • on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  • for the specific language governing permissions and limitations under the License.
  • Author: HomeSeer
  • Date: 12/2017
  • Changelog:
  • 1.0.dd.9 13-Feb-2019 Added dummy setLevel command with duration for compatibility with HA Bridge, others? (darwin@darwinsden.com)
  • 1.0.dd.8 28-Jul-2018 Additional protection against floating point default preference values
  • 1.0.dd.6 27-Jul-2018 Added call to set led flash rate and added protection against floating point default preference values
  • 1.0.dd.5 26-Mar-2018 Corrected issues: 1) Turning off all LEDs did not return switch to Normal mode,
  •                    2) Turning off last lit LED would set Normal mode, but leave LED state as on (darwin@darwinsden.com)
    
  • 1.0.dd.4 28-Feb-2018 Updated all LED option to use LED=0 (8 will be depricated) and increased delay by 50ms (darwin@darwinsden.com)
  • 1.0.dd.3 19-Feb-2018 Corrected bit-wise blink off operator (darwin@darwinsden.com)
  • 1.0.dd.2 16-Feb 2018 Added button number labels to virtual buttons and reduced size (darwin@darwinsden.com)
  • 1.0.dd.1 15-Feb 2018 Added option to set all LED's simultaneously(darwin@darwinsden.com)
  • 1.0 Jan 2017 Initial Version
  • Button Mappings:
  • ACTION BUTTON# BUTTON ACTION
  • Double-Tap Up 1 pressed
  • Double-Tap Down 2 pressed
  • Triple-Tap Up 3 pressed
  • Triple-Tap Down 4 pressed
  • Hold Up 5 pressed
  • Hold Down 6 pressed
  • Single-Tap Up 7 pressed
  • Single-Tap Down 8 pressed
  • 4 taps up 9 pressed
  • 4 taps down 10 pressed
  • 5 taps up 11 pressed
  • 5 taps down 12 pressed

*/

metadata {
definition (name: "WD200+ Dimmer", namespace: "homeseer", author: "support@homeseer.com") {
capability "Switch Level"
capability "Actuator"
capability "Indicator"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Button"
capability "Configuration"

    command "tapUp2"
    command "tapDown2"
    command "tapUp3"
    command "tapDown3"
    command "tapUp4"
    command "tapDown4"
    command "tapUp5"
    command "tapDown5"
    command "holdUp"
    command "holdDown"
    command "setStatusLed"
    command "setSwitchModeNormal"
    command "setSwitchModeStatus"
    command "setDefaultColor"
    command "setBlinkDurationMilliseconds"
    
    fingerprint mfr: "000C", prod: "4447", model: "3036"

}

simulator {
	status "on":  "command: 2003, payload: FF"
	status "off": "command: 2003, payload: 00"
	status "09%": "command: 2003, payload: 09"
	status "10%": "command: 2003, payload: 0A"
	status "33%": "command: 2003, payload: 21"
	status "66%": "command: 2003, payload: 42"
	status "99%": "command: 2003, payload: 63"

	// reply messages
	reply "2001FF,delay 5000,2602": "command: 2603, payload: FF"
	reply "200100,delay 5000,2602": "command: 2603, payload: 00"
	reply "200119,delay 5000,2602": "command: 2603, payload: 19"
	reply "200132,delay 5000,2602": "command: 2603, payload: 32"
	reply "20014B,delay 5000,2602": "command: 2603, payload: 4B"
	reply "200163,delay 5000,2602": "command: 2603, payload: 63"
}

preferences {      
   input "doubleTapToFullBright", "bool", title: "Double-Tap Up sets to full brightness",  defaultValue: false,  displayDuringSetup: true, required: false	       
   input "singleTapToFullBright", "bool", title: "Single-Tap Up sets to full brightness",  defaultValue: false,  displayDuringSetup: true, required: false	
   input "doubleTapDownToDim",    "bool", title: "Double-Tap Down sets to 25% level",      defaultValue: false,  displayDuringSetup: true, required: false	       
   input "reverseSwitch", "bool", title: "Reverse Switch",  defaultValue: false,  displayDuringSetup: true, required: false
   input "bottomled", "bool", title: "Bottom LED On if Load is Off",  defaultValue: false,  displayDuringSetup: true, required: false
   input ( "localcontrolramprate", "number", title: "Press Configuration button after changing preferences\n\nLocal Ramp Rate: Duration (0-90)(1=1 sec) [default: 3]", defaultValue: 3,range: "0..90", required: false)
   input ( "remotecontrolramprate", "number", title: "Remote Ramp Rate: duration (0-90)(1=1 sec) [default: 3]", defaultValue: 3, range: "0..90", required: false)       
   input ( "color", "enum", title: "Default LED Color", options: ["White", "Red", "Green", "Blue", "Magenta", "Yellow", "Cyan"], description: "Select Color", required: false)
}

tiles(scale: 2) {
	multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
		tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
			attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
			attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
			attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
			attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
		}
		tileAttribute ("device.level", key: "SLIDER_CONTROL") {
			attributeState "level", action:"switch level.setLevel"
		}
        tileAttribute("device.status", key: "SECONDARY_CONTROL") {
            attributeState("default", label:'${currentValue}', unit:"")
        }
	}

	standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
		state "default", label:'', action:"refresh.refresh", icon:"st.secondary.configure"
	}
    
    valueTile("firmwareVersion", "device.firmwareVersion", width:2, height: 2, decoration: "flat", inactiveLabel: false) {
		state "default", label: '${currentValue}'
	}
    
	valueTile("level", "device.level", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
		state "level", label:'${currentValue} %', unit:"%", backgroundColor:"#ffffff"
	}

    valueTile("tapUp2", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 1\nTap\n▲▲", backgroundColor: "#ffffff", action: "tapUp2"
	}     

    valueTile("tapDown2", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 2\nTap\n▼▼", backgroundColor: "#ffffff", action: "tapDown2"
	} 

    valueTile("tapUp3", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 3\nTap\n▲▲▲", backgroundColor: "#ffffff", action: "tapUp3"
	} 

    valueTile("tapDown3", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 4\nTap\n▼▼▼", backgroundColor: "#ffffff", action: "tapDown3"
	}
    valueTile("tapUp1", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 7\nTap\n▲", backgroundColor: "#ffffff", action: "tapUp1"
	}     

    valueTile("tapDown1", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 8\nTap\n▼", backgroundColor: "#ffffff", action: "tapDown1"
	} 

    valueTile("tapUp4", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 9\nTap\n▲▲▲▲", backgroundColor: "#ffffff", action: "tapUp4"
	} 
    
    valueTile("tapDown4", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 10\nTap\n▼▼▼▼", backgroundColor: "#ffffff", action: "tapDown4"
	} 
    
    valueTile("tapUp5", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 11\nTap\n▲▲▲▲▲", backgroundColor: "#ffffff", action: "tapUp5"
	} 

    valueTile("tapDown5", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 12\nTap\n▼▼▼▼▼", backgroundColor: "#ffffff", action: "tapDown5"
	} 

    valueTile("holdUp", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 5\nHold\n▲", backgroundColor: "#ffffff", action: "holdUp"
	} 

    valueTile("holdDown", "device.button", width: 1, height: 1, decoration: "flat") {
		state "default", label: "Button 6\nHold\n▼", backgroundColor: "#ffffff", action: "holdDown"
    }
    
	main(["switch"])
    
	details(["switch","tapUp2","tapDown2","tapUp3","tapDown3","holdUp","holdDown","tapUp1","tapDown1","tapUp4","tapDown4","tapUp5","tapDown5","level","firmwareVersion","refresh"])
}

}

def parse(String description) {
def result = null
log.debug (description)
if (description != "updated") {
def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
}
if (!result){
log.debug "Parse returned ${result} for command ${cmd}"
}
else {
log.debug "Parse returned ${result}"
}
return result
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
dimmerEvents(cmd)
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
dimmerEvents(cmd)
}

def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) {
dimmerEvents(cmd)
}

def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
dimmerEvents(cmd)
}

private dimmerEvents(physicalgraph.zwave.Command cmd) {
def value = (cmd.value ? "on" : "off")
def result = [createEvent(name: "switch", value: value)]
state.lastLevel = cmd.value
if (cmd.value && cmd.value <= 100) {
result << createEvent(name: "level", value: cmd.value, unit: "%")
}
return result
}

def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
log.debug "ConfigurationReport $cmd"
def value = "when off"
if (cmd.configurationValue[0] == 1) {value = "when on"}
if (cmd.configurationValue[0] == 2) {value = "never"}
createEvent([name: "indicatorStatus", value: value])
}

def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
createEvent([name: "hail", value: "hail", descriptionText: "Switch button was pressed", displayed: false])
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
state.manufacturer=cmd.manufacturerName
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr)
setFirmwareVersion()
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}

def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
//updateDataValue("applicationVersion", "${cmd.applicationVersion}")
log.debug ("received Version Report")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
state.firmwareVersion=cmd.applicationVersion+'.'+cmd.applicationSubVersion
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
setFirmwareVersion()
createEvent([descriptionText: "Firmware V"+state.firmwareVersion, isStateChange: false])
}

def zwaveEvent(physicalgraph.zwave.commands.firmwareupdatemdv2.FirmwareMdReport cmd) {
log.debug ("received Firmware Report")
log.debug "checksum: ${cmd.checksum}"
log.debug "firmwareId: ${cmd.firmwareId}"
log.debug "manufacturerId: ${cmd.manufacturerId}"
[:]
}

def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
[createEvent(name:"switch", value:"on"), response(zwave.switchMultilevelV1.switchMultilevelGet().format())]
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
}

def on() {
sendEvent(tapUp1Response("digital"))
delayBetween([
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
],5000)
}

def off() {
sendEvent(tapDown1Response("digital"))
delayBetween([
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
],5000)
}

def setLevel (value) {
log.debug "setLevel >> value: $value"
def valueaux = value as Integer
def level = Math.max(Math.min(valueaux, 99), 0)
if (level > 0) {
sendEvent(name: "switch", value: "on")
} else {
sendEvent(name: "switch", value: "off")
}
sendEvent(name: "level", value: level, unit: "%")
def result = []

result += response(zwave.basicV1.basicSet(value: level))
result += response("delay 5000")
result += response(zwave.switchMultilevelV1.switchMultilevelGet())
result += response("delay 5000")
result += response(zwave.switchMultilevelV1.switchMultilevelGet())

}

// dummy setLevel command with duration for compatibility with Home Assistant Bridge (others?)
def setLevel(value, duration) {
setLevel (value)
}

/*

  • Set dimmer to status mode, then set the color of the individual LED
  • led = 1-7
  • color = 0=0ff
  •      1=red
    
  •      2=green
    
  •      3=blue
    
  •      4=magenta
    
  •      5=yellow
    
  •      6=cyan
    
  •      7=white
    

*/

def setBlinkDurationMilliseconds (newBlinkDuration) {
def cmds= []
if (0<newBlinkDuration && newBlinkDuration<25500){
log.debug "setting blink duration to: ${newBlinkDuration} ms"
state.blinkDuration = newBlinkDuration.toInteger()/100
log.debug "blink duration config parameter 30 is: ${state.blinkDuration}"
cmds << zwave.configurationV2.configurationSet(configurationValue: [state.blinkDuration.toInteger()], parameterNumber: 30, size: 1).format()
} else
{
log.debug "commanded blink duration ${newBlinkDuration} is outside range 0 .. 25500 ms"
}
return cmds
}

def setStatusLed (led,color,blink) {
def cmds= []
if(state.statusled1==null) {
state.statusled1=0
state.statusled2=0
state.statusled3=0
state.statusled4=0
state.statusled5=0
state.statusled6=0
state.statusled7=0
state.blinkval=0
}

/* set led # and color */
switch(led) {
	case 1:
    	state.statusled1=color
        break
    case 2:
    	state.statusled2=color
        break
	case 3:
    	state.statusled3=color
        break
    case 4:
    	state.statusled4=color
        break
    case 5:
    	state.statusled5=color
        break
    case 6:
    	state.statusled6=color
        break
    case 7:
    	state.statusled7=color
        break
    case 0:
    case 8:
        // Special case - all LED's
    	state.statusled1=color
        state.statusled2=color
        state.statusled3=color
        state.statusled4=color
        state.statusled5=color
        state.statusled6=color
        state.statusled7=color
        break

}

if(state.statusled1==0 && state.statusled2==0 && state.statusled3==0 && state.statusled4==0 && state.statusled5==0 && state.statusled6==0 && state.statusled7==0)
{
	// no LEDS are set, put back to NORMAL mode
    cmds << zwave.configurationV2.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()         
}
else
{
   // at least one LED is set, put to status mode
   cmds << zwave.configurationV2.configurationSet(configurationValue: [1], parameterNumber: 13, size: 1).format()
}

if (led==8 | led==0) 
{
     for (def ledToChange = 1; ledToChange <= 7; ledToChange++)
     {
       // set color for all LEDs
       cmds << zwave.configurationV2.configurationSet(configurationValue: [color], parameterNumber: ledToChange+20, size: 1).format()
     }
}
else
{
       // set color for specified LED
       cmds << zwave.configurationV2.configurationSet(configurationValue: [color], parameterNumber: led+20, size: 1).format()
}   

// check if LED should be blinking
def blinkval = state.blinkval

if(blink)
{
        switch(led) {
        	case 1:
            	blinkval = blinkval | 0x1
                break
            case 2:
            	blinkval = blinkval | 0x2
                break
            case 3:
            	blinkval = blinkval | 0x4
                break
            case 4:
            	blinkval = blinkval | 0x8
                break
            case 5:
            	blinkval = blinkval | 0x10
                break
            case 6:
            	blinkval = blinkval | 0x20
                break
            case 7:
            	blinkval = blinkval | 0x40
                break
            case 0:
            case 8:
            	blinkval = 0x7F
                break
        }
    	cmds << zwave.configurationV2.configurationSet(configurationValue: [blinkval], parameterNumber: 31, size: 1).format()
        state.blinkval = blinkval
        // set blink frequency if not already set, 5=500ms
        if(state.blinkDuration == null | state.blinkDuration < 0 | state.blinkDuration > 255) {
           cmds << zwave.configurationV2.configurationSet(configurationValue: [5], parameterNumber: 30, size: 1).format()
        }
 }
 else
 {
    
    	switch(led) {
        	case 1:
            	blinkval = blinkval & 0xFE
                break
            case 2:
            	blinkval = blinkval & 0xFD
                break
            case 3:
            	blinkval = blinkval & 0xFB
                break
            case 4:
            	blinkval = blinkval & 0xF7
                break
            case 5:
            	blinkval = blinkval & 0xEF
                break
            case 6:
            	blinkval = blinkval & 0xDF
                break
            case 7:
            	blinkval = blinkval & 0xBF
                break
            case 0:  
            case 8:
            	blinkval = 0
                break         
        }
        cmds << zwave.configurationV2.configurationSet(configurationValue: [blinkval], parameterNumber: 31, size: 1).format()
        state.blinkval = blinkval
}     
delayBetween(cmds, 150)

}

/*

  • Set Dimmer to Normal dimming mode (exit status mode)

*/
def setSwitchModeNormal() {
def cmds= []
cmds << zwave.configurationV2.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
delayBetween(cmds, 500)
}

/*

  • Set Dimmer to Status mode (exit normal mode)

*/
def setSwitchModeStatus() {
def cmds= []
cmds << zwave.configurationV2.configurationSet(configurationValue: [1], parameterNumber: 13, size: 1).format()
delayBetween(cmds, 500)
}

/*

  • Set the color of the LEDS for normal dimming mode, shows the current dim level
    */
    def setDefaultColor(color) {
    def cmds= []
    cmds << zwave.configurationV2.configurationSet(configurationValue: [color], parameterNumber: 14, size: 1).format()
    delayBetween(cmds, 500)
    }

def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}

def refresh() {
log.debug "refresh() called"
configure()
}

def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
log.debug("sceneNumber: ${cmd.sceneNumber} keyAttributes: ${cmd.keyAttributes}")
def result = []

switch (cmd.sceneNumber) {
  case 1:
      // Up
      switch (cmd.keyAttributes) {
          case 0:
               // Press Once
              result += createEvent(tapUp1Response("physical"))  
              result += createEvent([name: "switch", value: "on", type: "physical"])
   
              if (singleTapToFullBright)
              {
                 result += setLevel(99)
                 result += response("delay 5000")
                 result += response(zwave.switchMultilevelV1.switchMultilevelGet())
              } 
              break
          case 1:
              result=createEvent([name: "switch", value: "on", type: "physical"])
              break
          case 2:
              // Hold
              result += createEvent(holdUpResponse("physical"))  
              result += createEvent([name: "switch", value: "on", type: "physical"])    
              break
          case 3: 
              // 2 Times
              result +=createEvent(tapUp2Response("physical"))
              if (doubleTapToFullBright)
              {
                 result += setLevel(99)
                 result += response("delay 5000")
                 result += response(zwave.switchMultilevelV1.switchMultilevelGet())
              }                    
              break
          case 4:
              // 3 times
              result=createEvent(tapUp3Response("physical"))
              break
          case 5:
              // 4 times
              result=createEvent(tapUp4Response("physical"))
              break
          case 6:
              // 5 times
              result=createEvent(tapUp5Response("physical"))
              break
          default:
              log.debug ("unexpected up press keyAttribute: $cmd.keyAttributes")
      }
      break
      
  case 2:
      // Down
      switch (cmd.keyAttributes) {
          case 0:
              // Press Once
              result += createEvent(tapDown1Response("physical"))
              result += createEvent([name: "switch", value: "off", type: "physical"]) 
              break
          case 1:
              result=createEvent([name: "switch", value: "off", type: "physical"])
              break
          case 2:
              // Hold
              result += createEvent(holdDownResponse("physical"))
              result += createEvent([name: "switch", value: "off", type: "physical"]) 
              break
          case 3: 
              // 2 Times
              result+=createEvent(tapDown2Response("physical"))
              if (doubleTapDownToDim)
              {
                 result += setLevel(25)
                 result += response("delay 5000")
                 result += response(zwave.switchMultilevelV1.switchMultilevelGet())
              }  
              break
          case 4:
              // 3 Times
              result=createEvent(tapDown3Response("physical"))
              break
          case 5:
              // 4 Times
              result=createEvent(tapDown4Response("physical"))
              break
          case 6:
              // 5 Times
              result=createEvent(tapDown5Response("physical"))
              break
          default:
              log.debug ("unexpected down press keyAttribute: $cmd.keyAttributes")
       } 
       break
       
  default:
       // unexpected case
       log.debug ("unexpected scene: $cmd.sceneNumber")

}
return result
}

def tapUp1Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▲")
[name: "button", value: "pushed", data: [buttonNumber: "7"], descriptionText: "$device.displayName Tap-Up-1 (button 7) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapDown1Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▼")
[name: "button", value: "pushed", data: [buttonNumber: "8"], descriptionText: "$device.displayName Tap-Down-1 (button 8) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapUp2Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▲▲")
[name: "button", value: "pushed", data: [buttonNumber: "1"], descriptionText: "$device.displayName Tap-Up-2 (button 1) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapDown2Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▼▼")
[name: "button", value: "pushed", data: [buttonNumber: "2"], descriptionText: "$device.displayName Tap-Down-2 (button 2) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapUp3Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▲▲▲")
[name: "button", value: "pushed", data: [buttonNumber: "3"], descriptionText: "$device.displayName Tap-Up-3 (button 3) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapUp4Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▲▲▲▲")
[name: "button", value: "pushed", data: [buttonNumber: "9"], descriptionText: "$device.displayName Tap-Up-4 (button 9) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapUp5Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▲▲▲▲▲")
[name: "button", value: "pushed", data: [buttonNumber: "11"], descriptionText: "$device.displayName Tap-Up-5 (button 11) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapDown3Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▼▼▼")
[name: "button", value: "pushed", data: [buttonNumber: "4"], descriptionText: "$device.displayName Tap-Down-3 (button 4) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapDown4Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▼▼▼▼")
[name: "button", value: "pushed", data: [buttonNumber: "10"], descriptionText: "$device.displayName Tap-Down-3 (button 10) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapDown5Response(String buttonType) {
sendEvent(name: "status" , value: "Tap ▼▼▼▼▼")
[name: "button", value: "pushed", data: [buttonNumber: "12"], descriptionText: "$device.displayName Tap-Down-3 (button 12) pressed",
isStateChange: true, type: "$buttonType"]
}

def holdUpResponse(String buttonType) {
sendEvent(name: "status" , value: "Hold ▲")
[name: "button", value: "pushed", data: [buttonNumber: "5"], descriptionText: "$device.displayName Hold-Up (button 5) pressed",
isStateChange: true, type: "$buttonType"]
}

def holdDownResponse(String buttonType) {
sendEvent(name: "status" , value: "Hold ▼")
[name: "button", value: "pushed", data: [buttonNumber: "6"], descriptionText: "$device.displayName Hold-Down (button 6) pressed",
isStateChange: true, type: "$buttonType"]
}

def tapUp1() {
sendEvent(tapUp1Response("digital"))
}

def tapDown1() {
sendEvent(tapDown1Response("digital"))
}

def tapUp2() {
sendEvent(tapUp2Response("digital"))
}

def tapDown2() {
sendEvent(tapDown2Response("digital"))
}

def tapUp3() {
sendEvent(tapUp3Response("digital"))
}

def tapDown3() {
sendEvent(tapDown3Response("digital"))
}

def tapUp4() {
sendEvent(tapUp4Response("digital"))
}

def tapDown4() {
sendEvent(tapDown4Response("digital"))
}

def tapUp5() {
sendEvent(tapUp5Response("digital"))
}

def tapDown5() {
sendEvent(tapDown5Response("digital"))
}

def holdUp() {
sendEvent(holdUpResponse("digital"))
}

def holdDown() {
sendEvent(holdDownResponse("digital"))
}

def setFirmwareVersion() {
def versionInfo = ''
if (state.manufacturer)
{
versionInfo=state.manufacturer+' '
}
if (state.firmwareVersion)
{
versionInfo=versionInfo+"Firmware V"+state.firmwareVersion
}
else
{
versionInfo=versionInfo+"Firmware unknown"
}
sendEvent(name: "firmwareVersion", value: versionInfo, isStateChange: true, displayed: false)
}

def configure() {
log.debug ("configure() called")

sendEvent(name: "numberOfButtons", value: 12, displayed: false)
def commands = []
commands << setDimRatePrefs()
commands << zwave.switchMultilevelV1.switchMultilevelGet().format()
commands << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
commands << zwave.versionV1.versionGet().format()
delayBetween(commands,500)
}

def setDimRatePrefs()
{
log.debug ("set prefs")
def cmds = []

if (color)
{
    switch (color) {
    	case "White":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [0], parameterNumber: 14, size: 1).format()
            break
  		case "Red":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [1], parameterNumber: 14, size: 1).format()
            break
        case "Green":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [2], parameterNumber: 14, size: 1).format()
            break
        case "Blue":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [3], parameterNumber: 14, size: 1).format()
            break
        case "Magenta":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [4], parameterNumber: 14, size: 1).format()
            break
        case "Yellow":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [5], parameterNumber: 14, size: 1).format()
            break
        case "Cyan":
        	cmds << zwave.configurationV2.configurationSet(configurationValue: [6], parameterNumber: 14, size: 1).format()
            break      
  	}
}    

if(localcontrolramprate != null) {
//log.debug localcontrolramprate
def localRamprate = Math.max(Math.min(localcontrolramprate.toInteger(), 90), 0)
cmds << zwave.configurationV2.configurationSet(configurationValue: [localRamprate.toInteger()], parameterNumber: 12, size: 1).format()
}

if(remotecontrolramprate != null) {
//log.debug remotecontrolramprate
def remoteRamprate = Math.max(Math.min(remotecontrolramprate.toInteger(), 90), 0)
cmds << zwave.configurationV2.configurationSet(configurationValue: [remoteRamprate.toInteger()], parameterNumber: 11, size: 1).format()
}

if (reverseSwitch)
{
cmds << zwave.configurationV2.configurationSet(configurationValue: [1], parameterNumber: 4, size: 1).format()
}
else
{
cmds << zwave.configurationV2.configurationSet(configurationValue: [0], parameterNumber: 4, size: 1).format()
}

if (bottomled)
{
cmds << zwave.configurationV2.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
}
else
{
cmds << zwave.configurationV2.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
}

//Enable the following configuration gets to verify configuration in the logs
//cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
//cmds << zwave.configurationV1.configurationGet(parameterNumber: 8).format()
//cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
//cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()

return cmds
}

def updated()
{
def cmds= []
cmds << setDimRatePrefs
delayBetween(cmds, 500)
}

By the documentation I have read, it sounds like a custom HE driver has already been ported using this. If anyone has it, please share.

Thank you,

I don't have one of these (though I think I have the similar switch version in a drawer of shame somewhere), but this might work--a quick port I did with changing the button events to be more Hubitat-y and some code cleanup because I couldn't quite stand the way they did a few things, though far more atrocities remain. :slight_smile:

Again, I can't test this since I don't have the device, so no guarantee that everything works. Also, if the device supports S2 (and is paired as such), this won't work without additional modifications, though that shouldn't be too hard if it does.

[EDIT: New code in later post]

I don't know how you do it but the multi-taps are working. Once I replaced the driver with yours, the number of buttons increased to 12 and I was able to set the multi-taps with the Button Controller.

I have been in the process of testing it and the custom driver did break some stuff though:

  1. Dimmer (Set Level): When I set an activity in a rule to dim the light (for this switch), it doesn't work and I get this error:


    The funny thing is I can still dim it with the paddle, "Set level" Command under "Edit Device" and Google Voice command.

  2. SetStatusLed no longer works, I even recreated the Rule but I get this error:


    Also, there is no Command to change it under "Edit Device".

BTW, the Custom Driver above is doubled up.

Side question, how do you put the driver info in its own window (above)? I could not figure it out.

Thank you,

Interesting--looks like HomeSeer missed the two-parameter declaration for setLeve() (the one that takes both a level and duration) in their code. I've added something back in (not super-happy with what I did and should probably rewrite the other one to look like this, but it should work).

For the setStatusLED() error, could it be that you chose a String parameter for the second (color) parameter? It needs to be a numeric type. Or at least that's what it looks like to me...if that doesn't make sense I could look at the manual for this device to see if that behavior is documented somewhere (I'm just going by what it looks like was done in the ST DTH).

I've updated the code above with the first change.

1 Like

In the code above there are two drivers, one after the other. Did you update the 1st or 2nd? I think the 1st.

Upon updating I get this error:

Sorry, I double-pasted the first time and updated the "first" the second time (where I tried to edit out that second paste but apparently didn't). Anyway, I've updated that post with something else that should fix that particular error. Sorry that I'm not much more help since I don't actually have one of these, but hopefully that works!

1 Like

No apologies necessary, in fact, I want to thank you for all you have done thus far. You have achieved a lot more than I could have on my own.

You are correct, once I changed the parameters to integers in lieu of strings, the rules started working, good call. Although the flash (3rd parameter is inconsistent).

I am still having an issue with the dimmer (Set Level) command.

Is it possible to add the commands under Set Status Led in "Edit Device"? three parameters but not necessary.

I enjoyed using the functions of this device while at ST. I cannot expect you to tweak all these issues without having this device. How about I buy and get it shipped to you if you wish? I think it would be beneficial for the HE community to have a working custom driver. I can't be the only one that this would serve. And who knows, you may end up liking it.

2 Likes

OK, here's another try. I see this supports a newer version of the SwitchMutliLevel class (amazing what happens if I look at the manual...), so this way should work if this is indeed the HS-WD200+ I'm looking at. I also modified the custom commands to constrain parameter value inputs a bit in the Hubitat admin UI according to what it looks like they're looking for (always numbers, never strings) and which paramaters appear to be required, along with descriptions (tooltip text on a desktop) with what the manual says the values mean.

You're certainly welcome to send one to me if you'd like me to test the changes in real life instead of having you do that part for me, but I should warn you that a couple of the errors I made were just mistakes on my part I would have made regardless. (Translation: I might not have 100% of the skill you're looking for.) I also wish I could use more devices like this in my house, but the lack of neutrals in many locations and HomeSeer's refusal to understand why anyone might want to disable local control (colloquially "the relay") in this day and age baffle my mind. I have a few Inovellis that are somewhat inspired by these, though. :slight_smile:

Anyway, here's my latest attempt!

[EDIT: Removed, newer code in later post]

1 Like

I have been testing this driver and I do not know how you did it but You fixed the dimming, multi-tap & Led control issues so now this driver works for my needs. :+1:

Changing the "Set Status Led" parameters under "Edit Device" is still flaky. Meaning sometimes it works, sometimes it doesn't, sometimes it gives the wrong result (ex. 7-1-1 should make the top Led blink red, but it becomes solid green). Changing these parameters in a rule do work as expected. Blinking parameter is still sporadic, maybe it's related to a switch mode or another setting I am unaware of.

There are other functions for this device I do not use that are not set like S2 or setting Led parameter 8 to control all Leds. In any case, the offer still stands. If you would like me to get a switch shipped to you, send an address. Or, if there is any other way I can show my appreciation.

You're correct, neutrals are required for this switch. Didn't think about that since my house is fairly new. On the plus side, this is one of the only switches I found that has a proper traditional traveler line for multi-way switching. Also, for me, this switch serves as a replacement for an alarm console. The Led lights display the state of doors, windows, media, water spills and HSM. While multi-taps allows me to control lights, scenes, media and HSM.

Thank you,
Bill V.

Hmm, not sure what could be going on there, but I just made a couple changes (above) that I hope will help. There's a small possibility they will have made things worse. :slight_smile: (I don't know what HomeSeer was going for in their original ST handler here, but I'm thinking it's possible some things that should have been integers were in fact strings, so I added some conversions. I'm not 100% sure what might happen if you don't have "blinkval" at all under "State Variables" on the device page, which you might not if you've never run the command before. I can add another line to address that if it fails.)

I forgot to mention that my previous update should also make these work if paired with S2, though obviously these changes haven't been tested by me with an actual device. If you have a spare and wanted to send it to me and then have me send it back to you, that is probably the only scenario that would not make me feel guilty, haha. (No need to buy a new one, but if HomeSeer saw the value in disabling local control--and I had more neutrals--I'd have these all over! Still not 100% sure I'm the person you want writing this, but I'd probably start over instead of using HomeSeer's ST DTH as a base if I did this again.)

The latest driver gives the following error when changing the Status Led.

Oops, looks like I had some misplaced (and missing) parentheses! Maybe this will help:

[EDIT: Removed; new code below]

The latest fixed the error but the blinking is still the same. I do not get any errors but cannot get it to blink, attached below is the state variables. blinkval: 255 but does not change.


Thanks

Hmm, not sure, but I just made another change that might help. Or might make it worse, but hopefully not again. :smiley:

Same, no blink. good news, I don't think it made it worse. :wink:

Hmm, no errors, either? If you turn on debug logging, what does the line with "setStatusLED" (should get logged when you run the command) say? Just wondering what valued are getting passed.