I have made a mod to @jp0550's mod for this driver. This will be my interim driver till Hubitat/Samsung resolve the duplicate events that occur after these button devices have been unused for a period of time. Essentially it will ignore multiple button press events that occur with a specified timeframe. When I receive duplicates my logs show that they occur within 2 seconds of each other. I have found that 2500ms to be the sweet spot for me. Your mileage may vary and so I made this an adjustable option in the driver preferences.
Hopefully I won't need this driver for much longer.
And, yes, I know everyone does not experience this issue even with the same firmware. This driver is for those that do.
/*
* 12/30/18 Edited by Stephan Hackett
* - added option to ignore duplicate events received within adjustable timeframe (2500ms/2.5s worked for me). Tweak this preference to fit your scenario.
*/
metadata {
definition ( name : "Smartthings Button", namespace: "stephack", author: "Robert Morris, Mitch Pond, jp0550, Stephan Hackett" ) {
capability "Holdable Button"
capability "Battery"
capability "Refresh"
capability "Double Tapable Button"
capability "Pushable Button"
capability "Temperature Measurement"
capability "Sensor"
capability "Actuator"
capability "Configuration"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0003,0019", manufacturer: "Samjin", model: "button"
}
}
preferences {
input("debounce", "number", title: "Ignore multiple events received within this timeframe (ms):")
}
def parse(description){
log.debug "Received message: $description"
def event = zigbee.getEvent(description)
if( description?.startsWith("catchall:") || description?.startsWith("read attr -") ){
def descMap = zigbee.parseDescriptionAsMap(description)
log.debug "Desc map: $descMap"
if(descMap.clusterInt == 0x0001 && descMap.attrInt == 0x0020){ //battery
event = getBatteryResult(zigbee.convertHexToInt(descMap.value))
}
}
else if( description?.startsWith("zone status") ){
event = parseIasButtonMessage(description)
}
log.debug "Parsed event $event"
def result = event ? createEvent(event) : []
if (description?.startsWith('enroll request')) {
List cmds = zigbee.enrollResponse()
log.debug "enroll response: ${cmds}"
result = cmds?.collect { new hubitat.device.HubAction(it) }
}
result
}
def parseIasButtonMessage(description){
def zs = zigbee.parseZoneStatus(description)
def eventType
if(zs.isAlarm1Set()) eventType = "pushed"
if(zs.isAlarm2Set()) eventType = "doubleTapped"
if(zs.isAlarm1Set() && zs.isAlarm2Set()) eventType = "held"
if(eventType){
def rejectTime = 0
if(debounce) rejectTime = debounce
def recentEvents = device.eventsSince(new Date(now() - rejectTime)).findAll{it.name == eventType}
log.info "Duplicate event rejected"
if(recentEvents.size == 0){
return [ name: eventType, value: 1, isStateChange: true, descriptionText: "Button 1 was $eventType" ]
}
}
}
def getBatteryResult(rawValue){
log.debug "Parse battery: $rawValue"
def volts = rawValue / 10.0
if(volts > 3.0 || volts == 0 || rawValue == 0xFF){
return [:]
}
else {
def result = [ name : 'battery' ]
def minVolts = 2.1
def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts)
result.value = Math.min(100, (int)(pct * 100))
def linkText = getLinkText(device)
result.descriptionText = "$linkText battery was ${result.value}%"
return result
}
}
def refresh(){
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x20) + zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0) + zigbee.enrollResponse()
}
def configure(){
log.debug "Configure"
sendEvent(name: 'numberOfButtons', value: 1)
zigbee.onOffConfig() +
zigbee.levelConfig() +
zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x20, DataType.UINT8, 30, 21600, 0x01) +
zigbee.temperatureConfig(30, 3600) +
zigbee.enrollResponse() +
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x20) +
zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0) + []
}