mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
MSA-1577: This SmartApp enables the end-to-end SmartThings scenarios via OpenT2T. More information on OpenT2T can be found at http://www.opentranslatorstothings.org/#/
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* OpenT2T SmartApp Test
|
||||
*
|
||||
* Copyright 2016 OpenT2T
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
definition(
|
||||
name: "OpenT2T SmartApp Test",
|
||||
namespace: "opent2t",
|
||||
author: "OpenT2T",
|
||||
description: "Test app to test end to end SmartThings scenarios via OpenT2T",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
||||
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
|
||||
|
||||
//Device Inputs
|
||||
preferences {
|
||||
section("Allow OpenT2T Test SmartApp to control these things...") {
|
||||
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false
|
||||
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
|
||||
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false
|
||||
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false
|
||||
input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false
|
||||
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
|
||||
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false
|
||||
input "cameras", "capability.videoCamera", title: "Which Cameras?", multiple: true, required: false
|
||||
}
|
||||
}
|
||||
|
||||
//API external Endpoints
|
||||
mappings {
|
||||
path("/subscriptionURL/:url") {
|
||||
action: [
|
||||
PUT: "updateEndpointURL"
|
||||
]
|
||||
}
|
||||
path("/connectionId/:connId") {
|
||||
action: [
|
||||
PUT: "updateConnectionId"
|
||||
]
|
||||
}
|
||||
path("/devices") {
|
||||
action: [
|
||||
GET: "getDevices"
|
||||
]
|
||||
}
|
||||
path("/devices/:id") {
|
||||
action: [
|
||||
GET: "getDevice"
|
||||
]
|
||||
}
|
||||
path("/update/:id") {
|
||||
action: [
|
||||
PUT: "updateDevice"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
state.connectionId = ""
|
||||
state.endpointURL = "https://ifs.windows-int.com/v1/cb/81C7E77B-EABC-488A-B2BF-FEC42F0DABD2/notify"
|
||||
registerSubscriptions()
|
||||
}
|
||||
|
||||
//Register events for each device
|
||||
def registerSubscriptions() {
|
||||
registerChangeHandler(switches)
|
||||
registerChangeHandler(motionSensors)
|
||||
registerChangeHandler(presenceSensors)
|
||||
registerChangeHandler(contactSensors)
|
||||
registerChangeHandler(waterSensors)
|
||||
registerChangeHandler(locks)
|
||||
registerChangeHandler(garageDoors)
|
||||
registerChangeHandler(cameras)
|
||||
}
|
||||
|
||||
def registerChangeHandler(myList) {
|
||||
myList.each { myDevice ->
|
||||
def theAtts = myDevice.supportedAttributes
|
||||
theAtts.each {att ->
|
||||
subscribe(myDevice, att.name, eventHandler)
|
||||
log.debug "Registering ${myDevice.displayName}.${att.name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//When events are triggered, send HTTP post to web socket servers
|
||||
def eventHandler(evt) {
|
||||
|
||||
def evt_device_id = evt.deviceId
|
||||
def evt_device_value = evt.value
|
||||
def evt_name = evt.name
|
||||
def evt_device = evt.device
|
||||
def evt_deviceType = getDeviceType(evt_device);
|
||||
def params = [
|
||||
uri: "${state.endpointURL}/${state.connectionId}",
|
||||
body: [
|
||||
name: evt_device.displayName,
|
||||
id: evt_device.id,
|
||||
deviceType:evt_deviceType,
|
||||
attributes: deviceAttributeList(evt_device)
|
||||
]
|
||||
]
|
||||
try {
|
||||
log.debug "POST URI: ${params.uri}"
|
||||
log.debug "Payload: ${params.body}"
|
||||
httpPostJson(params) { resp ->
|
||||
resp.headers.each {
|
||||
log.debug "${it.name} : ${it.value}"
|
||||
}
|
||||
log.debug "response status code: ${resp.status}"
|
||||
log.debug "response data: ${resp.data}"
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug "something went wrong: $e"
|
||||
}
|
||||
}
|
||||
|
||||
//Endpoints function; update subcription endpoint url [state.endpoint]
|
||||
void updateEndpointURL() {
|
||||
state.endpointURL = params.url
|
||||
log.debug "Updated EndpointURL to ${state.endpointURL}"
|
||||
}
|
||||
|
||||
//Endpoints function; update global variable [state.connectionId]
|
||||
void updateConnectionId() {
|
||||
def connId = params.connId
|
||||
state.connectionId = connId
|
||||
log.debug "Updated ConnectionID to ${state.connectionId}"
|
||||
}
|
||||
|
||||
//Endpoints functions; return data from all devices supported in JSON format
|
||||
def getDevices() {
|
||||
def deviceData = []
|
||||
switches.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
motionSensors.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
contactSensors.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
presenceSensors.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
waterSensors.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
locks.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
garageDoors.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
cameras.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
}
|
||||
log.debug "getDevices, return: ${deviceData}"
|
||||
return deviceData
|
||||
}
|
||||
|
||||
//Endpoints functions; return data from a specific device in JSON format
|
||||
def getDevice() {
|
||||
def it = findDevice(params.id)
|
||||
def deviceType = getDeviceType(it)
|
||||
def device = [name: it.displayName, id: it.id, deviceType:deviceType, attributes: deviceAttributeList(it)]
|
||||
log.debug "getDevice, return: ${device}"
|
||||
return device
|
||||
}
|
||||
|
||||
//Endpoints functions; update device data
|
||||
void updateDevice() {
|
||||
def device = findDevice(params.id)
|
||||
request.JSON.each {
|
||||
def command = it.key
|
||||
def value = it.value
|
||||
if (command){
|
||||
def commandList = mapDeviceCommands(command, value)
|
||||
command = commandList[0]
|
||||
value = commandList[1]
|
||||
if (!device) {
|
||||
log.debug "updateDevice, Device not found"
|
||||
httpError(404, "Device not found")
|
||||
} else if (!device.hasCommand(command)) {
|
||||
log.debug "updateDevice, Device does not have the command"
|
||||
httpError(404, "Device does not have the command")
|
||||
} else {
|
||||
if (command == "setColor") {
|
||||
log.debug "Update: [${command}, ${value}], device: ${device}"
|
||||
device."$command"(hex: value)
|
||||
} else if(value.isNumber()) {
|
||||
def intValue = value as Integer
|
||||
log.debug "Update: [${command}, ${intValue}(int)]"
|
||||
device."$command"(intValue)
|
||||
} else if (value){
|
||||
log.debug "Update: [${command}, ${value}]"
|
||||
device."$command"(value)
|
||||
} else {
|
||||
device."$command"()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Private Functions; manually map each device to a type given it's capabilities
|
||||
private getDeviceType(device) {
|
||||
def deviceType
|
||||
def caps = device.capabilities
|
||||
caps.each {
|
||||
log.debug "capabilities: [${device}, ${caps}]"
|
||||
if(it.name.toLowerCase().contains("switch")) {
|
||||
deviceType = "switch"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("water")) {
|
||||
deviceType = "waterSensor"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("motion")) {
|
||||
deviceType = "motionSensor"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("presence")) {
|
||||
deviceType = "presenceSensor"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("contact")) {
|
||||
deviceType = "contactSensor"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("lock")) {
|
||||
deviceType = "lock"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("level")) {
|
||||
deviceType = "light"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("garageDoorControl")) {
|
||||
deviceType = "garageDoor"
|
||||
}
|
||||
if(it.name.toLowerCase().contains("video")) {
|
||||
deviceType = "camera"
|
||||
}
|
||||
}
|
||||
return deviceType
|
||||
}
|
||||
|
||||
//Private Functions; return device
|
||||
private findDevice(deviceId) {
|
||||
def device = switches.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = motionSensors.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = waterSensors.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = contactSensors.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = presenceSensors.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = locks.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = garageDoors.find { it.id == deviceId }
|
||||
if (device) return device
|
||||
device = cameras.find { it.id == deviceId }
|
||||
return device
|
||||
}
|
||||
|
||||
//Private Functions; return a list of device attributes
|
||||
private deviceAttributeList(device) {
|
||||
device.supportedAttributes.collectEntries { attribute->
|
||||
try {
|
||||
[
|
||||
(attribute.name): device.currentValue(attribute.name)
|
||||
]
|
||||
} catch(e) {
|
||||
[
|
||||
(attribute.name): null
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Private Functions; map device command and value.
|
||||
//input command and value are from UWP,
|
||||
//returns resultCommand and resultValue that corresponds with function and value in SmartApps
|
||||
private mapDeviceCommands(command, value) {
|
||||
log.debug "mapDeviceCommands: [${command}, ${value}]"
|
||||
def resultCommand = command
|
||||
def resultValue = value
|
||||
switch (command) {
|
||||
case "switch":
|
||||
if (value == 1 || value == "1" || value == "on") {
|
||||
resultCommand = "on"
|
||||
resultValue = ""
|
||||
} else if (value == 0 || value == "0" || value == "off") {
|
||||
resultCommand = "off"
|
||||
resultValue = ""
|
||||
}
|
||||
break
|
||||
case "level":
|
||||
resultCommand = "setLevel"
|
||||
resultValue = value
|
||||
break
|
||||
case "hue":
|
||||
resultCommand = "setHue"
|
||||
resultValue = value
|
||||
Log
|
||||
break
|
||||
case "saturation":
|
||||
resultCommand = "setSaturation"
|
||||
resultValue = value
|
||||
break
|
||||
case "color":
|
||||
resultCommand = "setColor"
|
||||
resultValue = value
|
||||
case "locked":
|
||||
if (value == 1 || value == "1" || value == "lock") {
|
||||
resultCommand = "lock"
|
||||
resultValue = ""
|
||||
}
|
||||
else if (value == 0 || value == "0" || value == "unlock") {
|
||||
resultCommand = "unlock"
|
||||
resultValue = ""
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return [resultCommand,resultValue]
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user