Support of OTA firmware updates for Z-Wave / Z-Wave Plus devices

So I just found this, apparently there have been newer firmware version released and using the Homeseer stick and Z-Flash some people were having success updating the Leviton's. It seems one of the fixes was related to device status updates.

From what I understand I should be able to add this device to HE as a slave and then using the z-flash software update the dimmers.

Or could I use the stick that comes with HE and just get the z-flash software?

I can't offer advice on this obviously.

I ended up successfully updating all of my Leviton's to FW version 1.20 and it looks like all the issues that I had previously had, have been resolved. Status updates are now working properly and are very fast, even from the remote dimmer. I also noticed a speed increase even turning on lights from the dashboard or web interface is instantaneous now. The "physical" and "digital" events in the logs are also properly showing up depending on how the light is turned on.

3 Likes

Could you expand on how you eventually did this please.? I have many of these dimmers and they are not working correctly with the Generic Smart Z-Wave Dimmer driver. Support referred me to this thread.

Where do I get the Hex files - do I need to contact Leviton or is there a download I am unable to find with searches?
Did the z-wave stick that came with Hubitat work?
Do I need to get the software?

Amy other specifics.

Many thanks for your help.

There are two ways you can perform the upgrade, either with Hubitat's USB adapter or HomeSeer's. Either way you will need HomeSeer's Z-Flash software to update them. Hubitat's USB adapter actually stores all of the Z-wave information on it, so you will not need to exclude/include any of your devices.

If you choose to use Hubitat's USB adapter you will need to shutdown the hub and insert the USB adapter into a PC. I used a Windows 10 computer, so not sure if its possible with Linux/OSX. I have also linked the Windows driver you will need in order to use Hubitat's USB adapter. You will need to manually install the driver from device manager. I had to force it to install, because Windows did not detect it as the correct driver, but it does work fine.

Otherwise you can buy Homeseer's kit that includes a Z-wave/Zigbee USB adapter and you would include this device to HE and then you can update the FW.

Then run the Z-flash software and it should find the USB adapter. The Z-Flash will basically poll for each device and give you a listing of all devices and the current FW version. The Z-Flash software comes with the Leviton firmware hex files, so you will not need to download these. You can also flash all Dimmers/Switches of the same model at one time. It will take a while to flash the devices so be patient. Also I did find that two of my dimmers were not found the first time, but after I updated the rest those two showed up and I was able to successfully update them. I would use a laptop and find a central location in the house to update them.

Just to eliminate any possible issues after updating I did go through each device and exclude them from HE, reset each device to factory defaults and re-included it. Now this is probably not needed, but I did this for more of peace of mind, all the smartapps will still exist, you would just need to re-add the device.

HomeSeer Z-Flash Software

HomeSeer Z-Flash Kit (Includes USB Adapter)

Hubitat's USB Drivers (Windows 10)

3 Likes

Thank you. This is extremely helpful.

Do I need to obtain the Hex files for the firmware update from Leviton or is this taken care of by the Flash software?

The flash software includes it. When you select the device it actually knows and will let you select the FW from a drop down menu.

1 Like

Thank you again.

:grinning:

Update on progress:

This has solved my problem - the Leviton Z-wave plus dimmers (**Models DZD6HD and DZ1KD) were being recognized by Hubitat correctly and the Generic Smart Zwave Dimmer was being applied. Unfortunately this didn't work with the Dimmers which were not reporting a physical or digital change, although the device would switch on and off and dim.

I emailed support and got promptly referred to this topic referencing the updated z-wave firmware for these dimmers. I have about 50 of these, which I installed last year using Smartthings generic device drivers. They have always functioned flawlessly and I never saw the need to change the firmware.

Using the generic "non smart" driver I could get them to function but when I tried to modify the custom device handler from Smartthings community it wouldn't work either and I was hoping to be able to use this to set some of the parameters for fade time etc. without using the physical switch.

Using the links provided above I had to download the Z-flash utility from HomeSeer and connected this as a secondary controller to my Hubitat, after installing the driver on a windows 10 PC.

The software found the devices I had transferred and correctly identified the firmware versions and allowed me to update the dimmers. (This is painfully slow - 10 minutes or more per device and it fails if the dimmer is switched during the process). You can set the software to update the same models sequentially and leave it running.

This has solved the problem. The devices are now responding quickly and updating the status within seconds. Juust the way it should. The modified Smartthings driver also seems to work but it switches the dimmers to zero when they are switched rather than leaving them at the last l (on the dashboard).

So now I can get on with the rest of the whole house transfer. So far I've had to change a ocuple of custom divers to support a Z-wave outlet with power management. Things seem to be responding very quickly and the web interface is much better than using a phone/table to configure settings.

Good so far - will update as I make further progress (am updating the remaining firmwares while they are still connected to the Smartthings hub at present).

Well that is craptastic I don't have a Windows machine. Is there a linux alternative or even mac?

How did you set this up as a secondary controller? I haven't tried this yet, but are you saying that this controller was connected to hubitat and the update was done using hubitats stick?

@Keo

I've done something similar to update Aeon/Aeotec devices. They supply packages to do the updates that use the Zensys tools as the base. I have several "spare" ZSticks and one of them is joined to the Hubitat network as a Secondary. I plug that into my Mac, fire up my virtual Windows PC and run the Aeon software. I've updated Multisenor6's, Minimotes and Wallmotes this way.

I do not have to Exclude the devices before starting the update. I have not run into it, but I can imagine that leaving it as an active device while doing the update could, under just the right circumstance, fail. So far, I haven't run into it and I performed one of these updates as recently as last week.

From March 2018:

