2 * Copyright 2015 SmartThings
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 namespace: "smartthings",
21 author: "SmartThings",
22 description: "Add your Ubi device to your SmartThings Account",
23 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn.png",
24 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn@2x.png",
25 oauth: [displayName: "Ubi", displayLink: ""]
29 section("Allow a web application to control these things...") {
30 input name: "switches", type: "capability.switch", title: "Which Switches?", multiple: true, required: false
31 input name: "motions", type: "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
32 input name: "locks", type: "capability.lock", title: "Which Locks?", multiple: true, required: false
33 input name: "contactSensors", type: "capability.contactSensor", title: "Which Contact Sensors?", multiple: true, required: false
34 input name: "presenceSensors", type: "capability.presenceSensor", title: "Which Presence Sensors?", multiple: true, required: false
54 PUT: "updateSwitches",
55 POST: "updateSwitches"
58 path("/switches/:id") {
65 path("/switches/subscriptions") {
66 log.debug "switches added"
68 POST: "addSwitchSubscription"
71 path("/switches/subscriptions/:id") {
73 DELETE: "removeSwitchSubscription",
74 GET: "removeSwitchSubscription"
78 path("/motionSensors") {
86 path("/motionSensors/:id") {
93 path("/motionSensors/subscriptions") {
94 log.debug "motionSensors added"
96 POST: "addMotionSubscription"
99 path("/motionSensors/subscriptions/:id") {
100 log.debug "motionSensors Deleted"
102 DELETE: "removeMotionSubscription",
103 GET: "removeMotionSubscription"
121 path("/locks/subscriptions") {
123 POST: "addLockSubscription"
126 path("/locks/subscriptions/:id") {
128 DELETE: "removeLockSubscription",
129 GET: "removeLockSubscription"
133 path("/contactSensors") {
135 GET: "listContactSensors",
136 PUT: "updateContactSensor",
137 POST: "updateContactSensor"
140 path("/contactSensors/:id") {
142 GET: "showContactSensor",
143 PUT: "updateContactSensor",
144 POST: "updateContactSensor"
147 path("/contactSensors/subscriptions") {
148 log.debug "contactSensors/subscriptions"
150 POST: "addContactSubscription"
153 path("/contactSensors/subscriptions/:id") {
155 DELETE: "removeContactSensorSubscription",
156 GET: "removeContactSensorSubscription"
160 path("/presenceSensors") {
162 GET: "listPresenceSensors",
163 PUT: "updatePresenceSensor",
164 POST: "updatePresenceSensor"
167 path("/presenceSensors/:id") {
169 GET: "showPresenceSensor",
170 PUT: "updatePresenceSensor",
171 POST: "updatePresenceSensor"
174 path("/presenceSensors/subscriptions") {
175 log.debug "PresenceSensors/subscriptions"
177 POST: "addPresenceSubscription"
180 path("/presenceSensors/subscriptions/:id") {
182 DELETE: "removePresenceSensorSubscription",
183 GET: "removePresenceSensorSubscription"
198 path("/phrases/:phraseName") {
200 GET: "executePhrase",
201 POST: "executePhrase",
208 // subscribe(motions, "motion.active", motionOpenHandler)
210 // subscribe(contactSensors, "contact.open", contactOpenHandler)
211 // log.trace "contactSensors Installed"
218 // subscribe(motions, "motion.active", motionOpenHandler)
219 // subscribe(contactSensors, "contact.open", contactOpenHandler)
221 //log.trace "contactSensors Updated"
226 listSwitches() + listMotions() + listLocks() + listContactSensors() + listPresenceSensors() + listPhrasesWithType()
229 def listContactSensors() {
230 contactSensors.collect { device(it, "contactSensor") }
234 void updateContactSensors() {
235 updateAll(contactSensors)
238 def showContactSensor() {
239 show(contactSensors, "contact")
242 void updateContactSensor() {
243 update(contactSensors)
246 def addContactSubscription() {
247 log.debug "addContactSensorSubscription, params: ${params}"
248 addSubscription(contactSensors, "contact")
251 def removeContactSensorSubscription() {
252 removeSubscription(contactSensors)
256 def listPresenceSensors() {
257 presenceSensors.collect { device(it, "presenceSensor") }
261 void updatePresenceSensors() {
262 updateAll(presenceSensors)
265 def showPresenceSensor() {
266 show(presenceSensors, "presence")
269 void updatePresenceSensor() {
270 update(presenceSensors)
273 def addPresenceSubscription() {
274 log.debug "addPresenceSensorSubscription, params: ${params}"
275 addSubscription(presenceSensors, "presence")
278 def removePresenceSensorSubscription() {
279 removeSubscription(presenceSensors)
284 switches.collect { device(it, "switch") }
287 void updateSwitches() {
292 show(switches, "switch")
295 void updateSwitch() {
299 def addSwitchSubscription() {
300 log.debug "addSwitchSubscription, params: ${params}"
301 addSubscription(switches, "switch")
304 def removeSwitchSubscription() {
305 removeSubscription(switches)
309 motions.collect { device(it, "motionSensor") }
312 void updateMotions() {
317 show(motions, "motion")
320 void updateMotion() {
324 def addMotionSubscription() {
326 addSubscription(motions, "motion")
329 def removeMotionSubscription() {
330 removeSubscription(motions)
334 locks.collect { device(it, "lock") }
349 def addLockSubscription() {
350 addSubscription(locks, "lock")
353 def removeLockSubscription() {
354 removeSubscription(locks)
358 def motionOpenHandler(evt) {
359 //log.trace "$evt.value: $evt, $settings"
361 log.debug "$motions was active, sending push message to user"
362 //sendPush("Your ${contact1.label ?: contact1.name} was opened")
365 httpPostJson(uri: "http://automatesolutions.ca/test.php", path: '', body: [evt: [value: "motionSensor Active"]]) {
366 log.debug "Event data successfully posted"
370 def contactOpenHandler(evt) {
371 //log.trace "$evt.value: $evt, $settings"
373 log.debug "$contactSensors was opened, sending push message to user"
374 //sendPush("Your ${contact1.label ?: contact1.name} was opened")
377 httpPostJson(uri: "http://automatesolutions.ca/test.php", path: '', body: [evt: [value: "ContactSensor Opened"]]) {
378 log.debug "Event data successfully posted"
386 def deviceHandler(evt) {
387 log.debug "~~~~~TEST~~~~~~"
388 def deviceInfo = state[evt.deviceId]
391 httpPostJson(uri: deviceInfo.callbackUrl, path: '', body: [evt: [value: evt.value]]) {
392 log.debug "Event data successfully posted"
397 log.debug "No subscribed device found"
406 def device = (switches + motions + locks).find { it.id == params.id }
409 httpError(404, "Switch not found")
413 device.events(params)
417 def listPhrasesWithType() {
418 location.helloHome.getPhrases().collect {
428 location.helloHome.getPhrases().label
431 def executePhrase() {
432 def phraseName = params.phraseName
435 location.helloHome.execute(phraseName)
436 log.debug "executed phrase: $phraseName"
440 httpError(404, "Phrase not found")
444 private void updateAll(devices) {
445 def type = params.param1
446 def command = request.JSON?.command
448 httpError(404, "Devices not found")
451 devices.each { device ->
452 executeCommand(device, type, command)
457 private void update(devices) {
458 log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id"
459 def type = params.param1
460 def command = request.JSON?.command
461 def device = devices?.find { it.id == params.id }
464 httpError(404, "Device not found")
468 executeCommand(device, type, command)
473 * Validating the command passed by the user based on capability.
476 def validateCommand(device, deviceType, command) {
477 def capabilityCommands = getDeviceCapabilityCommands(device.capabilities)
478 def currentDeviceCapability = getCapabilityName(deviceType)
479 if (capabilityCommands[currentDeviceCapability]) {
480 return command in capabilityCommands[currentDeviceCapability] ? true : false
482 // Handling other device types here, which don't accept commands
483 httpError(400, "Bad request.")
488 * Need to get the attribute name to do the lookup. Only
489 * doing it for the device types which accept commands
490 * @return attribute name of the device type
492 def getCapabilityName(type) {
504 * Constructing the map over here of
505 * supported commands by device capability
506 * @return a map of device capability -> supported commands
508 def getDeviceCapabilityCommands(deviceCapabilities) {
510 deviceCapabilities.collect {
511 map[it.name] = it.commands.collect{ it.name.toString() }
517 * Validates and executes the command
518 * on the device or devices
520 def executeCommand(device, type, command) {
521 if (validateCommand(device, type, command)) {
524 httpError(403, "Access denied. This command is not supported by current capability.")
528 private show(devices, type) {
529 def device = devices.find { it.id == params.id }
532 httpError(404, "Device not found")
536 def attributeName = type
538 def s = device.currentState(attributeName)
539 [id: device.id, label: device.displayName, value: s?.value, unitTime: s?.date?.time, type: type]
543 private addSubscription(devices, attribute) {
544 //def deviceId = request.JSON?.deviceId
545 //def callbackUrl = request.JSON?.callbackUrl
547 log.debug "addSubscription, params: ${params}"
549 def deviceId = params.deviceId
550 def callbackUrl = params.callbackUrl
552 def myDevice = devices.find { it.id == deviceId }
555 log.debug "Adding switch subscription" + callbackUrl
556 state[deviceId] = [callbackUrl: callbackUrl]
557 log.debug "Added state: $state"
558 def subscription = subscribe(myDevice, attribute, deviceHandler)
559 if (subscription && subscription.eventSubscription) {
560 log.debug "Subscription is newly created"
562 log.debug "Subscription already exists, returning existing subscription"
563 subscription = app.subscriptions?.find { it.deviceId == deviceId && it.data == attribute && it.handler == 'deviceHandler' }
567 deviceId: subscription.deviceId,
568 data: subscription.data,
569 handler: subscription.handler,
570 callbackUrl: callbackUrl
575 private removeSubscription(devices) {
576 def deviceId = params.id
577 def device = devices.find { it.id == deviceId }
580 log.debug "Removing $device.displayName subscription"
581 state.remove(device.id)
586 private device(it, type) {
587 it ? [id: it.id, label: it.displayName, type: type] : null