Tuya Zigbee Wall Switch (aka. Lonsonho or Bandi)

Hey Mike!

Did you have a chance to look this switches?
Did you order one?

Thank you!
Andrew

no, i have not, I'm a little short on round-to-its at the moment...

If it's helps, we really order one for you :slight_smile:

Andrew

1 Like

It looks that there are many new switches that uses EF00 cluster. Probably I will got EF00 switches that I bought by mistake. I will be shure when I receive them, but they are from "Norkmles" company, and someone already reported in other thread that "Norkmles" are EF00 type. Found that thread, here: Norklmes zigbee switch - Support / Novice Help - Hubitat

Link to aliexpress where are Norklmes switches available:
No Neutral ZIGBEE Touch Light Wall Switch EU/US White Glass Blue LED TUYA Smart Home Phone 2Way/3Way For Alexa Google Home Alice|Switches| - AliExpress

There is no problem in funding (send paypal email by private message) 4 gang switch for you, 4 gang should give you possibility to code 1,2,3 gang variants too.

another edit: found "smart things" driver that have support for EF00 devices, maybe it would be possible to modify our drivers,

link here: BooungThings/integrated-zigbee-switch.groovy at master Β· WooBooung/BooungThings Β· GitHub

interesting info here,
#1: How to connect Tuya compatible 2 gangs Zigbee Switch module - Devices & Integrations - SmartThings Community
#2: UK Light switches – My experiences (2020) - Devices & Integrations / Connected Things - SmartThings Community

BTW: Looks like Lonshono/Bandi uses

  • endpointId: 01
  • application: 40
  • manufacturer: _TZE200_nkjintbl
  • model: TS0601
  • driver: v1.0.1.1123b
  • endpointId: 01
  • profileId: 0104
  • inClusters: 0000,0004,0005,EF00
  • outClusters: 0019,000A
  • isMultiEP: false

and Norklmes uses

  • endpointId: 01
  • application: 52
  • manufacturer: _TZE200_nkjintbl
  • model: TS0601
  • driver: dont have that info
  • endpointId: 01
  • profileId: 0104
  • inClusters: 0000,0004,0005,000A,EF00
  • outClusters: 0019
  • isMultiEP: false

Looks like they uses same _TZE200_nkjintbl info, but different cluster setup and different "application". Maybe it's same hardware, but with different (older/newer?) firmware versions?

another (my) device:

endpointId : 01
application : 42
manufacturer: _TZE200_aqnazj70
model : TS0601
deviceTypeId: 696
endpointId : 01
profileId : 0104
inClusters : 0000,0004,0005,EF00
outClusters : 0019,000A

1 Like

Hi Mike!

Does the new firmware supports now this wall switch?
Or still not?

Thanks
Andrew

You can try this driver

with little improvement maybe it will work.

1 Like

These are not supported.

It works!!! After changing the manufacturer it created 3 child devices and they are able to control the switches. I need to work some more on getting this in shape but this is great! Thank you!

EDIT: It doesn't see the switch state, hopefully I'll be able to get that sorted

You should edit this section too
β€œdef setupChildDevices()” or send me fingerprint and number of gangs for you switch

This is what I did, but Tuya seems to have different status codes than Moes or something.

I think the device with EF00 is old version and its not stable, some tuya manufacturer released newer version that use 0006 inClusters list, i got the EU/UK version, but for that i worked on this driver :
Driver for Tuya Plug with 2 USBs ports
changing the product name and model, and corrected the inclusters and outclusters, and added 4th child, the switchs i am using is 1/2/3/4 gangs,
but the problem is, this driver code creating 4 childs for any switch ( can someone help?)
I will attach switches photos and the driver code



Tuya 2 gang switch data:

ID: 5396

Manufacturer: _TZ3000_utcmqixy

Product Name:

Model Number: TS0012

deviceTypeId: 249

more...

manufacturer : _TZ3000_utcmqixy

idAsInt : 1

inClusters : 0000,0004,0005,0006

endpointId : 01

profileId : 0104

application : 42

outClusters : 0019,000A

initialized : true

model : TS0012

stage : 4

manufacturer :

idAsInt : 2

inClusters : 0004,0005,0006

endpointId : 02

profileId : 0104

application :

outClusters :

initialized : true

