Here is the new Z-Wave dimmer switch control I have created. This dimmer switch allows you to use the standard controls as well as the configurable Low/Med/High buttons and stepper to increase or decrease by a selected value. There are still a couple bugs I’m working to resolve but would like to release this, as functionally it is working as expected. Below is a screenshot:
Details:
Preferences:
Here is the code:
/* Dimmer-Switch-Levels.device.groovy
*
* Variation of the stock SmartThings "Dimmer-Switch"
* Variation of the twack "Better-Dimmer-Switch"
* Variation of the ChadCK "Z-Wave Smart Fan Control"
*
* Device type adds set levels low, medium, and High for preset values (Moods).
* Adds increment up and down buttons with ability to set value.
*
* pmjoen@yahoo.com
* 20160517
*
* v1.0 - Initial release of device handler
*
*/
metadata {
// Automatically generated. Make future change here.
definition (name: "Dimmer-Switch-Levels", namespace: "pmjoen", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Indicator"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Sensor"
command "on"
command "off"
command "low"
command "med"
command "high"
command "levelUp"
command "levelDown"
attribute "currentState", "string"
//fingerprint deviceId: "0x1101", inClusters: "0x26, 0x27, 0x70, 0x86, 0x72"
}
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4
, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "default", label:'ADJUSTING', action:"refresh.refresh", icon:"st.Lighting.light24", backgroundColor:"#2179b8", nextState: "turningOff"
attributeState "HIGH", label:'HIGH', action:"switch.off", icon:"st.Lighting.light24", backgroundColor:"#79b821", nextState: "turningOff"
attributeState "MED", label:'MED', action:"switch.off", icon:"st.Lighting.light24", backgroundColor:"#79b821", nextState: "turningOff"
attributeState "LOW", label:'LOW', action:"switch.off", icon:"st.Lighting.light24", backgroundColor:"#79b821", nextState: "turningOff"
attributeState "off", label:'OFF', action:"switch.on", icon:"st.Lighting.light24", backgroundColor:"#ffffff", nextState: "turningOn"
attributeState "on", label:'ON', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", action:"switch.on", label:'TURNINGON', icon:"st.Lighting.light24", backgroundColor:"#2179b8", nextState: "turningOn"
attributeState "turningOff", action:"switch.off", label:'TURNINGOFF', icon:"st.Lighting.light24", backgroundColor:"#2179b8", nextState: "turningOff"
}
tileAttribute("device.level", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "levelUp")
attributeState("VALUE_DOWN", action: "levelDown")
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
}
standardTile("indicator", "device.indicatorStatus", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "when off", action:"indicator.indicatorWhenOn", icon:"st.indicators.lit-when-off"
state "when on", action:"indicator.indicatorNever", icon:"st.indicators.lit-when-on"
state "never", action:"indicator.indicatorWhenOff", icon:"st.indicators.never-lit"
}
standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "level", label:'${currentValue} %', unit:"%", backgroundColor:"#ffffff"
}
standardTile("low", "device.currentState", inactiveLabel: false, width: 2, height: 2) {
state "default", label: 'LOW', action: "low", icon:"st.Weather.weather4", backgroundColor: "#ffffff"
state "ADJUSTING.LOW", label:'LOW', action: "low", icon:"st.Weather.weather4", backgroundColor: "#2179b8"
state "LOW", label:'LOW', action: "low", icon:"st.Weather.weather4", backgroundColor: "#79b821"
}
standardTile("med", "device.currentState", inactiveLabel: false, width: 2, height: 2) {
state "default", label: 'MED', action: "med", icon:"st.illuminance.illuminance.light", backgroundColor: "#ffffff"
state "ADJUSTING.MED", label:'MED', action: "med", icon:"st.illuminance.illuminance.light", backgroundColor: "#2179b8"
state "MED", label: 'MED', action: "med", icon:"st.illuminance.illuminance.light", backgroundColor: "#79b821"
}
standardTile("high", "device.currentState", inactiveLabel: false, width: 2, height: 2) {
state "default", label: 'HIGH', action: "high", icon:"st.illuminance.illuminance.bright", backgroundColor: "#ffffff"
state "ADJUSTING.HIGH", label:'HIGH', action: "high", icon:"st.illuminance.illuminance.bright", backgroundColor: "#2179b8"
state "HIGH", label: 'HIGH', action: "high", icon:"st.illuminance.illuminance.bright", backgroundColor: "#79b821"
}
main(["switch"])
details(["switch", "low", "med", "high", "level", "indicator", "refresh"])
}
preferences {
section("Light Level Values") {
input "lowThreshold", "number", title: "Low Level", range: "1..99"
input "medThreshold", "number", title: "Medium Level", range: "1..99"
input "highThreshold", "number", title: "High Level", range: "1..99"
}
section ("Interval Selection") {
input "stepper", "enum", title: "Interval Value", defaultValue: "10", options: ["5","10","20"]
}
}
}
def parse(String description) {
def item1 = [
canBeCurrentState: false,
linkText: getLinkText(device),
isStateChange: false,
displayed: false,
descriptionText: description,
value: description
]
def result
def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
if (cmd) {
result = createEvent(cmd, item1)
}
else {
item1.displayed = displayed(description, item1.isStateChange)
result = [item1]
}
log.debug "Parse returned ${result?.descriptionText}"
result
}
def createEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
for (int i = 0; i < result.size(); i++) {
result[i].type = "physical"
}
log.trace "BasicReport"
result
}
def createEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
for (int i = 0; i < result.size(); i++) {
result[i].type = "physical"
}
log.trace "BasicSet"
result
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStartLevelChange cmd, Map item1) {
[]
log.trace "StartLevel"
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd, Map item1) {
[response(zwave.basicV1.basicGet())]
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
for (int i = 0; i < result.size(); i++) {
result[i].type = "physical"
}
log.trace "SwitchMultiLevelSet"
result
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
result[0].descriptionText = "${item1.linkText} is ${item1.value}"
result[0].handlerName = cmd.value ? "statusOn" : "statusOff"
for (int i = 0; i < result.size(); i++) {
result[i].type = "digital"
}
log.trace "SwitchMultilevelReport"
result
}
def doCreateEvent(physicalgraph.zwave.Command cmd, Map item1) {
def result = [item1]
def lowThresholdvalue = (settings.lowThreshold != null && settings.lowThreshold != "") ? settings.lowThreshold.toInteger() : 33
def medThresholdvalue = (settings.medThreshold != null && settings.medThreshold != "") ? settings.medThreshold.toInteger() : 67
def highThresholdvalue = (settings.highThreshold != null && settings.highThreshold != "") ? settings.highThreshold.toInteger() : 99
item1.name = "switch"
item1.value = cmd.value ? "on" : "off"
if (item1.value == "off") {
sendEvent(name: "currentState", value: "off" as String)
}
item1.handlerName = item1.value
item1.descriptionText = "${item1.linkText} was turned ${item1.value}"
item1.canBeCurrentState = true
item1.isStateChange = isStateChange(device, item1.name, item1.value)
item1.displayed = false
if (cmd.value) {
def item2 = new LinkedHashMap(item1)
item2.name = "level"
item2.value = cmd.value as String
item2.unit = "%"
item2.descriptionText = "${item1.linkText} dimmed ${item2.value} %"
item2.canBeCurrentState = true
item2.isStateChange = isStateChange(device, item2.name, item2.value)
item2.displayed = false
if (item2.value.toInteger() == lowThresholdvalue) {
sendEvent(name: "currentState", value: "LOW" as String)
log.debug "mapitemcurrentStateLow"
} else if (item2.value.toInteger() == medThresholdvalue) {
sendEvent(name: "currentState", value: "MED" as String)
log.debug "mapitemcurrentStateMed"
} else if (item2.value.toInteger() == highThresholdvalue) {
sendEvent(name: "currentState", value: "HIGH" as String)
log.debug "mapitemcurrentStateHigh"
} else if (item2.value.toInteger() == 0) {
sendEvent(name: "currentState", value: "off" as String)
log.debug "mapitemcurrentStateOFF"
} else {
sendEvent(name: "currentState", value: "on" as String)
log.debug "mapitemcurrentStateON"
}
result << item2
}
log.trace "doCreateEvent"
result
}
def createEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd, Map map) {
//def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
def value = "when off"
log.trace "ConfigurationReport"
if (cmd.configurationValue[0] == 1) {value = "when on"}
if (cmd.configurationValue[0] == 2) {value = "never"}
[name: "indicatorStatus", value: value, display: false]
}
def createEvent(physicalgraph.zwave.Command cmd, Map map) {
// Handles any Z-Wave commands we aren't interested in
log.debug "UNHANDLED COMMAND $cmd"
}
def on() {
log.info "on"
delayBetween([zwave.basicV1.basicSet(value: 0xFF).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
}
def off() {
log.info "off"
delayBetween ([zwave.basicV1.basicSet(value: 0x00).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
}
def setLevel(value) {
def lowThresholdvalue = (settings.lowThreshold != null && settings.lowThreshold != "") ? settings.lowThreshold.toInteger() : 33
def medThresholdvalue = (settings.medThreshold != null && settings.medThreshold != "") ? settings.medThreshold.toInteger() : 67
def highThresholdvalue = (settings.highThreshold != null && settings.highThreshold != "") ? settings.highThreshold.toInteger() : 99
if (value == "LOW") { value = lowThresholdvalue }
if (value == "MED") { value = medThresholdvalue }
if (value == "HIGH") { value = highThresholdvalue }
def level = Math.min(value as Integer, 99)
if (level == lowThresholdvalue) {
sendEvent(name: "currentState", value: "LOW" as String)
log.debug "setLevelcurrentStateLow"
} else if (level == medThresholdvalue) {
sendEvent(name: "currentState", value: "MED" as String)
log.debug "setLevelcurrentStateMed"
} else if (level == highThresholdvalue) {
sendEvent(name: "currentState", value: "HIGH" as String)
log.debug "setLevelcurrentStateHigh"
} else if (level == 0) {
sendEvent(name: "currentState", value: "off" as String)
log.debug "setLevelcurrentStateOFF"
} else {
sendEvent(name: "currentState", value: "on" as String)
log.debug "setLevelcurrentStateON"
}
sendEvent(name: "level", value: level, unit: "%")
log.trace "setLevelValue: ${value}"
log.debug "Setting value to: ${currentState}"
delayBetween ([zwave.basicV1.basicSet(value: level as Integer).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 1000)
}
def resetLevel(value) {
def level = Math.min(value as Integer, 99)
delayBetween ([
delayBetween ([ zwave.basicV1.basicSet(value: level).format(),
zwave.basicV1.basicSet(value: 0x00).format()], 10),
zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
}
def setLevel(value, duration) {
def lowThresholdvalue = (settings.lowThreshold != null && settings.lowThreshold != "") ? settings.lowThreshold.toInteger() : 33
def medThresholdvalue = (settings.medThreshold != null && settings.medThreshold != "") ? settings.medThreshold.toInteger() : 67
def highThresholdvalue = (settings.highThreshold != null && settings.highThreshold != "") ? settings.highThreshold.toInteger() : 99
if (value == "LOW") { value = lowThresholdvalue }
if (value == "MED") { value = medThresholdvalue }
if (value == "HIGH") { value = highThresholdvalue }
def level = Math.min(value as Integer, 99)
def dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60)
if (level == lowThresholdvalue) {
sendEvent(name: "currentState", value: "LOW" as String)
log.debug "setLeveldurationcurrentStateLow"
} else if (level == medThresholdvalue) {
sendEvent(name: "currentState", value: "MED" as String)
log.debug "setLeveldurationcurrentStateMed"
} else if (level == highThresholdvalue) {
sendEvent(name: "currentState", value: "HIGH" as String)
log.debug "setLeveldurationcurrentStateHigh"
} else if (level == 0) {
sendEvent(name: "currentState", value: "off" as String)
log.debug "setLeveldurationcurrentStateOFF"
} else {
sendEvent(name: "currentState", value: "on" as String)
log.debug "setLeveldurationcurrentStateON"
}
log.trace "setLevelValueDuration: ${value}"
log.debug "Setting value duration to: ${Level}"
zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration).format()
}
def levelUp(){
def steppervalue = (settings.stepper != null && settings.stepper != "") ? settings.stepper.toInteger() : 10
int nextLevel = device.currentValue("level") + steppervalue
if( nextLevel > 100){
nextLevel = 100
}
log.trace "setLevelUp(value): ${level}"
log.debug "Setting dimmer level up to: ${nextLevel}"
delayBetween ([zwave.basicV1.basicSet(value: nextLevel).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 1500)
}
def levelDown(){
def steppervalue = (settings.stepper != null && settings.stepper != "") ? settings.stepper.toInteger() : 10
int nextLevel = device.currentValue("level") - steppervalue
if (nextLevel < 0){
nextLevel = 0
}
if (nextLevel == 0){
off()
}
else
{
log.trace "setLevelDown(value): ${level}"
log.debug "Setting dimmer level down to: ${nextLevel}"
delayBetween ([zwave.basicV1.basicSet(value: nextLevel).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 1500)
}
}
def low() {
log.trace "setLow"
setLevel("LOW")
}
def med() {
log.trace "setMed"
setLevel("MED")
}
def high() {
log.trace "setHigh"
setLevel("HIGH")
}
def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
def refresh() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
def indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on", display: false)
zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
}
def indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off", display: false)
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
}
def indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never", display: false)
zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()
}
I have also integrated with Github and will provide the info once I complete the bug fix. This is my first attempt at a device handler but wanted to share as I find the flexibility very useful.