Some minor changes in events' format
[smartthings-infrastructure.git] / Extractor / App1 / App1.groovy
index 49a97c3e9e3d332f78ebf126fc3b6d534f54e1f3..94ec37c73a6ba5e5fbec131bfd6c9a90f29bedae 100644 (file)
-/**
- *  groveStreams
- *
- *  Copyright 2014 Yves Racine
- *
- *  LinkedIn profile: ca.linkedin.com/pub/yves-racine-m-sc-a/0/406/4b/
- *
- *  Developer retains all right, title, copyright, and interest, including all copyright, patent rights, trade secret 
- *  in the Background technology. May be subject to consulting fees under the Agreement between the Developer and the Customer. 
- *  Developer grants a non exclusive perpetual license to use the Background technology in the Software developed for and delivered 
- *  to Customer under this Agreement. However, the Customer shall make no commercial use of the Background technology without
- *  Developer's written consent.
- *
- *  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. 
- *  Software Distribution is restricted and shall be done only with Developer's written approval.
- *
- *  Based on code from Jason Steele & Minollo
- *  Adapted to be compatible with MyEcobee and My Automatic devices which are available at my store:
- *          http://www.ecomatiqhomes.com/#!store/tc3yr 
- * 
- */
 definition(
-       name: "groveStreams",
-       namespace: "yracine",
-       author: "Yves Racine",
-       description: "Log to groveStreams and send data streams based on devices selection",
-       category: "My Apps",
-       iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee.png",
-       iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee@2x.png"
+    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"
 )
 
