/** * Zigbee 3 button remote (Smartenit ZBWS3B) * * Original code by GilbertChan, modified by obycode to add 'numButtons' * Thanks to Seth Jansen @sjansen for original contributions * * Modified by Jason Cheatham for Hubitat compatibility, 2018-03-24. */ metadata { definition(name: '3 Button Remote', namespace: 'jason0x43', author: 'Jason Cheatham') { capability 'PushableButton' capability 'Battery' capability 'Configuration' capability 'Refresh' attribute 'button2', 'enum', ['released', 'pressed'] attribute 'button3', 'enum', ['released', 'pressed'] attribute 'numberOfButtons', 'number' fingerprint( endpointId: '03', profileId: '0104', deviceId: '0000', deviceVersion: '00', inClusters: '03 0000 0003 0007', outClusters: '01 0006' ) } preferences { input( name: 'numberOfButtons', type: 'number', title: 'Number of buttons', required: true ) } } def updated() { sendEvent( name: 'numberOfButtons', value: settings.numberOfButtons ) } def parse(description) { log.trace "Parse description ${description}" def button = null if (description.startsWith('catchall:')) { return parseCatchAllMessage(description) } else if (description.startsWith('read attr - ')) { return parseReportAttributeMessage(description) } } def refresh() { log.debug 'Refreshing...' return [ // Request battery voltage from cluster 0x20; should be the // measured battery voltage in 100mv increments "st rattr 0x${device.deviceNetworkId} 0x01 0x0001 0x0020" //zigbee.readAttribute(0x0001, 0x0020) ] } def configure() { log.info 'Configuring...' def configCmds = [ // Switch control "zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0x0006 {${device.zigbeeId}} {}", 'delay 500', "zdo bind 0x${device.deviceNetworkId} 0x02 0x01 0x0006 {${device.zigbeeId}} {}", 'delay 500', "zdo bind 0x${device.deviceNetworkId} 0x03 0x01 0x0006 {${device.zigbeeId}} {}", 'delay 1500', ] + zigbee.configureReporting(0x0001, 0x0020, 0x20, 30, 21600, 0x01) //zigbee.batteryConfig() //+ refresh() return configCmds } /** * Store mode and settings */ def updateState(name, value) { state[name] = value } private parseCatchAllMessage(description) { def cluster = zigbee.parseDescriptionAsMap(description) if (cluster.profileId == '0104' && cluster.clusterInt == 6) { return [getButtonEvent(cluster.sourceEndpoint.toInteger())] } } private getButtonEvent(button) { def event = createEvent( name: 'pushed', value: button, descriptionText: "${device.displayName} button ${button} was pushed", isStateChange: true ) log.debug event.descriptionText return event } private parseReportAttributeMessage(description) { def cluster = zigbee.parseDescriptionAsMap(description) // Battery voltage is cluster 0x0001, attribute 0x20 if (cluster.clusterInt == 1 && cluster.attrInt == 32) { return [getBatteryEvent(Integer.parseInt(cluster.value, 16))] } } private getBatteryEvent(rawValue) { log.trace "Battery rawValue = ${rawValue}" def event = [ name: 'battery', value: '--', translatable: true ] // 0 and 0xff are invalid if (rawValue == 0 || rawValue == 255) { return createEvent(event) } // Raw value is in 100mV units def volts = rawValue / 10 // Assumes sensor's working floor is 2.1V def minVolts = 2.1 def maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) if (roundedPct <= 0) { roundedPct = 1 } event.value = Math.min(100, roundedPct) event.descriptionText = "${device.displayName} battery is at ${event.value}%" log.debug event.descriptionText return createEvent(event) }