[OBSOLETE] Leviton Decora Z-Wave Plus Dimmers (DZ6HD & DZ1KD)

Looks like you published a new device handler that fixed the issues, though the dimming can be a little slow to update as well as the parameters. I can deal with that, though.

Slower than before or in general? Don’t want to update if worse

Slow to update the device on the app, not the function of the device, itself. Actually, it works better than the older version.

1 Like

I feel like I’m close to getting the DZ15S working. I basically stripped out all the dimming features and only kept the parameter related to the LED indicator.

I must be missing something though, I can’t manage to get it to work.

 *  Copyright 2017 Jason Xia
 *  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.
metadata {
    definition (name: "Leviton Decora Z-Wave Plus Switch", namespace: "jasonxh", author: "Jason Xia", ocfDeviceType: "oic.d.light") {
        capability "Actuator"
        capability "Configuration"
        //capability "Health Check"
        capability "Indicator"
        capability "Light"
        capability "Polling"
        capability "Refresh"
        capability "Sensor"
        capability "Switch"

        fingerprint mfr:"001D", prod:"3401", model:"0001", deviceJoinName: "Leviton Decora Z-Wave Plus 15A Dimmer DZ15S"

    simulator {
        // TODO - the simulator is not working yet
        status "on":  "command: 2003, payload: FF"
        status "off": "command: 2003, payload: 00"

        reply "2001FF,delay 5000,2602": "command: 2603, payload: FF"
        reply "200100,delay 5000,2602": "command: 2603, payload: 00"

    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.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
                attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
                attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
                attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"

        standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh"

        valueTile("indicatorStatus", "device.indicatorStatus", width: 3, height: 1, decoration: "flat") {
            state "indicatorStatus", label: 'Indicator Status\n${currentValue}'

                 "indicatorStatus", "refresh"])

    preferences {
        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: "indicatorStatus", type: "enum", title: "Indicator LED is lit",
                options: ["When switch is off (default)", "When switch is on", "Never"],
                displayDuringSetup: false, required: false

def installed() {
    log.debug "installed..."

def updated() {
    if (state.lastUpdatedAt != null && state.lastUpdatedAt >= now() - 1000) {
        log.debug "ignoring double updated"
    log.debug "updated..."
    state.lastUpdatedAt = now()


def configure() {
    def commands = []
    if (indicatorStatus != null) {
    log.debug "Configuring with 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"

def on() {
    //short duration = 0
    //        zwave.switchMultilevelV2.switchMultilevelSet(value: 0xFF, dimmingDuration: duration).format(),
    //        zwave.switchMultilevelV1.switchMultilevelGet().format()
    //], (durationToSeconds(duration) + 1) * 1000)

def off() {
    //short duration = 0
    //        zwave.switchMultilevelV2.switchMultilevelSet(value: 0x00, dimmingDuration: duration).format(),
    //        zwave.switchMultilevelV1.switchMultilevelGet().format()
    //], (durationToSeconds(duration) + 1) * 1000) 

def poll() {
    delayBetween(statusCommands, 100)

def ping() {

def refresh() {
    def commands = statusCommands
    if (getDataValue("MSR") == null) {
        commands << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
    //for (i in 1..8) {
        commands << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
    log.debug "Refreshing with commands $commands"
    delayBetween(commands, 1000)

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)

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])

private zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {

private zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
    if (cmd.value == 0) {
    } else if (cmd.value > 0) {
    } else {
        log.debug "Bad switch value $cmd.value"

private zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
    def result = null
            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)

private zwaveEvent(physicalgraph.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(physicalgraph.zwave.commands.hailv1.Hail cmd) {
    [createEvent(name: "hail", value: "hail", descriptionText: "Switch button was pressed", displayed: false),

private zwaveEvent(physicalgraph.zwave.Command cmd) {
    log.warn "Unhandled zwave command $cmd"

private switchEvent(boolean on) {
    createEvent(name: "switch", value: on ? "on" : "off")

private getStatusCommands() {
            // Even though SwitchBinary is not advertised by this device, it seems to be the only way to assess its true
            // on/off status.

private int durationToSeconds(short duration) {
    if (duration >= 0 && duration <= 127) {
    } else if (duration >= 128 && duration <= 254) {
        (duration - 127) * 60
    } else if (duration == 255) {
        2   // factory default
    } else {
        log.error "Bad duration $duration"

private configurationCommand(param, value) {
    param = param as short
    value = value as short
            zwave.configurationV1.configurationSet(parameterNumber: param, configurationValue: [value]).format(),
            zwave.configurationV1.configurationGet(parameterNumber: param).format()
    ], 1000)

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()
1 Like

I have multiple Leviton DZ6HD/DZ1KD dimmers in my house using the jasonxh handler, but 2 of them regularly stop reporting their status correctly. However, the dimmer still works and I can turn the lights on or off from the SmartThings app, except the app has no idea what the correct status of the light is and it will stay stuck in this state. I’ve tried refreshing the device, rebooting the hub, Z-Wave repair, excluding/including the device, and resetting the dimmer. However, the only thing that seems to fix the problem (for a few days) is to pull out the tab that cuts power to the dimmer for a few minutes. After this happens it correctly reports its status.

Sometimes I can reproduce the issue by turning off the light and while it’s fading off I press down on the main paddle or down on the dim level. Other times I resort to randomly pushing buttons on the dimmer until the status becomes unresponsive. This problem only occurs on certain dimmers in my house, while others perform flawlessly with this device handler.

I contacted SmartThings support thinking that maybe it’s some kind of Z-Wave issue, but they had me go back to the “Dimmer Switch” device handler. Using the “Dimmer Switch” handler I cannot get the problem to occur. So I’m wondering does anyone else have this issue? My feeling is that the custom device handler somehow overwhelms the system in certain scenarios and the dimmer just stops reporting its status to the hub.

1 Like

I have several of these dimmers setup in single and 3 way. The 3 way switches are my issue and as commonly reported changes on the remote / matching switch do not send an event. This means that the status is incorrect until the next refresh event. By default, this happens at 32 minute intervals with the “Z-Wave Dimmer Switch Generic” type.

I’m intrigued by this DTH as it seems to offer a number of improvements but I’m confused how the refresh is implemented (probably doesn’t help that I’m a ST newb!). I’d like to shorten the interval to make this work a bit better for me.

The code that seems to implement this looks commented out. What am I missing? How do I tweak the refresh interval (that’s the checkInterval, right?)?

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])

@johnlinehan The code you mentioned is controlling the health check, which is different from polling. It’s disabled because the capability is not officially supported yet for 3rd party DTHs and was causing sporadic issues for some users. Maybe you can give this a try: “Pollster” - A SmartThings Polling Daemon. Do pay attention to the warnings about aggressive polling intervals though.

Thanks. That’s really helpful and is what I’m looking for. I’m new to Smarthings and smart devices in general but I’m looking forward to learn & explore more about these customizations.

Greetings, jasonxh.

Thank you for publishing your Leviton Decora Z-Wave Plus Dimmers DTH. I have successfully integrated your DTH with my Decora Smart Z-Wave dimmer DZ6HD and the set up some simple schedules for turning my lights on at sunset +30 minutes and then off at 2230.

These routines worked fine for a week or so, but now the tiles on the app no longer update the status of the lights on a stable/regular basis and after turning the lights “off” when they were on, the app returns “Turning Off” but after a short while falls back to showing a status of “On” when indeed the lights have actually turned off. This means I can no longer rely on the app to report back accurately the “real” status of my lights. The dimmer levels also do not report accurately the state of the lights.

The whole idea of buying the Decora Smart Dimmer was to be able to automate them and have them function when I’m not home and such. And, I didn’t know that Smartthings/Leviton did not actually support their full functionality when I bought the dimmer and companion, so I’m very thankful for your DTH and app.

Can you think of a reason why the lights are no longer updating their status to the app reliably? Is there anything I can do to troubleshoot this problem?

Thank you in advance for any help or guidance you can provide.

Warm greetings from frozen Fox, Alaska.


1 Like

I should have replied to capfan’s post from a week ago. I’m new to the community so please forgive me.

I tried removing power from the affected Decora Smart Z-wave Dimmer using the “Air Gap” feature as capfan did and found that the app and DTH now work again. I’m not sure why hard resetting the Decora Smart Z-wave Dimmer fixed the problem, but it did. I wonder if the dimmer is faulty somehow as capfan indicated he, too, was able to get the jasonxh handler working again using the same hard power reset fix. I guess I’ll have to keep an eye out on it for now and if the dimmer continues to “sieze up” I’ll have to investigate possibly returning the dimmer and swapping it out for a new one of the same model.

Warm greetings from the Upper Bog.

I’ve found that going back to the “Dimmer Switch” device handler resolves the dimmer locking up problem for me. I seem to have this issue with dimmers that are located farther away from the hub than others. Perhaps they are communicating through another Z-Wave device in the mesh before the packets get to the hub, but generally the status of these dimmers in the SmartThings app gets updated slower than others.

If I press up on the main paddle and then quickly press down on the thin dim paddle, and vice versa, and keep doing this quickly I can usually get the device to lock up. Doing the same thing with “Dimmer Switch” does not result in a lock up.

@capfan @oopala2003 Thanks for reporting the issue. I spent the last couple of hours trying to reproduce this issue again, and finally I got my switch into this non-replying state, though it kept taking commands. This really points to a firmware issue of the dimmer, which seems to be aggravated by large influx of Z-Wave commands. I just pushed a change to cut down on the number of message exchanges when device buttons are pressed. Hopefully this can help mitigate the issue. Please install the latest version of this DTH and let me know how it works.

1 Like

I’m still having the same issue after the update. I pressed up on the main paddle and immediately pressed down on the thin dim-level paddle and status reporting broke. I agree that something is wrong with the dimmer firmware. Excluding, resetting, then including the dimmer does not fix the issue once it happens. Rebooting the hub and repairing Z-Wave does not fix the problem. But for some reason cutting off power to the dimmer for a few minutes fixes the problem.

Well that’s a bummer… I’m surprised at how easy it is for you to repro this though. Maybe two more tweaks you can try:

Yeah, it actually seems like it got easier to reproduce the issue with the newest device handler. I will try out the delays and see what happens. I agree that somehow the dimmer is getting overwhelmed with packets and locks up. My feeling is that it is linked to the dimmer most likely communicating to the hub through an intermediate Z-Wave device (or two) which changes the timing of traffic. Again, I cannot reproduce this issue with dimmers located close to the hub.

1 Like

I installed the latest update and will do some testing to see how it functions. Thank you for your help and updates, @jasonxh. Also thanks to @capfan for working to help troubleshoot this issue. I only have 2 Z-wave devices in my SmartThings network; a Samsung SmartThings motion detector and the Leviton Decora Smart Dimmer so my situation is a bit different than capfan’s. My SmartThings hub is 20 or so feet away from the dimmer in question and the motion detector is located near the dimmer.

Hi, new user here. I found this DTH and configured it for my DZ6HD dimmer, and it seems to work great so far, with the exception of Alexa. Alexa won’t run any commands that do something with this switch. Is there a way that I can fix this without going back to the generic zwave dimmer DTH?



Alexa may have created a duplicate device, or just won’t update with the new device handler. You’ll need to go to alexa.amazon.com and “forget” the devices there (there’s no longer an option in the app), then rediscover your switch in the Alexa app. That should fix it!

I also have a reporting issue with a few specific switches at my house. It’s always the same 3 leviton switches that show a “on” status when the switch/light is off. If I toggle it to off, it stays at an off status for a while and eventually will change itself back to on, but the light never really turns on. I can make it turn on just fine if I toggle it off and then back on. I haven’t tried going back to dimmer switch device handler yet.


@mlamb01 have you made sure you’ve granted the permission to Alexa in SmartApps, either explicitly or through the blanket permission? Once you go through that, just ask Alexa to discover devices and it should work.