2 // Automatically generated. Make future change here.
3 definition (name: "Orbit Water Timer", namespace: "mitchpond", author: "Mitch Pond") {
7 capability "Configuration"
14 fingerprint endpointId: "01", profileId: "0104", inClusters: "0000,0001,0003,0020,0006,0201", outClusters: "000A,0019"
17 // UI tile definitions
19 standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
20 state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", nextState: "turningOn", backgroundColor: "#ffffff"
21 state "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", nextState: "turningOff", backgroundColor: "#79b821"
22 state "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", nextState: "turningOn", backgroundColor: "#ffffff"
23 state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", nextState: "turningOff", backgroundColor: "#79b821"
25 valueTile("battery", "device.battery", decoration: "flat") {
26 state "battery", label:'${currentValue}% battery', unit:""
28 standardTile("configure", "device.configure", decoration: "flat") {
29 state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
31 standardTile("refresh", "command.refresh", decoration: "flat") {
32 state "default", label: '', action: 'refresh.refresh', icon: 'st.secondary.refresh'
36 details (["switch","battery","refresh","configure"])
40 // Parse incoming device messages to generate events
41 def parse(String description) {
42 log.debug("Raw: $description")
44 if (description?.startsWith("catchall:")) {
45 def report = zigbee.parse(description)
46 switch(report.clusterId) {
48 log.debug "Received Poll Control packet"
51 return (report.data).equals([0x01,0x00])? createEvent(name: 'switch', value: 'on') :
52 ((report.data).equals([0x00, 0x00, 0x00, 0x10, 0x01]) && (report.command == 0x01))? createEvent(name: 'switch', value: 'on') :
53 (report.data).equals([0x00,0x00])? createEvent(name: 'switch', value: 'off') :
54 ((report.data).equals([0x00, 0x00, 0x00, 0x10, 0x00]) && (report.command == 0x01))? createEvent(name: 'switch', value: 'off') : null
58 else if (description?.startsWith('read attr -')) {
59 return parseReportAttributeMessage(description)
66 //Perform initial device setup and binding
68 log.debug("Running configure for Orbit timer...")
71 "zcl global send-me-a-report 0x06 0x00 0x10 0 3600 {}", "delay 200",
72 "send 0x${device.deviceNetworkId} 1 1", "delay 500",
74 //"st cmd 0x${device.deviceNetworkId} 1 0x20 0x02 {14}", "delay 500", //set Long Poll Interval
75 //"st wattr 0x${device.deviceNetworkId} 1 0x20 0x00 0x23 {240}", "delay 500", //attempt to set check-in interval
77 "zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 500", //device reports back success
78 "zdo bind 0x${device.deviceNetworkId} 1 1 0 {${device.zigbeeId}} {}", "delay 500",
79 "zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 500"
84 /* successful attribute reads
86 "st rattr 0x${device.deviceNetworkId} 1 0x01 0x0020", "delay 500",
88 //cluster 20 poll control check-in is being sent by device. Should be able to alter polling duration and start fast poll
96 //"raw 0x000A {D8CE3955 e2 00 00 00 01}","delay 500",
97 //"send 0x${device.deviceNetworkId} 1 1",
98 //"st rattr 0x${device.deviceNetworkId} 1 0x01 0x0020", "delay 500", //works!
99 //"st rattr 0x${device.deviceNetworkId} 1 0x000A 0x0005", "delay 500", //unsupp attrib
100 //"st wattr 0x${device.deviceNetworkId} 1 0x000A 0x0000 0xe2 {D8CE3955}","delay 500", //no response
101 //"zcl global discover 0x0A 0x00 20","delay 200", //did nothing
102 //"send 0x${device.deviceNetworkId} 1 1", "delay 1000",
103 "st wattr 0x${device.deviceNetworkId} 1 0x20 0x00 0x23 {F0}", "delay 500"
106 //def report = zigbee.parse('catchall: 0104 0020 01 01 0140 00 20C4 00 00 0000 04 01')
108 //log.debug "Command is: ${report.command}"
109 //log.debug((report.command) == 0x01)
111 def identify() {"st cmd 0x${device.deviceNetworkId} 1 3 0 {0A 00}"}
112 def getClusters() { "zdo active 0x${device.deviceNetworkId}" }
116 "st rattr 0x${device.deviceNetworkId} 1 0x01 0x0020",
117 "st rattr 0x${device.deviceNetworkId} 1 0x06 0x0000"
121 // Commands to device
130 private parseReportAttributeMessage(String description) {
131 Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
132 def nameAndValue = param.split(":")
133 map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
135 //log.debug "Desc Map: $descMap"
139 if (descMap.cluster == "0001" && descMap.attrId == "0020") {
140 log.debug "Received battery level report"
141 results = createEvent(getBatteryResult(Integer.parseInt(descMap.value, 16)))
147 //Converts the battery level response into a percentage to display in ST
148 //and creates appropriate message for given level
150 private getBatteryResult(rawValue) {
151 def linkText = getLinkText(device)
153 def result = [name: 'battery']
155 def volts = rawValue / 10
158 result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
163 def pct = (volts - minVolts) / (maxVolts - minVolts)
164 result.value = Math.min(100, (int) pct * 100)
165 result.descriptionText = "${linkText} battery was ${result.value}%"
171 private String swapEndianHex(String hex) {
172 reverseArray(hex.decodeHex()).encodeHex()
175 private byte[] reverseArray(byte[] array) {
177 int j = array.length - 1;