--- /dev/null
+/**
+ * Example: Control a switch with a contact sensor
+ *
+ * Copyright 2014 Andrew Mager
+ *
+ * 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: "Example: Control a switch and lock with a contact sensor",
+ namespace: "com.smarthings.developers",
+ author: "Andrew Mager & Kris Schaller",
+ description: "Using a contact sensor, control a switch and a lock.",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
+
+
+// This is where a user will select devices to be used by this SmartApp
+preferences {
+ // You can create multiple sections to organize the configuration fields of your SmartApp
+ section(title: "Select Devices") {
+ // Inputs assign variables to a group of physical devices
+ input "contact", "capability.contactSensor", title: "Select a contact sensor", multiple: false
+ input "light", "capability.switch", title: "Select a light or outlet", required: true
+ }
+}
+
+// This function runs when the SmartApp is installed
+def installed() {
+ // This is a standard debug statement in Groovy
+ log.debug "Installed with settings: ${settings}"
+ initialize()
+}
+
+// This function runs when the SmartApp has been updated
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ // Notice that all event subscriptions are removed when a SmartApp is updated
+ unsubscribe()
+ initialize()
+}
+
+// This function is where you initialize callbacks for event listeners
+def initialize() {
+ // The subscribe function takes a input, a state, and a callback method
+ subscribe(contact, "contact.open", openHandler)
+ subscribe(contact, "contact.closed", closedHandler)
+}
+
+// These are our callback methods
+def openHandler(evt) {
+ log.debug "$evt.name: $evt.value"
+ // Turn the light on
+ light.on()
+}
+
+def closedHandler(evt) {
+ log.debug "$evt.name: $evt.value"
+ // Turn the light off and lock the lock
+ light.off()
+}
--- /dev/null
+/**
+ * Example: Control a switch with a contact sensor
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "Example: Control a device with an API call",
+ namespace: "com.smarthings.developers",
+ author: "Andrew Mager & Kris Schaller",
+ description: "Make an HTTP request to a SmartApp to control devices.",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
+
+
+preferences {
+ section(title: "Select Devices") {
+ input "light", "capability.switch", title: "Select a light or outlet", required: true, multiple:false
+ }
+}
+
+// Since the SmartApp doesn't have any dependencies when it's installed or updated,
+// we don't need to worry about those states.
+def installed() {}
+def updated() {}
+
+
+// This block defines an endpoint, and which functions will fire depending on which type
+// of HTTP request you send
+mappings {
+ // The path is appended to the endpoint to make requests
+ path("/switch") {
+ // These actions link HTTP verbs to specific callback functions in your SmartApp
+ action: [
+ GET: "getSwitch", // "When an HTTP GET request is received, run getSwitch()"
+ PUT: "setSwitch"
+ ]
+ }
+}
+
+
+// Callback functions
+def getSwitch() {
+ // This returns the current state of the switch in JSON
+ return light.currentState("switch")
+}
+
+def setSwitch() {
+ switch(request.JSON.value) {
+ case "on":
+ light.on();
+ break;
+ case "off":
+ light.off();
+ break;
+ default:
+ break;
+ }
+}
--- /dev/null
+/**
+ * [Workshop Demo] SMS to Hue
+ *
+ * Copyright 2015 Andrew Mager
+ *
+ * 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: "[Workshop Demo] SMS to Hue",
+ namespace: "com.smartthings.dev",
+ author: "Andrew Mager",
+ description: "Change the color of Hue bulbs from an SMS.",
+ category: "My Apps",
+ 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",
+ oauth: true)
+
+
+preferences {
+ section("Control these hue bulbs...") {
+ input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:false, multiple:true
+ }
+}
+
+
+// This block defines an endpoint, and which functions will fire depending on which type
+// of HTTP request you send
+mappings {
+ // The path is appended to the endpoint to make request
+ path("/hue") {
+ action: [
+ PUT: "postHue"
+ ]
+ }
+}
+
+
+def installed() {}
+def updated() {}
+
+
+
+/*
+ This function receives a JSON payload and parses out the color from a tweet.
+ For example, someone tweets, "@SmartThingsDev #IoTWorld2015 color=blue". Then it sends the
+ correct color as a string to setHueColor().
+*/
+def postHue() {
+ /*
+ "request.JSON?" checks to make sure that the object exists. And ".text" is the
+ key for the value that we're looking for. It's the body of the tweet.
+ */
+ def color = (request.JSON?.value).toLowerCase()
+
+ try {
+ // Finds the text "color=[colorname]" and parses out the color name
+ setHueColor(color)
+ }
+ catch (any) {
+ log.trace "Something went wrong."
+ }
+}
+
+
+// This function takes a String of text and associates it with an Integer value for the color.
+private setHueColor(color) {
+
+ // Initaliaze values for hue, saturation, and level
+ def hueColor = 0
+ def saturation = 100
+ def level = 100
+
+ switch(color) {
+ case "white":
+ hueColor = 52
+ saturation = 19
+ break;
+ case "blue":
+ hueColor = 70
+ break;
+ case "green":
+ hueColor = 39
+ break;
+ case "yellow":
+ hueColor = 25
+ break;
+ case "orange":
+ hueColor = 10
+ break;
+ case "purple":
+ hueColor = 75
+ break;
+ case "pink":
+ hueColor = 83
+ break;
+ case "red":
+ hueColor = 100
+ break;
+ }
+
+ // Set the new value of hue, saturation, and level
+ def newValue = [hue: hueColor, saturation: saturation, level: level]
+
+ // Update each Hue bulb with the new values
+ hues*.setColor(newValue)
+}
--- /dev/null
+/**
+ * Weather Underground PWS Connect
+ *
+ * Copyright 2015 Andrew Mager
+ *
+ * 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.
+ *
+ */
+
+// This imports the Java class "DecimalFormat"
+import java.text.DecimalFormat
+
+definition(
+ name: "Weather Underground PWS Connect",
+ namespace: "co.mager",
+ author: "Andrew Mager",
+ description: "Connect your SmartSense Temp/Humidity sensor to your Weather Underground Personal Weather Station.",
+ category: "Green Living",
+ iconUrl: "http://i.imgur.com/HU0ANBp.png",
+ iconX2Url: "http://i.imgur.com/HU0ANBp.png",
+ iconX3Url: "http://i.imgur.com/HU0ANBp.png",
+ oauth: true)
+
+
+preferences {
+ section("Select a sensor") {
+ input "temp", "capability.temperatureMeasurement", title: "Temperature", required: true
+ input "humidity", "capability.relativeHumidityMeasurement", title: "Humidity", required: true
+ }
+ section("Configure your Weather Underground credentials") {
+ input "weatherID", "text", title: "Weather Station ID", required: true
+ input "password", "password", title: "Weather Underground password", required: true
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+ initialize()
+}
+
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ unsubscribe()
+ initialize()
+}
+
+
+def initialize() {
+
+ /*
+ Check to see if the sensor is reporting temperature, then run the updateCurrentWeather
+ every 10 minutes
+ */
+ if (temp.currentTemperature) {
+ runEvery5Minutes(updateCurrentWeather)
+ }
+}
+
+
+/*
+ Updates the Weather Underground Personal Weather Station (PWS) Upload Protocol
+ Reference: http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol
+*/
+def updateCurrentWeather() {
+
+ // Logs of the current data from the sensor
+ log.trace "Temp: " + temp.currentTemperature
+ log.trace "Humidity: " + humidity.currentHumidity
+ log.trace "Dew Point: " + calculateDewPoint(temp.currentTemperature, humidity.currentHumidity)
+
+ // Builds the URL that will be sent to Weather Underground to update your PWS
+ def params = [
+ uri: "http://weatherstation.wunderground.com",
+ path: "/weatherstation/updateweatherstation.php",
+ query: [
+ "ID": weatherID,
+ "PASSWORD": password,
+ "dateutc": "now",
+ "tempf": temp.currentTemperature,
+ "humidity": humidity.currentHumidity,
+ "dewptf": calculateDewPoint(temp.currentTemperature, humidity.currentHumidity),
+ "action": "updateraw",
+ "softwaretype": "SmartThings"
+ ]
+ ]
+
+ try {
+ // Make the HTTP request using httpGet()
+ httpGet(params) { resp -> // This is how we define the "return data". Can also use $it.
+ log.debug "response data: ${resp.data}"
+ }
+ } catch (e) {
+ log.error "something went wrong: $e"
+ }
+
+}
+
+// Calculates dewpoint based on temperature and humidity
+def calculateDewPoint(t, rh) {
+ def dp = 243.04 * ( Math.log(rh / 100) + ( (17.625 * t) / (243.04 + t) ) ) / (17.625 - Math.log(rh / 100) - ( (17.625 * t) / (243.04 + t) ) )
+ // Format the response for Weather Underground
+ return new DecimalFormat("##.##").format(dp)
+}
+
--- /dev/null
+/**
+ * Contact Activated Lighting
+ *
+ * Copyright 2016 Tim Slagle
+ *
+ * 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: "Contact Activated Lighting",
+ namespace: "tslagle13",
+ author: "Tim Slagle",
+ description: "Create child apps that will use a contact sensor to turn on lights.",
+ category: "Convenience",
+ 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")
+
+
+preferences {
+ page(name: "mainPage", title: "Child Apps", install: true, uninstall: true) {
+ section {
+ app(name: "childRule", appName: "Light Rule", namespace: "tslagle13", title: "New Lighting Rule", multiple: true)
+ }
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+
+ initialize()
+}
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ // TODO: subscribe to attributes, devices, locations, etc.
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Light Rule
+ *
+ * Copyright 2016 Tim Slagle
+ *
+ * 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: "Light Rule",
+ namespace: "tslagle13",
+ author: "Tim Slagle",
+ description: "Light rule child app for \"Motion Activated Light\"",
+ category: "Convenience",
+ parent: "tslagle13:Contact Activated Lighting",
+ 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")
+
+
+preferences {
+ page name: "mainPage", title: "Automate Lights & Switches", install: false, uninstall: true, nextPage: "namePage"
+ page name: "namePage", title: "Automate Lights & Switches", install: true, uninstall: true
+}
+
+def mainPage() {
+ dynamicPage(name: "mainPage") {
+ section("Which contact sensor?") {
+ input "contactSensor", "capability.contactSensor", title: "Which contact sensor(s)?", multiple: true
+ }
+ section("Which light would you like to turn on?") {
+ input "light", "capability.switch", title: "Which light?", multiple: true
+ }
+ section("Extras") {
+ input "contactInactive", "bool", title: "Turn off if contacts closes?", submitOnChange: true
+ if (contactInactive) {
+ input "delay", "number", title: "After how many seconds?", required: false
+ }
+ }
+ }
+}
+
+def namePage() {
+ if (!overrideLabel) {
+ // if the user selects to not change the label, give a default label
+ def l = "$contactSensor turns on $light"
+ log.debug "will set default label of $l"
+ app.updateLabel(l)
+ }
+ dynamicPage(name: "namePage") {
+ if (overrideLabel) {
+ section("Automation name") {
+ label title: "Enter custom name", defaultValue: app.label, required: false
+ }
+ } else {
+ section("Automation name") {
+ paragraph app.label
+ }
+ }
+ section {
+ input "overrideLabel", "bool", title: "Edit automation name", defaultValue: "false", required: "false", submitOnChange: true
+ }
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+
+ initialize()
+}
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ subscribe (contactSensor, "contact" , contactHandler)
+}
+
+def contactHandler(evt){
+ log.debug evt.name
+ log.debug evt.value
+ log.debug evt.date
+ log.debug evt.isStateChange()
+
+ if (evt.value == "open") {
+ turnLightOn()
+ }
+ else if (contactInactive) {
+ runIn(delay , turnLightOff)
+ }
+}
+
+def turnLightOn() {
+ light.on()
+}
+
+def turnLightOff() {
+ light.off()
+}
--- /dev/null
+/**
+ * Example: Control a switch with a contact sensor
+ *
+ * Copyright 2015 Andrew Mager
+ *
+ * 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: "Example: Control a switch with a contact sensor",
+ namespace: "com.smarthings.dev",
+ author: "Andrew Mager",
+ description: "Using a contact sensor, control a switch.",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
+
+
+preferences {
+ section("Select Devices") {
+ input "contact", "capability.contactSensor", title: "Select a contact sensor", multiple: false
+ input "light", "capability.switch", title: "Select a light or outlet"
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+ initialize()
+}
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ subscribe contact, "contact.open", openHandler
+ subscribe contact, "contact.closed", closedHandler
+}
+
+def openHandler(evt) {
+ log.debug "$evt.name: $evt.value"
+ light.on()
+}
+
+def closedHandler(evt) {
+ log.debug "$evt.name: $evt.value"
+ light.off()
+}
+
+// TODO: implement event handlers
--- /dev/null
+/**
+ * Granny's Faucet
+ * Notifies you when Granny is up and running
+ * Let you know when she hasn't been around so you can check in on her
+ *
+ * Copyright 2015 SmartThings Hack
+ *
+ * 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: "Granny's Faucet",
+ namespace: "com.firstbuild",
+ author: "SmartThings Hack",
+ description: "Check to see if Granny used the faucet in a 24 hour period and send a notification if she does.",
+ category: "My Apps",
+ 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")
+
+
+preferences {
+ section("Which Faucets?") {
+ input "faucet", "capability.accelerationSensor", title: "Which faucet?", required:true
+ }
+ section("Who to text") {
+ input "phone", "phone", title: "Phone number?", required: true
+ }
+ section("How often do you want grandma to check in?") {
+ input "minutes", "number", title: "Delay in minutes before we notify you", defaultValue: 1
+ }
+}
+
+def installed() {
+ log.trace "Installed with settings: ${settings}"
+ initialize()
+}
+
+def updated() {
+ log.trace "Updated with settings: ${settings}"
+ state.lastOpened= [date:now()] // now() is ms time built into SmartApps
+ log.debug "Last Updated Date: $state.lastOpened.date"
+
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ subscribe(faucet, "acceleration.active", faucetActiveHandler)
+ subscribe(faucet, "acceleration.inactive", faucetInactiveHandler)
+}
+
+def faucetInactiveHandler(evt) {
+ log.trace "#faucetClosedHandler#"
+ def inputSeconds = 60*minutes.toInteger()
+ log.debug "waiting...$inputSeconds"
+ runIn(inputSeconds, alertMe)
+}
+
+def faucetActiveHandler(evt) {
+ // Don't send a continuous stream of text messages
+ def inputSeconds = 60*minutes.toInteger()
+ def deltaSeconds = inputSeconds
+ def timeAgo = new Date(now() - (1000 * deltaSeconds)) // 61 seconds ago
+ def recentEvents = faucet.eventsSince(timeAgo)
+ log.trace "Found ${recentEvents?.size() ?: 0} events in the last $deltaSeconds seconds"
+ log.debug "Recent Events $recentEvents.value"
+ def alreadySentSms = recentEvents.count {
+ it.value && it.value == "active"
+ } > 1
+
+ if (alreadySentSms) {
+ log.debug "SMS already sent to $phone1 within the last $minutes minute"
+ } else {
+ //
+ sendSms(phone, "Grandma opened faucet")
+ state.lastOpened.date = now()
+ log.debug "Grandma Opened Faucet: $state.lastOpened"
+
+ }
+}
+
+def alertMe() {
+ log.trace "#alerting...#"
+ def targetTime = state.lastOpened.date + minutes.toInteger()*60*1000
+ log.debug "#alertMe: last: ${state.lastOpened.date} , now: ${now()}, targetTime: ${targetTime}} "
+ if ( now() > targetTime ){
+ log.debug "Grandma needs water badly"
+ sendSms(phone, "Grandma needs water badly")
+ } else {
+ log.debug "Grandma's aight!"
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * My Living Room Lighting
+ *
+ * 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.
+ *
+ */
+ definition(
+ name: "My Living Room Lighting",
+ namespace: "smartthings",
+ author: "smartthings",
+ description: "allow a button controller to control my hue lamps, tv lights, and floor lamp",
+ category: "My Apps",
+ 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")
+
+
+ preferences {
+ section("Control which hue lamps?") {
+ input "hueLamps", "capability.colorControl", required: true, multiple: true
+ }
+ section("Control which TV lights?") {
+ input "tvLights", "capability.colorControl", required: false
+ }
+ section("Control other (non-hue) lamps?") {
+ input "otherLights", "capability.switch", required: false, multiple: true
+ }
+ section("Which button controller?") {
+ input "buttonDevice", "capability.button", required: true
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+ initialize()
+}
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ subscribe(buttonDevice, "button", buttonEvent)
+ hueLamps.each {
+ log.debug "lamp ${it.displayName} hue: ${it.currentHue}"
+ log.debug "lamp ${it.displayName} saturation: ${it.currentSaturation}"
+ log.debug "lamp ${it.displayName} color ${it.currentColor}"
+ log.debug "lamp ${it.displayName} level ${it.currentLevel}"
+ }
+
+ log.debug "tv hue: ${tvLights?.currentHue}"
+ log.debug "tv saturation: ${tvLights?.currentSaturation}"
+ log.debug "tv color ${tvLights?.currentColor}"
+ log.debug "tv level ${tvLights?.currentLevel}"
+}
+
+def buttonEvent(evt) {
+ def buttonState = evt.value // "pushed" or "held"
+ def buttonNumber = parseJson(evt.data)?.buttonNumber
+
+ log.debug "buttonState: $buttonState"
+ log.debug "buttonNumber: $buttonNumber"
+
+ if (!(1..4).contains(buttonNumber)) {
+ log.error "This app only supports four buttons. Invalid buttonNumber: $buttonNumber"
+ } else if (!(buttonState == "pushed" || buttonState == "held")) {
+ log.error "This app only supports button pushed and held values. Invalid button state: $buttonState"
+ } else {
+ def meth = "handleButton" + buttonNumber + buttonState.capitalize()
+ log.debug "meth: $meth"
+ "$meth"()
+ }
+ }
+
+// normal "white" lighting
+def handleButton1Pushed() {
+ log.debug "handle1Pushed"
+
+ hueLamps.setColor(level: 100, hue: 20, saturation: 80)
+
+ // notice the "?." operator - tvLights may not be set (required: false).
+ tvLights?.setColor(level: 100, hue: 100, saturation: 100)
+ otherLights?.on()
+}
+
+// turn everything off
+def handleButton1Held() {
+ log.debug "handleButton1Held"
+
+ hueLamps.off()
+ tvLights?.off()
+ otherLights?.off()
+}
+
+// soft, dim white light
+def handleButton2Pushed() {
+ log.debug "handleButton2Pushed"
+
+ hueLamps.setColor(level: 50, hue: 20, saturation: 80)
+ tvLights.setColor(level: 30, hue: 70, saturation: 70)
+ otherLights?.on()
+}
+
+// set to what you want!
+def handleButton2Held() {
+ log.debug "handleButton2Held"
+}
+
+// dim red light
+def handleButton3Pushed() {
+ hueLamps.setColor(level: 40, hue: 100, saturation: 100)
+ tvLights?.setColor(level: 30, hue: 100, saturation: 100)
+ otherLights?.off()
+}
+
+// set to what you want!
+def handleButton3Held() {
+ log.debug "handleButton3Held"
+}
+
+// dim blue light
+def handleButton4Pushed() {
+ log.debug "handleButton4Pushed"
+
+ hueLamps.setColor(level: 10, hue: 70, saturation: 100)
+ tvLights?.setColor(level: 10, hue: 70, saturation: 100)
+ otherLights?.off()
+}
+
+// debug information
+def handleButton4Held() {
+ hueLamps.each {
+ log.debug "lamp ${it.displayName} hue: ${it.currentHue}"
+ log.debug "lamp ${it.displayName} saturation: ${it.currentSaturation}"
+ log.debug "lamp ${it.displayName} level ${it.currentLevel}"
+ }
+
+ log.debug "tv hue: ${tvLights?.currentHue}"
+ log.debug "tv saturation: ${tvLights?.currentSaturation}"
+ log.debug "tv color ${tvLights?.currentColor}"
+ log.debug "tv level ${tvLights?.currentLevel}"
+}
--- /dev/null
+/**
+ * Example of passing params via href element to a dynamic page
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "href params example",
+ namespace: "smartthings",
+ author: "SmartThings",
+ description: "passing params via href element to a dynamic page",
+ category: "",
+ 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")
+
+
+// ========================================================
+// PAGES
+// ========================================================
+
+preferences {
+ page(name: "firstPage")
+ page(name: "secondPage")
+ page(name: "thirdPage")
+}
+
+def firstPage() {
+
+ def hrefParams = [
+ foo: "bar",
+ thisIs: "totally working",
+ install: checkSomeCustomLogic(),
+ nextPage: "thirdPage"
+ ]
+
+ dynamicPage(name: "firstPage", uninstall: true) {
+ /*
+ * The href element accepts a key of `params` and expects a `Map` as the value.
+ * Anything passed in `params` will be sent along with the request but will not be persisted in any way.
+ * The params will be used going to the next page but will not be available when backing out of that page.
+ * This, combined with the fact that pages refresh when navigating back to them, means that your params will not be
+ * available if your user hits the back button.
+ */
+ section {
+ href(
+ name: "toSecondPage",
+ page: "secondPage",
+ params: hrefParams,
+ description: "includes params: ${hrefParams}",
+ state: hrefState()
+ )
+ }
+ }
+}
+
+def secondPage(params) {
+ /*
+ * firstPage included `params` in the href element that navigated to here.
+ * You must specify some variable name in the method declaration. (I used 'params' here, but it can be any variable name you want).
+ * If you do not specify a variable name, there is no way to get the params that you specified in your `href` element.
+ */
+
+ log.debug "params: ${params}"
+
+ dynamicPage(name: "secondPage", uninstall: true, install: params?.install) {
+ if (params.nextPage) {
+ section {
+ href(
+ name: "toNextPage",
+ page: params.nextPage,
+ description: hrefState() ? "You've already been to the third page": "go checkout the third page",
+ state: hrefState()
+ )
+ }
+ } else {
+ section {
+ paragraph "There were no params included when fetching this page."
+ }
+ }
+ }
+}
+
+def thirdPage() {
+
+ state.reachedThirdPage = true
+
+ dynamicPage(name: "thirdPage") {
+ section {
+ image "https://placekitten.com/g/600/500"
+ }
+ }
+}
+
+// ========================================================
+// HELPERS
+// ========================================================
+
+
+def checkSomeCustomLogic() {
+ // ...
+ false
+}
+
+def hrefState() {
+ /*
+ * `state: "complete"` makes the right side of the href green.
+ * It's a great way to show the user that they've already set up some stuff on that page.
+ * In other words, it's a great way to show state ;)
+ * If you're using hrefs, it's a good idea to set `state` when appropriate.
+ */
+ state.reachedThirdPage ? "complete": ""
+}
+
+// ========================================================
+// HANDLERS
+// ========================================================
+
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+ initialize()
+}
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ // TODO: subscribe to attributes, devices, locations, etc.
+}
+
+// TODO: implement event handlers
\ No newline at end of file
--- /dev/null
+/**
+ * Control a Switch with an API call
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "Control a Switch with an API call",
+ namespace: "smartthings",
+ author: "SmartThings",
+ description: "V2 of 'RESTful Switch' example. Trying to make OAuth work properly.",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
+ oauth: true)
+
+preferences {
+ section("which switches?") {
+ input "theSwitches", "capability.switch", multiple: true
+ }
+}
+
+mappings {
+ path("/switches") {
+ // GET requests to /switches endpoint go to listSwitches.
+ // PUT requests go to updateSwitches
+ action: [
+ GET: "getSwitches",
+ PUT: "updateSwitches"
+ ]
+ }
+
+ // GET requests to endpoint /switches/<id> go to getSwitch
+ // PUT requests to endpoint /switches/<id> go to updateSwitch
+ path("/switches/:id") {
+ action: [
+ GET: "getSwitch",
+ PUT: "updateSwitch"
+ ]
+ }
+}
+
+// return a map in the form of [switchName, switchStatus]
+// the returned value will be converted to JSON by the platform
+def getSwitches() {
+ def status = [:]
+ theSwitches.each {theSwitch ->
+ log.trace "will populate status map"
+ log.trace "theSwitch id: ${theSwitch.id}"
+ status.put(theSwitch.displayName, theSwitch.currentSwitch)
+ }
+
+ log.debug "listSwitches returning: $status"
+ return status
+}
+
+def getSwitch() {
+ def theSwitch = theSwitches.find{it.id == params.id}
+ [theSwitch.displayName, theSwitch.currentSwitch]
+}
+
+// execute the command specified in the request
+// returns a 400 error if a non-supported command
+// is specified (only on, off, or toggle supported)
+// assumes request body with JSON in format {"command" : "<value>"}
+def updateSwitches() {
+ log.trace "updateSwitches: request: $request"
+ log.trace "updateSwitches: params: $params"
+
+ theSwitches.each {
+ doCommand(it, request.JSON.command)
+ }
+}
+
+// execute the command specified in the request
+// return a 400 error if a non-supported command
+// is specified (only on, off, or toggle supported)
+// assumes request body with JSON in format {"command" : "<value>"}
+def updateSwitch() {
+ log.trace "updateSwitch: look for swithc with id ${params.id}"
+ def theSwitch = theSwitches.find{it.id == params.id}
+ doCommand(theSwitch, request.JSON.command)
+}
+
+def doCommand(theSwitch, command) {
+ if (command == "toggle") {
+ if (theSwitch.currentSwitch == "on") {
+ log.debug "will try and turn switch ${theSwitch.displayName} on"
+ theSwitch.off()
+ } else {
+ log.debug "will try and turn switch ${theSwitch.displayName} off"
+ theSwitch.on()
+ }
+ } else if (command == "on" || command == "off") {
+ theSwitch."$command"()
+ } else {
+ httpError(400, "Unsupported command - only 'toggle', 'off', and 'on' supported")
+ }
+}
+
+// called when SmartApp is installed
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+}
+
+// called when any preferences are changed in this SmartApp.
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ unsubscribe()
+}
--- /dev/null
+/**
+ * Turn on at Sunset
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "Turn on at Sunset",
+ namespace: "examples",
+ author: "SmartThings",
+ description: "Turn on lights at sunset, based on your location's geofence.",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine@2x.png",
+ iconX3Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine@2x.png")
+
+preferences {
+ section("Lights") {
+ input "switches", "capability.switch", title: "Which lights to turn on?"
+ }
+}
+
+def installed() {
+ initialize()
+}
+
+def updated() {
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ subscribe(location, "sunset", sunsetHandler)
+}
+
+def sunsetHandler(evt) {
+ log.debug "turning on lights at sunset"
+ switches.on()
+}
--- /dev/null
+/**
+ * Turn on before Sunset
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "Turn on before Sunset",
+ namespace: "exmaples",
+ author: "SmartThings",
+ description: "Turn on lights a number of minutes before sunset, based on your location's geofence",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine@2x.png",
+ iconX3Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine@2x.png")
+
+preferences {
+ section("Lights") {
+ input "switches", "capability.switch", title: "Which lights to turn on?"
+ input "offset", "number", title: "Turn on this many minutes before sunset"
+ }
+}
+
+def installed() {
+ initialize()
+}
+
+def updated() {
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ subscribe(location, "sunsetTime", sunsetTimeHandler)
+
+ //schedule it to run today too
+ scheduleTurnOn(location.currentValue("sunsetTime"))
+}
+
+def sunsetTimeHandler(evt) {
+ //when I find out the sunset time, schedule the lights to turn on with an offset
+ scheduleTurnOn(evt.value)
+}
+
+def scheduleTurnOn(sunsetString) {
+ //get the Date value for the string
+ def sunsetTime = Date.parse("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", sunsetString)
+
+ //calculate the offset
+ def timeBeforeSunset = new Date(sunsetTime.time - (offset * 60 * 1000))
+
+ log.debug "Scheduling for: $timeBeforeSunset (sunset is $sunsetTime)"
+
+ //schedule this to run one time
+ runOnce(timeBeforeSunset, turnOn)
+}
+
+def turnOn() {
+ log.debug "turning on lights"
+ switches.on()
+}
--- /dev/null
+/**
+ * Turn on by ZIP code
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "Turn on by ZIP code",
+ namespace: "examples",
+ author: "SmartThings",
+ description: "Turn on lights based on ZIP code",
+ category: "My Apps",
+ iconUrl: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine.png",
+ iconX2Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine@2x.png",
+ iconX3Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/rise-and-shine@2x.png")
+
+preferences {
+ section("Lights") {
+ input "switches", "capability.switch", title: "Which lights to turn on?"
+ }
+ section("Sunset offset (optional)...") {
+ input "sunsetOffsetValue", "text", title: "HH:MM", required: false
+ }
+ section("Zip code") {
+ input "zipCode", "text", required: false
+ }
+}
+
+def installed() {
+ initialize()
+}
+
+def updated() {
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+ scheduleNextSunset()
+}
+
+def scheduleNextSunset(date = null) {
+ def s = getSunriseAndSunset(zipCode: zipCode, sunsetOffset: getSunsetOffset(), date: date)
+ def now = new Date()
+ def setTime = s.sunset
+ log.debug "setTime: $setTime"
+
+ // use state to keep track of sunset times between executions
+ // if sunset time has changed, unschedule and reschedule handler with updated time
+ if(state.setTime != setTime.time) {
+ unschedule("sunsetHandler")
+
+ if(setTime.before(now)) {
+ setTime = setTime.next()
+ }
+
+ state.setTime = setTime.time
+
+ log.info "scheduling sunset handler for $setTime"
+ schedule(setTime, sunsetHandler)
+ }
+}
+
+def sunsetHandler() {
+ log.debug "turning on lights"
+ switches.on()
+
+ // schedule for tomorrow
+ scheduleNextSunset(new Date() + 1)
+}
+
+private getSunsetOffset() {
+ //if there is an offset, make negative since we only care about before
+ sunsetOffsetValue ? "-$sunsetOffsetValue" : null
+}
--- /dev/null
+/**
+ * Tweet to Hue
+ *
+ * Copyright 2015 Andrew Mager & Kris Schaller
+ *
+ * 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: "Tweet to Hue",
+ namespace: "com.smartthings.dev",
+ author: "Andrew Mager & Kris Schaller",
+ description: "Update a Hue bulb's color based on a tweet.",
+ category: "Fun & Social",
+ 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",
+ oauth: true)
+
+
+preferences {
+ section("Control these hue bulbs...") {
+ input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:false, multiple:true
+ }
+}
+
+
+/* This block defines which functions will fire when you hit certain endpoints. */
+
+mappings {
+ path("/hue") {
+ action: [
+ PUT: "postHue"
+ ]
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+
+ initialize()
+}
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+
+ unsubscribe()
+ initialize()
+}
+
+def initialize() {
+
+}
+
+/**
+* Body: { color=[yourcolor] } to change color
+* Example:
+* {
+* "value" : " #smartthings is so color=blue"
+* }
+*/
+
+def postHue() {
+ def tweetText = request.JSON.text
+ log.info "POST: $tweetText"
+
+ try {
+ def tweetColor = (tweetText =~ /color=(\w+)/)[0][1].toLowerCase()
+ log.debug (tweetText =~ /color=(\w+)/)
+ setHueColor(tweetColor)
+ }
+ catch (any) {
+ log.trace "POST: Check Body (e.g: @RT: #smartthings color=red)"
+ }
+}
+
+private setHueColor(color) {
+
+ def hueColor = 0
+ def saturation = 100
+
+ switch(color) {
+ case "white":
+ hueColor = 52
+ saturation = 19
+ break;
+ case "blue":
+ hueColor = 70
+ break;
+ case "green":
+ hueColor = 39
+ break;
+ case "yellow":
+ hueColor = 25
+ break;
+ case "orange":
+ hueColor = 10
+ break;
+ case "purple":
+ hueColor = 75
+ break;
+ case "pink":
+ hueColor = 83
+ break;
+ case "red":
+ hueColor = 100
+ break;
+ }
+
+ state.previous = [:]
+
+ hues.each {
+ state.previous[it.id] = [
+ "switch": it.currentValue("switch"),
+ "level" : it.currentValue("level"),
+ "hue": it.currentValue("hue"),
+ "saturation": it.currentValue("saturation")
+ ]
+ }
+
+ log.debug "current values = $state.previous"
+
+ def newValue = [hue: hueColor, saturation: saturation, level: 100]
+ log.debug "new value = $newValue"
+
+ hues*.setColor(newValue)
+}
--- /dev/null
+/**
+ * Web Services Tutorial
+ *
+ * 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.
+ *
+ */
+definition(
+ name: "Web Services Tutorial",
+ namespace: "smartthings",
+ author: "SmartThings",
+ description: "web services tutorial",
+ category: "",
+ 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",
+ oauth: [displayName: "web services tutorial ", displayLink: "http://localhost:4567"])
+
+
+preferences {
+ section ("Allow external service to control these things...") {
+ input "switches", "capability.switch", multiple: true, required: true
+ }
+}
+
+mappings {
+ path("/switches") {
+ action: [
+ GET: "listSwitches"
+ ]
+ }
+ path("/switches/:command") {
+ action: [
+ PUT: "updateSwitches"
+ ]
+ }
+}
+
+// returns a list like
+// [[name: "kitchen lamp", value: "off"], [name: "bathroom", value: "on"]]
+def listSwitches() {
+
+ def resp = []
+ switches.each {
+ resp << [name: it.displayName, value: it.currentValue("switch")]
+ }
+ return resp
+}
+
+void updateSwitches() {
+ // use the built-in request object to get the command parameter
+ def command = params.command
+
+ // all switches have the comand
+ // execute the command on all switches
+ // (note we can do this on the array - the command will be invoked on every element
+ switch(command) {
+ case "on":
+ switches.on()
+ break
+ case "off":
+ switches.off()
+ break
+ default:
+ httpError(400, "$command is not a valid command for all switches specified")
+ }
+
+}
+def installed() {}
+
+def updated() {}
--- /dev/null
+/**
+ * Weather Underground PWS Connect
+ *
+ * Copyright 2015 Andrew Mager
+ *
+ * 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.
+ *
+ */
+
+import java.text.DecimalFormat
+
+definition(
+ name: "Weather Underground PWS Connect",
+ namespace: "co.mager",
+ author: "Andrew Mager",
+ description: "Connect your SmartSense Temp/Humidity sensor to your Weather Underground Personal Weather Station.",
+ category: "Green Living",
+ iconUrl: "http://i.imgur.com/HU0ANBp.png",
+ iconX2Url: "http://i.imgur.com/HU0ANBp.png",
+ iconX3Url: "http://i.imgur.com/HU0ANBp.png",
+ oauth: true)
+
+
+preferences {
+ section("Select a sensor") {
+ input "temp", "capability.temperatureMeasurement", title: "Temperature", required: true
+ input "humidity", "capability.relativeHumidityMeasurement", title: "Humidity", required: true
+ }
+ section("Configure your Weather Underground credentials") {
+ input "weatherID", "text", title: "Weather Station ID", required: true
+ input "password", "password", title: "Weather Underground password", required: true
+
+ }
+}
+
+def installed() {
+ log.debug "Installed with settings: ${settings}"
+ initialize()
+}
+
+
+def updated() {
+ log.debug "Updated with settings: ${settings}"
+ initialize()
+}
+
+
+def initialize() {
+
+ runEvery10Minutes(updateCurrentWeather)
+
+ log.trace "Temp: " + temp.currentTemperature
+ log.trace "Humidity: " + humidity.currentHumidity
+ log.trace "Dew Point: " + calculateDewPoint(temp.currentTemperature, humidity.currentHumidity)
+
+}
+
+
+def updateCurrentWeather() {
+
+ def params = [
+ uri: "http://weatherstation.wunderground.com",
+ path: "/weatherstation/updateweatherstation.php",
+ query: [
+ "ID": weatherID,
+ "PASSWORD": password,
+ "dateutc": "now",
+ "tempf": temp.currentTemperature,
+ "humidity": humidity.currentHumidity,
+ "dewptf": calculateDewPoint(temp.currentTemperature, humidity.currentHumidity),
+ "action": "updateraw",
+ "softwaretype": "SmartThings"
+ ]
+ ]
+
+ if (temp.currentTemperature) {
+ try {
+ httpGet(params) { resp ->
+ log.debug "response data: ${resp.data}"
+ }
+ } catch (e) {
+ log.error "something went wrong: $e"
+ }
+ }
+
+}
+
+
+def calculateDewPoint(t, rh) {
+ def dp = 243.04 * ( Math.log(rh / 100) + ( (17.625 * t) / (243.04 + t) ) ) / (17.625 - Math.log(rh / 100) - ( (17.625 * t) / (243.04 + t) ) )
+ return new DecimalFormat("##.##").format(dp)
+}