I think I know the problem. When you have a fade time set in the device, it actually is fading down to zero. So, when you turn it back on, there is no setting for it to use other than 100 because that's it's default setting. I had my fade times at zero and didn't see the behavior you saw. I swapped my fade times to 5 and bingo, that's when the device set itself to 100% when the on-command was sent.
Use the following driver ported over from ST and you will be all set.
/**
*
* 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.
*
* Adapted for Hubitat based on the Leviton Decora Z-Wave Plus Dimmer DTH developed by Jason Xia (jasonxh) for SmartThings
*/
metadata {
definition (name: "Leviton Z-Wave Plus Dimmer", namespace: "ryan780", author: "Ryan C.") {
capability "Actuator"
capability "Configuration"
capability "Health Check"
capability "Indicator"
capability "Light"
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Switch"
capability "Switch Level"
attribute "loadType", "enum", ["incandescent", "led", "cfl"]
attribute "presetLevel", "number"
attribute "minLevel", "number"
attribute "maxLevel", "number"
attribute "fadeOnTime", "number"
attribute "fadeOffTime", "number"
attribute "levelIndicatorTimeout", "number"
attribute "firmwareVersion", "string"
command "low"
command "medium"
command "high"
command "levelUp"
command "levelDown"
}
preferences {
input name: "levelIncrement", type: "number", title: "In-App Level Increment",
description: "1 - 100 (default $defaultLevelIncrement)", range: "1..100", defaultValue: defaultLevelIncrement,
displayDuringSetup: false, required: false
input type: "paragraph", element: "paragraph", title: "Device Preferences",
description: "The following preferences are configuring the device behaviors. " +
"All of them are optional. Leave a preference empty to skip configuring it."
input name: "loadType", type: "enum", title: "Load type",
options: ["Incandescent (default)", "LED", "CFL"],
displayDuringSetup: false, required: false
input name: "indicatorStatus", type: "enum", title: "Indicator LED is lit",
options: ["When switch is off (default)", "When switch is on", "Never"],
displayDuringSetup: false, required: false
input name: "presetLevel", type: "number", title: "Light turns on to level",
description: "0 to 100 (default 0)", range: "0..100",
displayDuringSetup: false, required: false
input type: "paragraph", element: "paragraph", title: "",
description: "0 = last dim level (default)\n1 - 100 = fixed level"
input name: "minLevel", type: "number", title: "Minimum light level",
description: "0 to 100 (default 10)", range: "0..100",
displayDuringSetup: false, required: false
input name: "maxLevel", type: "number", title: "Maximum light level",
description: "0 to 100 (default 100)", range: "0..100",
displayDuringSetup: false, required: false
input name: "fadeOnTime", type: "number", title: "Fade-on time",
description: "0 to 253 (default 2)", range: "0..253",
displayDuringSetup: false, required: false
input type: "paragraph", element: "paragraph", title: "",
description: "0 = instant on\n1 - 127 = 1 - 127 seconds (default 2)\n128 - 253 = 1 - 126 minutes"
input name: "fadeOffTime", type: "number", title: "Fade-off time",
description: "0 to 253 (default 2)", range: "0..253",
displayDuringSetup: false, required: false
input type: "paragraph", element: "paragraph", title: "",
description: "0 = instant off\n1 - 127 = 1 - 127 seconds (default 2)\n128 - 253 = 1 - 126 minutes"
input name: "levelIndicatorTimeout", type: "number", title: "Dim level indicator timeout",
description: "0 to 255 (default 3)", range: "0..255",
displayDuringSetup: false, required: false
input type: "paragraph", element: "paragraph", title: "",
description: "0 = dim level indicator off\n1 - 254 = timeout in seconds (default 3)\n255 = dim level indicator always on"
}
}
def installed() {
log.debug "installed..."
initialize()
response(refresh())
}
def updated() {
if (state.lastUpdatedAt != null && state.lastUpdatedAt >= now() - 1000) {
log.debug "ignoring double updated"
return
}
log.debug "updated..."
state.lastUpdatedAt = now()
initialize()
response(configure())
}
def configure() {
def commands = []
if (loadType != null) {
commands.addAll(setLoadType(loadType))
}
if (indicatorStatus != null) {
commands.addAll(setIndicatorStatus(indicatorStatus))
}
if (presetLevel != null) {
commands.addAll(setPresetLevel(presetLevel as short))
}
if (minLevel != null) {
commands.addAll(setMinLevel(minLevel as short))
}
if (maxLevel != null) {
commands.addAll(setMaxLevel(maxLevel as short))
}
if (fadeOnTime != null) {
commands.addAll(setFadeOnTime(fadeOnTime as short))
}
if (fadeOffTime != null) {
commands.addAll(setFadeOffTime(fadeOffTime as short))
}
if (levelIndicatorTimeout != null) {
commands.addAll(setLevelIndicatorTimeout(levelIndicatorTimeout as short))
}
log.debug "Configuring with commands $commands"
commands
}
def parse(String description) {
def result = null
def cmd = zwave.parse(description, [0x20: 1, 0x25:1, 0x26: 1, 0x70: 1, 0x72: 2])
if (cmd) {
result = zwaveEvent(cmd)
log.debug "Parsed $cmd to $result"
} else {
log.debug "Non-parsed event: $description"
}
result
}
def on() {
def fadeOnTime = device.currentValue("fadeOnTime")
def presetLevel = device.currentValue("presetLevel")
short duration = fadeOnTime == null ? 255 : fadeOnTime
short level = presetLevel == null || presetLevel == 0 ? 0xFF : toZwaveLevel(presetLevel as short)
delayBetween([
zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: duration).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
], durationToSeconds(duration) * 1000 + commandDelayMs)
}
def off() {
def fadeOffTime = device.currentValue("fadeOffTime")
short duration = fadeOffTime == null ? 255 : fadeOffTime
delayBetween([
zwave.switchMultilevelV2.switchMultilevelSet(value: 0x00, dimmingDuration: duration).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
], durationToSeconds(duration) * 1000 + commandDelayMs)
}
def setLevel(value, durationSeconds = null) {
log.debug "setLevel >> value: $value, durationSeconds: $durationSeconds"
short level = toDisplayLevel(value as short)
short dimmingDuration = durationSeconds == null ? 255 : secondsToDuration(durationSeconds as int)
sendEvent(name: "level", value: level, unit: "%")
sendEvent(name: "switch", value: level > 0 ? "on" : "off")
delayBetween([
zwave.switchMultilevelV2.switchMultilevelSet(value: toZwaveLevel(level), dimmingDuration: dimmingDuration).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
], durationToSeconds(dimmingDuration) * 1000 + commandDelayMs)
}
def poll() {
delayBetween(statusCommands, commandDelayMs)
}
def ping() {
poll()
}
def refresh() {
def commands = statusCommands
commands << zwave.versionV1.versionGet().format()
if (getDataValue("MSR") == null) {
commands << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
}
for (i in 1..8) {
commands << zwave.configurationV1.configurationGet(parameterNumber: i).format()
}
log.debug "Refreshing with commands $commands"
delayBetween(commands, commandDelayMs)
}
def indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never")
configurationCommand(7, 0)
}
def indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off")
configurationCommand(7, 255)
}
def indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on")
configurationCommand(7, 254)
}
def low() {
setLevel(10)
}
def medium() {
setLevel(50)
}
def high() {
setLevel(100)
}
def levelUp() {
setLevel(device.currentValue("level") + (levelIncrement ?: defaultLevelIncrement))
}
def levelDown() {
setLevel(device.currentValue("level") - (levelIncrement ?: defaultLevelIncrement))
}
private static int getCommandDelayMs() { 1000 }
private static int getDefaultLevelIncrement() { 10 }
private initialize() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
}
private zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
dimmerEvent(cmd.value)
}
private zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) {
dimmerEvent(cmd.value)
}
private zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
response(zwave.switchMultilevelV1.switchMultilevelGet().format())
}
private zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
if (cmd.value == 0) {
switchEvent(false)
} else if (cmd.value == 255) {
switchEvent(true)
} else {
log.debug "Bad switch value $cmd.value"
}
}
private zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
def result = null
switch (cmd.parameterNumber) {
case 1:
result = createEvent(name: "fadeOnTime", value: cmd.configurationValue[0])
break
case 2:
result = createEvent(name: "fadeOffTime", value: cmd.configurationValue[0])
break
case 3:
result = createEvent(name: "minLevel", value: cmd.configurationValue[0])
break
case 4:
result = createEvent(name: "maxLevel", value: cmd.configurationValue[0])
break
case 5:
result = createEvent(name: "presetLevel", value: cmd.configurationValue[0])
break
case 6:
result = createEvent(name: "levelIndicatorTimeout", value: cmd.configurationValue[0])
break
case 7:
def value = null
switch (cmd.configurationValue[0]) {
case 0: value = "never"; break
case 254: value = "when on"; break
case 255: value = "when off"; break
}
result = createEvent(name: "indicatorStatus", value: value)
break
case 8:
def value = null
switch (cmd.configurationValue[0]) {
case 0: value = "incandescent"; break
case 1: value = "led"; break
case 2: value = "cfl"; break
}
result = createEvent(name: "loadType", value: value)
break
}
result
}
private zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: $cmd.manufacturerId"
log.debug "manufacturerName: $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)
updateDataValue("manufacturer", cmd.manufacturerName)
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}
private zwaveEvent(hubitat.zwave.commands.hailv1.Hail cmd) {
createEvent(name: "hail", value: "hail", descriptionText: "Switch button was pressed", displayed: false)
}
private zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
createEvent(name: "firmwareVersion", value: "${cmd.applicationVersion}.${cmd.applicationSubVersion}", displayed: false)
}
private zwaveEvent(hubitat.zwave.Command cmd) {
log.warn "Unhandled zwave command $cmd"
}
private dimmerEvent(short level) {
def result = null
if (level == 0) {
result = [createEvent(name: "level", value: 0, unit: "%"), switchEvent(false)]
} else if (level >= 1 && level <= 100) {
result = [createEvent(name: "level", value: toDisplayLevel(level), unit: "%")]
if (!isNewFirmware && device.currentValue("switch") != "on") {
// Don't blindly trust level. Explicitly request on/off status.
result << response(zwave.switchBinaryV1.switchBinaryGet().format())
} else {
result << switchEvent(true)
}
} else {
log.debug "Bad dimming level $level"
}
result
}
private switchEvent(boolean on) {
createEvent(name: "switch", value: on ? "on" : "off")
}
private getStatusCommands() {
def cmds = []
if (!isNewFirmware) {
// Even though SwitchBinary is not advertised by this device, it seems to be the only way to assess its true
// on/off status.
cmds << zwave.switchBinaryV1.switchBinaryGet().format()
}
cmds << zwave.switchMultilevelV1.switchMultilevelGet().format()
cmds
}
private short toDisplayLevel(short level) {
level = Math.max(0, Math.min(100, level))
(level == (short) 99) ? 100 : level
}
private short toZwaveLevel(short level) {
Math.max(0, Math.min(99, level))
}
private int durationToSeconds(short duration) {
if (duration >= 0 && duration <= 127) {
duration
} else if (duration >= 128 && duration <= 254) {
(duration - 127) * 60
} else if (duration == 255) {
2 // factory default
} else {
log.error "Bad duration $duration"
0
}
}
private short secondsToDuration(int seconds) {
if (seconds >= 0 && seconds <= 127) {
seconds
} else if (seconds >= 128 && seconds <= 127 * 60) {
127 + Math.round(seconds / 60)
} else {
log.error "Bad seconds $seconds"
255
}
}
private configurationCommand(param, value) {
param = param as short
value = value as short
delayBetween([
zwave.configurationV1.configurationSet(parameterNumber: param, configurationValue: [value]).format(),
zwave.configurationV1.configurationGet(parameterNumber: param).format()
], commandDelayMs)
}
private setFadeOnTime(short time) {
sendEvent(name: "fadeOnTime", value: time)
configurationCommand(1, time)
}
private setFadeOffTime(short time) {
sendEvent(name: "fadeOffTime", value: time)
configurationCommand(2, time)
}
private setMinLevel(short level) {
sendEvent(name: "minLevel", value: level)
configurationCommand(3, level)
}
private setMaxLevel(short level) {
sendEvent(name: "maxLevel", value: level)
configurationCommand(4, level)
}
private setPresetLevel(short level) {
sendEvent(name: "presetLevel", value: level)
configurationCommand(5, level)
}
private setLevelIndicatorTimeout(short timeout) {
sendEvent(name: "levelIndicatorTimeout", value: timeout)
configurationCommand(6, timeout)
}
private setLoadType(String loadType) {
switch (loadType) {
case "Incandescent (default)":
sendEvent(name: "loadType", value: "incandescent")
return configurationCommand(8, 0)
case "LED":
sendEvent(name: "loadType", value: "led")
return configurationCommand(8, 1)
case "CFL":
sendEvent(name: "loadType", value: "cfl")
return configurationCommand(8, 2)
}
}
private setIndicatorStatus(String status) {
switch (indicatorStatus) {
case "When switch is off (default)": return indicatorWhenOff()
case "When switch is on": return indicatorWhenOn()
case "Never": return indicatorNever()
}
}
private boolean getIsNewFirmware() { device.currentValue("firmwareVersion") ==~ /1\.2\d/ }
There's more stuff in here to clean up to play nicer with Hubitat vs. ST but this should at least get you started with something that should work. I'll post an update when I've cleaned it up.