Yagusmart 4 button Scene Switch

I have a scene device exactly like yours, from Zemismart. I use the driver below, it works perfectly. It was adapted to HE by a friend, I hope it may help!

/**

*/
import hubitat.zigbee.zcl.DataType

metadata {
definition (name: "Zemismart Zigbee Button Remote", namespace: "gbrown", author: "G.Brown") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "DoubleTapableButton"
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Battery"

    fingerprint inClusters: "0000,0001,0006", outClusters: "0019", manufacturer: "_TYZB02_key8kk7r", model: "TS0041"
    fingerprint inClusters: "0000,0001,0006", outClusters: "0019", manufacturer: "_TYZB02_key8kk7r", model: "TS0042"
    fingerprint inClusters: "0000,0001,0006", outClusters: "0019", manufacturer: "_TYZB02_key8kk7r", model: "TS0043"
    fingerprint inClusters: "0000,000A,0001,0006", outClusters: "0019", manufacturer: "_TZ3000_vp6clf9d", model: "TS0044"
    
    attribute "batteryLastReplaced", "String"
    command "resetBatteryReplacedDate"
}

preferences {
    input name: "debugEnable", type: "bool", title: "Enable debug logging", defaultValue: false
    
    //Battery Voltage Range
	input name: "voltsmin", title: "Min Volts (0% battery = ___ volts, range 2.0 to 2.7). Default = 2.5 Volts", description: "", type: "decimal", range: "2..2.7"
	input name: "voltsmax", title: "Max Volts (100% battery = ___ volts, range 2.8 to 3.4). Default = 3.0 Volts", description: "", type: "decimal", range: "2.8..3.4"

}

}

private sendButtonNumber() {
def remoteModel = device.getDataValue("model")
switch(remoteModel){
case "TS0041":
sendEvent(name: "numberOfButtons", value: 1, isStateChange: true)
break
case "TS0042":
sendEvent(name: "numberOfButtons", value: 2, isStateChange: true)
break
case "TS0043":
sendEvent(name: "numberOfButtons", value: 3, isStateChange: true)
break
case "TS0044":
sendEvent(name: "numberOfButtons", value: 4, isStateChange: true)
break
}
}

def installed() {
sendButtonNumber
state.start = now()
}

def updated() {
sendButtonNumber
}

def refresh() {
// read battery level attributes
return zigbee.readAttribute(0x0001, 0x0020) + zigbee.configureReporting(0x0001, 0x0020, 0x20, 3600, 21600, 0x01)
// this device doesn't support 0021
zigbee.readAttribute(0x0001, 0x0021)
}

def configure() {
sendButtonNumber

def configCmds = []

for (int endpoint=1; endpoint<=3; endpoint++) {
def list = ["0006", "0001", "0000"]
// the config to the switch
for (cluster in list) {
configCmds.add("zdo bind 0x${device.deviceNetworkId} 0x0${endpoint} 0x01 0x${cluster} {${device.zigbeeId}} {}")
}
}
return configCmds
}

def parse(String description) {
Map map = [:]
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
def parsedMap = zigbee.parseDescriptionAsMap(description)
if (debugEnable){
log.debug("Message Map: '$parsedMap'")
}

    switch(parsedMap.sourceEndpoint) {
        case "04": 
            button = "4"
            break
        case "03": 
            button = "3"
            break
        case "02": 
            button = "2"
            break
        case "01": 
            button = "1"
            break
    }
    switch(parsedMap.data) {
        case "[00]": 
            name = "pushed" 
            break
        case "[01]": 
            name = "doubleTapped" 
            break
        case "[02]": 
            name = "held" 
            break
}
    sendEvent(name: name, value: button, descriptionText: "Button $button was $name",isStateChange:true)
//}  

if (cluster == "0001" & attrId == "0020")
// Parse battery level from hourly announcement message
	map = parseBattery(valueHex)
else
	//displayDebugLog("Unable to parse message")
    log.debug("Unable to parse message")
if (map != [:]) {
	//displayDebugLog("Creating event $map")
    log.debug("Creating event $map")
	return createEvent(map)
} //else
  //return [:]

}
return

}

