Compare commits

..

1 Commits

Author SHA1 Message Date
Matthew Page
ab2ba8104d MSA-1255: The following app submitted will be an endpoint for our IOS app Gidjit.
Gidjit is like having a home screen based on your environment. It scans your surroundings looking for home devices, personal electronic devices, times and locations of interest, and more. It will present a list of corresponding launcher panels that allow you to quickly access actions like open an app, control/monitor a device, execute a SmartThings Routine, or link to the control/launch screen of a device. For example based on the users location they will quickly be able to access a preset routine. We are really looking forward to having SmartThings in integration with the app. 

Link: https://itunes.apple.com/us/app/gidjit-smart-launcher/id961388659?mt=8

The app currently will not have the SmartThing's support until the next version that will be released when this is hopefully approved, as we will also have to go through the Apple approval process allowing them to test the features.

Thank you for your time!

Matt
2016-05-07 16:51:30 -05:00
7 changed files with 266 additions and 203 deletions

View File

@@ -94,11 +94,11 @@ def parse(String description) {
def cmd = zwave.parse(description, [0x31: 1, 0x32: 1, 0x60: 3])
if (cmd) {
result = createEvent(zwaveEvent(cmd))
log.debug "Parse returned ${result?.descriptionText}"
storeGraphData(result.name, result.value)
} else {
log.debug "zwave.parse returned null command. Cannot create event"
}
log.debug "Parse returned ${result?.descriptionText}"
storeGraphData(result.name, result.value)
return result
}

View File

@@ -37,6 +37,9 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}

View File

@@ -38,6 +38,9 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}

View File