model :

stage : 4

1 Like

Below in setupChildDevices() function in line 192 is another if that setup the child devices based on the manufacturer, you need to edit that as well

I changed the driver too, but it did not create child devices for me.

So, do we have a working code for the 2 gang switch?
@jacubmikita ?

Thanks

3 gang in my case, yes

Great!
@jacubmikita
Can you please share the code with me?
So i can try it.

Thanks
Brain

This is my current version

import hubitat.device.HubAction
import hubitat.device.Protocol

metadata {
   definition (name: "Moes ZigBee Wall Switch 1/2/3-Gang", namespace: "Moes 1.31", author: "Martin Kura") {
       capability "Initialize"
       capability "Actuator"
//       capability "Configuration"
       capability "Refresh"
       capability "Switch"
       
       fingerprint profileId:"0104", model:"TS0601", manufacturer:"_TZE200_amp6tsvy", endpointId:"01", inClusters:"0000,0004,0005,EF00", outClusters:"0019,000A", application:"42", deviceJoinName: "Moes 1-Gang Switch / ZTS-EU1"
   fingerprint profileId:"0104", model:"TS0601", manufacturer:"_TZE200_g1ib5ldv", endpointId:"01", inClusters:"0000,0004,0005,EF00", outClusters:"0019,000A", application:"42", deviceJoinName: "Moes 2-Gang Switch / ZTS-EU2"
       fingerprint profileId:"0104", model:"TS0601", manufacturer:"_TZE200_kyfqmmyl", endpointId:"01", inClusters:"0000,0004,0005,EF00", outClusters:"0019,000A", application:"52", deviceJoinName: "Moes 3-Gang Switch / ZTS-EU3"
   }
       attribute "switchLightMode","enum",["OFF", "ON", "Position"]
       attribute "relayMode","enum",["OFF", "ON", "Last state"]
       attribute "lastCheckin", "string"

   preferences {
       input(name: "switchLightMode", type: "enum", title: ("Switch Backlight Mode"), description: ("- select type of backlight indicator (default: Position)"), options: ["OFF", "ON", "Position"], defaultValue: "Position", submitOnChange: true)
   input(name: "relayMode", type: "enum", title: ("Switch Relay Mode"), description: ("- select relay renew state after AC failed (default: OFF)"), options: ["OFF", "ON", "Last state"], defaultValue: "OFF", submitOnChange: true)
       input(name: "debugLogging", type: "bool", title: ("Enable debug logging"), description: "", defaultValue: true, submitOnChange: true, displayDuringSetup: true)
       input(name: "infoLogging", type: "bool", title: ("Enable info logging"), description: "", defaultValue: true, submitOnChange: true, displayDuringSetup: true)
   }
}

def initialize() {
   if (infoLogging) log.info "Initializing..."
   log.warn "Debug logging will be automatically disabled after 30 minutes!"
   setupChildDevices()
   device.updateSetting("switchLightMode",[type:"enum",value:"Position"])
   device.updateSetting("relayMode",[type:"enum",value:"OFF"])
   device.updateSetting("debugLogging",[type:"bool",value:"true"])
   device.updateSetting("infoLogging",[type:"bool",value:"true"])
   if (debugLogging) runIn(1800,logsOff)
   refresh()
}

void logsOff(){
   log.warn "Debug logging disabled..."
   device.updateSetting("debugLogging",[value:"false",type:"bool"])
}

/*def configure(){
    if (debugLogging) log.debug "Configuring Reporting and Bindings..."
  
   def cmds = [
           //bindings
           "zdo bind 0x${device.deviceNetworkId} 0x01 0x00 0xEF00 {${device.zigbeeId}} {}", "delay 200",
           "zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0xEF00 {${device.zigbeeId}} {}", "delay 200",
           //"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 0x01 0x0004 {${device.zigbeeId}} {}", "delay 200",
           //"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 0x01 0x0005 {${device.zigbeeId}} {}", "delay 200",
           //reporting
           "he cr 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0 0x00 0 0xFFFF {}","delay 200",
           "he cr 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0 0x01 0 0xFFFF {}", "delay 200",
           //"he cr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0 0x0000 0 0xFFFF {}", "delay 200",
          //"he cr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0 0x0001 0 0xFFFF {}", "delay 200",
          // "he cr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0 0x0007 0 0xFFFF {}", "delay 200",
          // "he cr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0300 0 0x0008 1 0xFFFE {}", "delay 200",
   ] + refresh()
   return cmds
   
}     */ 

