Tuya Zigbee Roller Shade port help

ok it arrive today
only issue seam to be
groovy.lang.MissingMethodException: No signature of method: com.hubitat.zigbee.Zigbee.convertToHexString() is applicable for argument types: (java.math.BigDecimal, java.lang.Integer) values: [10, 2]
Possible solutions: convertToHexString(java.lang.Integer, java.lang.Integer) on line 161 (setPosition)
for this
sendTuyaCommand("0202", "00", "04000000"+zigbee.convertToHexString(data, 2))

also no idea how to set upper and lower limits

change to "converToHexString(data.intValue(), 2)"

There are other things in setLevel that may not work as expected, not sure what is returned by "device.currentValue("level")", if that is not a BigDecimal the if statement below will never be true. Try it as is and see how it works.

I don't see anything in that driver about being able to do that. Can you find other drivers for ST that have been created for this roller shade?

still groovy.lang.MissingMethodException: No signature of method: user_driver_ShinJjang_ZemiSmart_Zigbee_Blind_907.convertToHexString() is applicable for argument types: (java.lang.Integer, java.lang.Integer) values: [10, 2] on line 164 (setLevel)

for

sendTuyaCommand("0202", "00", "04000000"+convertToHexString(data.intValue(), 2))

Sorry, I remembered there was such a command, obviously I was wrong, use this instead:

At the top of the file, include Hexutils:
import hubitat.helper.HexUtils

Then use this:
HexUtils.integerToHexString(data.intValue(), 2)

like this? do i need to configer or anything to load the utility?
sendTuyaCommand("0202", "00", "04000000"+HexUtils.integerToHexString(data.intValue(), 2))

To load it, just place the import line in the groovy file outside of all methods, preferably just above the metadata section at the top.

done

but i think without setting the limits its not doing anything

These are custom commands, so without knowing what the specifics are it will not be possible to know. I'm receiving a Tuya Zigbee gateway tomorrow, if I can trick it into thinking I have a Roller Shade maybe I can capture the correct commands there, but otherwise the best route is to find a driver for some other platform, it doesn't need to be SmartThings, just something, show me that driver and I can see if they have those commands in there.

Did it come with the 433mhz remote?
In the youtube video the guy who wrote the ST driver uses the remote for setting the limit so loos like the driver doesn't do it.

1 Like

no remote

found this they seam to be doing something different with"OCcommand"
https://raw.githubusercontent.com/shin4299/XiaomiSJ/master/devicetypes/shinjjang/zemismart-zigbee-blind.src/zemismart-zigbee-blind.groovy

looks like it is adjusting the open and and closed positions based on what you need.
i.e. if closed is really 10% than it sends the level of 10% as close.
I don't think the level shown will be correct though.

im stumped

Reading that code it looks like if you set the Preference Ocommand to 2 (replace) and use the open and close commands that should set the open and closed positions. You might have to open it to the right position and then set that Preference and use the open/close command. It really feels messy and not very intuitive using this, but it may very well be what you are looking for.

found the remote, managed to set up and down limits. but the preset isnt working
this is the results when i pause it mid motion

[raw:catchall: 0104 EF00 01 01 0040 00 61DE 01 00 0000 02 01 00010302000400000046, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:61DE, isClusterSpecific:true, isManufacturerSpecific:false, manufacturerId:0000, command:02, direction:01, data:[00, 01, 03, 02, 00, 04, 00, 00, 00, 46]]

edit curntly set level just closes it

position 10
dev:16382020-07-04 05:38:55.889 pm debug[raw:catchall: 0104 EF00 01 01 0040 00 61DE 01 00 0000 01 01 00350104000101, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:61DE, isClusterSpecific:true, isManufacturerSpecific:false, manufacturerId:0000, command:01, direction:01, data:[00, 35, 01, 04, 00, 01, 01]]

dev:16382020-07-04 05:38:55.819 pm debugarrived at position :10

position 30
dev:16382020-07-04 05:40:35.813 pm debug[raw:catchall: 0104 EF00 01 01 0040 00 61DE 01 00 0000 01 01 00560104000101, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:61DE, isClusterSpecific:true, isManufacturerSpecific:false, manufacturerId:0000, command:01, direction:01, data:[00, 56, 01, 04, 00, 01, 01]]

dev:16382020-07-04 05:40:35.763 pm debugarrived at position :30

Post your current driver code and I will add some things from the other driver tomorrow so you can test those. It's too late here now to do more right now. Time to sleep.

thanks

