Update WindowOrDoorOpen.groovy
[smartapps.git] / third-party / Orbit Water Timer.groovy
1 metadata {
2         // Automatically generated. Make future change here.
3         definition (name: "Orbit Water Timer", namespace: "mitchpond", author: "Mitch Pond") {
4                 capability "Actuator"
5                 capability "Switch"
6                 capability "Sensor"
7         capability "Configuration"
8         capability "Refresh"
9         
10         command "test"
11         command "identify"
12         command "getClusters"
13
14         fingerprint endpointId: "01", profileId: "0104", inClusters: "0000,0001,0003,0020,0006,0201", outClusters: "000A,0019"
15         }
16
17         // UI tile definitions
18         tiles {
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"
24                 }
25                 valueTile("battery", "device.battery", decoration: "flat") {
26                         state "battery", label:'${currentValue}% battery', unit:""
27                 }
28                 standardTile("configure", "device.configure", decoration: "flat") {
29                         state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
30                 }
31                 standardTile("refresh", "command.refresh", decoration: "flat") {
32                         state "default", label: '', action: 'refresh.refresh', icon: 'st.secondary.refresh'
33                 }
34
35                 main "switch"
36                 details (["switch","battery","refresh","configure"])
37         }
38 }
39
40 // Parse incoming device messages to generate events
41 def parse(String description) {
42         log.debug("Raw: $description")
43     
44         if (description?.startsWith("catchall:")) {
45                 def report = zigbee.parse(description)
46                 switch(report.clusterId) {
47                         case 0x0020:
48                                 log.debug "Received Poll Control packet"
49                         break
50                         case 0x0006:
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
55                         break
56         }
57     }
58     else if (description?.startsWith('read attr -')) {
59         return parseReportAttributeMessage(description)
60     }
61     //log.debug(report)
62     
63     
64 }
65
66 //Perform initial device setup and binding
67 def configure(){
68         log.debug("Running configure for Orbit timer...")
69     
70         [
71         "zcl global send-me-a-report 0x06 0x00 0x10 0 3600 {}", "delay 200",
72         "send 0x${device.deviceNetworkId} 1 1", "delay 500",
73     
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      
76     
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"
80         ]
81         refresh()
82 }
83
84 /* successful attribute reads
85 //battery voltage
86 "st rattr 0x${device.deviceNetworkId} 1 0x01 0x0020", "delay 500",
87
88 //cluster 20 poll control check-in is being sent by device. Should be able to alter polling duration and start fast poll
89
90
91
92 */
93
94 def test(){
95         [
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"
104     ]
105     //getClusters()
106     //def report = zigbee.parse('catchall: 0104 0020 01 01 0140 00 20C4 00 00 0000 04 01')
107     //log.debug report
108     //log.debug "Command is: ${report.command}"
109     //log.debug((report.command) == 0x01)
110 }
111 def identify() {"st cmd 0x${device.deviceNetworkId} 1 3 0 {0A 00}"}
112 def getClusters() { "zdo active 0x${device.deviceNetworkId}" }
113
114 def refresh() {
115         delayBetween([
116                 "st rattr 0x${device.deviceNetworkId} 1 0x01 0x0020",
117                 "st rattr 0x${device.deviceNetworkId} 1 0x06 0x0000"
118                 ],750)
119 }
120
121 // Commands to device
122 def on() {
123         'zcl on-off on'
124 }
125
126 def off() {
127         'zcl on-off off'
128 }
129
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()]
134         }
135         //log.debug "Desc Map: $descMap"
136
137         def results = []
138     
139         if (descMap.cluster == "0001" && descMap.attrId == "0020") {
140                 log.debug "Received battery level report"
141                 results = createEvent(getBatteryResult(Integer.parseInt(descMap.value, 16)))
142         }
143
144         return results
145 }
146
147 //Converts the battery level response into a percentage to display in ST
148 //and creates appropriate message for given level
149
150 private getBatteryResult(rawValue) {
151         def linkText = getLinkText(device)
152
153         def result = [name: 'battery']
154
155         def volts = rawValue / 10
156         def descriptionText
157         if (volts > 3.5) {
158                 result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
159         }
160         else {
161                 def minVolts = 2.1
162                 def maxVolts = 3.0
163                 def pct = (volts - minVolts) / (maxVolts - minVolts)
164                 result.value = Math.min(100, (int) pct * 100)
165                 result.descriptionText = "${linkText} battery was ${result.value}%"
166         }
167
168         return result
169 }
170
171 private String swapEndianHex(String hex) {
172         reverseArray(hex.decodeHex()).encodeHex()
173 }
174
175 private byte[] reverseArray(byte[] array) {
176         int i = 0;
177         int j = array.length - 1;
178         byte tmp;
179         while (j > i) {
180                 tmp = array[j];
181                 array[j] = array[i];
182                 array[i] = tmp;
183                 j--;
184                 i++;
185         }
186         return array
187 }