def installed() {
   log.info "Installing..."
   log.warn "Debug logging will be automatically disabled after 30 minutes!"
   setupChildDevices()
   device.updateSetting("switchLightMode",[type:"enum",value:"Position"])
   device.updateSetting("relayMode",[type:"enum",value:"OFF"])
   device.updateSetting("debugLogging",[type:"bool",value:"true"])
   device.updateSetting("infoLogging",[type:"bool",value:"true"])
   if (debugLogging) runIn(1800,logsOff)
   refresh()
}

def updated() {
   log.warn "debug logging is: ${debugLogging == true}"
   log.warn "description logging is: ${infoLogging == true}"
   if (infoLogging) log.info "Updated..."
   if (debugLogging) log.debug "Parent updated"
   switchLightModeConfig() + relayModeConfig() + refresh()
}

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) {
       	if (debugLogging) log.debug descMap
   		if ( descMap?.command == "01" || descMap?.command == "02" ) {
   			def switchFunc = (descMap?.data[2])
               def switchAttr = (descMap?.data[3])   
               def switchState = (descMap?.data[6]) == "01" ? "on" : "off"
               if (switchFunc <= "03" && switchAttr =="01") {
  	            def cd = getChildDevice("${device.id}-${switchFunc}")
   					if (cd == null) {
   					return createEvent(name: "switch", value: switchState)
   					}
           if (descMap?.command == "00") {
   		// switch toggled
   		cd.parse([[name: "switch", value:switchState, descriptionText: "Child switch ${switchFunc} turned $switchState"]])
   		} 
   		else if (descMap?.command == "02") {
           // report switch status
           cd.parse([[name: "switch", value:switchState, descriptionText: "Child switch ${switchFunc} is $switchState"]])
   		}
           if (switchState == "on") {
   		if (debugLogging) log.debug "Parent Switch ON"
   		return createEvent(name: "switch", value: "on")
   		} 
   		else if (switchState == "off") {
   		def cdsOn = 0
   		// cound number of switches on
   		getChildDevices().each {child ->
           if (getChildId(child) != switchFunc && child.currentValue('switch') == "on") {
               cdsOn++
           }
   		}
   		if (cdsOn == 0) {
           if (debugLogging) log.debug "Parent Switch OFF"
           return createEvent(name: "switch", value: "off")
   		}    
   		}
               }
   		}
   	}
   }
}   

def lastCheckin() {    // send event for heartbeat 
   def now = new Date()
   sendEvent(name: "lastCheckin", value: now)
}

def off() {
   if (infoLogging) log.info "Turn all switches OFF"	
   return  [
   "he cmd 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00 {00010D01000100}","delay 200",
   //"he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x01 {}","delay 200"
        ]
}

def on() {
   if (infoLogging) log.info "Turn all switches ON"
   return  [
   "he cmd 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00 {00010D01000101}","delay 200",
  // "he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x01 {}","delay 200"
         ]
}

def refresh() {
   if (infoLogging) log.info "Refreshing..."
   return  [
   //"he rattr  0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x04 {}","delay 200",  //light state
   //"he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x01 {}","delay 200",  //light state
   //"he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0005 0x00 {}","delay 200",  //
   lastCheckin()
   ]   
}

private String getChildId(childDevice) {
   return childDevice.deviceNetworkId.substring(childDevice.deviceNetworkId.length() - 2)
}

def componentOn(childDevice) {
   if (debugLogging) log.debug "component state is ON - ${childDevice} {${childDevice.deviceNetworkId}}"
   if (infoLogging) log.info "${childDevice} is ON"
   String fullDataOn = "0001" + getChildId(childDevice) + "01000101"
   sendHubCommand(new HubAction("he cmd 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00 {${fullDataOn}}", Protocol.ZIGBEE))
   if (debugLogging) log.debug "{executed} 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00 {${fullDataOn}}"
}