Summary
/** zemismart
*  Tuya Window Shade (v.0.1.0) Hubitat v1
 *	Copyright 2020 iquix
 *
 *	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.
 This DTH is coded based on iquix's tuya-window-shade DTH.
 https://github.com/iquix/Smartthings/blob/master/devicetypes/iquix/tuya-window-shade.src/tuya-window-shade.groovy
 */

import groovy.json.JsonOutput
//mc // import physicalgraph.zigbee.zcl.DataType
import hubitat.zigbee.zcl.DataType
import hubitat.helper.HexUtils

metadata {
	definition(name: "ZemiSmart Zigbee Blind", namespace: "ShinJjang", author: "ShinJjang-iquix", ocfDeviceType: "oic.d.blind", vid: "generic-shade") {
		capability "Actuator"
		capability "Configuration"
		capability "Window Shade"
// mc not supported in HE		capability "Window Shade Preset"
		capability "Switch Level"

		command "pause"
        command "presetPosition"
        
        attribute "Direction", "enum", ["Reverse","Forward"]

		fingerprint endpointId: "01", profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0019", manufacturer: "_TYST11_wmcdj3aq", model: "mcdj3aq", deviceJoinName: "Zemismart Zigbee Blind"
//mc changeed endpointId from 0x01 to 01	
    }

	preferences {
        input "preset", "number", title: "Preset position", description: "Set the window shade preset position", defaultValue: 50, range: "0..100", required: false, displayDuringSetup: false
        input name: "Direction", type: "enum", title: "Direction Set", defaultValue: "00", options:["01": "Reverse", "00": "Forward"], displayDuringSetup: true
	}
// removed tiles section as not used in Hubitat
}

private getCLUSTER_TUYA() { 0xEF00 }
private getSETDATA() { 0x00 }

// Parse incoming device messages to generate events
def parse(String description) {
	if (description?.startsWith('catchall:') || description?.startsWith('read attr -')) {
		Map descMap = zigbee.parseDescriptionAsMap(description)        
		if (descMap?.clusterInt==CLUSTER_TUYA) {
        	log.debug descMap
			if ( descMap?.command == "01" || descMap?.command == "02" ) {
				def dp = zigbee.convertHexToInt(descMap?.data[3]+descMap?.data[2])
                log.debug "dp = " + dp
				switch (dp) {
					case 1025: // 0x04 0x01: Confirm opening/closing/stopping (triggered from Zigbee)
                    	def data = descMap.data[6]
                    	if (descMap.data[6] == "00") {
                        	log.debug "parsed opening"
                            levelEventMoving(100)
                        } else if (descMap.data[6] == "02") {
                        	log.debug "parsed closing"
                            levelEventMoving(0)
                        }
                    else {log.debug "parsed else stoping $data"}
                    	break
					case 1031: // 0x04 0x07: Confirm opening/closing/stopping (triggered from remote)
                    	def data = descMap.data[6]
                    	if (descMap.data[6] == "01") {
                        	log.debug "closing"
                            levelEventMoving(0)
                        } else if (descMap.data[6] == "00") {
                        	log.debug "opening"
                            levelEventMoving(100)
                        }
                    	break
					case 514: // 0x02 0x02: Started moving to position (triggered from Zigbee)
                    	def pos = zigbee.convertHexToInt(descMap.data[9])
						log.debug "moving to position :"+pos
                        levelEventMoving(pos)
                        break
					case 515: // 0x02 0x03: Arrived at position
                    	def pos = zigbee.convertHexToInt(descMap.data[9])
                    	log.debug "arrived at position :"+pos
                    	levelEventArrived(pos)
                        break
				}
			}
		}
	}
}

private levelEventMoving(currentLevel) {
	def lastLevel = device.currentValue("level")
	log.debug "levelEventMoving - currentLevel: ${currentLevel} lastLevel: ${lastLevel}"
	if (lastLevel == "undefined" || currentLevel == lastLevel) { //Ignore invalid reports
		log.debug "Ignore invalid reports"
	} else {
		if (lastLevel < currentLevel) {
			sendEvent([name:"windowShade", value: "opening"])
		} else if (lastLevel > currentLevel) {
			sendEvent([name:"windowShade", value: "closing"])
		}
    }
}

private levelEventArrived(level) {
	if (level == 0) {
    	sendEvent(name: "windowShade", value: "closed")
    } else if (level == 100) {
    	sendEvent(name: "windowShade", value: "open")
    } else if (level > 0 && level < 100) {
		sendEvent(name: "windowShade", value: "partially open")
    } else {
    	sendEvent(name: "windowShade", value: "unknown")
        return
    }
    sendEvent(name: "level", value: (level))
    //mc added
    sendEvent(name: "position", value: (level))
    //mc
}