// Convert 2-byte hex string to voltage
// 0x0020 BatteryVoltage - The BatteryVoltage attribute is 8 bits in length and specifies the current actual (measured) battery voltage, in units of 100mV.
private parseBattery(valueHex) {
//displayDebugLog("Battery parse string = ${valueHex}")
log.debug("Battery parse string = ${valueHex}")
def rawVolts = hexStrToSignedInt(valueHex) / 10
def minVolts = voltsmin ? voltsmin : 2.5
def maxVolts = voltsmax ? voltsmax : 3.0
def pct = (rawVolts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.min(100, Math.round(pct * 100))
def descText = "Battery level is ${roundedPct}% (${rawVolts} Volts)"
displayInfoLog(descText)
def result = [
name : 'battery',
value : roundedPct,
unit : "%",
isStateChange : true,
descriptionText: descText
]
return result
}

//Reset the batteryLastReplaced date to current date
def resetBatteryReplacedDate(paired) {
def newlyPaired = paired ? " for newly paired sensor" : ""
sendEvent(name: "batteryLastReplaced", value: new Date().toLocaleString(), descriptionText: "Set battery last replaced date")
displayInfoLog("Setting Battery Last Replaced to current date${newlyPaired}")
}

Hi for this device i can use the drive above?
4 Button Tuya

This device should work with this built in driver
Tuya Zigbee Scene Switch

1 Like

It should hopefully pick up the built in driver "Tuya ZigBee Scene Switch" when it's paired.

If not, change to that driver and see if it works.

1 Like

Thanks all

Did it pick that driver up when paired? If not and you change over to that driver and it works OK, let us know because then the "fingerprint" of your version of the device can be added to the driver so that it's recognized automatically in the future.

1 Like

I will
THANKS

image
:sweat: long trip

very nice switch . i cut out the back for the switch to fit . It sits nicely on a traditional UK wall switch.

coincidence or wanted?
anyway lucky
Yes it work well, i see justa little delay using realease... it take 2 second after i release it to execute the funtion.
apceptable for me

Eduardo, do you have the source for a working driver for this device? I have exactly the same device and I have been trying to get it working:

  • endpointId: 01
  • application: 41
  • manufacturer: _TZ3000_xabckq1v
  • model: TS004F
  • softwareBuild:
  • inClusters: 0000,0001,0003,0004,0006,1000
  • outClusters: 0019,000A,0003,0004,0005,0006,0008,1000
  • isMultiEP: false

I have recently purchased the same scene switch * model: TS004F 'Powered by Tuya'. It does not work for me too. Only the first button is sending some Zigbee data to the hub after reset (removal and placing the battery again), but then it just stops. Seems like the switch is waiting for some confirmation from hub or something... AliExpress seller states this _TZ3000_xabckq1v switch works with Tuya zigbee switch only and refuses a refund.

Tried it also with my old ST hub, searching for similar models SmatThings Device Handlers - again no success. Some packages received after the first press of the 1st button and then nothing. The only difference is that in ST I can see Zigbee communication when pressing the 2nd, 3rd and 4th buttons, while HE does not show anything in zigbee logs for these buttons 2,3 and 4.

I have given up, going to list this switch in the local second-hand online sales site. It may work for someone who has the Tuya zigbee gateway.

@mr.murraybrandon, @kkossev, did you try this driver?

Hi Marcus,

Thanks for your advice.
Yes, I cut and pasted that driver and it doesn't work. (sorry for the formatting below).
I also added a push(button) function because the documentation says a capability of PushableButton needs a push(button) function to call. So not sure how the original can work without one, but still my version below doesn't work. I am confident that if this device works with a Tuya hub it can be made to work with Hubitat.

Hubitat's Button Implementation

I wonder if I have to "subscribe" to the button presses to be able to hear them? None of the below code does a subscribe either! So really confused.

I feel like I am missing a crucial piece of "how to code and debug new zigbee device drivers". Why for example does the documentation specify both a push(button) function and a subscribe(deviceList, "pushed", buttonHandler) function are required yet none of the drivers that work implement such a function, or even a pushed() function?

/**

  • Copyright 2019 G.Brown (MorkOz)
  • 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.
  • Adapted and modified from code written by at9, motley74, sticks18 and AnotherUser
  • Original sources:
  • https://github.com/at-9/hubitat/blob/master/Drivers/at-9-Zemismart-3-Gang-Sticker-Switch
  • SmartThingsPublic/osram-lightify-dimming-switch.groovy at master · motley74/SmartThingsPublic · GitHub
  • SmartThingsPublic-1/osram-lightify-4x-switch.groovy at master · AnotherUser17/SmartThingsPublic-1 · GitHub
  • Message Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 C500, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[C5, 00]]'
  • Message Map: '[raw:catchall: 0104 0001 01 01 0040 00 5360 00 00 0000 07 01 00, profileId:0104, clusterId:0001, clusterInt:1, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:07, direction:01, data:[00]]'
  • Version Author Note
  • 0.1 G.Brown (MorkOz) Initial release

*/
import hubitat.zigbee.zcl.DataType

metadata {
definition (name: "4 Scene Switch Zigbee", namespace: "brando", author: "M.Brando") {
capability "Actuator"
capability "PushableButton"
capability "HoldableButton"
capability "DoubleTapableButton"
capability "Configuration"
capability "Refresh"
capability "Sensor"

    fingerprint inClusters: "0000,0001,0006", outClusters: "0019", manufacturer: "_TYZB02_key8kk7r", model: "TS0041"
    fingerprint inClusters: "0000,0001,0006", outClusters: "0019", manufacturer: "_TYZB02_key8kk7r", model: "TS0042"
    fingerprint inClusters: "0000,0001,0006", outClusters: "0019", manufacturer: "_TYZB02_key8kk7r", model: "TS0043"		
    fingerprint inClusters: "0000,0001,0003,0004,0006,1000", outClusters: "0019,000A,0003,0004,0005,0006,0008,1000", manufacturer: "_TZ3000_xabckq1v", model: "TS004F"
}

preferences {
    input name: "debugEnable", type: "bool", title: "Enable debug logging", defaultValue: true
}

}

private sendButtonNumber() {
log.debug("sendButtonNumber()")
def remoteModel = device.getDataValue("model")
log.debug("remoteModel '$remoteModel'")
switch(remoteModel){
case "TS0041":
sendEvent(name: "numberOfButtons", value: 1, isStateChange: true)
break
case "TS0042":
sendEvent(name: "numberOfButtons", value: 2, isStateChange: true)
break
case "TS0043":
sendEvent(name: "numberOfButtons", value: 3, isStateChange: true)
break
case "TS004F":
sendEvent(name: "numberOfButtons", value: 4, isStateChange: true)
break
}
}

def installed() {
log.debug("installed()")
sendButtonNumber
state.start = now()
}

def updated() {
log.debug("updated()")
sendButtonNumber
}

def refresh() {
log.debug("refresh()")
// read battery level attributes
return zigbee.readAttribute(0x0001, 0x0020) + zigbee.configureReporting(0x0001, 0x0020, 0x20, 3600, 21600, 0x01)
// this device doesn't support 0021
zigbee.readAttribute(0x0001, 0x0021)
}

def configure() {
log.debug("configure()")
sendButtonNumber

def configCmds = []

for (int endpoint=1; endpoint<=3; endpoint++) {
def list = ["0006", "0001", "0000"]
// the config to the switch
for (cluster in list) {
configCmds.add("zdo bind 0x${device.deviceNetworkId} 0x0${endpoint} 0x01 0x${cluster} {${device.zigbeeId}} {}")
}
}
return configCmds
}

def push(button)
{
log.debug "Button Pushed: ${button}"
}

def hold(button)
{
log.debug "Button Held: ${button}"
}

def doubleTap(button)
{
log.debug "Button Double Tapped: ${button}"
}

def parse(String description)
{
log.debug("parse(): '$description'")

if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) 
{
    def parsedMap = zigbee.parseDescriptionAsMap(description)
    if (debugEnable)
    {
        log.debug("Message Map: '$parsedMap'")
    }
    switch(parsedMap.sourceEndpoint) 
    {
    case "04": 
        button = "1"
        break
    case "03": 
        button = "3"
        break
    case "02": 
        button = "4"
        break
    case "01": 
        button = "2"
        break
    }
    switch(parsedMap.data) 
    {
    case "[00]": 
        eventName = "pushed" 
        break
    case "[01]": 
        eventName = "doubleTapped" 
        break
    case "[02]": 
        eventName = "held" 
        break
    }
    sendEvent(name: eventName, value: button, descriptionText: "Button $button was $name", isStateChange:true)
}
return

}

