Closed PremiumUsername closed 2 years ago
I see now that my custom quirk doesn't seem to be loading ok.
File "/usr/local/lib/python3.9/site-packages/zhaquirks/tuya/__init__.py", line 917, in command
TUYA_COVER_COMMAND[manufacturer][command_id],
KeyError: '_TZE200_hsgrhjpf'
Seems to me like it's not using the init file I put in the local folder. Why is that?
The INIT must being put in the HA docker container or your local quirk can getting data from it (local quirks is getting all from the container and cant getting from local quirks).
Instruction editing files in the HA container: https://github.com/zigpy/zha-device-handlers/discussions/693
I've now edited the init file directly in the container and now the buttons work.
in the file ts0601.py I used:
MODELS_INFO: [
("_TZE200_zah67ekd", "TS0601"),
("_TZE200_xuzcvlku", "TS0601"),
("_TZE200_rddyvrci", "TS0601"),
("_TZE200_nueqqe6k", "TS0601"),
("_TZE200_gubdgai2", "TS0601"),
("_TZE200_yenbr4om", "TS0601"),
("_TZE200_5sbebbzs", "TS0601"),
("_TZE200_hsgrhjpf", "TS0601"),
],
and in init.py:
TUYA_COVER_COMMAND = {
"_TZE200_zah67ekd": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_fzo2pocs": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_xuzcvlku": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_rddyvrci": {0x0000: 0x0002, 0x0001: 0x0001, 0x0002: 0x0000},
"_TZE200_3i3exuay": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_nueqqe6k": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_gubdgai2": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_zpzndjez": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_cowvfni3": {0x0000: 0x0002, 0x0001: 0x0000, 0x0002: 0x0001},
"_TYST11_wmcdj3aq": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_yenbr4om": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_5sbebbzs": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_hsgrhjpf": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
}
I still don't know how or if it is possible to calibrate the end positions somehow. So the slider doesn't work. How is it I'm supposed to set the end positions, what clusters/commands should I use?
I dont knowing but i think it can being made with the buttons but you need reading in the forum how to do that.
If the Up, Down and Stop working OK (then 100% open the up is grayed out and the down is grayed out then 100% closed) ?
If it OK i can doing one PR for adding it do it being supported in next release of HA.
I dont knowing but i think it can being made with the buttons but you need reading in the forum how to do that.
If the Up, Down and Stop working OK (then 100% open the up is grayed out and the down is grayed out then 100% closed) ?
If it OK i can doing one PR for adding it do it being supported in next release of HA.
If I manually set the slider to somewhere in the middle I can use both the UP and Down button, otherwise one button is greyed out. I think this part is working ok. The missing functionality stems form me not having limits set so I think adding it would be fine.
I may add that the manual only shows how to set the limits via the Queqi gateway. There are no instructions for using the set-buttons and the method for first version of M515EGZT doesn't seem to work, so I think I need to do this via zigbee. Maybe someone could sniff what the gateway is doing when it sets the limits.
@PremiumUsername did you have any luck in finding out how to set limits manually (with buttons on the device), instead of through Tuya app? Or have you found an inx manual for TM616EGZT? Thanks
Sadly, I haven't found a way to do so. I also tried to use a remote from a zemismart zigbee curtain motor, but I wasn't able to pair it, the manuals for these products seems incomplete.
I did find this on the zemismart website:
/**
* Tuya Window Shade (v.0.1.0)
* 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
import physicalgraph.zigbee.zcl.DataType
metadata {
definition(name: "ZemiSmart Vertical Blind", namespace: "ShinJjang", author: "ShinJjang-iquix", ocfDeviceType: "oic.d.blind", vid: "generic-shade") {
capability "Actuator"
capability "Configuration"
capability "Window Shade"
capability "Window Shade Preset"
capability "Switch Level"
capability "Sensor"
command "pause"
command "levelOpenClose"
attribute "Direction", "enum", ["Reverse","Forward"]
attribute "OCcommand", "enum", ["Replace","Original"]
attribute "stapp", "enum", ["Reverse","Forward"]
attribute "remote", "enum", ["Reverse","Forward"]
fingerprint endpointId: "0x01", profileId: "0104", inClusters: "0000 0004 0005 EF00", outClusters: "0019, 000A", manufacturer: "_TZE200_xuzcvlku", model: "TS0601", deviceJoinName: "Zemismart Vertical Blind"
}
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", options:["01": "Reverse", "00": "Forward"], required: true, displayDuringSetup: true
input name: "OCcommand", type: "enum", title: "Replace Open and Close commands", options:["2": "Replace", "0": "Original"], required: true, displayDuringSetup: true
input name: "stapp", type: "enum", title: "app opening,closing Change", options:["2": "Reverse", "0": "Forward"], required: true, displayDuringSetup: true
input name: "remote", type: "enum", title: "RC opening,closing Change", options:["1": "Reverse", "0": "Forward"], required: true, displayDuringSetup: true
}
tiles(scale: 2) {
multiAttributeTile(name:"windowShade", type: "generic", width: 6, height: 4) {
tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") {
attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing"
attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening"
attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing"
attributeState "opening", label: 'Opening', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing"
attributeState "closing", label: 'Closing', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening"
}
}
standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc"
}
standardTile("presetPosition", "device.presetPosition", width: 2, height: 2, decoration: "flat") {
state "default", label: "Preset", action:"presetPosition", icon:"st.Home.home2"
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("shadeLevel", "device.level", width: 4, height: 1) {
state "level", label: 'Shade is ${currentValue}% up', defaultState: true
}
controlTile("levelSliderControl", "device.level", "slider", width:2, height: 1, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}
main "windowShade"
details(["windowShade", "contPause", "presetPosition", "shadeLevel", "levelSliderControl", "refresh"])
}
}
private getCLUSTER_TUYA() { 0xEF00 }
private getSETDATA() { 0x00 }
// Parse incoming device messages to generate events
def parse(String description) {
log.debug description
if (description?.startsWith('catchall:') || description?.startsWith('read attr -')) {
Map descMap = zigbee.parseDescriptionAsMap(description)
if (descMap?.clusterInt==CLUSTER_TUYA) {
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:
def parData = descMap.data[6] as int
if(parData != 1){
def stappVal = (stapp ?:"0") as int
def data = Math.abs(parData - stappVal)
sendEvent([name:"windowShade", value: (data == 0 ? "opening":"closing"), displayed: true])
log.debug "App control=" + (data == 0 ? "opening":"closing")
}
break
case 1031: // 0x04 0x07: Confirm opening/closing/stopping (triggered from remote)
def parData = descMap.data[6] as int
def remoteVal = remote as int
def data = Math.abs(parData - remoteVal)
sendEvent([name:"windowShade", value: (data == 0 ? "opening":"closing"), displayed: true])
log.debug "Remote control=" + (data == 0 ? "opening":"closing")
break
case 514: // 0x02 0x02: Started moving to position (triggered from Zigbee)
def setLevel = zigbee.convertHexToInt(descMap.data[9])
def lastLevel = device.currentValue("level")
//sendEvent([name:"windowShade", value: (setLevel >= lastLevel ? "opening":"closing"), displayed: true])
log.debug "Remote control=" + (setLevel >= lastLevel ? "opening":"closing")
log.debug "setLevel : $setLevel"
log.debug "lastLevel : $lastLevel"
if (setLevel > 0 && setLevel <100)
{
sendEvent(name: "windowShade", value: "partially open")
}
else
{
if (setLevel == 0)
sendEvent([name:"windowShade", value: "open", displayed: true])
if (setLevel == 100)
sendEvent([name:"windowShade", value: "closed", displayed: true])
}
//log.debug "arrived at position :"+pos
sendEvent(name: "level", value: (setLevel))
break
case 515: // 0x02 0x03: Arrived at position
def pos = zigbee.convertHexToInt(descMap.data[9])
log.debug "arrived at position :"+pos
if (pos > 0 && pos <100) {
sendEvent(name: "windowShade", value: "partially open")
} else {
sendEvent([name:"windowShade", value: (pos == 100 ? "open":"closed"), displayed: true])
}
sendEvent(name: "level", value: (pos))
break
default: log.debug "abnormal case : $dp"
break
}
}
}
}
}
def close() {
log.info "close()"
def cm = (OCcommand ?:"0") as int
log.debug "cm=${cm}"
def val = Math.abs(2 - cm)
sendTuyaCommand("0104", "00", "010" + val)
}
def open() {
log.info "open()"
def cm = (OCcommand ?:"0") as int
def val = Math.abs(0 - cm)
sendTuyaCommand("0104", "00", "010" + val)
}
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, displayed: true)
return
}
sendTuyaCommand("0202", "00", "04000000"+zigbee.convertToHexString(data, 2))
}
def refresh() {
zigbee.readAttribute(CLUSTER_TUYA, 0x00, )
}
def presetPosition() {
setLevel(preset ?: 50)
}
def installed() {
sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false)
}
def updated() {
log.debug "val(${Direction}),valC(${OCcommand}),valR(${remote})"
DirectionSet(Direction ?:"00")
}
def DirectionSet(Dval) {
log.info "Dset(${Dval})"
sendHubCommand(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 "${zigbee.convertToHexString(rand(256), 2)}=${dp},${fn},${data}"
zigbee.command(CLUSTER_TUYA, SETDATA, "00" + zigbee.convertToHexString(rand(256), 2) + dp + fn + data)
}
private rand(n) {
return (new Random().nextInt(n))
}
Maybe that could be of some help.
Thanks for getting back to me. Yes - I am using iquix DH in Smartthings, and it works well. Unfortunately, still not found a way to set the limits using physical buttons, or through Smartthings. Only option is to set limits in Smart Life. Thanks
Ran into the same issue today not being able to set upper and lower limits, the device says "V2-RA" at the back:
However, devices labeled "ZM" at the back are able to set upper and lower limits at the device itself:
@dhc25 you mentioned that you used "Smart Life" to set the upper and lower limits. Do you have to use a Tuya ZigBee gateway with it? I am using a CC2652P2 Zigbee Coordinator from @tube0013.
I'm using Zigbee2MQTT, so https://github.com/Koenkk/zigbee2mqtt/issues/12300 helped.
The manual included with the device says the model is: M515EGZT -V2version-12v. When I bought it it said Tuya in the listing but The product is not branded. The device says TM616EGZT on the back.
Device signature - this can be acquired by removing the device from ZHA and pairing it again from the add devices screen. Be sure to add the entire content of the log panel after pairing the device to a code block below this line.
Additional context It pairs OK. No buttons at first. Tried using a custom quirk using the same key settings as for TZE200_nueqqe6k:
TUYA_COVER_COMMAND = { "_TZE200_hsgrhjpf": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001}, }
... then I see buttons but they can't be used.When I chose a point on the slider the device blinks once but nothing happens. I haven't set limits for the device (don't know how), so I can't see how the slider could ever work. Pressing the stop, up or down buttons just gives an error message "Failed to call service..."