def componentOff(childDevice) {
   if (debugLogging) log.debug "component state is OFF - ${childDevice} {${childDevice.deviceNetworkId}}"
   if (infoLogging) log.info "${childDevice} is OFF"
   String fullDataOff = "0001" + getChildId(childDevice) + "01000100"
   sendHubCommand(new HubAction("he cmd 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00 {${fullDataOff}}", Protocol.ZIGBEE))
   if (debugLogging) log.debug "{executed} 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00 {${fullDataOff}}"
}

def componentRefresh(childDevice) {
   if (debugLogging) log.debug "component refresh ${childDevice.deviceNetworkId} ${childDevice}"    
   sendHubCommand(new HubAction("he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00", Protocol.ZIGBEE))
   if (debugLogging) log.debug "{executed} 0x${device.deviceNetworkId} 0x${device.endpointId} 0xEF00 0x00"
}

def setupChildDevices() {
   if (debugLogging) log.debug "Parent setupChildDevices"
   deleteObsoleteChildren() 
   def buttons = 0
   switch (device.data.manufacturer) {
       case '_TZE200_amp6tsvy':
           buttons = 1
       break
       case '_TZE200_g1ib5ldv':
           buttons = 2
       break
   case '_TZE200_kyfqmmyl':
           buttons = 3
       break
   }
   if (infoLogging) log.info  "model: ${device.data.manufacturer}   buttons: $buttons"
   createChildDevices((int)buttons)
}

def createChildDevices(int buttons) {
   if (debugLogging) log.debug "Parent createChildDevices"
 
   if (buttons <= 1){
   if (debugLogging) log.debug "This device have only: $buttons button, Child devices not needed."
       return         } 

   else    
   for (i in 1..buttons) {
       def childId = "${device.id}-0${i}"
       def existingChild = getChildDevices()?.find { it.deviceNetworkId == childId}
   
       if (existingChild) {
           if (infoLogging) log.info "Child device ${childId} already exists (${existingChild})"
       } 
   	else {
           if (infoLogging) log.info "Creating device ${childId}"
           addChildDevice("hubitat", "Generic Component Switch", childId, [isComponent: true, name: "Switch EP0${i}", label: "${device.displayName} EP0${i}"])
       }
   }
}

def deleteObsoleteChildren() {
   if (debugLogging) log.debug "Parent deleteChildren"
   
   getChildDevices().each {child->
       if (!child.deviceNetworkId.startsWith(device.id) || child.deviceNetworkId == "${device.id}-00") {
           if (infoLogging) log.info "Deleting ${child.deviceNetworkId}"
 		    deleteChildDevice(child.deviceNetworkId)
       }
   }
}

def switchLightModeConfig(){
def cmds = []
   switch(switchLightMode) {
       case "OFF":
        if (infoLogging) log.info "Backlight - OFF"
    zigbee.command(0xEF00, 0x0, "00010f04000100")
       break
       case "ON":
        if (infoLogging) log.info "Backlight - ON"
    zigbee.command(0xEF00, 0x0, "00010f04000101")
       break
       case "Position":
        if (infoLogging) log.info "Backlight - position"
    zigbee.command(0xEF00, 0x0, "00010f04000102")
       break
   }
} 

def relayModeConfig(){
def cmds = []
   switch(relayMode) {
       case "OFF":
        if (infoLogging) log.info "Relay state - OFF"
    	 zigbee.command(0xEF00, 0x0, "00010e04000100")
       break
       case "ON":
        if (infoLogging) log.info "Relay state - ON"
	 zigbee.command(0xEF00, 0x0, "00010e04000101")
       break
       case "Last state":
        if (infoLogging) log.info "Relay state - last state"
	 zigbee.command(0xEF00, 0x0, "00010e04000102")
       break
   }
}
2 Likes

OMG! It s working!
Awesome! Thank you!

How did you get it to initially pair/connect?

I picked up one of these Moe's 4 button scene controllers

but I can't find a reset button or documentation on how to get it into Zigbee pairing mode.

Hello,
I have a problem with two gang Tuya switch,
It have a description :

  • endpointId: 01
  • model: TS0601
  • application: 44
  • manufacturer: _TZE200_wunufsil
    It works as a one gang on the latest driver from @martinkura but i can not add secound button.
    I have tryed to change manufacturer name in code, line 13 and 200 but with no result,
    Do you have any idea how to make it work as two gang switch?