Hi there, sorry to hitch the thread. But I am facing the same issue too. ): Would you be able to help? Had amended the finger print to match but still when any switch if turned off using HE, all switches turn on for 3-gang. Works perfectly for 3-gang.
Here's my code which I had amended the fingerprint to match.
/**
import hubitat.device.HubAction
import hubitat.device.Protocol
def version() { "0.2.7" }
def timeStamp() {"2022/06/06 9:48 AM"}
metadata {
definition (name: "Moes ZigBee Wall Switch Multi-Gang", namespace: "muxa", author: "Muxa", importUrl: "https://raw.githubusercontent.com/kkossev/hubitat-muxa-fork/development/drivers/zemismart-zigbee-multigang-switch.groovy", singleThreaded: true ) {
capability "Initialize"
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Switch"
capability "Health Check"
fingerprint profileId:"0104", endpointId:"01", inClusters:"0000,0003,0004,0005,0006,E000,E001", outClusters:"0019,000A", model:"TS0012", manufacturer:"_TZ3000_18ejxno0", deviceJoinName: "Tuya Zigbee Switch Multi-Gang" // check!
fingerprint profileId:"0104", endpointId:"01", inClusters:"0000,0003,0004,0005,0006", outClusters:"0019,000A", model:"TS0013", manufacturer:"_TZ3000_qewo8dlz", deviceJoinName: "Tuya Zigbee Switch Multi-Gang"
command "powerOnState", [
[name:"powerOnState", type: "ENUM", constraints: ["--- Select ---", "OFF", "ON", "Last state"], description: "Select Power On State"]
]
attribute "lastCheckin", "string"
}
preferences {
input (name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true)
input (name: "txtEnable", type: "bool", title: "Enable description text logging", defaultValue: true)
}
}
// Parse incoming device messages to generate events
def parse(String description) {
checkDriverVersion()
//log.debug "${device.displayName} Parsing '${description}'"
def descMap = [:]
try {
descMap = zigbee.parseDescriptionAsMap(description)
}
catch ( e ) {
if (settings?.logEnable) log.warn "${device.displayName} exception caught while parsing description ${description} \r descMap: ${descMap}"
return null
}
logDebug "Parsed: $descMap"
Map map = null // [:]
if (descMap.cluster == "0006" && descMap.attrId == "0000") {
// descMap.command =="0A" - switch toggled physically
// descMap.command =="01" - get switch status
// descMap.command =="0B" - command response
def cd = getChildDevice("${device.id}-${descMap.endpoint}")
if (cd == null) {
if (!(device.data.model in ['TS0011'])) {
log.warn "${device.displayName} Child device ${device.id}-${descMap.endpoint} not found. Initialise parent device first"
return
}
}
def switchAttribute = descMap.value == "01" ? "on" : "off"
if (cd != null ) {
if (descMap.command in ["0A", "0B"]) {
// switch toggled
cd.parse([[name: "switch", value:switchAttribute, descriptionText: "Child switch ${descMap.endpoint} turned $switchAttribute"]])
}
else if (descMap.command =="01") {
// report switch status
cd.parse([[name: "switch", value:switchAttribute, descriptionText: "Child switch ${descMap.endpoint} is $switchAttribute"]])
}
}
if (switchAttribute == "on") {
logDebug "Parent switch on"
return createEvent(name: "switch", value: "on")
}
else if (switchAttribute == "off") {
def cdsOn = 0
// cound number of switches on
getChildDevices().each {child ->
if (getChildId(child) != descMap.endpoint && child.currentValue('switch') == "on") {
cdsOn++
}
}
if (cdsOn == 0) {
logDebug "Parent switch off"
return createEvent(name: "switch", value: "off")
}
}
} // OnOff cluster, attrId "0000"
else if (descMap.cluster == "0006" && descMap.attrId != "0000") { // other attr
processOnOfClusterOtherAttr( descMap )
}
else {
logDebug "${device.displayName} unprocessed EP: ${descMap.sourceEndpoint} cluster: ${descMap.clusterId} attrId: ${descMap.attrId}"
}
}
def off() {
if (settings?.txtEnable) log.info "${device.displayName} Turning all child switches off"
"he cmd 0x${device.deviceNetworkId} 0xFF 0x0006 0x0 {}"
}
def on() {
if (settings?.txtEnable) log.info "${device.displayName} Turning all child switches on"
"he cmd 0x${device.deviceNetworkId} 0xFF 0x0006 0x1 {}"
}
def refresh() {
logDebug "refreshing"
"he rattr 0x${device.deviceNetworkId} 0xFF 0x0006 0x0"
}
def ping() {
refresh()
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
private String getChildId(childDevice) {
return childDevice.deviceNetworkId.substring(childDevice.deviceNetworkId.length() - 2)
}
def componentOn(childDevice) {
logDebug "sending componentOn ${childDevice.deviceNetworkId}"
sendHubCommand(new HubAction("he cmd 0x${device.deviceNetworkId} 0x${getChildId(childDevice)} 0x0006 0x1 {}", Protocol.ZIGBEE))
}
def componentOff(childDevice) {
logDebug "sending componentOff ${childDevice.deviceNetworkId}"
sendHubCommand(new HubAction("he cmd 0x${device.deviceNetworkId} 0x${getChildId(childDevice)} 0x0006 0x0 {}", Protocol.ZIGBEE))
}
def componentRefresh(childDevice) {
logDebug "sending componentRefresh ${childDevice.deviceNetworkId} ${childDevice}"
sendHubCommand(new HubAction("he rattr 0x${device.deviceNetworkId} 0x${getChildId(childDevice)} 0x0006 0x0", Protocol.ZIGBEE))
}
def setupChildDevices() {
logDebug "Parent setupChildDevices"
deleteObsoleteChildren()
def buttons = 0
switch (device.data.model) {
case 'TS0004' :
case 'TS0014' :
buttons = 4
break
case 'TS0003' :
case 'TS0013' :
buttons = 3
break
case 'TS0002' :
case 'TS0012' :
buttons = 2
break
case 'TS0011' :
buttons = 0
break
default :
break
}
logDebug "model: ${device.data.model} buttons: $buttons"
createChildDevices((int)buttons)
}
def createChildDevices(int buttons) {
logDebug "Parent createChildDevices"
if (buttons == 0)
return
for (i in 1..buttons) {
def childId = "${device.id}-0${i}"
def existingChild = getChildDevices()?.find { it.deviceNetworkId == childId}
if (existingChild) {
log.info "${device.displayName} Child device ${childId} already exists (${existingChild})"
} else {
log.info "${device.displayName} Creatung device ${childId}"
addChildDevice("hubitat", "Generic Component Switch", childId, [isComponent: true, name: "Switch EP0${i}", label: "${device.displayName} EP0${i}"])
}
}
}
def deleteObsoleteChildren() {
logDebug "Parent deleteChildren"
getChildDevices().each {child->
if (!child.deviceNetworkId.startsWith(device.id) || child.deviceNetworkId == "${device.id}-00") {
log.info "${device.displayName} Deleting ${child.deviceNetworkId}"
deleteChildDevice(child.deviceNetworkId)
}
}
}
def driverVersionAndTimeStamp() {version()+' '+timeStamp()}
def checkDriverVersion() {
if (state.driverVersion == null || (driverVersionAndTimeStamp() != state.driverVersion)) {
if (txtEnable==true) log.debug "${device.displayName} updating the settings from the current driver version ${state.driverVersion} to the new version ${driverVersionAndTimeStamp()}"
initializeVars( fullInit = false )
state.driverVersion = driverVersionAndTimeStamp()
}
}
void initializeVars(boolean fullInit = true) {
if (settings?.txtEnable) log.info "${device.displayName} InitializeVars()... fullInit = ${fullInit}"
if (fullInit == true ) {
state.clear()
state.driverVersion = driverVersionAndTimeStamp()
}
if (settings?.logEnable == null) device.updateSetting("logEnable", true)
if (settings?.txtEnable == null) device.updateSetting("txtEnable", true)
}
def initialize() {
logDebug "Initializing..."
initializeVars(fullInit = true)
setupChildDevices()
}
def installed() {
logDebug "Parent installed"
}
def updated() {
logDebug "Parent updated"
}
def tuyaBlackMagic() {
return zigbee.readAttribute(0x0000, [0x0004, 0x000, 0x0001, 0x0005, 0x0007, 0xfffe], [:], delay=200)
}
def configure() {
logDebug " configure().."
List cmds = []
cmds += tuyaBlackMagic()
//cmds += refresh()
cmds += zigbee.onOffConfig()
cmds += zigbee.onOffRefresh()
sendZigbeeCommands(cmds)
}
void sendZigbeeCommands(List cmds) {
logDebug "sendZigbeeCommands received : ${cmds}"
sendHubCommand(new hubitat.device.HubMultiAction(cmds, hubitat.device.Protocol.ZIGBEE))
}
def logDebug(msg) {
String sDnMsg = device.displayName + " " + msg
if (settings?.logEnable) log.debug sDnMsg
}
def powerOnState(relayMode) {
List cmds = []
int modeEnum = 99
switch(relayMode) {
case "OFF" :
modeEnum = 0
break
case "ON" :
modeEnum = 1
break
case "Last state" :
modeEnum = 2
break
default :
log.error "${device.displayName} please select a Power On State option"
return
}
logDebug ("setting Power On State option to: ${relayMode}")
cmds += zigbee.writeAttribute(0x0006, 0x8002, DataType.ENUM8, modeEnum)
sendZigbeeCommands(cmds)
}
def processOnOfClusterOtherAttr( descMap ) {
logDebug "cluster OnOff attribute ${descMap.attrId} reported: value=${descMap.value}"
def mode
def attrName
def value = descMap.value as int
switch (descMap.attrId) {
case "8000" :
attrName = "Child Lock"
mode = value == 0 ? "off" : "on"
break
case "8001" :
attrName = "LED mode"
mode = value == 0 ? "Disabled" : value == 1 ? "Lit when On" : value == 2 ? "Lit when Off" : null
break
case "8002" :
attrName = "Power On State"
mode = value == 0 ? "off" : value == 1 ? "on" : value == 2 ? "Last state" : null
break
default :
logDebug "processOnOfClusterOtherAttr: UNPROCESSED On/Off Cluster attrId: ${descMap.attrId} value: ${descMap.value}"
break
}
if (txtEnable) log.info "${device.displayName} ${attrName} is: ${mode}"
}