def close() {
	log.info "close()"
	def currentLevel = device.currentValue("level")
    if (currentLevel == 0) {
        log.debug "if closed"
    	sendEvent(name: "windowShade", value: "closed")
        return
    }
	sendTuyaCommand("0104", "00", "0102")
}

def open() {
	log.info "open()"
    def currentLevel = device.currentValue("level")
    if (currentLevel == 100) {
    	sendEvent(name: "windowShade", value: "open")
        return
    }
	sendTuyaCommand("0104", "00", "0100")
}

def pause() {
	log.info "pause()"
	sendTuyaCommand("0104", "00", "0101")
    
}

def setLevel(data, rate = null) {
	log.info "setLevel("+data+")"
    def currentLevel = device.currentValue("level")
    if (currentLevel == data) {
    	sendEvent(name: "level", value: currentLevel)
        //mc added
        sendEvent(name: "position", value: (level))
        //mc
        return
    }
	//sendTuyaCommand("0202", "00", "04000000"+zigbee.convertToHexString(data, 2))
    //sendTuyaCommand("0202", "00", "04000000"+convertToHexString(data.intValue(), 2))
    sendTuyaCommand("0202", "00", "04000000"+HexUtils.integerToHexString(data.intValue(), 2))
    
}

//mc new for HE Commands
def setPosition(position){
    log.info "setPos to $position"
    //setLevel(data = position, rate = null)
    setLevel(position, null)
}
//mc

//custom command
def presetPosition() {
    setLevel(preset ?: 50)
}

def installed() {
	sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false)
    
}

def updated() {
	def val = Direction
    sendEvent([name:"Direction", value: (val == "00" ? "Forward" : "Reverse")])    
	DirectionSet(val)
}	

def DirectionSet(Dval) {
	log.info "Dset(${Dval})"
   //sendHubCommand(zigbee.command(CLUSTER_TUYA, SETDATA, "00" + zigbee.convertToHexString(rand(256), 2) + "05040001" + Dval))
    zigbee.command(CLUSTER_TUYA, SETDATA, "00" + zigbee.convertToHexString(rand(256), 2) + "05040001" + Dval)
}

def configure() {
	log.info "configure()"
}

private sendTuyaCommand(dp, fn, data) {
	log.info "send tuya command ${dp},${fn},${data}"
	zigbee.command(CLUSTER_TUYA, SETDATA, "00" + zigbee.convertToHexString(rand(256), 2) + dp + fn + data)
    // if issue use this
    //sendHubCommand(zigbee.command(CLUSTER_TUYA, SETDATA, "00" + zigbee.convertToHexString(rand(256), 2) + dp + fn + data))
    //
}

private rand(n) {
	return (new Random().nextInt(n))
}

found this as well but dosnt seam to use the same clusers

had a play this morn
sendTuyaCommand("0202", "00", "04000000"+HexUtils.integerToHexString(data.intValue(), 2))
//sendTuyaCommand("0202", "00", "04000000"+data)

so the commented out line kinda works i put in a value of 50 and it moved to 80 its like it dosnt need the 2

fixed that bit it was the number of zeros on the hex conversion
sendTuyaCommand("0202", "00", "04000000"+HexUtils.integerToHexString(data.intValue(), 1))

0x50 = 80, so yes, that would make sense.

You would not have a whole byte in the data if you have a number below 16, that is why the 2 is needed in "HexUtils.integerToHexString(data.intValue(), 2)". Having it as 1 would not be good, it might still work if the string to byte parser is forgiving for the last byte, but best to leave it in.

This one does just use a recalculated level to get the "correct" location.

After checking the other one closer, there is no command in there either to set/calibrate the real open and close positions.

I did a search, and from what I can find, no implementation of any Tuya blinds drivers have commands for setting open and close positions:

https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/converters/toZigbee.js

That doesn't mean they are not there, it just means no one knows of them, yet.

This post describes how to capture the commands needed if you have a Tuya Zigbee gateway:
https://medium.com/@dzegarra/zigbee2mqtt-how-to-add-support-for-a-new-tuya-based-device-part-2-5492707e882d

I will see if I can get my Tuya gateway to send these commands even though I don't have any blinds or curtains. I just received it about 2 hours ago and haven't even unpacked it.