-
-
-preferences {
-       section("About") {
-               paragraph "groveStreams, the smartapp that sends your device states to groveStreams for data correlation"
-               paragraph "Version 2.2.2" 
-               paragraph "If you like this smartapp, please support the developer via PayPal and click on the Paypal link below " 
-                       href url: "https://www.paypal.me/ecomatiqhomes",
-                               title:"Paypal donation..."
-               paragraph "Copyright©2014 Yves Racine"
-                       href url:"http://github.com/yracine/device-type.myecobee", style:"embedded", required:false, title:"More information..."  
-                               description: "http://github.com/yracine"
-       }
-       section("Log devices...") {
-               input "temperatures", "capability.temperatureMeasurement", title: "Temperatures", required: false, multiple: true
-               input "thermostats", "capability.thermostat", title: "Thermostats", required: false, multiple: true
-               //input "ecobees", "device.myEcobeeDevice", title: "Ecobees", required: false, multiple: true
-               input "automatic", "capability.presenceSensor", title: "Automatic Connected Device(s)", required: false, multiple: true
-               input "detectors", "capability.smokeDetector", title: "Smoke/CarbonMonoxide Detectors", required: false, multiple: true
-               input "humidities", "capability.relativeHumidityMeasurement", title: "Humidity sensors", required: false, multiple: true
-               input "waters", "capability.waterSensor", title: "Water sensors", required: false, multiple: true
-               input "illuminances", "capability.illuminanceMeasurement", title: "Illuminance sensor", required: false, multiple: true
-               input "locks", "capability.lock", title: "Locks", required: false, multiple: true
-               input "contacts", "capability.contactSensor", title: "Doors open/close", required: false, multiple: true
-               input "accelerations", "capability.accelerationSensor", title: "Accelerations", required: false, multiple: true
-               input "motions", "capability.motionSensor", title: "Motions", required: false, multiple: true
-               input "presence", "capability.presenceSensor", title: "Presence", required: false, multiple: true
-               input "switches", "capability.switch", title: "Switches", required: false, multiple: true
-               input "dimmerSwitches", "capability.switchLevel", title: "Dimmer Switches", required: false, multiple: true
-               input "batteries", "capability.battery", title: "Battery-powered devices", required: false, multiple: true
-               input "powers", "capability.powerMeter", title: "Power Meters", required: false, multiple: true
-               input "energys", "capability.energyMeter", title: "Energy Meters", required: false, multiple: true
-
-       }
-
-       section("GroveStreams Feed PUT API key...") {
-               input "channelKey", "text", title: "API key"
-       }
-       section("Sending data at which interval in minutes (default=5)?") {
-               input "givenInterval", "number", title: 'Send Data Interval', required: false
-       }
-}
-
-def installed() {
-       initialize()
-}
-
-def updated() {
-       unsubscribe()
-       unschedule()
-       initialize()
-}
-
-def initialize() {
-       subscribe(temperatures, "temperature", handleTemperatureEvent)
-       subscribe(humidities, "humidity", handleHumidityEvent)
-       subscribe(waters, "water", handleWaterEvent)
-       subscribe(waters, "water", handleWaterEvent)
-       subscribe(detectors, "smoke", handleSmokeEvent)
-       subscribe(detectors, "carbonMonoxide", handleCarbonMonoxideEvent)
-       subscribe(illuminances, "illuminance", handleIlluminanceEvent)
-       subscribe(contacts, "contact", handleContactEvent)
-       subscribe(locks, "lock", handleLockEvent)
-       subscribe(accelerations, "acceleration", handleAccelerationEvent)
-       subscribe(motions, "motion", handleMotionEvent)
-       subscribe(presence, "presence", handlePresenceEvent)
-       subscribe(switches, "switch", handleSwitchEvent)
-       subscribe(dimmerSwitches, "switch", handleSwitchEvent)
-       subscribe(dimmerSwitches, "level", handleSetLevelEvent)
-       subscribe(batteries, "battery", handleBatteryEvent)
-       subscribe(powers, "power", handlePowerEvent)
-       subscribe(energys, "energy", handleEnergyEvent)
-       subscribe(energys, "cost", handleCostEvent)
-       subscribe(thermostats, "heatingSetpoint", handleHeatingSetpointEvent)
-       subscribe(thermostats, "coolingSetpoint", handleCoolingSetpointEvent)
-       subscribe(thermostats, "thermostatMode", handleThermostatModeEvent)
-       subscribe(thermostats, "fanMode", handleFanModeEvent)
-       subscribe(thermostats, "thermostatOperatingState", handleThermostatOperatingStateEvent)
-       /*subscribe(ecobees, "dehumidifierMode", handleDehumidifierModeEvent)
-       subscribe(ecobees, "equipmentStatus", handleEquipmentStatusEvent)
-       subscribe(ecobees, "dehumidifierLevel", handleDehumidifierLevelEvent)
-       subscribe(ecobees, "humidifierMode", handleHumidifierModeEvent)
-       subscribe(ecobees, "humidifierLevel", handleHumidifierLevelEvent)
-       subscribe(ecobees, "fanMinOnTime", handleFanMinOnTimeEvent)
-       subscribe(ecobees, "ventilatorMode", handleVentilatorModeEvent)
-       subscribe(ecobees, "ventilatorMinOnTime", handleVentilatorMinOnTimeEvent)
-       subscribe(ecobees, "programScheduleName", handleProgramNameEvent)
-       subscribe(ecobees, "auxHeat1RuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "auxHeat2RuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "auxHeat3RuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "compCool1RuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "compCool2RuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "fanRuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "humidifierRuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "dehumidifierRuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "ventilatorRuntimeDaily", handleDailyStats)
-       subscribe(ecobees, "presence", handlePresenceEvent)
-       subscribe(ecobees, "compCool2RuntimeDaily", handleDailyStats)*/
-       subscribe(automatic, "yesterdayTripsAvgAverageKmpl",handleDailyStats)
-       subscribe(automatic, "yesterdayTripsAvgDistanceM",handleDailyStats)
-       subscribe(automatic, "yesterdayTripsAvgDurationS",handleDailyStats)
-       subscribe(automatic, "yesterdayTotalDistanceM",handleDailyStats)
-       subscribe(automatic, "yesterdayTripsAvgFuelVolumeL",handleDailyStats)
-       subscribe(automatic, "yesterdayTotalFuelVolumeL",handleDailyStats)
-       subscribe(automatic, "yesterdayTotalDurationS:",handleDailyStats)
-       subscribe(automatic, "yesterdayTotalNbTrips",handleDailyStats)
-       subscribe(automatic, "yesterdayTotalHardAccels",handleDailyStats)
-       subscribe(automatic, "yesterdayTotalHardBrakes:",handleDailyStats)
-       subscribe(automatic, "yesterdayTripsAvgScoreSpeeding",handleDailyStats)
-       subscribe(automatic, "yesterdayTripsAvgScoreEvents",handleDailyStats)
-       def queue = []
-       atomicState.queue=queue
-    
-       if (atomicState.queue==null) {
-               atomicState.queue = []
-       }    
-       atomicState?.poll = [ last: 0, rescheduled: now() ]
-
-       Integer delay  = givenInterval ?: 5 // By default, schedule processQueue every 5 min.
-       log.debug "initialize>scheduling processQueue every ${delay} minutes"
-
-       //Subscribe to different events (ex. sunrise and sunset events) to trigger rescheduling if needed
-       subscribe(location, "sunrise", rescheduleIfNeeded)
-       subscribe(location, "sunset", rescheduleIfNeeded)
-       subscribe(location, "mode", rescheduleIfNeeded)
-       subscribe(location, "sunriseTime", rescheduleIfNeeded)
-       subscribe(location, "sunsetTime", rescheduleIfNeeded)
-       subscribe(app, appTouch)
-
-       //rescheduleIfNeeded()   
-}
-
-def appTouch(evt) {
-       rescheduleIfNeeded(evt)
-       processQueue()
-       def queue = []
-       atomicState.queue=queue
-}
-
-
-def rescheduleIfNeeded(evt) {
-       if (evt) log.debug("rescheduleIfNeeded>$evt.name=$evt.value")
-       Integer delay  = givenInterval ?: 5 // By default, schedule processQueue every 5 min.
-       BigDecimal currentTime = now()    
-       BigDecimal lastPollTime = (currentTime - (atomicState?.poll["last"]?:0))  
-       if (lastPollTime != currentTime) {    
-               Double lastPollTimeInMinutes = (lastPollTime/60000).toDouble().round(1)      
-               log.info "rescheduleIfNeeded>last poll was  ${lastPollTimeInMinutes.toString()} minutes ago"
-       }
-       if (((atomicState?.poll["last"]?:0) + (delay * 60000) < currentTime) && canSchedule()) {
-               log.info "rescheduleIfNeeded>scheduling processQueue in ${delay} minutes.."
-               unschedule()  
-               schedule("14:00", processQueue)
-       }
-       // Update rescheduled state
-    
-       if (!evt) {
-               atomicState.poll["rescheduled"] = now()    
-       }        
-}    
-
-def handleTemperatureEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleHumidityEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleHeatingSetpointEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleCoolingSetpointEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleThermostatModeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleFanModeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleHumidifierModeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleHumidifierLevelEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleDehumidifierModeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleDehumidifierLevelEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleVentilatorModeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleFanMinOnTimeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleVentilatorMinOnTimeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleThermostatOperatingStateEvent(evt) {
-       queueValue(evt) {
-               it == "idle" ? 0 : (it == 'fan only') ? 1 : (it == 'heating') ? 2 : 3
-       }
-
-}
-def handleDailyStats(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-
-}
-def handleEquipmentStatusEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
+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
+        }
+    }
+}
+
+def installed(){
+    initialize()
+}
+
+def updated(){
+    unsubscribe()
+    unschedule()
+    initialize()
+}
+
+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 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 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!")
+    }
+}
+
+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!")
+        }
+    }
 }