Hi @mr.murraybrandon, I'm sorry I can't help...

@mr.murraybrandon I did similar experiments with the driver as yours without success...
Adding the PushableButton capability is not so much important at this stage, at least not before the TS004F scene switch starts sending any data to HE when buttons 2,3,4 are pushed. In my setup only button 1 sends a couple of data frames after the switch joined the zigbee network and then it stops... until the device is reset by removing and re-inserting the batteries. Unfortunately I am not at home at the moment and I can not post the raw data logs.

Thanks kkossev, that actually gives me an idea of how this device works. I think perhaps it needs to be initialised/reset after every time a button is pressed. For example when it is first installed it sends a payload when any button is pressed. If you reset programmatically it will send another payload - if you don't it sends nothing!

Unfortunately though all the payloads are identical with the exception of a sequence number in the data section:

BOTTOM LEFT
dev:22021-05-02 21:08:03.388 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 4100, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[41, 00]]'
dev:22021-05-02 21:08:03.377 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 4000, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[40, 00]]'
dev:22021-05-02 21:08:03.361 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 3E00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3E, 00]]'
dev:22021-05-02 21:08:03.357 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 3F00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3F, 00]]'
dev:22021-05-02 21:08:03.331 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 3D00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3D, 00]]'
dev:22021-05-02 21:08:03.318 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 3C00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3C, 00]]'
dev:22021-05-02 21:08:03.294 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 3B00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3B, 00]]'
dev:22021-05-02 21:08:03.280 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 3A00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3A, 00]]'