@@ -33,6 +33,9 @@ metadata {
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
}
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%'
}
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {

View File

@@ -110,7 +110,7 @@ def installed() {
sendEvent(name: "multilineText", value: "Line 1 YES\nLine 2 YES\nLine 3 NO")
}
def parse(String description) {
def parse() {
// This is a simulated device. No incoming data to parse.
}

View File

@@ -0,0 +1,252 @@
/**
* Gidjit Hub
*
* Copyright 2016 Matthew Page
*
* 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: "Gidjit Hub",
namespace: "com.gidjit.smartthings.hub",
author: "Matthew Page",
description: "Act as an endpoint so user's of Gidjit can quickly access and control their devices and execute routines. Users can do this quickly as Gidjit filters these actions based on their environment",
category: "Convenience",
iconUrl: "http://www.gidjit.com/appicon.png",
iconX2Url: "http://www.gidjit.com/appicon@2x.png",
iconX3Url: "http://www.gidjit.com/appicon@3x.png",
oauth: [displayName: "Gidjit", displayLink: "www.gidjit.com"])
preferences {
section ("Allow Gidjit to have access, there by allowing you to quickly control and monitor the following devices") {
input "switches", "capability.switch", title: "Control/Monitor your switches", multiple: true, required: false
input "thermostats", "capability.thermostat", title: "Control/Monitor your thermostats", multiple: true, required: false
input "windowShades", "capability.windowShade", title: "Control/Monitor your window shades", multiple: true, required: false //windowShade
//input "bulbs", "capability.colorControl", title: "Control your lights", multiple: true, required: false //windowShade
}
}
mappings {
path("/structureinfo") {
action: [
GET: "structureInfo"
]
}
path("/helloactions") {
action: [
GET: "helloActions"
]
}
path("/helloactions/:label") {
action: [
PUT: "executeAction"
]
}
path("/switch/:id/:command") {
action: [
PUT: "updateSwitch"
]
}
path("/thermostat/:id/:command") {
action: [
PUT: "updateThermostat"
]
}
path("/windowshade/:id/:command") {
action: [
PUT: "updateWindowShade"
]
}
path("/acquiredata/:id") {
action: [
GET: "acquiredata"
]
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// subscribe to attributes, devices, locations, etc.
}
def helloActions() {
def actions = location.helloHome?.getPhrases()*.label
if(!actions) {
return []
}
return actions
}
def executeAction() {
def actions = location.helloHome?.getPhrases()*.label
def a = actions?.find() { it == params.label }
if (!a) {
httpError(400, "invalid label $params.label")
return
}
location.helloHome?.execute(params.label)
}
/* this is the primary function called to query at the structure and its devices */
def structureInfo() { //list all devices
def list = [:]
def currId = location.id
list[currId] = [:]
list[currId].name = location.name
list[currId].id = location.id
list[currId].temperatureScale = location.temperatureScale
list[currId].devices = [:]
def setValues = {
if (params.brief) {
return [id: it.id, name: it.displayName]
}
def newList = [id: it.id, name: it.displayName, suppCapab: it.capabilities.collect {
"$it.name"
}, suppAttributes: it.supportedAttributes.collect {
"$it.name"
}, suppCommands: it.supportedCommands.collect {
"$it.name"
}]
return newList
}
switches?.each {
list[currId].devices[it.id] = setValues(it)
}
thermostats?.each {
list[currId].devices[it.id] = setValues(it)
}
windowShades?.each {
list[currId].devices[it.id] = setValues(it)
}
return list
}
/* This function returns all of the current values of the specified Devices attributes */
def acquiredata() {
def resp = [:]
if (!params.id) {
httpError(400, "invalid id $params.id")
return
}
def dev = switches.find() { it.id == params.id } ?: windowShades.find() { it.id == params.id } ?:
thermostats.find() { it.id == params.id }
if (!dev) {
httpError(400, "invalid id $params.id")
return
}
def att = dev.supportedAttributes
att.each {
resp[it.name] = dev.currentValue("$it.name")
}
return resp
}
void updateSwitch() {
// use the built-in request object to get the command parameter
def command = params.command
def sw = switches.find() { it.id == params.id }
if (!sw) {
httpError(400, "invalid id $params.id")
return
}
switch(command) {
case "on":
if ( sw.currentSwitch != "on" ) {
sw.on()
}
break
case "off":
if ( sw.currentSwitch != "off" ) {
sw.off()
}
break
default:
httpError(400, "$command is not a valid")
}
}
void updateThermostat() {
// use the built-in request object to get the command parameter
def command = params.command
def therm = thermostats.find() { it.id == params.id }
if (!therm || !command) {
httpError(400, "invalid id $params.id")
return
}
def passComm = [
"off",
"heat",
"emergencyHeat",
"cool",
"fanOn",
"fanAuto",
"fanCirculate",
"auto"
]
def passNumParamComm = [
"setHeatingSetpoint",
"setCoolingSetpoint",
]
def passStringParamComm = [
"setThermostatMode",
"setThermostatFanMode",
]
if (command in passComm) {
therm."$command"()
} else if (command in passNumParamComm && params.p1 && params.p1.isFloat()) {
therm."$command"(Float.parseFloat(params.p1))
} else if (command in passStringParamComm && params.p1) {
therm."$command"(params.p1)
} else {
httpError(400, "$command is not a valid command")
}
}
void updateWindowShade() {
// use the built-in request object to get the command parameter
def command = params.command
def ws = windowShades.find() { it.id == params.id }
if (!ws || !command) {
httpError(400, "invalid id $params.id")
return
}
def passComm = [
"open",
"close",
"presetPosition",
]
if (command in passComm) {
ws."$command"()
} else {
httpError(400, "$command is not a valid command")
}
}
// TODO: implement event handlers

View File

@@ -1,198 +0,0 @@
/**
* 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.
*
* Good Night
*
* Author: SmartThings
* Date: 2013-03-07
*/
definition(
name: "이현주",
namespace: "smartthings",
author: "SmartThings",
description: "Changes mode when motion ceases after a specific time of night.",
category: "Mode Magic",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/good-night.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/good-night@2x.png"
)
preferences {
section("When there is no motion on any of these sensors") {
input "motionSensors", "capability.motionSensor", title: "Where?", multiple: true
}
section("For this amount of time") {
input "minutes", "number", title: "Minutes?"
}
section("After this time of day") {
input "timeOfDay", "time", title: "Time?"
}
section("And (optionally) these switches are all off") {
input "switches", "capability.switch", multiple: true, required: false
}
section("Change to this mode") {
input "newMode", "mode", title: "Mode?"
}
section( "Notifications" ) {
input("recipients", "contact", title: "Send notifications to") {
input "sendPushMessage", "enum", title: "Send a push notification?", options: ["Yes", "No"], required: false
input "phoneNumber", "phone", title: "Send a Text Message?", required: false
}
}
}
def installed() {
log.debug "Current mode = ${location.mode}"
createSubscriptions()
}
def updated() {
log.debug "Current mode = ${location.mode}"
unsubscribe()
createSubscriptions()
}
def createSubscriptions()
{
subscribe(motionSensors, "motion.active", motionActiveHandler)
subscribe(motionSensors, "motion.inactive", motionInactiveHandler)
subscribe(switches, "switch.off", switchOffHandler)
subscribe(location, modeChangeHandler)
if (state.modeStartTime == null) {
state.modeStartTime = 0
}
}
def modeChangeHandler(evt) {
state.modeStartTime = now()
}
def switchOffHandler(evt) {
if (correctMode() && correctTime()) {
if (allQuiet() && switchesOk()) {
takeActions()
}
}
}
def motionActiveHandler(evt)
{
log.debug "Motion active"
}
def motionInactiveHandler(evt)
{
// for backward compatibility
if (state.modeStartTime == null) {
subscribe(location, modeChangeHandler)
state.modeStartTime = 0
}
if (correctMode() && correctTime()) {
runIn(minutes * 60, scheduleCheck, [overwrite: false])
}
}
def scheduleCheck()
{
log.debug "scheduleCheck, currentMode = ${location.mode}, newMode = $newMode"
if (correctMode() && correctTime()) {
if (allQuiet() && switchesOk()) {
takeActions()
}
}
}
private takeActions() {
def message = "Goodnight! SmartThings changed the mode to '$newMode'"
send(message)
setLocationMode(newMode)
log.debug message
}
private correctMode() {
if (location.mode != newMode) {
true
} else {
log.debug "Location is already in the desired mode: doing nothing"
false
}
}
private correctTime() {
def t0 = now()
def modeStartTime = new Date(state.modeStartTime)
def startTime = timeTodayAfter(modeStartTime, timeOfDay, location.timeZone)
if (t0 >= startTime.time) {
true
} else {
log.debug "The current time of day (${new Date(t0)}), is not in the correct time window ($startTime): doing nothing"
false
}
}
private switchesOk() {
def result = true
for (it in (switches ?: [])) {
if (it.currentSwitch == "on") {
result = false
break
}
}
log.debug "Switches are all off: $result"
result
}
private allQuiet() {
def threshold = 1000 * 60 * minutes - 1000
def states = motionSensors.collect { it.currentState("motion") ?: [:] }.sort { a, b -> b.dateCreated <=> a.dateCreated }
if (states) {
if (states.find { it.value == "active" }) {
log.debug "Found active state"
false
} else {
def sensor = states.first()
def elapsed = now() - sensor.rawDateCreated.time
if (elapsed >= threshold) {
log.debug "No active states, and enough time has passed"
true
} else {
log.debug "No active states, but not enough time has passed"
false
}
}
} else {
log.debug "No states to check for activity"
true
}
}
private send(msg) {
if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients)
}
else {
if (sendPushMessage != "No") {
log.debug("sending push message")
sendPush(msg)
}
if (phoneNumber) {
log.debug("sending text message")
sendSms(phoneNumber, msg)
}
}
log.debug msg
}