Anything like "Enhanced-Dimmer-Switch" for 45857GE zigbee switches?

Immediately after installing SmartThings I went out and replaced 4 switches (all 3-way) with the 45857GE switches. They work great but after installing the Hue bridge and some Hue bulbs in other fixtures I realized I want my main lights to dim on and off rather than have the insta-on and insta-off like flipping a standard switch. I searched around (a lot) and found “Enhanced-Dimmer-Switch” but after installing I realized it doesn’t work for my switches (it’s designed for GE12724 switches).

Is there a similar GitHub (or other) solution for dimming this switch on and off?

I’ve thought about taking a look at this as I have a few of these but there is nothing out there today. Unfortunately from what I can tell there is no direct documentation on what is/is not supported with this switch. Looks like a lot of trial and error.

2 Likes

I am dipping my toe into the CoRE SmartApp to see what’s available there and if a solution is possible from that angle. It’s a little intimidating but I don’t mind learning something new! I am relatively tech savvy but will admit I am a n00b to SmartThings.

1 Like

I just looked at my dimmer and the OnOffTransitionTime zigbee attribute. This attribute represents the time taken to move to or from the target level when on or off commands are received. When I checked the attribute it stated unsupported. So it looks like GE did not implement that ability.

cluster: 0008, size: 06, attrId: 0010, result: unsupported attr

2 Likes

Thanks for taking a look! I will definitely take this into account when I change other switches. I have 8 (not smart) Lutron dimmer switches in my home theater that I need to change so I will definitely do some more research now that I know what to look for.

So after looking some more I think there is a way to do this. It will require more changes than I thought (as the simple fix above is not supported). I’ll update you when I have some sample code.

2 Likes

You’re awesome! The more I use the switches the more it bugs me. I even formulated a plan to move them elsewhere in the house and replace them with a model that works the way I want. Please let me know if you get it worked out!

After doing more work I can kind of simulate it through SmartThings zigbee commands but unfortunately I can’t change how the physical button presses act. The only way to do that was with the attribute that GE does not support.

1 Like

Here is what I’ve put together. Unfortunately it is kludgy as the official method to do this is not supported. Also to note: off now sets the current level to 0%. This is different than how all other DTHs work. Let me know if this is helpful.

/**
*  Copyright 2015 SmartThings
*
*  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: "Enhanced ZigBee Dimmer Power", namespace: "smartthings", author: "SmartThings") {
        capability "Actuator"
        capability "Configuration"
        capability "Refresh"
        capability "Power Meter"
        capability "Sensor"
        capability "Switch"
        capability "Switch Level"
        capability "Health Check"

        fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04"
        fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702"
        fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-CIA19NAE26", deviceJoinName: "Sengled Element touch"
        fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Zigbee Plug-In Dimmer"
        fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Zigbee In-Wall Dimmer"
    }

    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:"#79b821", 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:"#79b821", nextState:"turningOff"
                attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
            }
            tileAttribute ("device.level", key: "SLIDER_CONTROL") {
                attributeState "level", action:"switch level.setLevel"
            }
            tileAttribute ("power", key: "SECONDARY_CONTROL") {
                attributeState "power", label:'${currentValue} W'
            }
        }
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
            state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
        }
        main "switch"
        details(["switch", "refresh"])
    }
    preferences {
        section ("Zigbee Dimmer Properties"){
            input "transitionTime", "number", title: "Tranistion Time (0-15)", description: true, defaultValue: 5, required: false, range: "0..15"
            input "minLevel", "number", title: "Minimum Dimmer Level (1-50)", description: true, defaultValue: 1, required: false, range: "1..50"
            input "maxLevel", "number", title: "Maximum Dimmer Level (51-100)", description: true, defaultValue: 100, required: false, range: "51..100"
        }
    }
}

private getCLUSTER_LEVEL() { 0x0008 }
private getLEVEL_CMD_MOVE_TO_LEVEL_ON_OFF() { 0x04 }
private getLEVEL_ATTR_ON_LEVEL() { 0x0011 }

    // Parse incoming device messages to generate events
def parse(String description) {
    log.debug "description is $description"

    def event = zigbee.getEvent(description)
    if (event) {
        log.info event
        if (event.name == "power") {
            if (device.getDataValue("manufacturer") != "OSRAM") {       //OSRAM devices do not reliably update power
                event.value = (event.value as Integer) / 10             //TODO: The divisor value needs to be set as part of configuration
                sendEvent(event)
            }
        }
        else {
            sendEvent(event)
        }
    }
    else {
        def cluster = zigbee.parse(description)
        if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
            if (cluster.data[0] == 0x00){
                log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
                sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
            }
            else {
                log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
            }
        }
        else {
            log.warn "DID NOT PARSE MESSAGE for description : $description"
            log.debug zigbee.parseDescriptionAsMap(description)
        }
    }
}

def off() {
    //zigbee.off()
    state.currentLevel = (device.currentValue('level')) ? device.currentValue('level') : state.currentLevel
    def onLevel = (state.currentLevel && state.currentLevel < 100) ? state.currentLevel * 2.55 : 254
    def cmds = setLevel(0, true) + zigbee.writeAttribute(CLUSTER_LEVEL, LEVEL_ATTR_ON_LEVEL, 0x20, zigbee.convertToHexString(onLevel,2))
    log.info "off() -- cmds: $cmds -- $state.currentLevel"
    return cmds
}

def on() {
    //zigbee.on()
    def value = (state.currentLevel) ? state.currentLevel : myMaxLevel
    def cmds = setLevel(value)
    log.info "on() -- cmds: $cmds -- $state.currentLevel"
    return cmds
}

def setLevel(value, dontSetOnLevel=false) {
    //zigbee.setLevel(value)
    def cmds
    def myTime = (transitionTime) ? transitionTime : 5
    def myMinLevel = (minLevel) ? minLevel : 1
    def myMaxLevel = (maxLevel) ? maxLevel : 100
    if ( value && value < myMinLevel ) {
        value = myMinLevel
    } else if ( value > myMaxLevel ) {
        value = myMaxLevel
    }
    def myLevel = ( value < 100 ) ? value * 2.55 : 254
    if (dontSetOnLevel) {
        cmds = zigbee.command(CLUSTER_LEVEL, LEVEL_CMD_MOVE_TO_LEVEL_ON_OFF, zigbee.convertToHexString(myLevel,2) + zigbee.convertToHexString(myTime,2) + "00")
    } else {
        def myOnLevel = myLevel
        state.currentLevel = value
        if ( ! value ) {
            myOnLevel = ( myMaxLevel < 100 ) ? myMaxLevel * 2.55 : 254
            state.currentLevel = myMaxLevel
        }
        cmds = zigbee.command(CLUSTER_LEVEL, LEVEL_CMD_MOVE_TO_LEVEL_ON_OFF, zigbee.convertToHexString(myLevel,2) + zigbee.convertToHexString(myTime,2) + "00") +
               zigbee.writeAttribute(CLUSTER_LEVEL, LEVEL_ATTR_ON_LEVEL, 0x20, zigbee.convertToHexString(myOnLevel,2))
    }
    log.info "setLevel() -- cmds: $cmds -- $state.currentLevel"
    return cmds
}

    /**
     * PING is used by Device-Watch in attempt to reach the Device
     * */