-
-def handleProgramNameEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleWaterEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleSmokeEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-def handleCarbonMonoxideEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleIlluminanceEvent(evt) {
-       log.debug ("handleIlluminanceEvent> $evt.name= $evt.value")
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleLockEvent(evt) {
-       queueValue(evt) {
-               it == "locked" ? 1 : 0
-       }
-}
-
-def handleBatteryEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handleContactEvent(evt) {
-       queueValue(evt) {
-               it == "open" ? 1 : 0
-       }
-}
-
-def handleAccelerationEvent(evt) {
-       queueValue(evt) {
-               it == "active" ? 1 : 0
-       }
-}
-
-def handleMotionEvent(evt) {
-       queueValue(evt) {
-               it == "active" ? 1 : 0
-       }
-}
-
-def handlePresenceEvent(evt) {
-       queueValue(evt) {
-               it == "present" ? 1 : 0
-       }
-}
-
-def handleSwitchEvent(evt) {
-       queueValue(evt) {
-               it == "on" ? 1 : 0
-       }
-}
-
-def handleSetLevelEvent(evt) {
-       queueValue(evt) {
-               it.toString()
-       }
-}
-
-def handlePowerEvent(evt) {
-       if (evt.value) {
-               queueValue(evt) {
-                       it.toString()
-               }
-       }
-}
-
-def handleEnergyEvent(evt) {
-       if (evt.value) {
-               queueValue(evt) {
-                       it.toString()
-               }
-       }
-}
-def handleCostEvent(evt) {
-       if (evt.value) {
-               queueValue(evt) {
-                       it.toString()
-               }
-       }
-}
-
-private queueValue(evt, Closure convert) {
-       def MAX_QUEUE_SIZE=95000
-       def jsonPayload = [compId: evt.displayName, streamId: evt.name, data: convert(evt.value), time: now()]
-       def queue
-
-       queue = atomicState.queue
-       queue << jsonPayload
-       atomicState.queue = queue    
-       def queue_size = queue.toString().length()
-       def last_item_in_queue = queue[queue.size() -1]    
-       log.debug "queueValue>queue size in chars=${queue_size}, appending ${jsonPayload} to queue, last item in queue= $last_item_in_queue"
-       if (queue_size >  MAX_QUEUE_SIZE) {
-               processQueue()
-       }
-}
-
-def processQueue() {
-       Integer delay  = givenInterval ?: 5 // By default, schedule processQueue every 5 min.
-       atomicState?.poll["last"] = now()
-
-       if (((atomicState?.poll["rescheduled"]?:0) + (delay * 60000)) < now()) {
-               log.info "processQueue>scheduling rescheduleIfNeeded() in ${delay} minutes.."
-               schedule("0 0/${delay} * * * ?", rescheduleIfNeeded)
-               // Update rescheduled state
-               atomicState?.poll["rescheduled"] = now()
-       }
-
-       def queue = atomicState.queue
-    
-   
-       def url = "https://grovestreams.com/api/feed?api_key=${channelKey}"
-       log.debug "processQueue"
-       if (queue != []) {
-               log.debug "Events to be sent to groveStreams: ${queue}"
-
-               /*try {
-                       httpPutJson([uri: url, body: queue]) {response ->
-                               if (response.status != 200) {
-                                       log.debug "GroveStreams logging failed, status = ${response.status}"
-                               } else {
-                                       log.debug "GroveStreams accepted event(s)"
-                                       // reset the queue 
-                                       queue =[]                         
-                                       atomicState.queue = queue                     
-                               }
-                       }
-               } catch (groovyx.net.http.ResponseParseException e) {
-                       // ignore error 200, bogus exception
-                       if (e.statusCode != 200) {
-                               log.error "Grovestreams: ${e}"
-                       } else {
-                               log.debug "GroveStreams accepted event(s)"
-                       }
-                       // reset the queue 
-                       queue =[]                         
-                       atomicState.queue = queue                      
-            
-               } catch (e) {
-                       def errorInfo = "Error sending value: ${e}"
-                       log.error errorInfo
-                       // reset the queue 
-                       queue =[]                         
-                       atomicState.queue = queue                        
-               }*/
-       }
-
-}
-