Instantly share code, notes, and snippets.
Created
July 13, 2022 10:16
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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