Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nksglns/a0cc110f87233ba0da809ec5b1ce7e44 to your computer and use it in GitHub Desktop.
Save nksglns/a0cc110f87233ba0da809ec5b1ce7e44 to your computer and use it in GitHub Desktop.
A device handler for WOOX's 4 button fob for SmartThings Groovy IDE.
import groovy.json.JsonOutput
import physicalgraph.zigbee.zcl.DataType
metadata {
definition(name: "WOOX Zigbee 4 Button FOB", namespace: "smartthings", author: "Nikos Galanis") {
capability "Button"
capability "Configuration"
fingerprint inClusters: "0000,0001,0500,0501", outClusters: "0019,000A", manufacturer: "_TZ3000_p6ju8myv", model: "TS0215A", deviceJoinName: "WOOX Remote Control"
}
preferences {
input name: "debugEnable", type: "bool", title: "Enable debug logging", defaultValue: false
}
tiles {
standardTile("button", "device.button", width: 2, height: 2) {
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
}
main (["button"])
details(["button"])
}
}
private getCLUSTER_GROUPS() { 0x0004 }
private channelNumber(String dni) {
dni.split(":")[-1] as Integer
}
private getButtonName(buttonNum) {
return "${device.displayName} " + "Button ${buttonNum}"
}
private void createChildButtonDevices(numberOfButtons) {
state.oldLabel = device.label
def existingChildren = getChildDevices()
log.debug "Creating $numberOfButtons children"
for (i in 1..numberOfButtons) {
def newChildNetworkId = "${device.deviceNetworkId}:${i}"
def childExists = (existingChildren.find {child -> child.getDeviceNetworkId() == newChildNetworkId} != NULL)
if (!childExists) {
log.debug "Creating child $i"
def child = addChildDevice("Child Button", newChildNetworkId, device.hubId,
[completedSetup: true, label: getButtonName(i),
isComponent: true, componentName: "button$i", componentLabel: "Button ${i}"])
child.sendEvent(name: "supportedButtonValues", value: ["pushed"].encodeAsJSON(), displayed: false)
child.sendEvent(name: "numberOfButtons", value: 1, displayed: false)
child.sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], displayed: false)
} else {
log.debug "Child $i already exists, not creating"
}
}
}
def installed() {
def numberOfButtons = 4
state.ignoreNextButton3 = false
createChildButtonDevices(numberOfButtons)
sendEvent(name: "supportedButtonValues", value: ["pushed"].encodeAsJSON(), displayed: false)
sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false)
numberOfButtons.times {
sendEvent(name: "button", value: "pushed", data: [buttonNumber: it+1], displayed: false)
}
// These devices don't report regularly so they should only go OFFLINE when Hub is OFFLINE
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
}
def updated() {
if (childDevices && device.label != state.oldLabel) {
childDevices.each {
def newLabel = getButtonName(channelNumber(it.deviceNetworkId))
it.setLabel(newLabel)
}
state.oldLabel = device.label
}
}
def configure() {
log.debug "Configuring device ${device.getDataValue("model")}"
def cmds = zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21, DataType.UINT8, 30, 21600, 0x01) +
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21) +
zigbee.addBinding(zigbee.ONOFF_CLUSTER) +
// This device doesn't report a binding to this group but will send all messages to this group ID
addHubToGroup(0x4003)
cmds
}
def parse(String description) {
log.debug "Parsing message from device: '$description'"
def event = zigbee.getEvent(description)
if (event) {
log.debug "Creating event: ${event}"
sendEvent(event)
} else {
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
def descMap = zigbee.parseDescriptionAsMap(description)
//log.debug descMap
if (descMap.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.attrInt == 0x0021) {
event = getBatteryEvent(zigbee.convertHexToInt(descMap.value))
} else {
event = getButtonEvent(descMap)
}
}
def result = []
if (event) {
log.debug "Creating event: ${event}"
result = createEvent(event)
}
return result
}
}
private Map getBatteryEvent(value) {
def result = [:]
result.value = value / 2
result.name = 'battery'
result.descriptionText = "${device.displayName} battery was ${result.value}%"
return result
}
private sendButtonEvent(buttonNumber, buttonState) {
def child = childDevices?.find { channelNumber(it.deviceNetworkId) == buttonNumber }
if (child) {
def descriptionText = "$child.displayName was $buttonState" // TODO: Verify if this is needed, and if capability template already has it handled
child?.sendEvent([name: "button", value: buttonState, data: [buttonNumber: 1], descriptionText: descriptionText, isStateChange: true])
} else {
log.debug "Child device $buttonNumber not found!"
}
}
private Map getButtonEvent(Map descMap) {
def buttonState = ""
def buttonNumber = 0
Map result = [:]
switch (descMap.data) {
case "[00, 00, FF]":
//button = "Disarm"
buttonNumber = 4
break
case "[01, 00, FF]":
//button = "Partial"
buttonNumber = 3
break
case "[03, 00, FF]":
//ARM
buttonNumber = 2
break
case "[]":
buttonNumber = 1
break
}
if (buttonNumber != 0) {
// Create and send component event
sendButtonEvent(buttonNumber, "pushed")
}
result
}
private List addHubToGroup(Integer groupAddr) {
["st cmd 0x0000 0x01 ${CLUSTER_GROUPS} 0x00 {${zigbee.swapEndianHex(zigbee.convertToHexString(groupAddr,4))} 00}",
"delay 200"]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment