Yagusmart 4 button Scene Switch

Unfortunately all these variants seem to have all sorts of different behaviours :frowning:

My 4-button doesn't accept any configuration for battery reporting, but reports battery percentage every time button 1 is pressed (bottom left).

Whereas my 3-button accepts configuration for the battery percentage attribute OK and appears to adhere to it.

My 2-button and 1-button versions don't do either of the above, but occasionally, seemingly randomly, they do report battery percentage.

Nicely consistent!

What Driver are you using Martyn? I have a couple of the 4 button devices and they don't have any battery information showing at all.

I'm currently using mine with deCONZ.

Looking at the driver you're using from post 9, if you enable debug logging do you get anything logged for Cluster 0001 and Attribute 0021 when you press any of the buttons, or periodically?

That driver isn't currently "doing" anything even if it did receive battery reports, but seeing if your device is actually sending them would still be visible in the logs.

Based on what Mike mentioned above, it sounds like the built in driver should report battery if / when the device sends them, so you could try that.

To be honest I hadn't realised there was a built in driver for this, there is nothing in the compatible docs list that I could find, but I've just tried adding one to my spare hub (with no custom driver installed) and it picked it up as "Tuya Zigbee Scene Switch" and works great with single and double tap detected and battery reporting at 100%. As you found, it seems to update the battery on the press of button 1.

I've no idea how long the driver has been on for this but good work @mike.maxwell and the Hubitat team!

Yeah it was in the 2.2.5 release notes, unfortunately I think the compatible devices list lags behind a bit until somebody gets round to updating it.

I don't think Mike implemented the held event because it's something like 5+ seconds to trigger it, which isn't really usable for most applications.

1 Like

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...