diff --git a/build.gradle b/build.gradle index 2334d49..2667f45 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ buildscript { username smartThingsArtifactoryUserName password smartThingsArtifactoryPassword } - url "http://artifactory.smartthings.com/libs-release-local" + url "https://artifactory.smartthings.com/libs-release-local" } } } @@ -27,9 +27,37 @@ buildscript { repositories { mavenLocal() jcenter() + maven { + credentials { + username smartThingsArtifactoryUserName + password smartThingsArtifactoryPassword + } + url "https://artifactory.smartthings.com/libs-release-local" + } +} + +sourceSets { + devicetypes { + groovy { + srcDirs = ['devicetypes'] + } + } + smartapps { + groovy { + srcDirs = ['smartapps'] + } + } } dependencies { + devicetypesCompile 'org.codehaus.groovy:groovy-all:2.4.7' + devicetypesCompile 'smartthings:appengine-z-wave:0.1.2' + devicetypesCompile 'smartthings:appengine-zigbee:0.1.11' + smartappsCompile 'org.codehaus.groovy:groovy-all:2.4.7' + smartappsCompile 'smartthings:appengine-common:0.1.8' + smartappsCompile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1' + smartappsCompile 'org.grails:grails-web:2.3.11' + smartappsCompile 'org.json:json:20140107' } slackSendMessage { diff --git a/circle.yml b/circle.yml index 3785924..a78f804 100644 --- a/circle.yml +++ b/circle.yml @@ -5,7 +5,9 @@ machine: dependencies: override: - - echo "Nothing to do." + - ./gradlew dependencies -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" + post: + - ./gradlew compileSmartappsGroovy compileDevicetypesGroovy -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" test: override: diff --git a/devicetypes/dianoga/netatmo-additional-module.src/netatmo-additional-module.groovy b/devicetypes/dianoga/netatmo-additional-module.src/netatmo-additional-module.groovy index 00916de..9717a28 100644 --- a/devicetypes/dianoga/netatmo-additional-module.src/netatmo-additional-module.groovy +++ b/devicetypes/dianoga/netatmo-additional-module.src/netatmo-additional-module.groovy @@ -15,6 +15,7 @@ */ metadata { definition (name: "Netatmo Additional Module", namespace: "dianoga", author: "Brian Steere") { + capability "Sensor" capability "Relative Humidity Measurement" capability "Temperature Measurement" diff --git a/devicetypes/dianoga/netatmo-basestation.src/netatmo-basestation.groovy b/devicetypes/dianoga/netatmo-basestation.src/netatmo-basestation.groovy index f0a844c..899a987 100644 --- a/devicetypes/dianoga/netatmo-basestation.src/netatmo-basestation.groovy +++ b/devicetypes/dianoga/netatmo-basestation.src/netatmo-basestation.groovy @@ -15,6 +15,7 @@ */ metadata { definition (name: "Netatmo Basestation", namespace: "dianoga", author: "Brian Steere") { + capability "Sensor" capability "Relative Humidity Measurement" capability "Temperature Measurement" diff --git a/devicetypes/dianoga/netatmo-outdoor-module.src/netatmo-outdoor-module.groovy b/devicetypes/dianoga/netatmo-outdoor-module.src/netatmo-outdoor-module.groovy index 45ef2b2..9ea2db8 100644 --- a/devicetypes/dianoga/netatmo-outdoor-module.src/netatmo-outdoor-module.groovy +++ b/devicetypes/dianoga/netatmo-outdoor-module.src/netatmo-outdoor-module.groovy @@ -15,6 +15,7 @@ */ metadata { definition (name: "Netatmo Outdoor Module", namespace: "dianoga", author: "Brian Steere") { + capability "Sensor" capability "Relative Humidity Measurement" capability "Temperature Measurement" } diff --git a/devicetypes/dianoga/netatmo-rain.src/netatmo-rain.groovy b/devicetypes/dianoga/netatmo-rain.src/netatmo-rain.groovy index a882f23..1ed8474 100644 --- a/devicetypes/dianoga/netatmo-rain.src/netatmo-rain.groovy +++ b/devicetypes/dianoga/netatmo-rain.src/netatmo-rain.groovy @@ -15,6 +15,8 @@ */ metadata { definition (name: "Netatmo Rain", namespace: "dianoga", author: "Brian Steere") { + capability "Sensor" + attribute "rain", "number" attribute "rainSumHour", "number" attribute "rainSumDay", "number" diff --git a/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy b/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy index 864420f..7504d93 100644 --- a/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy @@ -33,8 +33,8 @@ metadata { tiles(scale: 2) { multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app tileAttribute("device.motion", key:"PRIMARY_CONTROL") { - attributeState("inactive", icon:"st.motion.motion.inactive", backgroundColor:"#79b821") - attributeState("active", icon:"st.motion.motion.active", backgroundColor:"#ffa81e") + attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821") + attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e") } tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { @@ -278,4 +278,4 @@ private encap(physicalgraph.zwave.Command cmd) { } else { crc16(cmd) } -} \ No newline at end of file +} diff --git a/smartapps/curb/curb-control.src/curb-control.groovy b/smartapps/curb/curb-control.src/curb-control.groovy index 3a1c83d..3bd1ec4 100644 --- a/smartapps/curb/curb-control.src/curb-control.groovy +++ b/smartapps/curb/curb-control.src/curb-control.groovy @@ -65,7 +65,16 @@ void updateSwitch() { private void updateAll(devices) { def command = request.JSON?.command if (command) { - devices."$command"() + switch(command) { + case "on": + devices.on() + break + case "off": + devices.off() + break + default: + httpError(403, "Access denied. This command is not supported by current capability.") + } } } @@ -77,7 +86,16 @@ private void update(devices) { if (!device) { httpError(404, "Device not found") } else { - device."$command"() + switch(command) { + case "on": + device.on() + break + case "off": + device.off() + break + default: + httpError(403, "Access denied. This command is not supported by current capability.") + } } } } diff --git a/smartapps/dianoga/netatmo-connect.src/netatmo-connect.groovy b/smartapps/dianoga/netatmo-connect.src/netatmo-connect.groovy index 7a9e946..65ed151 100644 --- a/smartapps/dianoga/netatmo-connect.src/netatmo-connect.groovy +++ b/smartapps/dianoga/netatmo-connect.src/netatmo-connect.groovy @@ -58,7 +58,7 @@ def authPage() { if (canInstallLabs()) { def redirectUrl = getBuildRedirectUrl() - log.debug "Redirect url = ${redirectUrl}" + // log.debug "Redirect url = ${redirectUrl}" if (state.authToken) { description = "Tap 'Next' to proceed" @@ -113,13 +113,13 @@ def oauthInitUrl() { scope: "read_station" ] - log.debug "REDIRECT URL: ${getVendorAuthPath() + toQueryString(oauthParams)}" + // log.debug "REDIRECT URL: ${getVendorAuthPath() + toQueryString(oauthParams)}" redirect (location: getVendorAuthPath() + toQueryString(oauthParams)) } def callback() { - log.debug "callback()>> params: $params, params.code ${params.code}" + // log.debug "callback()>> params: $params, params.code ${params.code}" def code = params.code def oauthState = params.state @@ -135,7 +135,7 @@ def callback() { scope: "read_station" ] - log.debug "TOKEN URL: ${getVendorTokenPath() + toQueryString(tokenParams)}" + // log.debug "TOKEN URL: ${getVendorTokenPath() + toQueryString(tokenParams)}" def tokenUrl = getVendorTokenPath() def params = [ @@ -144,7 +144,7 @@ def callback() { body: tokenParams ] - log.debug "PARAMS: ${params}" + // log.debug "PARAMS: ${params}" httpPost(params) { resp -> @@ -156,7 +156,7 @@ def callback() { state.refreshToken = data.refresh_token state.authToken = data.access_token state.tokenExpires = now() + (data.expires_in * 1000) - log.debug "swapped token: $resp.data" + // log.debug "swapped token: $resp.data" } } @@ -292,7 +292,7 @@ def refreshToken() { response.data.each {key, value -> def data = slurper.parseText(key); - log.debug "Data: $data" + // log.debug "Data: $data" state.refreshToken = data.refresh_token state.accessToken = data.access_token diff --git a/smartapps/juano2310/jawbone-up-connect.src/jawbone-up-connect.groovy b/smartapps/juano2310/jawbone-up-connect.src/jawbone-up-connect.groovy index 26dd7e5..4e120c1 100644 --- a/smartapps/juano2310/jawbone-up-connect.src/jawbone-up-connect.groovy +++ b/smartapps/juano2310/jawbone-up-connect.src/jawbone-up-connect.groovy @@ -28,7 +28,7 @@ mappings { path("/receivedToken") { action: [ POST: "receivedToken", GET: "receivedToken"] } path("/receiveToken") { action: [ POST: "receiveToken", GET: "receiveToken"] } path("/hookCallback") { action: [ POST: "hookEventHandler", GET: "hookEventHandler"] } - path("/oauth/initialize") {action: [GET: "oauthInitUrl"]} + path("/oauth/initialize") {action: [GET: "oauthInitUrl"]} path("/oauth/callback") { action: [ GET: "callback" ] } } @@ -44,7 +44,7 @@ def callback() { } else { log.warn "No authQueryString" } - + if (state.JawboneAccessToken) { log.debug "Access token already exists" setup() @@ -73,7 +73,7 @@ def callback() { def authPage() { log.debug "authPage" - def description = null + def description = null if (state.JawboneAccessToken == null) { if (!state.accessToken) { log.debug "About to create access token" @@ -82,12 +82,13 @@ def authPage() { description = "Click to enter Jawbone Credentials" def redirectUrl = buildRedirectUrl log.debug "RedirectURL = ${redirectUrl}" - def donebutton= state.JawboneAccessToken != null + def donebutton= state.JawboneAccessToken != null return dynamicPage(name: "Credentials", title: "Jawbone UP", nextPage: null, uninstall: true, install: donebutton) { + section { paragraph title: "Note:", "This device has not been officially tested and certified to “Work with SmartThings”. You can connect it to your SmartThings home but performance may vary and we will not be able to provide support or assistance." } section { href url:redirectUrl, style:"embedded", required:true, title:"Jawbone UP", state: hast ,description:description } } } else { - description = "Jawbone Credentials Already Entered." + description = "Jawbone Credentials Already Entered." return dynamicPage(name: "Credentials", title: "Jawbone UP", uninstall: true, install:true) { section { href url: buildRedirectUrl("receivedToken"), style:"embedded", state: "complete", title:"Jawbone UP", description:description } } @@ -107,7 +108,7 @@ def receiveToken(redirectUrl = null) { def params = [ uri: "https://jawbone.com/auth/oauth2/token?${toQueryString(oauthParams)}", ] - httpGet(params) { response -> + httpGet(params) { response -> log.debug "${response.data}" log.debug "Setting access token to ${response.data.access_token}, refresh token to ${response.data.refresh_token}" state.JawboneAccessToken = response.data.access_token @@ -149,7 +150,7 @@ def connectionStatus(message, redirectUrl = null) { """ } - + def html = """ @@ -229,12 +230,12 @@ def validateCurrentToken() { log.debug "validateCurrentToken" def url = "https://jawbone.com/nudge/api/v.1.1/users/@me/refreshToken" def requestBody = "secret=${appSettings.clientSecret}" - + try { httpPost(uri: url, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ], body: requestBody) {response -> if (response.status == 200) { log.debug "${response.data}" - log.debug "Setting refresh token to ${response.data.data.refresh_token}" + log.debug "Setting refresh token" state.refreshToken = response.data.data.refresh_token } } @@ -258,7 +259,7 @@ def validateCurrentToken() { state.remove("refreshToken") } } else { - log.debug "Setting access token to ${data.access_token}, refresh token to ${data.refresh_token}" + log.debug "Setting access token" state.JawboneAccessToken = data.access_token state.refreshToken = data.refresh_token } @@ -271,10 +272,10 @@ def validateCurrentToken() { } def initialize() { - log.debug "Callback URL - Webhook" - def localServerUrl = getApiServerUrl() + log.debug "Callback URL - Webhook" + def localServerUrl = getApiServerUrl() def hookUrl = "${localServerUrl}/api/token/${state.accessToken}/smartapps/installations/${app.id}/hookCallback" - def webhook = "https://jawbone.com/nudge/api/v.1.1/users/@me/pubsub?webhook=$hookUrl" + def webhook = "https://jawbone.com/nudge/api/v.1.1/users/@me/pubsub?webhook=$hookUrl" httpPost(uri: webhook, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) } @@ -284,16 +285,16 @@ def setup() { if (state.JawboneAccessToken) { def urlmember = "https://jawbone.com/nudge/api/users/@me/" - def member = null - httpGet(uri: urlmember, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + def member = null + httpGet(uri: urlmember, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> member = response.data.data } - + if (member) { state.member = member def externalId = "${app.id}.${member.xid}" - // find the appropriate child device based on my app id and the device network id + // find the appropriate child device based on my app id and the device network id def deviceWrapper = getChildDevice("${externalId}") // invoke the generatePresenceEvent method on the child device @@ -312,7 +313,7 @@ def setup() { } def installed() { - + if (!state.accessToken) { log.debug "About to create access token" createAccessToken() @@ -324,7 +325,7 @@ def installed() { } def updated() { - + if (!state.accessToken) { log.debug "About to create access token" createAccessToken() @@ -348,29 +349,29 @@ def uninstalled() { } def pollChild(childDevice) { - def member = state.member - generatePollingEvents (member, childDevice) + def member = state.member + generatePollingEvents (member, childDevice) } def generatePollingEvents (member, childDevice) { // lets figure out if the member is currently "home" (At the place) - def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" - def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" - def urlsleeps = "https://jawbone.com/nudge/api/users/@me/sleeps" + def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" + def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" + def urlsleeps = "https://jawbone.com/nudge/api/users/@me/sleeps" def goals = null def moves = null - def sleeps = null - httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + def sleeps = null + httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> goals = response.data.data - } - httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + } + httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> moves = response.data.data.items[0] - } - + } + try { // we are going to just ignore any errors log.debug "Member = ${member.first}" log.debug "Moves Goal = ${goals.move_steps} Steps" - log.debug "Moves = ${moves.details.steps} Steps" + log.debug "Moves = ${moves.details.steps} Steps" childDevice?.sendEvent(name:"steps", value: moves.details.steps) childDevice?.sendEvent(name:"goal", value: goals.move_steps) @@ -378,29 +379,29 @@ def generatePollingEvents (member, childDevice) { } catch (e) { // eat it - } + } } def generateInitialEvent (member, childDevice) { // lets figure out if the member is currently "home" (At the place) - def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" - def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" - def urlsleeps = "https://jawbone.com/nudge/api/users/@me/sleeps" + def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" + def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" + def urlsleeps = "https://jawbone.com/nudge/api/users/@me/sleeps" def goals = null def moves = null - def sleeps = null - httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + def sleeps = null + httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> goals = response.data.data - } - httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + } + httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> moves = response.data.data.items[0] - } - + } + try { // we are going to just ignore any errors log.debug "Member = ${member.first}" log.debug "Moves Goal = ${goals.move_steps} Steps" log.debug "Moves = ${moves.details.steps} Steps" - log.debug "Sleeping state = false" + log.debug "Sleeping state = false" childDevice?.generateSleepingEvent(false) childDevice?.sendEvent(name:"steps", value: moves.details.steps) childDevice?.sendEvent(name:"goal", value: goals.move_steps) @@ -408,27 +409,27 @@ def generateInitialEvent (member, childDevice) { } catch (e) { // eat it - } + } } def setColor (steps,goal,childDevice) { def result = steps * 100 / goal - if (result < 25) + if (result < 25) childDevice?.sendEvent(name:"steps", value: "steps", label: steps) - else if ((result >= 25) && (result < 50)) + else if ((result >= 25) && (result < 50)) childDevice?.sendEvent(name:"steps", value: "steps1", label: steps) - else if ((result >= 50) && (result < 75)) + else if ((result >= 50) && (result < 75)) childDevice?.sendEvent(name:"steps", value: "steps1", label: steps) - else if (result >= 75) - childDevice?.sendEvent(name:"steps", value: "stepsgoal", label: steps) + else if (result >= 75) + childDevice?.sendEvent(name:"steps", value: "stepsgoal", label: steps) } def hookEventHandler() { // log.debug "In hookEventHandler method." log.debug "request = ${request}" - - def json = request.JSON - + + def json = request.JSON + // get some stuff we need def userId = json.events.user_xid[0] def json_type = json.events.type[0] @@ -437,39 +438,39 @@ def hookEventHandler() { //log.debug json log.debug "Userid = ${userId}" log.debug "Notification Type: " + json_type - log.debug "Notification Action: " + json_action - + log.debug "Notification Action: " + json_action + // find the appropriate child device based on my app id and the device network id def externalId = "${app.id}.${userId}" def childDevice = getChildDevice("${externalId}") - + if (childDevice) { - switch (json_action) { - case "enter_sleep_mode": - childDevice?.generateSleepingEvent(true) - break - case "exit_sleep_mode": - childDevice?.generateSleepingEvent(false) - break - case "creation": + switch (json_action) { + case "enter_sleep_mode": + childDevice?.generateSleepingEvent(true) + break + case "exit_sleep_mode": + childDevice?.generateSleepingEvent(false) + break + case "creation": childDevice?.sendEvent(name:"steps", value: 0) break case "updation": - def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" - def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" + def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" + def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" def goals = null - def moves = null - httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + def moves = null + httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> goals = response.data.data - } - httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> + } + httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> moves = response.data.data.items[0] - } + } log.debug "Goal = ${goals.move_steps} Steps" - log.debug "Steps = ${moves.details.steps} Steps" + log.debug "Steps = ${moves.details.steps} Steps" childDevice?.sendEvent(name:"steps", value: moves.details.steps) - childDevice?.sendEvent(name:"goal", value: goals.move_steps) - //setColor(moves.details.steps,goals.move_steps,childDevice) + childDevice?.sendEvent(name:"goal", value: goals.move_steps) + //setColor(moves.details.steps,goals.move_steps,childDevice) break case "deletion": app.delete() diff --git a/smartapps/michaelstruck/smart-home-ventilation.src/smart-home-ventilation.groovy b/smartapps/michaelstruck/smart-home-ventilation.src/smart-home-ventilation.groovy index 071a251..57fa957 100644 --- a/smartapps/michaelstruck/smart-home-ventilation.src/smart-home-ventilation.groovy +++ b/smartapps/michaelstruck/smart-home-ventilation.src/smart-home-ventilation.groovy @@ -14,7 +14,7 @@ * for the specific language governing permissions and limitations under the License. * */ - + definition( name: "Smart Home Ventilation", namespace: "MichaelStruck", @@ -164,7 +164,7 @@ def installed() { def updated() { unschedule() turnOffSwitch() //Turn off all switches if the schedules are changed while in mid-schedule - unsubscribe + unsubscribe() log.debug "Updated with settings: ${settings}" init() } @@ -174,12 +174,12 @@ def init() { schedule (midnightTime, midNight) subscribe(location, "mode", locationHandler) startProcess() -} +} // Common methods def startProcess () { - createDayArray() + createDayArray() state.dayCount=state.data.size() if (state.dayCount){ state.counter = 0 @@ -190,7 +190,7 @@ def startProcess () { def startDay() { def start = convertEpoch(state.data[state.counter].start) def stop = convertEpoch(state.data[state.counter].stop) - + runOnce(start, turnOnSwitch, [overwrite: true]) runOnce(stop, incDay, [overwrite: true]) } @@ -218,7 +218,7 @@ def locationHandler(evt) { } if (!result) { startProcess() - } + } } def midNight(){ @@ -238,7 +238,7 @@ def turnOffSwitch() { } log.debug "Home ventilation switches are off." } - + def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) { def title = "" def dayListClean = "On " @@ -252,7 +252,7 @@ def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) { dayListClean = "${dayListClean}, " } } - } + } else { dayListClean = "Every day" } @@ -272,7 +272,7 @@ def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) { modeListClean = "${modeListClean} ${modePrefix}" } } - } + } else { modeListClean = "${modeListClean}all modes" } @@ -283,16 +283,16 @@ def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) { title += "\nSchedule 2: ${humanReadableTime(on2)} to ${humanReadableTime(off2)}" } if (on3 && off3) { - title += "\nSchedule 3: ${humanReadableTime(on3)} to ${humanReadableTime(off3)}" + title += "\nSchedule 3: ${humanReadableTime(on3)} to ${humanReadableTime(off3)}" } if (on4 && off4) { - title += "\nSchedule 4: ${humanReadableTime(on4)} to ${humanReadableTime(off4)}" + title += "\nSchedule 4: ${humanReadableTime(on4)} to ${humanReadableTime(off4)}" } if (on1 || on2 || on3 || on4) { title += "\n$modeListClean" - title += "\n$dayListClean" + title += "\n$dayListClean" } - + if (!on1 && !on2 && !on3 && !on4) { title="Click to configure scenario" } @@ -374,7 +374,7 @@ def createDayArray() { timeOk(timeOnD1, timeOffD1) timeOk(timeOnD2, timeOffD2) timeOk(timeOnD3, timeOffD3) - timeOk(timeOnD4, timeOffD4) + timeOk(timeOnD4, timeOffD4) } } state.data.sort{it.start} @@ -384,7 +384,7 @@ def createDayArray() { private def textAppName() { def text = "Smart Home Ventilation" -} +} private def textVersion() { def text = "Version 2.1.2 (05/31/2015)" @@ -416,4 +416,4 @@ private def textHelp() { "that each scenario does not overlap and run in separate modes (i.e. Home, Out of town, etc). Also note that you should " + "avoid scheduling the ventilation fan at exactly midnight; the app resets itself at that time. It is suggested to start any new schedule " + "at 12:15 am or later." -} \ No newline at end of file +} diff --git a/smartapps/smartthings/beacon-control.src/beacon-control.groovy b/smartapps/smartthings/beacon-control.src/beacon-control.groovy index 17fddad..007b455 100644 --- a/smartapps/smartthings/beacon-control.src/beacon-control.groovy +++ b/smartapps/smartthings/beacon-control.src/beacon-control.groovy @@ -114,13 +114,16 @@ def beaconHandler(evt) { if (allOk) { def data = new groovy.json.JsonSlurper().parseText(evt.data) - log.debug " data: $data - phones: " + phones*.deviceNetworkId + // removed logging of device names. can be added back for debugging + //log.debug " data: $data - phones: " + phones*.deviceNetworkId def beaconName = getBeaconName(evt) - log.debug " beaconName: $beaconName" + // removed logging of device names. can be added back for debugging + //log.debug " beaconName: $beaconName" def phoneName = getPhoneName(data) - log.debug " phoneName: $phoneName" + // removed logging of device names. can be added back for debugging + //log.debug " phoneName: $phoneName" if (phoneName != null) { def action = data.presence == "1" ? "arrived" : "left" def msg = "$phoneName has $action ${action == 'arrived' ? 'at ' : ''}the $beaconName" diff --git a/smartapps/smartthings/bon-voyage.src/bon-voyage.groovy b/smartapps/smartthings/bon-voyage.src/bon-voyage.groovy index a843a71..cb9593d 100644 --- a/smartapps/smartthings/bon-voyage.src/bon-voyage.groovy +++ b/smartapps/smartthings/bon-voyage.src/bon-voyage.groovy @@ -49,13 +49,15 @@ preferences { def installed() { log.debug "Installed with settings: ${settings}" - log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" + // commented out log statement because presence sensor label could contain user's name + //log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" subscribe(people, "presence", presence) } def updated() { log.debug "Updated with settings: ${settings}" - log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" + // commented out log statement because presence sensor label could contain user's name + //log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" unsubscribe() subscribe(people, "presence", presence) } diff --git a/smartapps/smartthings/flood-alert.src/flood-alert.groovy b/smartapps/smartthings/flood-alert.src/flood-alert.groovy index 73cae0b..f44aa48 100644 --- a/smartapps/smartthings/flood-alert.src/flood-alert.groovy +++ b/smartapps/smartthings/flood-alert.src/flood-alert.groovy @@ -54,10 +54,10 @@ def waterWetHandler(evt) { def alreadySentSms = recentEvents.count { it.value && it.value == "wet" } > 1 if (alreadySentSms) { - log.debug "SMS already sent to $phone within the last $deltaSeconds seconds" + log.debug "SMS already sent within the last $deltaSeconds seconds" } else { def msg = "${alarm.displayName} is wet!" - log.debug "$alarm is wet, texting $phone" + log.debug "$alarm is wet, texting phone number" if (location.contactBookEnabled) { sendNotificationToContacts(msg, recipients) diff --git a/smartapps/smartthings/garage-door-monitor.src/garage-door-monitor.groovy b/smartapps/smartthings/garage-door-monitor.src/garage-door-monitor.groovy index 4cabc5c..cd07b23 100644 --- a/smartapps/smartthings/garage-door-monitor.src/garage-door-monitor.groovy +++ b/smartapps/smartthings/garage-door-monitor.src/garage-door-monitor.groovy @@ -90,7 +90,7 @@ def takeAction(){ } def sendTextMessage() { - log.debug "$multisensor was open too long, texting $phone" + log.debug "$multisensor was open too long, texting phone" updateSmsHistory() def openMinutes = maxOpenTime * (state.smsHistory?.size() ?: 1) diff --git a/smartapps/smartthings/greetings-earthling.src/greetings-earthling.groovy b/smartapps/smartthings/greetings-earthling.src/greetings-earthling.groovy index 2797c09..e97c684 100644 --- a/smartapps/smartthings/greetings-earthling.src/greetings-earthling.groovy +++ b/smartapps/smartthings/greetings-earthling.src/greetings-earthling.groovy @@ -47,13 +47,13 @@ preferences { def installed() { log.debug "Installed with settings: ${settings}" - log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" + // log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" subscribe(people, "presence", presence) } def updated() { log.debug "Updated with settings: ${settings}" - log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" + // log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" unsubscribe() subscribe(people, "presence", presence) } @@ -71,11 +71,10 @@ def presence(evt) def person = getPerson(evt) def recentNotPresent = person.statesSince("presence", t0).find{it.value == "not present"} if (recentNotPresent) { - log.debug "skipping notification of arrival of ${person.displayName} because last departure was only ${now() - recentNotPresent.date.time} msec ago" + log.debug "skipping notification of arrival of Person because last departure was only ${now() - recentNotPresent.date.time} msec ago" } else { def message = "${person.displayName} arrived at home, changing mode to '${newMode}'" - log.info message send(message) setLocationMode(newMode) } @@ -106,6 +105,4 @@ private send(msg) { sendSms(phone, msg) } } - - log.debug msg } diff --git a/smartapps/smartthings/habit-helper.src/habit-helper.groovy b/smartapps/smartthings/habit-helper.src/habit-helper.groovy index 6e8194c..64d2052 100644 --- a/smartapps/smartthings/habit-helper.src/habit-helper.groovy +++ b/smartapps/smartthings/habit-helper.src/habit-helper.groovy @@ -57,12 +57,11 @@ def scheduleCheck() def message = message1 ?: "SmartThings - Habit Helper Reminder!" if (location.contactBookEnabled) { - log.debug "Texting reminder: ($message) to contacts:${recipients?.size()}" + log.debug "Texting reminder to contacts:${recipients?.size()}" sendNotificationToContacts(message, recipients) } else { - - log.debug "Texting reminder: ($message) to $phone1" + log.debug "Texting reminder" sendSms(phone1, message) } } diff --git a/smartapps/smartthings/hue-connect.src/hue-connect.groovy b/smartapps/smartthings/hue-connect.src/hue-connect.groovy index ccd0146..fd3beb0 100644 --- a/smartapps/smartthings/hue-connect.src/hue-connect.groovy +++ b/smartapps/smartthings/hue-connect.src/hue-connect.groovy @@ -801,10 +801,12 @@ def parse(childDevice, description) { } // Philips Hue priority for color is xy > ct > hs +// For SmartThings, try to always send hue, sat and hex private sendColorEvents(device, xy, hue, sat, ct, colormode = null) { if (device == null || (xy == null && hue == null && sat == null && ct == null)) return + def events = [:] // For now, only care about changing color temperature if requested by user if (ct != null && (colormode == "ct" || (xy == null && hue == null && sat == null))) { // for some reason setting Hue to their specified minimum off 153 yields 154, dealt with below @@ -818,13 +820,13 @@ private sendColorEvents(device, xy, hue, sat, ct, colormode = null) { if (hue != null) { // 0-65535 def value = Math.min(Math.round(hue * 100 / 65535), 65535) as int - device.sendEvent([name: "hue", value: value, descriptionText: "Color has changed"]) + events["hue"] = [name: "hue", value: value, descriptionText: "Color has changed", displayed: false] } if (sat != null) { // 0-254 def value = Math.round(sat * 100 / 254) as int - device.sendEvent([name: "saturation", value: value, descriptionText: "Color has changed"]) + events["saturation"] = [name: "saturation", value: value, descriptionText: "Color has changed", displayed: false] } // Following is used to decide what to base hex calculations on since it is preferred to return a colorchange in hex @@ -836,17 +838,28 @@ private sendColorEvents(device, xy, hue, sat, ct, colormode = null) { def model = state.bulbs[id]?.modelid def hex = colorFromXY(xy, model) - // TODO Disabled until a solution for the jumping color picker can be figured out - //device.sendEvent([name: "color", value: hex.toUpperCase(), descriptionText: "Color has changed", displayed: false]) + // Create Hue and Saturation events if not previously existing + def hsv = hexToHsv(hex) + if (events["hue"] == null) + events["hue"] = [name: "hue", value: hsv[0], descriptionText: "Color has changed", displayed: false] + if (events["saturation"] == null) + events["saturation"] = [name: "saturation", value: hsv[1], descriptionText: "Color has changed", displayed: false] + + events["color"] = [name: "color", value: hex.toUpperCase(), descriptionText: "Color has changed", displayed: true] } else if (colormode == "hs" || colormode == null) { // colormode is "hs" or "xy" is missing, default to follow hue/sat which is already handled above + def hueValue = (hue != null) ? events["hue"].value : Integer.parseInt("$device.currentHue") + def satValue = (sat != null) ? events["saturation"].value : Integer.parseInt("$device.currentSaturation") - // TODO Disabled until the standard behavior of lights is defined (hue and sat events are sent above) - //def hex = colorUtil.hslToHex((int) device.currentHue, (int) device.currentSaturation) - // device.sendEvent([name: "color", value: hex.toUpperCase(), descriptionText: "Color has changed"]) + + def hex = hsvToHex(hueValue, satValue) + events["color"] = [name: "color", value: hex.toUpperCase(), descriptionText: "Color has changed", displayed: true] } - return debug + boolean sendColorChanged = false + events.each { + device.sendEvent(it.value) + } } private sendBasicEvents(device, param, value) { @@ -887,8 +900,6 @@ private handleCommandResponse(body) { def updates = [:] body.each { payload -> - log.debug $payload - if (payload?.success) { def childDeviceNetworkId = app.id + "/" def eventType @@ -1101,26 +1112,22 @@ def setColor(childDevice, huesettings) { def sat = null def xy = null - // For now ignore model to get a consistent color if same color is set across multiple devices - // def model = state.bulbs[getId(childDevice)]?.modelid - if (huesettings.hex != null) { + // Prefer hue/sat over hex to make sure it works with the majority of the smartapps + if (huesettings.hue != null || huesettings.sat != null) { + // If both hex and hue/sat are set, send all values to bridge to get hue/sat in response from bridge to + // generate hue/sat events even though bridge will prioritize XY when setting color + if (huesettings.hue != null) + value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535) + if (huesettings.saturation != null) + value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254) + } else if (huesettings.hex != null && false) { + // For now ignore model to get a consistent color if same color is set across multiple devices + // def model = state.bulbs[getId(childDevice)]?.modelid // value.xy = calculateXY(huesettings.hex, model) // Once groups, or scenes are introduced it might be a good idea to use unique models again value.xy = calculateXY(huesettings.hex) } - // If both hex and hue/sat are set, send all values to bridge to get hue/sat in response from bridge to - // generate hue/sat events even though bridge will prioritize XY when setting color - if (huesettings.hue != null) - value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535) - else - value.hue = Math.min(Math.round(childDevice.device?.currentValue("hue") * 65535 / 100), 65535) - - if (huesettings.saturation != null) - value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254) - else - value.sat = Math.min(Math.round(childDevice.device?.currentValue("saturation") * 254 / 100), 254) - /* Disabled for now due to bad behavior via Lightning Wizard if (!value.xy) { // Below will translate values to hex->XY to take into account the color support of the different hue types @@ -1654,3 +1661,101 @@ private boolean checkPointInLampsReach(p, colorPoints) { return false; } } + +/** + * Converts an RGB color in hex to HSV. + * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. + * + * @param colorStr color value in hex (#ff03d3) + * + * @return HSV representation in an array (0-100) [hue, sat, value] + */ +def hexToHsv(colorStr){ + def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255 + def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255 + def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255; + + def max = Math.max(Math.max(r, g), b) + def min = Math.min(Math.min(r, g), b) + + def h, s, v = max; + + def d = max - min; + s = max == 0 ? 0 : d / max; + + if(max == min){ + h = 0; + }else{ + switch(max){ + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + + return [(h * 100).round(), (s * 100).round(), (v * 100).round()]; +} + +/** + * Converts HSV color to RGB in hex. + * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. + * + * @param hue hue 0-100 + * @param sat saturation 0-100 + * @param value value 0-100 (defaults to 100) + + * @return the color in hex (#ff03d3) + */ +def hsvToHex(hue, sat, value = 100){ + def r, g, b; + def h = hue / 100 + def s = sat / 100 + def v = value / 100 + + def i = Math.floor(h * 6); + def f = h * 6 - i; + def p = v * (1 - s); + def q = v * (1 - f * s); + def t = v * (1 - (1 - f) * s); + + switch (i % 6) { + case 0: + r = v + g = t + b = p + break + case 1: + r = q + g = v + b = p + break + case 2: + r = p + g = v + b = t + break + case 3: + r = p + g = q + b = v + break + case 4: + r = t + g = p + b = v + break + case 5: + r = v + g = p + b = q + break + } + + // Converting float components to int components. + def r1 = String.format("%02X", (int) (r * 255.0f)); + def g1 = String.format("%02X", (int) (g * 255.0f)); + def b1 = String.format("%02X", (int) (b * 255.0f)); + + return "#$r1$g1$b1" +} diff --git a/smartapps/smartthings/it-moved.src/it-moved.groovy b/smartapps/smartthings/it-moved.src/it-moved.groovy index 1023807..a7a6899 100644 --- a/smartapps/smartthings/it-moved.src/it-moved.groovy +++ b/smartapps/smartthings/it-moved.src/it-moved.groovy @@ -53,14 +53,14 @@ def accelerationActiveHandler(evt) { def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1 if (alreadySentSms) { - log.debug "SMS already sent to $phone1 within the last $deltaSeconds seconds" + log.debug "SMS already sent within the last $deltaSeconds seconds" } else { if (location.contactBookEnabled) { - log.debug "$accelerationSensor has moved, texting contacts: ${recipients?.size()}" + log.debug "accelerationSensor has moved, texting contacts: ${recipients?.size()}" sendNotificationToContacts("${accelerationSensor.label ?: accelerationSensor.name} moved", recipients) } else { - log.debug "$accelerationSensor has moved, texting $phone1" + log.debug "accelerationSensor has moved, sending text message" sendSms(phone1, "${accelerationSensor.label ?: accelerationSensor.name} moved") } } diff --git a/smartapps/smartthings/its-too-hot.src/its-too-hot.groovy b/smartapps/smartthings/its-too-hot.src/its-too-hot.groovy index 5b8e10d..6ffcebf 100644 --- a/smartapps/smartthings/its-too-hot.src/its-too-hot.groovy +++ b/smartapps/smartthings/its-too-hot.src/its-too-hot.groovy @@ -69,10 +69,10 @@ def temperatureHandler(evt) { def alreadySentSms = recentEvents.count { it.doubleValue >= tooHot } > 1 if (alreadySentSms) { - log.debug "SMS already sent to $phone1 within the last $deltaMinutes minutes" + log.debug "SMS already sent within the last $deltaMinutes minutes" // TODO: Send "Temperature back to normal" SMS, turn switch off } else { - log.debug "Temperature rose above $tooHot: sending SMS to $phone1 and activating $mySwitch" + log.debug "Temperature rose above $tooHot: sending SMS and activating $mySwitch" def tempScale = location.temperatureScale ?: "F" send("${temperatureSensor1.displayName} is too hot, reporting a temperature of ${evt.value}${evt.unit?:tempScale}") switch1?.on() diff --git a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy index 587c311..7832b68 100644 --- a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy +++ b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy @@ -50,9 +50,9 @@ def authPage() { } def description = "Tap to enter LIFX credentials" def redirectUrl = "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" // this triggers oauthInit() below -// def redirectUrl = "${apiServerUrl}" - log.debug "app id: ${app.id}" - log.debug "redirect url: ${redirectUrl}" + // def redirectUrl = "${apiServerUrl}" + // log.debug "app id: ${app.id}" + // log.debug "redirect url: ${redirectUrl}"s return dynamicPage(name: "Credentials", title: "Connect to LIFX", nextPage: null, uninstall: true, install:true) { section { href(url:redirectUrl, required:true, title:"Connect to LIFX", description:"Tap here to connect your LIFX account") @@ -372,7 +372,7 @@ def updateDevices() { def childDevice = getChildDevice(device.id) selectors.add("${device.id}") if (!childDevice) { - log.info("Adding device ${device.id}: ${device.product}") + // log.info("Adding device ${device.id}: ${device.product}") def data = [ label: device.label, level: Math.round((device.brightness ?: 1) * 100), diff --git a/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy b/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy index df4cd5a..b7084c3 100644 --- a/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy +++ b/smartapps/smartthings/logitech-harmony-connect.src/logitech-harmony-connect.groovy @@ -51,7 +51,7 @@ definition( } preferences(oauthPage: "deviceAuthorization") { - page(name: "Credentials", title: "Connect to your Logitech Harmony device", content: "authPage", install: false, nextPage: "deviceAuthorization") + page(name: "Credentials", title: "Connect to your Logitech Harmony device", content: "authPage", install: false, nextPage: "deviceAuthorization") page(name: "deviceAuthorization", title: "Logitech Harmony device authorization", install: true) { section("Allow Logitech Harmony to control these things...") { input "switches", "capability.switch", title: "Which Switches?", multiple: true, required: false @@ -102,7 +102,8 @@ def authPage() { description = "Click to enter Harmony Credentials" def redirectUrl = buildRedirectUrl return dynamicPage(name: "Credentials", title: "Harmony", nextPage: null, uninstall: true, install:false) { - section { href url:redirectUrl, style:"embedded", required:true, title:"Harmony", description:description } + section { paragraph title: "Note:", "This device has not been officially tested and certified to “Work with SmartThings”. You can connect it to your SmartThings home but performance may vary and we will not be able to provide support or assistance." } + section { href url:redirectUrl, style:"embedded", required:true, title:"Harmony", description:description } } } else { //device discovery request every 5 //25 seconds @@ -314,8 +315,6 @@ def installed() { } def updated() { - unsubscribe() - unschedule() if (!state.accessToken) { log.debug "About to create access token" createAccessToken() diff --git a/smartapps/smartthings/presence-change-push.src/presence-change-push.groovy b/smartapps/smartthings/presence-change-push.src/presence-change-push.groovy index af5fa72..04e8c90 100644 --- a/smartapps/smartthings/presence-change-push.src/presence-change-push.groovy +++ b/smartapps/smartthings/presence-change-push.src/presence-change-push.groovy @@ -41,10 +41,10 @@ def updated() { def presenceHandler(evt) { if (evt.value == "present") { - log.debug "${presence.label ?: presence.name} has arrived at the ${location}" + // log.debug "${presence.label ?: presence.name} has arrived at the ${location}" sendPush("${presence.label ?: presence.name} has arrived at the ${location}") } else if (evt.value == "not present") { - log.debug "${presence.label ?: presence.name} has left the ${location}" + // log.debug "${presence.label ?: presence.name} has left the ${location}" sendPush("${presence.label ?: presence.name} has left the ${location}") } } diff --git a/smartapps/smartthings/presence-change-text.src/presence-change-text.groovy b/smartapps/smartthings/presence-change-text.src/presence-change-text.groovy index d4ad1f3..4c4d5a2 100644 --- a/smartapps/smartthings/presence-change-text.src/presence-change-text.groovy +++ b/smartapps/smartthings/presence-change-text.src/presence-change-text.groovy @@ -47,7 +47,7 @@ def updated() { def presenceHandler(evt) { if (evt.value == "present") { - log.debug "${presence.label ?: presence.name} has arrived at the ${location}" + // log.debug "${presence.label ?: presence.name} has arrived at the ${location}" if (location.contactBookEnabled) { sendNotificationToContacts("${presence.label ?: presence.name} has arrived at the ${location}", recipients) @@ -56,7 +56,7 @@ def presenceHandler(evt) { sendSms(phone1, "${presence.label ?: presence.name} has arrived at the ${location}") } } else if (evt.value == "not present") { - log.debug "${presence.label ?: presence.name} has left the ${location}" + // log.debug "${presence.label ?: presence.name} has left the ${location}" if (location.contactBookEnabled) { sendNotificationToContacts("${presence.label ?: presence.name} has left the ${location}", recipients) diff --git a/smartapps/smartthings/ridiculously-automated-garage-door.src/ridiculously-automated-garage-door.groovy b/smartapps/smartthings/ridiculously-automated-garage-door.src/ridiculously-automated-garage-door.groovy index f491c6c..824d8d9 100644 --- a/smartapps/smartthings/ridiculously-automated-garage-door.src/ridiculously-automated-garage-door.groovy +++ b/smartapps/smartthings/ridiculously-automated-garage-door.src/ridiculously-automated-garage-door.groovy @@ -67,7 +67,7 @@ def updated() { } def subscribe() { - log.debug "present: ${cars.collect{it.displayName + ': ' + it.currentPresence}}" + // log.debug "present: ${cars.collect{it.displayName + ': ' + it.currentPresence}}" subscribe(doorSensor, "contact", garageDoorContact) subscribe(cars, "presence", carPresence) diff --git a/smartapps/smartthings/smart-security.src/smart-security.groovy b/smartapps/smartthings/smart-security.src/smart-security.groovy index 6d15cff..acc571e 100644 --- a/smartapps/smartthings/smart-security.src/smart-security.groovy +++ b/smartapps/smartthings/smart-security.src/smart-security.groovy @@ -71,7 +71,7 @@ def updated() { private subscribeToEvents() { subscribe intrusionMotions, "motion", intruderMotion - subscribe residentMotions, "motion", residentMotion + // subscribe residentMotions, "motion", residentMotion subscribe intrusionContacts, "contact", contact subscribe alarms, "alarm", alarm subscribe(app, appTouch) @@ -156,6 +156,7 @@ def residentMotion(evt) // startReArmSequence() // } //} + unsubscribe(residentMotions) } def contact(evt) @@ -214,7 +215,7 @@ def checkForReArm() } else { log.warn "checkForReArm: lastIntruderMotion was null, unable to check for re-arming intrusion detection" - } + } } private startAlarmSequence() diff --git a/smartapps/smartthings/text-me-when-it-opens.src/text-me-when-it-opens.groovy b/smartapps/smartthings/text-me-when-it-opens.src/text-me-when-it-opens.groovy index 08a9887..cbf8698 100644 --- a/smartapps/smartthings/text-me-when-it-opens.src/text-me-when-it-opens.groovy +++ b/smartapps/smartthings/text-me-when-it-opens.src/text-me-when-it-opens.groovy @@ -48,7 +48,7 @@ def updated() def contactOpenHandler(evt) { log.trace "$evt.value: $evt, $settings" - log.debug "$contact1 was opened, texting $phone1" + log.debug "$contact1 was opened, sending text" if (location.contactBookEnabled) { sendNotificationToContacts("Your ${contact1.label ?: contact1.name} was opened", recipients) } diff --git a/smartapps/smartthings/text-me-when-theres-motion-and-im-not-here.src/text-me-when-theres-motion-and-im-not-here.groovy b/smartapps/smartthings/text-me-when-theres-motion-and-im-not-here.src/text-me-when-theres-motion-and-im-not-here.groovy index a3fac54..1094255 100644 --- a/smartapps/smartthings/text-me-when-theres-motion-and-im-not-here.src/text-me-when-theres-motion-and-im-not-here.groovy +++ b/smartapps/smartthings/text-me-when-theres-motion-and-im-not-here.src/text-me-when-theres-motion-and-im-not-here.groovy @@ -50,7 +50,7 @@ def updated() { def motionActiveHandler(evt) { log.trace "$evt.value: $evt, $settings" - + if (presence1.latestValue("presence") == "not present") { // Don't send a continuous stream of text messages def deltaSeconds = 10 @@ -60,14 +60,14 @@ def motionActiveHandler(evt) { def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1 if (alreadySentSms) { - log.debug "SMS already sent to $phone1 within the last $deltaSeconds seconds" + log.debug "SMS already sent within the last $deltaSeconds seconds" } else { if (location.contactBookEnabled) { log.debug "$motion1 has moved while you were out, sending notifications to: ${recipients?.size()}" sendNotificationToContacts("${motion1.label} ${motion1.name} moved while you were out", recipients) } else { - log.debug "$motion1 has moved while you were out, texting $phone1" + log.debug "$motion1 has moved while you were out, sending text" sendSms(phone1, "${motion1.label} ${motion1.name} moved while you were out") } } diff --git a/smartapps/smartthings/the-gun-case-moved.src/the-gun-case-moved.groovy b/smartapps/smartthings/the-gun-case-moved.src/the-gun-case-moved.groovy index 196d57a..1cce9c2 100644 --- a/smartapps/smartthings/the-gun-case-moved.src/the-gun-case-moved.groovy +++ b/smartapps/smartthings/the-gun-case-moved.src/the-gun-case-moved.groovy @@ -53,13 +53,13 @@ def accelerationActiveHandler(evt) { def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1 if (alreadySentSms) { - log.debug "SMS already sent to $phone1 within the last $deltaSeconds seconds" + log.debug "SMS already sent to phone within the last $deltaSeconds seconds" } else { if (location.contactBookEnabled) { sendNotificationToContacts("Gun case has moved!", recipients) } else { - log.debug "$accelerationSensor has moved, texting $phone1" + log.debug "$accelerationSensor has moved, texting phone" sendSms(phone1, "Gun case has moved!") } } diff --git a/smartapps/smartthings/wemo-connect.src/wemo-connect.groovy b/smartapps/smartthings/wemo-connect.src/wemo-connect.groovy index 35cbf4f..73b4426 100644 --- a/smartapps/smartthings/wemo-connect.src/wemo-connect.groovy +++ b/smartapps/smartthings/wemo-connect.src/wemo-connect.groovy @@ -86,6 +86,7 @@ def firstPage() def lightSwitchesDiscovered = lightSwitchesDiscovered() return dynamicPage(name:"firstPage", title:"Discovery Started!", nextPage:"", refreshInterval: refreshInterval, install:true, uninstall: true) { + section { paragraph title: "Note:", "This device has not been officially tested and certified to “Work with SmartThings”. You can connect it to your SmartThings home but performance may vary and we will not be able to provide support or assistance." } section("Select a device...") { input "selectedSwitches", "enum", required:false, title:"Select Wemo Switches \n(${switchesDiscovered.size() ?: 0} found)", multiple:true, options:switchesDiscovered input "selectedMotions", "enum", required:false, title:"Select Wemo Motions \n(${motionsDiscovered.size() ?: 0} found)", multiple:true, options:motionsDiscovered @@ -681,4 +682,4 @@ private Boolean hasAllHubsOver(String desiredFirmware) { private List getRealHubFirmwareVersions() { return location.hubs*.firmwareVersionString.findAll { it } -} \ No newline at end of file +} diff --git a/smartapps/smartthings/withings.src/withings.groovy b/smartapps/smartthings/withings.src/withings.groovy index 24cfcd3..0e09ffc 100644 --- a/smartapps/smartthings/withings.src/withings.groovy +++ b/smartapps/smartthings/withings.src/withings.groovy @@ -60,7 +60,7 @@ def authPage() { def oauthInitUrl() { def token = getToken() - log.debug "initiateOauth got token: $token" + //log.debug "initiateOauth got token: $token" // store these for validate after the user takes the oauth journey state.oauth_request_token = token.oauth_token @@ -76,7 +76,7 @@ def getToken() { ] def requestTokenBaseUrl = "https://oauth.withings.com/account/request_token" def url = buildSignedUrl(requestTokenBaseUrl, params) - log.debug "getToken - url: $url" + //log.debug "getToken - url: $url" return getJsonFromUrl(url) } @@ -182,7 +182,7 @@ def exchangeToken() { def requestTokenBaseUrl = "https://oauth.withings.com/account/access_token" def url = buildSignedUrl(requestTokenBaseUrl, params, tokenSecret) - log.debug "signed url: $url with secret $tokenSecret" + //log.debug "signed url: $url with secret $tokenSecret" def token = getJsonFromUrl(url) @@ -198,8 +198,8 @@ def exchangeToken() { def load() { def json = get(getMeasurement(new Date() - 30)) - - log.debug "swapped, then received: $json" + // removed logging of actual json payload. Can be put back for debugging + log.debug "swapped, then received json" parse(data:json) def html = """