SmarthomeDB Curtains Driver Needs Fixing

I got this driver from SmarthomeDB for their curtain controller device. I think they did a real quick and dirty conversion from their Smartthings code. It seems buggy, though. I asked them for support and they kinda just stopped responding. Ugh.

The code does actually work. I can control the curtains. However it's really difficult to do automation rules because of some oddities. I was hoping I could get some help fixing up the driver to resolve the issues below. The driver code is available here.

  • The On/Off state always reports as NULL
  • The Closed/Open state isn't quite right. It checks for CLOSED, but it reports CLOSE causing a incorrected False in the Rule Machine logic.
  • It spams the log with these messages every few minutes. (I don't know if this is a problem or not.)

dev:5452020-10-03 01:47:18.755 pm warnjava.lang.NullPointerException: Cannot invoke method endsWith() on null object

dev:5452020-10-03 01:47:18.751 pm debug[raw:catchall: 0000 0013 00 00 0040 00 76FE 00 00 0000 00 00 00FE76D3A0AE14004B12008E, profileId:0000, clusterId:0013, clusterInt:19, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:76FE, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[00, FE, 76, D3, A0, AE, 14, 00, 4B, 12, 00, 8E]]

dev:5452020-10-03 01:46:56.758 pm debugJust Closed mode null

dev:5452020-10-03 01:46:56.755 pm debug

dev:5452020-10-03 01:46:56.752 pm debug100

dev:5452020-10-03 01:46:56.749 pm debug[raw:76FE0101020808002064, dni:76FE, endpoint:01, cluster:0102, size:08, attrId:0008, encoding:20, command:0A, value:64, clusterInt:258, attrInt:8]

dev:5452020-10-03 01:45:56.726 pm debugJust Closed mode null

dev:5452020-10-03 01:45:56.723 pm debug

dev:5452020-10-03 01:45:56.719 pm debug100

dev:5452020-10-03 01:45:56.716 pm debug[raw:76FE0101020808002064, dni:76FE, endpoint:01, cluster:0102, size:08, attrId:0008, encoding:20, command:0A, value:64, clusterInt:258, attrInt:8]

That site says the code was updated 44 minutes ago.

The code that is there is incomplete. It includes a Capability Switch, yet has on/off commented out. One or the other is wrong. :slight_smile: Same for Configure, setPosition and levelOpenClose

I've cleaned up what I can, but since I don't own shades, I doubt I can do more.

New Code
/**
 *
 *  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. * 2017 */

metadata {
    definition(name:"Curtains", namespace:"SmartHomeDB", author:"SmartHomeDB: Ray Zheng") {
        capability "Actuator"
        capability "Configuration"
        capability "Refresh"
        //capability "Switch Level"
        capability "WindowShade"
        capability "Switch"

        fingerprint deviceId:"0104", inClusters:"0000, 0001, 0005, 0004, 0102", outClusters:"0019", manufacturer:"SmartHomeDB", model:"093199ff04984948b4c78167c8e7f47e"
        }
    }

    command "levelOpenClose"
    
    preferences {
    	input name:"mode", type:"bool", title:"Set SmartHomeDB Curtain Direction", description:"Reverse Mode ON", required:true, displayDuringSetup:true 
      input name: "debugOutput",   type: "bool", title: "<b>Enable debug logging?</b>",   description: "<br>", defaultValue: true
    }

def configure() {
    if (debugOutput) log.debug "Configure"
}


def updated() {
    if (debugOutput) runIn(1800,logsOff)
}


/* Parse incoming device messages to generate events
		specification: windowShade - ENUM ["opening", "partially open", "closed", "open", "closing", "unknown"] <-- these are the only 
		values that attribute "windowShade" may contain
*/


def parse(String description) {

    def parseMap = zigbee.parseDescriptionAsMap(description)

    def event = zigbee.getEvent(description)

    if (debugOutput) log.debug(parseMap)

    try {

        if (parseMap.raw.startsWith("0104")) {

            if (debugOutput) log.debug "Curtain"

        }else if (parseMap.raw.endsWith("0007")) {

            if (debugOutput) log.debug "running…"

        }else if (parseMap.endpoint.endsWith("01")) {

            if (parseMap["cluster"] == "0102" && parseMap["attrId"] == "0008") {



                long theValue = Long.parseLong(parseMap["value"], 16)

                def eventStack = []

                if (debugOutput) log.debug(theValue)
                if (debugOutput) log.debug(mode)
             if (mode == true) {

                if (theValue > 95) {
                    if (debugOutput) log.debug "Just Closed"

                    eventStack.push(createEvent(name:"windowShade", value:"closed"))

                }else if (theValue < 5) {

                   if (debugOutput) log.debug "Just Fully Open"

                    eventStack.push(createEvent(name:"windowShade", value:"open"))

                }else {
                    if (debugOutput) log.debug "Motion"
                    eventStack.push(createEvent(name:"windowShade", value:"unknown"))

                }

             }

             else {

               if (theValue < 5) {

                    if (debugOutput) log.debug "Just Fully Open mode null"

                    eventStack.push(createEvent(name:"windowShade", value:"open"))
                    
                }else if (theValue > 95) {

                    if (debugOutput) log.debug "Just Closed mode null"

                    eventStack.push(createEvent(name:"windowShade", value:"closed"))


                }else {

                    if (debugOutput) log.debug "In Motion"
                    eventStack.push(createEvent(name:"windowShade", value:"unknown"))

                }

			}

                return eventStack

            }

        }else {

            if (debugOutput) log.debug "Unhandled Event - description:${description}, parseMap:${parseMap}, event:${event}"

        }



        if (event["name"] == "switch") {

        	if (debugOutput) log.debug("add event: ${event}")

            return createEvent(name:"switch", value:event["value"])

        }

    }catch (Exception e) {

        log.warn e

    }

}



def off() { close() }
def close() {

    if (debugOutput) log.debug "Set Close"

	if (mode == true) {

    zigbee.command(0x0102, 0x00)

    }else {

    zigbee.command(0x0102, 0x01)

    }

}



def on() { open() }
def open() {

    if (debugOutput) log.debug "Set Open"

	if (mode == true) {

    zigbee.command(0x0102, 0x01)

    }else {

    zigbee.command(0x0102, 0x00)

    }

}


def setPosition(val) {
    if (debugOutput) log.debug "unImplemented: Set Position $val %"
}

def levelOpenClose(val) {
    if (debugOutput) log.debug "unImplemented: Set Level Open/Close"
}

def refresh() {

    if (debugOutput) log.debug "refresh()"

    zigbee.command(0x0102, 0x02)
}


def logsOff(){
	log.warn "debug logging disabled..."
	device.updateSetting("debugOutput",[value:"false",type:"bool"])
}
1 Like

Thanks. It was "updated" 44 minutes ago after my original post because that's when I posted it. I've been using that code as-is for at least a year. It's what the manufacturer sent me. shrug

Thanks for cleaning it up a little, though. Hopefully I can do some RM on it now at least.