Update WindowOrDoorOpen.groovy
[smartapps.git] / official / alfred-workflow.groovy
1 /**
2  *  Copyright 2015 SmartThings
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  *  in compliance with the License. You may obtain a copy of the License at:
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
10  *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
11  *  for the specific language governing permissions and limitations under the License.
12  *
13  *  Alfred Workflow
14  *
15  *  Author: SmartThings
16  */
17
18 definition(
19     name: "Alfred Workflow",
20     namespace: "vlaminck",
21     author: "SmartThings",
22     description: "This SmartApp allows you to interact with the things in your physical graph through Alfred.",
23     category: "Convenience",
24     iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app.png",
25     iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app@2x.png",
26     oauth: [displayName: "SmartThings Alfred Workflow", displayLink: ""]
27 )
28
29 preferences {
30         section("Allow Alfred to Control These Things...") {
31                 input "switches", "capability.switch", title: "Which Switches?", multiple: true, required: false
32         input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
33         }
34 }
35
36 mappings {
37         path("/switches") {
38                 action: [
39                         GET: "listSwitches",
40                         PUT: "updateSwitches"
41                 ]
42         }
43         path("/switches/:id") {
44                 action: [
45                         GET: "showSwitch",
46                         PUT: "updateSwitch"
47                 ]
48         }
49     path("/locks") {
50                 action: [
51                         GET: "listLocks",
52                         PUT: "updateLocks"
53                 ]
54         }
55         path("/locks/:id") {
56                 action: [
57                         GET: "showLock",
58                         PUT: "updateLock"
59                 ]
60         }
61 }
62
63 def installed() {}
64
65 def updated() {}
66
67 def listSwitches() {
68         switches.collect { device(it,"switch") }
69 }
70 void updateSwitches() {
71         updateAll(switches)
72 }
73 def showSwitch() {
74         show(switches, "switch")
75 }
76 void updateSwitch() {
77         update(switches)
78 }
79
80 def listLocks() {
81         locks.collect { device(it, "lock") }
82 }
83 void updateLocks() {
84         updateAll(locks)
85 }
86 def showLock() {
87         show(locks, "lock")
88 }
89 void updateLock() {
90         update(locks)
91 }
92
93 private void updateAll(devices) {
94         def command = request.JSON?.command
95         def type = params.param1
96         if (!devices) {
97                 httpError(404, "Devices not found")
98         }
99         
100         if (command){
101                 devices.each { device ->
102                         executeCommand(device, type, command)
103                 }
104         }
105 }
106
107 private void update(devices) {
108         log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id"
109         def command = request.JSON?.command
110         def type = params.param1
111         def device = devices?.find { it.id == params.id }
112
113         if (!device) {
114                 httpError(404, "Device not found")
115         }
116
117         if (command) {
118                 executeCommand(device, type, command)
119         }
120 }
121
122 /**
123  * Validating the command passed by the user based on capability.
124  * @return boolean
125  */
126 def validateCommand(device, deviceType, command) {
127         def capabilityCommands = getDeviceCapabilityCommands(device.capabilities)
128         def currentDeviceCapability = getCapabilityName(deviceType)
129         if (capabilityCommands[currentDeviceCapability]) {
130                 return command in capabilityCommands[currentDeviceCapability] ? true : false
131         } else {
132                 // Handling other device types here, which don't accept commands
133                 httpError(400, "Bad request.")
134         }
135 }
136
137 /**
138  * Need to get the attribute name to do the lookup. Only
139  * doing it for the device types which accept commands
140  * @return attribute name of the device type
141  */
142 def getCapabilityName(type) {
143     switch(type) {
144                 case "switches":
145                         return "Switch"
146                 case "locks":
147                         return "Lock"
148                 default:
149                         return type
150         }
151 }
152
153 /**
154  * Constructing the map over here of
155  * supported commands by device capability
156  * @return a map of device capability -> supported commands
157  */
158 def getDeviceCapabilityCommands(deviceCapabilities) {
159         def map = [:]
160         deviceCapabilities.collect {
161                 map[it.name] = it.commands.collect{ it.name.toString() }
162         }
163         return map
164 }
165
166 /**
167  * Validates and executes the command
168  * on the device or devices
169  */
170 def executeCommand(device, type, command) {
171         if (validateCommand(device, type, command)) {
172                 device."$command"()
173         } else {
174                 httpError(403, "Access denied. This command is not supported by current capability.")
175         }       
176 }
177
178 private show(devices, name) {
179         def device = devices.find { it.id == params.id }
180         if (!device) {
181                 httpError(404, "Device not found")
182         }
183         else {
184                 def s = device.currentState(name)
185                 [id: device.id, label: device.displayName, name: device.displayName, state: s]
186         }
187 }
188
189 private device(it, name) {
190         if (it) {
191                 def s = it.currentState(name)
192                 [id: it.id, label: it.displayName, name: it.displayName, state: s]
193     }
194 }