BOTTOM RIGHT
dev:22021-05-02 21:09:14.275 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 4A00, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[4A, 00]]'
dev:22021-05-02 21:09:14.271 debugMessage Map: '[raw:catchall: 0000 8021 00 00 0040 00 5360 00 00 0000 00 00 4900, profileId:0000, clusterId:8021, clusterInt:32801, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[49, 00]]'

I suspect the device isn't being initialised with the right number of buttons to enable so it always sends an event for the same button, no matter which one is pressed. Note that to pair it with the hub, you need to press specifically the bottom left button for about 15 seconds (not 10) until the whole thing starts to flash before it will pair.

I have some other generic "tuya/zigbee" sensors (contact switch, motion sensor etc) working fine and they send correct data. I'd love to get this firmware version working using a Hubitat driver because it is ubiquitous. I did a query on some that visually match on Ali Express and so far they're all TS0044 and TZ3000 devices according to the sellers. Actual product number being sold (if you want to avoid it) is ZN262259.

is embedded
image

Sorry, but the embedded driver shows no different events when you press the buttons, not even in the debug logs, only one event at the start of operation.

It only generates an event in the debug logs when you press a button after hitting the Configure option:

2021-05-06 18:47:52.721 [debug](http://192.168.1.247/device/edit/2)descMap:[raw:catchall: 0000 8005 00 00 0040 00 5360 00 00 0000 00 00 3B0060530101, profileId:0000, clusterId:8005, clusterInt:32773, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5360, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[3B, 00, 60, 53, 01, 01]]

But after that pressing any buttons generates no event at all, unless you Configure again...

Maybe a bit silly, but have you thought you may have a faulty unit?