Merge branch 'master' of ssh://plrg.eecs.uci.edu/home/git/smartthings-infrastructure
[smartthings-infrastructure.git] / Extractor / App1 / App1.groovy
index 1c2c55f1302f347ebad33690ef38eff3ac551876..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: "Enhanced Auto Lock Door",
-    namespace: "Lock Auto Super Enhanced",
-    author: "Arnaud",
-    description: "Automatically locks a specific door after X minutes when closed  and unlocks it when open after X seconds.",
-    category: "Safety & Security",
-    iconUrl: "http://www.gharexpert.com/mid/4142010105208.jpg",
-    iconX2Url: "http://www.gharexpert.com/mid/4142010105208.jpg"
+    name: "Make It So",
+    namespace: "smartthings",
+    author: "SmartThings",
+    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{
-    section("Select the door lock:") {
-        input "lock1", "capability.lock", required: true
-    }
-    section("Select the door contact sensor:") {
-        input "contact", "capability.contactSensor", required: true
-    }   
-    section("Automatically lock the door when closed...") {
-        input "minutesLater", "number", title: "Delay (in minutes):", required: true
-    }
-    section("Automatically unlock the door when open...") {
-        input "secondsLater", "number", title: "Delay (in seconds):", required: true
-    }
-    section( "Notifications" ) {
-        input("recipients", "contact", title: "Send notifications to", required: false) {
-            input "phoneNumber", "phone", title: "Warn with text message (optional)", description: "Phone Number", required: false
-        }
-    }
+preferences {
+       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(){
-    initialize()
+def installed() {
+       subscribe(location, changedLocationMode)
+       subscribe(app, appTouch)
+       saveState()
 }
 
-def updated(){
-    unsubscribe()
-    unschedule()
-    initialize()
+def updated() {
+       unsubscribe()
+       subscribe(location, changedLocationMode)
+       subscribe(app, appTouch)
+       saveState()
 }
 
-def initialize(){
-    log.debug "Settings: ${settings}"
-    subscribe(lock1, "lock", doorHandler, [filterEvents: false])
-    subscribe(lock1, "unlock", doorHandler, [filterEvents: false])  
-    subscribe(contact, "contact.open", doorHandler)
-    subscribe(contact, "contact.closed", doorHandler)
+def appTouch(evt)
+{
+       restoreState(currentMode)
 }
 
-def lockDoor(){
-    log.debug "Locking the door."
-    lock1.lock()
-    if(location.contactBookEnabled) {
-        if ( recipients ) {
-            log.debug ( "Sending Push Notification..." ) 
-            sendNotificationToContacts( "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!", recipients)
-        }
-    }
-    if (phoneNumber) {
-        log.debug("Sending text message...")
-        sendSms( phoneNumber, "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!")
-    }
+def changedLocationMode(evt)
+{
+       restoreState(evt.value)
 }
 
-def unlockDoor(){
-    log.debug "Unlocking the door."
-    lock1.unlock()
-    if(location.contactBookEnabled) {
-        if ( recipients ) {
-            log.debug ( "Sending Push Notification..." ) 
-            sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!", recipients)
-        }
-    }
-    if ( phoneNumber ) {
-        log.debug("Sending text message...")
-        sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!")
-    }
+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 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 doorHandler(evt){
-    if ((contact.latestValue("contact") == "open") && (evt.value == "locked")) { // If the door is open and a person locks the door then...  
-        //def delay = (secondsLater) // runIn uses seconds
-        runIn( secondsLater, unlockDoor )   // ...schedule (in minutes) to unlock...  We don't want the door to be closed while the lock is engaged. 
-    }
-    else if ((contact.latestValue("contact") == "open") && (evt.value == "unlocked")) { // If the door is open and a person unlocks it then...
-        unschedule( unlockDoor ) // ...we don't need to unlock it later.
-    }
-    else if ((contact.latestValue("contact") == "closed") && (evt.value == "locked")) { // If the door is closed and a person manually locks it then...
-        unschedule( lockDoor ) // ...we don't need to lock it later.
-    }   
-    else if ((contact.latestValue("contact") == "closed") && (evt.value == "unlocked")) { // If the door is closed and a person unlocks it then...
-       //def delay = (minutesLater * 60) // runIn uses seconds
-        runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
-    }
-    else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "open")) { // If a person opens an unlocked door...
-        unschedule( lockDoor ) // ...we don't need to lock it later.
-    }
-    else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "closed")) { // If a person closes an unlocked door...
-        //def delay = (minutesLater * 60) // runIn uses seconds
-        runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
-    }
-    else { //Opening or Closing door when locked (in case you have a handle lock)
-        log.debug "Unlocking the door."
-        lock1.unlock()
-        if(location.contactBookEnabled) {
-            if ( recipients ) {
-                log.debug ( "Sending Push Notification..." ) 
-                sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!", recipients)
-            }
-        }
-        if ( phoneNumber ) {
-            log.debug("Sending text message...")
-            sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!")
-        }
-    }
+private getCurrentMode()
+{
+       location.mode ?: "_none_"
 }