I like the Aeon ZStick because it has a battery and a button. The battery means it works when not plugged into USB power. And the button puts it into Include or Exclude mode. For pretty much the same $ you'd pay for any ZWave USB stick, the extra feature is worth it, to me.

The problem is the Z-Flash software is Windows only, there may be an alternative but I am not sure. You could also just spin up a Windows VM temporary.

I think the Hubitat stick will work but I haven't tried using it away from the main device. I have a Z-stick from Aeotec which is useful for getting information about Z-wave nodes, pairing devices etc.

This can be recognized as a secondary Z-wave controller and as such can access the information about the primary Z-wave network.

Very handy. Have'nt explored how well Hubitat handles primary/secondary controllers but I suspect it will be more compliant than Smartthings (which had idiosyncracies that made it of limited use) others may know more.

The Hubitat stick will work I used it and was successful. All Z-Wave information is saved to the stick.

I actually bought the HomeSeer kit, but still wanted to see if it would work with Hubitat's USB. Going forward I would just use the HomeSeer USB, so I do not need to take the hub offline.

If anyone is looking for a good driver for the Leviton Dimmer's the one linked below is what I use and you can configured all the advanced functions.

https://community.hubitat.com/t/leviton-z-wave-plus-dimmers-firmware-update-may-needed-to-work-with-generic-smart-driver/4442/2?u=raidflex

1 Like

Continuing the discussion from Rule Help - Persistent light state option with motion controller:

This merits a new topic that I hope others will find useful if they have Levition Plus Z-Wave Dimmers and Switches that don't behave nicely when they transfer them, I suspect there will still be versions for sale that haven't been updated to the new firmware and for those if us who were early adopters we seem to have an additional challenge to get them to work. I still find them a great dimmer/switch ... and when the update is applied the response to a change is lightening fast on a dashboard.

[Rule Help - Persistent light state option with motion controller]

This has solved my problem - the Leviton Z-wave plus dimmers (**Models DZD6HD and DZ1KD ) were being recognized by Hubitat correctly and the Generic Smart Zwave Dimmer was being applied. Unfortunately this didn't work with the Dimmers which were not reporting a physical or digital change, although the device would switch on and off and dim.

I emailed support and got promptly referred to this topic referencing the updated z-wave firmware for these dimmers. I have about 50 of these, which I installed last year using Smartthings generic device drivers. They have always functioned flawlessly and I never saw the need to change the firmware.

Using the generic "non smart" driver I could get them to function but when I tried to modify the custom device handler from Smartthings community it wouldn't work either and I was hoping to be able to use this to set some of the parameters for fade time etc. without using the physical switch.

Using the links provided above I had to download the Z-flash utility from HomeSeer and connected this as a secondary controller to my Hubitat, after installing the driver on a windows 10 PC.

The software found the devices I had transferred and correctly identified the firmware versions and allowed me to update the dimmers. (This is painfully slow - 10 minutes or more per device and it fails if the dimmer is switched during the process). You can set the software to update the same models sequentially and leave it running.

This has solved the problem. The devices are now responding quickly and updating the status within seconds. Just the way it should. The modified Smartthings driver also seems to work but it switches the dimmers to zero when they are switched rather than leaving them at the last l (on the dashboard).

So now I can get on with the rest of the whole house transfer. So far I've had to change a couple of custom divers to support a Z-wave outlet with power management. Things seem to be responding very quickly and the web interface is much better than using a phone/table to configure settings.

Good so far - will update as I make further progress (am updating the remaining firmwares while they are still connected to the Smartthings hub at present).

Reply

Bookmark Share Flag Invite Reply

Tracking

You will see a count of new replies because you posted a reply to this topic.

Suggested Topics

There are 5 unread and 9 new topics remaining, or browse other topics in Automations

Here is a good driver to use that has basically all advanced functions for the Leviton dimmers.

/**
 *  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 Dimmer", 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"
        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"

        command "low"
        command "medium"
        command "high"
        command "levelUp"
        command "levelDown"

        fingerprint mfr:"001D", prod:"3201", model:"0001", deviceJoinName: "Leviton Decora Z-Wave Plus 600W Dimmer"
        fingerprint mfr:"001D", prod:"3301", model:"0001", deviceJoinName: "Leviton Decora Z-Wave Plus 1000W Dimmer"
    }

    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 = last dim level (default)\n1 - 100 = fixed level", range: "0..100",
                displayDuringSetup: false, required: false
        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 = instant on\n1 - 127 = 1 - 127 seconds (default 2)\n128 - 253 = 1 - 126 minutes", range: "0..253",
                displayDuringSetup: false, required: false
        input name: "fadeOffTime", type: "number", title: "Fade-off time",
                description: "0 = instant off\n1 - 127 = 1 - 127 seconds (default 2)\n128 - 253 = 1 - 126 minutes", range: "0..253",
                displayDuringSetup: false, required: false
        input name: "levelIndicatorTimeout", type: "number", title: "Dim level indicator timeout",
                description: "0 = dim level indicator off\n1 - 254 = timeout in seconds (default 3)\n255 = dim level indicator always on", range: "0..255",
                displayDuringSetup: false, required: false
    }
}

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

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.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 (device.currentValue("switch") != "on") {
            // Don't blindly trust level. Explicitly request on/off status.
            result = [result, response(zwave.switchBinaryV1.switchBinaryGet().format())]
        }
    } else {
        log.debug "Bad dimming level $level"
    }
    result
}

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.
            zwave.switchBinaryV1.switchBinaryGet().format(),
            zwave.switchMultilevelV1.switchMultilevelGet().format()
    ]
}

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()
    }
}
3 Likes

Thanks - I will give this a try.:grinning:

interestingly this driver also seems to work well with a GE dimmer switch that i tried it with.

have had this one installed for a while now … so not sure how to look up the model # of this device.