def ping() {
    return zigbee.onOffRefresh()
}

def refresh() {
    zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.simpleMeteringPowerRefresh() + zigbee.electricMeasurementPowerRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.simpleMeteringPowerConfig() + zigbee.electricMeasurementPowerConfig()
}

def configure() {
    log.debug "Configuring Reporting and Bindings."

    // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
    // enrolls with default periodic reporting until newer 5 min interval is confirmed
    sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
    refresh()
}
1 Like

We just got home and I installed it on my switches… Works like a charm!! We tend to use voice commands more than anything these days so the fact that the switch doesn’t dim isn’t a big deal at all for my application.

Thank you for taking the time to make this and share it! I appreciate the work.

1 Like

I think there may have been a bug (I updated the code above but have not gotten a chance to test). To experience the bug:

  1. Turn off switch via SmartThings
  2. Turn on switch (manually or by SmartThings)
  3. Change the dimmer level (manually or by SmartThings)
  4. Turn off the switch manually
  5. Turn on the switch manually

I think if you do that, the switch will turn on the original dimmer level before your change. Not a big deal but the code above should fix it.

1 Like

I can confirm the bug. You’re right that it’s not a big deal but I am updating the code and will reply if anything odd happens.

One thing I have noticed a couple of times is that a switch will be at 0% when I try to turn the light manually (resulting in nothing happening). To fix it I just have to press and hold the switch ‘up’ to bring the brightness up but it confused me the first time it happened. I think it has only happened in my bedroom where I have “Gentle Wake Up” enabled so that’s likely what’s causing the issue. I am going to play around with it and pay more attention as to when it happens.

Thanks again!!

With the new code I can turn on the lights with SmartThings but can not turn them off with SmartThings (manual switch still works). When giving the command to the Echo “Turn off the lights” it will give an “OK” response but nothing happens. Pressing the button in SmartThings changes it to “turningoff” but nothing happens.

Unfortunately I overwrote the old code without saving it so I am reverting back to the original DH for now.

Sorry about that. I’ll have some time this evening to work on it. Should have the revised code within a few hours.

Also due to how the DTH works you will likely have some weird legacy artifacts when switching back to the old DTH (such as the dimmer level going to 0% when off and always turning back on to the same %). To fix you’ll need to reset the switch by pulling the air gap.

2 Likes

OK I believe it is fixed. I also added the capability to add a max and/or min dimmer level. I have some bulbs that don’t turn on below 25%. I used CoRE before but if someone specified a value less than 25% they turned off then back on - now they stay on with this DTH.

1 Like

That one works to turn off the lights but there is about a 3 second delay in turning them off through SmartThings. Turning them on is relatively ‘instant’ but turning them off seems to lag. Is that by design?

Let me fix that. It is because I send two commands to the switch. By default now SmartThings adds a 2 second delay between zigbee commands.

This line in off

def cmds = zigbee.writeAttribute(CLUSTER_LEVEL, LEVEL_ATTR_ON_LEVEL, 0x20, zigbee.convertToHexString(onLevel,2)) + setLevel(0, true)

became

def cmds = setLevel(0, true) + zigbee.writeAttribute(CLUSTER_LEVEL, LEVEL_ATTR_ON_LEVEL, 0x20, zigbee.convertToHexString(onLevel,2))
1 Like

Sadly… We are back to not turning them off at all. :-/ It’s definitely in that line because swapping them back out allows them to be turned off but with the delay. I wish I knew more about code!

Apparently I can’t type myself. I changed it in my code but edited it above incorrectly. Had a lowercase L instead of capital. Give it one more try.

1 Like

Bingo! That one works. I obviously don’t have the eye for detail to do this kind of code. I would have never caught a lower case L being the problem. :slight_smile:

Thanks again (again)! :slight_smile: