mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
- now validating commands per capability of the device in the smartapp removed commented out code
589 lines
12 KiB
Groovy
589 lines
12 KiB
Groovy
/**
|
|
* Copyright 2015 SmartThings
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
* in compliance with the License. You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing permissions and limitations under the License.
|
|
*
|
|
* Ubi
|
|
*
|
|
* Author: SmartThings
|
|
*/
|
|
|
|
definition(
|
|
name: "Ubi",
|
|
namespace: "smartthings",
|
|
author: "SmartThings",
|
|
description: "Add your Ubi device to your SmartThings Account",
|
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn.png",
|
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn@2x.png",
|
|
oauth: [displayName: "Ubi", displayLink: ""]
|
|
)
|
|
|
|
preferences {
|
|
section("Allow a web application to control these things...") {
|
|
input name: "switches", type: "capability.switch", title: "Which Switches?", multiple: true, required: false
|
|
input name: "motions", type: "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
|
|
input name: "locks", type: "capability.lock", title: "Which Locks?", multiple: true, required: false
|
|
input name: "contactSensors", type: "capability.contactSensor", title: "Which Contact Sensors?", multiple: true, required: false
|
|
input name: "presenceSensors", type: "capability.presenceSensor", title: "Which Presence Sensors?", multiple: true, required: false
|
|
}
|
|
}
|
|
|
|
mappings {
|
|
path("/list") {
|
|
action: [
|
|
GET: "listAll"
|
|
]
|
|
}
|
|
|
|
path("/events/:id") {
|
|
action: [
|
|
GET: "showEvents"
|
|
]
|
|
}
|
|
|
|
path("/switches") {
|
|
action: [
|
|
GET: "listSwitches",
|
|
PUT: "updateSwitches",
|
|
POST: "updateSwitches"
|
|
]
|
|
}
|
|
path("/switches/:id") {
|
|
action: [
|
|
GET: "showSwitch",
|
|
PUT: "updateSwitch",
|
|
POST: "updateSwitch"
|
|
]
|
|
}
|
|
path("/switches/subscriptions") {
|
|
log.debug "switches added"
|
|
action: [
|
|
POST: "addSwitchSubscription"
|
|
]
|
|
}
|
|
path("/switches/subscriptions/:id") {
|
|
action: [
|
|
DELETE: "removeSwitchSubscription",
|
|
GET: "removeSwitchSubscription"
|
|
]
|
|
}
|
|
|
|
path("/motionSensors") {
|
|
action: [
|
|
GET: "listMotions",
|
|
PUT: "updateMotions",
|
|
POST: "updateMotions"
|
|
|
|
]
|
|
}
|
|
path("/motionSensors/:id") {
|
|
action: [
|
|
GET: "showMotion",
|
|
PUT: "updateMotion",
|
|
POST: "updateMotion"
|
|
]
|
|
}
|
|
path("/motionSensors/subscriptions") {
|
|
log.debug "motionSensors added"
|
|
action: [
|
|
POST: "addMotionSubscription"
|
|
]
|
|
}
|
|
path("/motionSensors/subscriptions/:id") {
|
|
log.debug "motionSensors Deleted"
|
|
action: [
|
|
DELETE: "removeMotionSubscription",
|
|
GET: "removeMotionSubscription"
|
|
]
|
|
}
|
|
|
|
path("/locks") {
|
|
action: [
|
|
GET: "listLocks",
|
|
PUT: "updateLocks",
|
|
POST: "updateLocks"
|
|
]
|
|
}
|
|
path("/locks/:id") {
|
|
action: [
|
|
GET: "showLock",
|
|
PUT: "updateLock",
|
|
POST: "updateLock"
|
|
]
|
|
}
|
|
path("/locks/subscriptions") {
|
|
action: [
|
|
POST: "addLockSubscription"
|
|
]
|
|
}
|
|
path("/locks/subscriptions/:id") {
|
|
action: [
|
|
DELETE: "removeLockSubscription",
|
|
GET: "removeLockSubscription"
|
|
]
|
|
}
|
|
|
|
path("/contactSensors") {
|
|
action: [
|
|
GET: "listContactSensors",
|
|
PUT: "updateContactSensor",
|
|
POST: "updateContactSensor"
|
|
]
|
|
}
|
|
path("/contactSensors/:id") {
|
|
action: [
|
|
GET: "showContactSensor",
|
|
PUT: "updateContactSensor",
|
|
POST: "updateContactSensor"
|
|
]
|
|
}
|
|
path("/contactSensors/subscriptions") {
|
|
log.debug "contactSensors/subscriptions"
|
|
action: [
|
|
POST: "addContactSubscription"
|
|
]
|
|
}
|
|
path("/contactSensors/subscriptions/:id") {
|
|
action: [
|
|
DELETE: "removeContactSensorSubscription",
|
|
GET: "removeContactSensorSubscription"
|
|
]
|
|
}
|
|
|
|
path("/presenceSensors") {
|
|
action: [
|
|
GET: "listPresenceSensors",
|
|
PUT: "updatePresenceSensor",
|
|
POST: "updatePresenceSensor"
|
|
]
|
|
}
|
|
path("/presenceSensors/:id") {
|
|
action: [
|
|
GET: "showPresenceSensor",
|
|
PUT: "updatePresenceSensor",
|
|
POST: "updatePresenceSensor"
|
|
]
|
|
}
|
|
path("/presenceSensors/subscriptions") {
|
|
log.debug "PresenceSensors/subscriptions"
|
|
action: [
|
|
POST: "addPresenceSubscription"
|
|
]
|
|
}
|
|
path("/presenceSensors/subscriptions/:id") {
|
|
action: [
|
|
DELETE: "removePresenceSensorSubscription",
|
|
GET: "removePresenceSensorSubscription"
|
|
]
|
|
}
|
|
|
|
path("/state") {
|
|
action: [
|
|
GET: "currentState"
|
|
]
|
|
}
|
|
|
|
path("/phrases") {
|
|
action: [
|
|
GET: "listPhrases"
|
|
]
|
|
}
|
|
path("/phrases/:phraseName") {
|
|
action: [
|
|
GET: "executePhrase",
|
|
POST: "executePhrase",
|
|
]
|
|
}
|
|
|
|
}
|
|
|
|
def installed() {
|
|
// subscribe(motions, "motion.active", motionOpenHandler)
|
|
|
|
// subscribe(contactSensors, "contact.open", contactOpenHandler)
|
|
// log.trace "contactSensors Installed"
|
|
|
|
}
|
|
|
|
def updated() {
|
|
|
|
// unsubscribe()
|
|
// subscribe(motions, "motion.active", motionOpenHandler)
|
|
// subscribe(contactSensors, "contact.open", contactOpenHandler)
|
|
|
|
//log.trace "contactSensors Updated"
|
|
|
|
}
|
|
|
|
def listAll() {
|
|
listSwitches() + listMotions() + listLocks() + listContactSensors() + listPresenceSensors() + listPhrasesWithType()
|
|
}
|
|
|
|
def listContactSensors() {
|
|
contactSensors.collect { device(it, "contactSensor") }
|
|
}
|
|
|
|
|
|
void updateContactSensors() {
|
|
updateAll(contactSensors)
|
|
}
|
|
|
|
def showContactSensor() {
|
|
show(contactSensors, "contact")
|
|
}
|
|
|
|
void updateContactSensor() {
|
|
update(contactSensors)
|
|
}
|
|
|
|
def addContactSubscription() {
|
|
log.debug "addContactSensorSubscription, params: ${params}"
|
|
addSubscription(contactSensors, "contact")
|
|
}
|
|
|
|
def removeContactSensorSubscription() {
|
|
removeSubscription(contactSensors)
|
|
}
|
|
|
|
|
|
def listPresenceSensors() {
|
|
presenceSensors.collect { device(it, "presenceSensor") }
|
|
}
|
|
|
|
|
|
void updatePresenceSensors() {
|
|
updateAll(presenceSensors)
|
|
}
|
|
|
|
def showPresenceSensor() {
|
|
show(presenceSensors, "presence")
|
|
}
|
|
|
|
void updatePresenceSensor() {
|
|
update(presenceSensors)
|
|
}
|
|
|
|
def addPresenceSubscription() {
|
|
log.debug "addPresenceSensorSubscription, params: ${params}"
|
|
addSubscription(presenceSensors, "presence")
|
|
}
|
|
|
|
def removePresenceSensorSubscription() {
|
|
removeSubscription(presenceSensors)
|
|
}
|
|
|
|
|
|
def listSwitches() {
|
|
switches.collect { device(it, "switch") }
|
|
}
|
|
|
|
void updateSwitches() {
|
|
updateAll(switches)
|
|
}
|
|
|
|
def showSwitch() {
|
|
show(switches, "switch")
|
|
}
|
|
|
|
void updateSwitch() {
|
|
update(switches)
|
|
}
|
|
|
|
def addSwitchSubscription() {
|
|
log.debug "addSwitchSubscription, params: ${params}"
|
|
addSubscription(switches, "switch")
|
|
}
|
|
|
|
def removeSwitchSubscription() {
|
|
removeSubscription(switches)
|
|
}
|
|
|
|
def listMotions() {
|
|
motions.collect { device(it, "motionSensor") }
|
|
}
|
|
|
|
void updateMotions() {
|
|
updateAll(motions)
|
|
}
|
|
|
|
def showMotion() {
|
|
show(motions, "motion")
|
|
}
|
|
|
|
void updateMotion() {
|
|
update(motions)
|
|
}
|
|
|
|
def addMotionSubscription() {
|
|
|
|
addSubscription(motions, "motion")
|
|
}
|
|
|
|
def removeMotionSubscription() {
|
|
removeSubscription(motions)
|
|
}
|
|
|
|
def listLocks() {
|
|
locks.collect { device(it, "lock") }
|
|
}
|
|
|
|
void updateLocks() {
|
|
updateAll(locks)
|
|
}
|
|
|
|
def showLock() {
|
|
show(locks, "lock")
|
|
}
|
|
|
|
void updateLock() {
|
|
update(locks)
|
|
}
|
|
|
|
def addLockSubscription() {
|
|
addSubscription(locks, "lock")
|
|
}
|
|
|
|
def removeLockSubscription() {
|
|
removeSubscription(locks)
|
|
}
|
|
|
|
/*
|
|
def motionOpenHandler(evt) {
|
|
//log.trace "$evt.value: $evt, $settings"
|
|
|
|
log.debug "$motions was active, sending push message to user"
|
|
//sendPush("Your ${contact1.label ?: contact1.name} was opened")
|
|
|
|
|
|
httpPostJson(uri: "http://automatesolutions.ca/test.php", path: '', body: [evt: [value: "motionSensor Active"]]) {
|
|
log.debug "Event data successfully posted"
|
|
}
|
|
|
|
}
|
|
def contactOpenHandler(evt) {
|
|
//log.trace "$evt.value: $evt, $settings"
|
|
|
|
log.debug "$contactSensors was opened, sending push message to user"
|
|
//sendPush("Your ${contact1.label ?: contact1.name} was opened")
|
|
|
|
|
|
httpPostJson(uri: "http://automatesolutions.ca/test.php", path: '', body: [evt: [value: "ContactSensor Opened"]]) {
|
|
log.debug "Event data successfully posted"
|
|
}
|
|
|
|
|
|
}
|
|
*/
|
|
|
|
|
|
def deviceHandler(evt) {
|
|
log.debug "~~~~~TEST~~~~~~"
|
|
def deviceInfo = state[evt.deviceId]
|
|
if (deviceInfo)
|
|
{
|
|
httpPostJson(uri: deviceInfo.callbackUrl, path: '', body: [evt: [value: evt.value]]) {
|
|
log.debug "Event data successfully posted"
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log.debug "No subscribed device found"
|
|
}
|
|
}
|
|
|
|
def currentState() {
|
|
state
|
|
}
|
|
|
|
def showStates() {
|
|
def device = (switches + motions + locks).find { it.id == params.id }
|
|
if (!device)
|
|
{
|
|
httpError(404, "Switch not found")
|
|
}
|
|
else
|
|
{
|
|
device.events(params)
|
|
}
|
|
}
|
|
|
|
def listPhrasesWithType() {
|
|
location.helloHome.getPhrases().collect {
|
|
[
|
|
"id" : it.id,
|
|
"label": it.label,
|
|
"type" : "phrase"
|
|
]
|
|
}
|
|
}
|
|
|
|
def listPhrases() {
|
|
location.helloHome.getPhrases().label
|
|
}
|
|
|
|
def executePhrase() {
|
|
def phraseName = params.phraseName
|
|
if (phraseName)
|
|
{
|
|
location.helloHome.execute(phraseName)
|
|
log.debug "executed phrase: $phraseName"
|
|
}
|
|
else
|
|
{
|
|
httpError(404, "Phrase not found")
|
|
}
|
|
}
|
|
|
|
private void updateAll(devices) {
|
|
def type = params.param1
|
|
def command = request.JSON?.command
|
|
if (!devices) {
|
|
httpError(404, "Devices not found")
|
|
}
|
|
if (command){
|
|
devices.each { device ->
|
|
executeCommand(device, type, command)
|
|
}
|
|
}
|
|
}
|
|
|
|
private void update(devices) {
|
|
log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id"
|
|
def type = params.param1
|
|
def command = request.JSON?.command
|
|
def device = devices?.find { it.id == params.id }
|
|
|
|
if (!device) {
|
|
httpError(404, "Device not found")
|
|
}
|
|
|
|
if (command) {
|
|
executeCommand(device, type, command)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validating the command passed by the user based on capability.
|
|
* @return boolean
|
|
*/
|
|
def validateCommand(device, deviceType, command) {
|
|
def capabilityCommands = getDeviceCapabilityCommands(device.capabilities)
|
|
def currentDeviceCapability = getCapabilityName(deviceType)
|
|
if (capabilityCommands[currentDeviceCapability]) {
|
|
return command in capabilityCommands[currentDeviceCapability] ? true : false
|
|
} else {
|
|
// Handling other device types here, which don't accept commands
|
|
httpError(400, "Bad request.")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Need to get the attribute name to do the lookup. Only
|
|
* doing it for the device types which accept commands
|
|
* @return attribute name of the device type
|
|
*/
|
|
def getCapabilityName(type) {
|
|
switch(type) {
|
|
case "switches":
|
|
return "Switch"
|
|
case "locks":
|
|
return "Lock"
|
|
default:
|
|
return type
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Constructing the map over here of
|
|
* supported commands by device capability
|
|
* @return a map of device capability -> supported commands
|
|
*/
|
|
def getDeviceCapabilityCommands(deviceCapabilities) {
|
|
def map = [:]
|
|
deviceCapabilities.collect {
|
|
map[it.name] = it.commands.collect{ it.name.toString() }
|
|
}
|
|
return map
|
|
}
|
|
|
|
/**
|
|
* Validates and executes the command
|
|
* on the device or devices
|
|
*/
|
|
def executeCommand(device, type, command) {
|
|
if (validateCommand(device, type, command)) {
|
|
device."$command"()
|
|
} else {
|
|
httpError(403, "Access denied. This command is not supported by current capability.")
|
|
}
|
|
}
|
|
|
|
private show(devices, type) {
|
|
def device = devices.find { it.id == params.id }
|
|
if (!device)
|
|
{
|
|
httpError(404, "Device not found")
|
|
}
|
|
else
|
|
{
|
|
def attributeName = type
|
|
|
|
def s = device.currentState(attributeName)
|
|
[id: device.id, label: device.displayName, value: s?.value, unitTime: s?.date?.time, type: type]
|
|
}
|
|
}
|
|
|
|
private addSubscription(devices, attribute) {
|
|
//def deviceId = request.JSON?.deviceId
|
|
//def callbackUrl = request.JSON?.callbackUrl
|
|
|
|
log.debug "addSubscription, params: ${params}"
|
|
|
|
def deviceId = params.deviceId
|
|
def callbackUrl = params.callbackUrl
|
|
|
|
def myDevice = devices.find { it.id == deviceId }
|
|
if (myDevice)
|
|
{
|
|
log.debug "Adding switch subscription" + callbackUrl
|
|
state[deviceId] = [callbackUrl: callbackUrl]
|
|
log.debug "Added state: $state"
|
|
def subscription = subscribe(myDevice, attribute, deviceHandler)
|
|
if (subscription && subscription.eventSubscription) {
|
|
log.debug "Subscription is newly created"
|
|
} else {
|
|
log.debug "Subscription already exists, returning existing subscription"
|
|
subscription = app.subscriptions?.find { it.deviceId == deviceId && it.data == attribute && it.handler == 'deviceHandler' }
|
|
}
|
|
[
|
|
id: subscription.id,
|
|
deviceId: subscription.deviceId,
|
|
data: subscription.data,
|
|
handler: subscription.handler,
|
|
callbackUrl: callbackUrl
|
|
]
|
|
}
|
|
}
|
|
|
|
private removeSubscription(devices) {
|
|
def deviceId = params.id
|
|
def device = devices.find { it.id == deviceId }
|
|
if (device)
|
|
{
|
|
log.debug "Removing $device.displayName subscription"
|
|
state.remove(device.id)
|
|
unsubscribe(device)
|
|
}
|
|
}
|
|
|
|
private device(it, type) {
|
|
it ? [id: it.id, label: it.displayName, type: type] : null
|
|
}
|