Merge branch 'master' of ssh://plrg.eecs.uci.edu/home/git/smartthings-infrastructure
[smartthings-infrastructure.git] / Extractor / App1 / App1.groovy
index b94d720c26e4d62334b42874fbf0925656a6fdd7..718d69ef7448d4cbd969f398b17485fc205676e9 100644 (file)
-////////////////
+/**
+ *  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.
+ *
+ *  Make it So
+ *
+ *  Author: SmartThings
+ *  Date: 2013-03-06
+ */
 definition(
-    name: "NFC Tag Toggle",
+    name: "Make It So",
     namespace: "smartthings",
     author: "SmartThings",
-    description: "Allows toggling of a switch, lock, or garage door based on an NFC Tag touch event",
-    category: "SmartThings Internal",
-    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Developers/nfc-tag-executor.png",
-    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Developers/nfc-tag-executor@2x.png",
-    iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Developers/nfc-tag-executor@2x.png")
-
+    description: "Saves the states of a specified set switches and thermostat setpoints and restores them at each mode change. To use 1) Set the mode, 2) Change switches and setpoint to where you want them for that mode, and 3) Install or update the app. Changing to that mode or touching the app will set the devices to the saved state.",
+    category: "Convenience",
+    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/light_thermo-switch.png",
+    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/light_thermo-switch@2x.png"
+)
 
 preferences {
-    page(name: "pageOne", title: "Device selection", uninstall: true, nextPage: "pageTwo") {
-        section("Select an NFC tag") {
-            input "tag", "capability.touchSensor", title: "NFC Tag"
-        }
-        section("Select devices to control") {
-            input "switch1", "capability.switch", title: "Light or switch", required: false, multiple: true
-            input "lock", "capability.lock", title: "Lock", required: false, multiple: true
-            input "garageDoor", "capability.doorControl", title: "Garage door controller", required: false, multiple: true
-        }
-    }
-    
-    page(name: "pageTwo", title: "Master devices", install: true, uninstall: true)
-}
-
-def pageTwo() {
-       dynamicPage(name: "pageTwo") {
-       section("If set, the state of these devices will be toggled each time the tag is touched, " + 
-                "e.g. a light that's on will be turned off and one that's off will be turned on, " +
-                "other devices of the same type will be set to the same state as their master device. " +
-                "If no master is designated then the majority of devices of the same type will be used " +
-                "to determine whether to turn on or off the devices.") {
-            
-            if (switch1 || masterSwitch) {
-                input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
-            }
-            if (lock || masterLock) {
-                input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
-            }
-            if (garageDoor || masterDoor) {
-                input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
-            }            
-               }
-               section([mobileOnly:true]) {
-                       label title: "Assign a name", required: false
-                       mode title: "Set for specific mode(s)", required: false
-               }        
-    }
+       section("Switches") {
+               input "switches", "capability.switch", multiple: true, required: false
+       }
+       section("Thermostats") {
+               input "thermostats", "capability.thermostat", multiple: true, required: false
+       }
+       section("Locks") {
+               input "locks", "capability.lock", multiple: true, required: false
+       }
 }
 
 def installed() {
-       log.debug "Installed with settings: ${settings}"
-
-       initialize()
+       subscribe(location, changedLocationMode)
+       subscribe(app, appTouch)
+       saveState()
 }
 
 def updated() {
-       log.debug "Updated with settings: ${settings}"
-
        unsubscribe()
-       initialize()
+       subscribe(location, changedLocationMode)
+       subscribe(app, appTouch)
+       saveState()
 }
 
-def initialize() {
-       subscribe tag, "nfcTouch", touchHandler
-    subscribe app, touchHandler
+def appTouch(evt)
+{
+       restoreState(currentMode)
+}
+
+def changedLocationMode(evt)
+{
+       restoreState(evt.value)
+}
+
+private restoreState(mode)
+{
+       log.info "restoring state for mode '$mode'"
+       def map = state[mode] ?: [:]
+       switches?.each {
+               def value = map[it.id]
+               if (value?.switch == "on") {
+                       def level = value.level
+                       if (level) {
+                               log.debug "setting $it.label level to $level"
+                               it.setLevel(level)
+                       }
+                       else {
+                               log.debug "turning $it.label on"
+                               it.on()
+                       }
+               }
+               else if (value?.switch == "off") {
+                       log.debug "turning $it.label off"
+                       it.off()
+               }
+       }
+
+       thermostats?.each {
+               def value = map[it.id]
+               if (value?.coolingSetpoint) {
+                       log.debug "coolingSetpoint = $value.coolingSetpoint"
+                       it.setCoolingSetpoint(value.coolingSetpoint)
+               }
+               if (value?.heatingSetpoint) {
+                       log.debug "heatingSetpoint = $value.heatingSetpoint"
+                       it.setHeatingSetpoint(value.heatingSetpoint)
+               }
+       }
+
+       locks?.each {
+               def value = map[it.id]
+               if (value) {
+                       if (value?.locked) {
+                               it.lock()
+                       }
+                       else {
+                               it.unlock()
+                       }
+               }
+       }
 }
 
-private currentStatus(devices, master, attribute) {
-       log.trace "currentStatus($devices, $master, $attribute)"
-       def result = null
-       if (master) {
-       result = devices.find{it.id == master}?.currentValue(attribute)
-    }
-    else {
-       def map = [:]
-        devices.each {
-               def value = it.currentValue(attribute)
-            map[value] = (map[value] ?: 0) + 1
-            log.trace "$it.displayName: $value"
-        }
-        log.trace map
-        result = map.collect{it}.sort{it.value}[-1].key
-    }
-    log.debug "$attribute = $result"
-    result
+
+private saveState()
+{
+       def mode = currentMode
+       def map = state[mode] ?: [:]
+
+       switches?.each {
+               map[it.id] = [switch: it.currentSwitch, level: it.currentLevel]
+       }
+
+       thermostats?.each {
+               map[it.id] = [coolingSetpoint: it.currentCoolingSetpoint, heatingSetpoint: it.currentHeatingSetpoint]
+       }
+
+       locks?.each {
+               map[it.id] = [locked: it.currentLock == "locked"]
+       }
+
+       state[mode] = map
+       log.debug "saved state for mode ${mode}: ${state[mode]}"
+       log.debug "state: $state"
 }
 
-def touchHandler(evt) {
-       log.trace "touchHandler($evt.descriptionText)"
-    if (switch1) {
-       def status = currentStatus(switch1, masterSwitch, "switch")
-        switch1.each {
-            if (status == "on") {
-                it.off()
-            }
-            else {
-                it.on()
-            }
-        }
-    }
-    
-    if (lock) {
-       def status = currentStatus(lock, masterLock, "lock")
-        lock.each {
-            if (status == "locked") {
-                lock.unlock()
-            }
-            else {
-                lock.lock()
-            }
-        }
-    }
-    
-    if (garageDoor) {
-        def status = currentStatus(garageDoor, masterDoor, "status")
-       garageDoor.each {
-               if (status == "open") {
-               it.close()
-            }
-            else {
-               it.open()
-            }
-        }
-    }
+private getCurrentMode()
+{
+       location.mode ?: "_none_"
 }