"First commit!"
authoramiraj <amiraj.95@uci.edu>
Fri, 28 Jun 2019 23:06:02 +0000 (16:06 -0700)
committeramiraj <amiraj.95@uci.edu>
Fri, 28 Jun 2019 23:06:02 +0000 (16:06 -0700)
28 files changed:
ContactSensor/contacting.groovy [new file with mode: 0644]
ContactSensor/contacts.groovy [new file with mode: 0644]
Event/Event.groovy [new file with mode: 0644]
Extractor/App.groovy [new file with mode: 0644]
Extractor/ExtractedObjects.groovy [new file with mode: 0644]
Extractor/ExtractorScript.py [new file with mode: 0644]
GlobalVariables/GlobalVariables.groovy [new file with mode: 0644]
Location/Phrase.groovy [new file with mode: 0644]
Location/locationVar.groovy [new file with mode: 0644]
Lock/locking.groovy [new file with mode: 0644]
Lock/locks.groovy [new file with mode: 0644]
Logger/Logger.groovy [new file with mode: 0644]
Methods/EventHandler.groovy [new file with mode: 0644]
Methods/definition.groovy [new file with mode: 0644]
Methods/preferences.groovy [new file with mode: 0644]
Methods/runIn.groovy [new file with mode: 0644]
Methods/sendNotificationToContacts.groovy [new file with mode: 0644]
Methods/sendSms.groovy [new file with mode: 0644]
Methods/setLocationMode.groovy [new file with mode: 0644]
Methods/subscribe.groovy [new file with mode: 0644]
Methods/unschedule.groovy [new file with mode: 0644]
README
Runner.py [new file with mode: 0644]
Switch/switches.groovy [new file with mode: 0644]
Switch/switching.groovy [new file with mode: 0644]
appTouch/Touch.groovy [new file with mode: 0644]
main.groovy [new file with mode: 0644]
makefile [new file with mode: 0644]

diff --git a/ContactSensor/contacting.groovy b/ContactSensor/contacting.groovy
new file mode 100644 (file)
index 0000000..e6d8848
--- /dev/null
@@ -0,0 +1,34 @@
+//Create a class for contact sensor
+package ContactSensor
+
+public class contacting{
+       List contacts
+       int count
+       
+       contacting(int count) {
+               this.count = count
+               if (count == 1) {
+                       contacts = [new contacts(0, "contact0", "closed", "closed")]
+               } else if (count == 2) {
+                       contacts = [new contacts(0, "contact0", "closed", "closed"), new contacts(1, "contact1", "closed", "closed")]
+               } else if (count == 3) {
+                       contacts = [new contacts(0, "contact0", "closed", "closed"), new contacts(1, "contact1", "closed", "closed"), new contacts(2,"contact2", "closed", "closed")]
+               }
+       }
+
+       def currentValue(String S) {
+               if (count == 1) {
+                       contacts[0].currentValue(S)
+               } else {
+                       contacts*.currentValue(S)
+               }
+       }
+
+       def latestValue(String S) {
+               if (count == 1) {
+                       contacts[0].latestValue(S)
+               } else {
+                       contacts*.latestValue(S)
+               }
+       }
+}
diff --git a/ContactSensor/contacts.groovy b/ContactSensor/contacts.groovy
new file mode 100644 (file)
index 0000000..09f64bf
--- /dev/null
@@ -0,0 +1,29 @@
+//Create a class for contact sensor
+package ContactSensor
+
+public class contacts {
+       private int id = 0
+       private String displayName
+       private String currentContact
+       private String contactLatestValue
+
+       contacts(int id, String displayName, String currentContact, String contactLatestValue) {
+               this.id = id
+               this.displayName = displayName
+               this.currentContact = currentContact
+               this.contactLatestValue = contactLatestValue
+       }
+       
+       def currentValue(String S) {
+               if (S == "contact") {
+                       return currentContact
+               }
+       }
+
+       def latestValue(String S) {
+               if (S == "contact") {
+                       return contactLatestValue
+               }
+       }
+}
+
diff --git a/Event/Event.groovy b/Event/Event.groovy
new file mode 100644 (file)
index 0000000..fb738c7
--- /dev/null
@@ -0,0 +1,20 @@
+//Create a class for Events
+package Event
+
+public class Event {
+       private int deviceId
+       private String value
+       private String linkText
+       private String displayName
+       private String name
+       private String descriptionText
+       
+       Event() {
+               this.deviceId = 0
+               this.linkText = ""
+               this.value = ""
+               this.displayName = ""
+               this.name = ""
+               this.descriptionText = ""
+       }
+}
diff --git a/Extractor/App.groovy b/Extractor/App.groovy
new file mode 100644 (file)
index 0000000..0c52140
--- /dev/null
@@ -0,0 +1,124 @@
+///////////////////////////////////////////
+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"
+)
+
+preferences{
+    section("Select the door lock:") {
+        input "lock1", "capability.lock", required: true, multiple: 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){
+    log.debug evt.value
+    log.debug contact.latestValue("contact")
+    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
+       log.debug "1"
+        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...
+       log.debug "2"        
+       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...
+       log.debug "3"
+        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...
+       log.debug "4"
+       //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...
+       log.debug "5"
+        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
+       log.debug "6"
+        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!")
+        }
+    }
+}
diff --git a/Extractor/ExtractedObjects.groovy b/Extractor/ExtractedObjects.groovy
new file mode 100644 (file)
index 0000000..7e7e4db
--- /dev/null
@@ -0,0 +1,24 @@
+//Global Object for class lock!
+@Field def lock1 = new locking(1)
+//Global Object for class contactSensor!
+@Field def contact = new contacting(1)
+//Global variable for number!
+@Field def minutesLater = 1
+//Global variable for number!
+@Field def secondsLater = 10
+//Global variable for recipients!
+@Field def recipients = ['AJ']
+//Global variable for phone number!
+@Field def phoneNumber = 9495379373
+//Global Object for functions in subscribe method!
+@Field def installed = this.&installed
+//Global Object for functions in subscribe method!
+@Field def updated = this.&updated
+//Global Object for functions in subscribe method!
+@Field def initialize = this.&initialize
+//Global Object for functions in subscribe method!
+@Field def lockDoor = this.&lockDoor
+//Global Object for functions in subscribe method!
+@Field def unlockDoor = this.&unlockDoor
+//Global Object for functions in subscribe method!
+@Field def doorHandler = this.&doorHandler
diff --git a/Extractor/ExtractorScript.py b/Extractor/ExtractorScript.py
new file mode 100644 (file)
index 0000000..b9654b4
--- /dev/null
@@ -0,0 +1,219 @@
+readyToReturn = 0
+ToReturn = ""
+
+def GetToken(f):
+       global readyToReturn
+       global ToReturn
+       Skip = ["(", "\"", ":", ",", "{", "}", ")", '\n', '\t', ' ', "/"]
+       S = ""
+       if (readyToReturn):
+               readyToReturn = 0
+               return ToReturn
+       ToReturn = ""
+       c = f.read(1)
+       while(True):
+               if (c in Skip):
+                       if (S != ""):
+                               if (c == "{" or c == "}"):
+                                       readyToReturn = 1
+                                       ToReturn = c
+                                       return S
+                               else:
+                                       return S
+                                       
+                       else:
+                               if (c == "{" or c == "}"):
+                                       return c
+                               else:
+                                       c = f.read(1)
+                                       continue
+               S += c
+               c = f.read(1)
+               if not c:
+                       return "EOF"
+               
+               
+       
+               
+
+F = open("Extractor/App.groovy", "r")
+Out = open("Extractor/ExtractedObjects.groovy", "w+")
+Temp = GetToken(F)
+
+Objects = []
+Functions = []
+
+       
+while (Temp != "EOF"):
+       #Extract the global objects for input
+       if (Temp == "input"):
+               Object = ""
+               Type = ""
+               Temp = GetToken(F) #name or "name"
+               #input name: "name", type: "type",...
+               if (Temp == "name"):
+                       Temp = GetToken(F) #"name"
+                       Object = Temp
+                       GetToken(F) #type
+                       Temp = GetToken(F) #"type"
+                       Type = Temp             
+               #input "name", "type",...
+               else:
+                       Object = Temp
+                       Temp = GetToken(F) #"type"
+                       Type = Temp
+               Temp = GetToken(F)
+               Title = ""
+               Required = ""
+               Multiple = ""
+               while (Temp != "input" and Temp != "}"):
+                       if (Temp == "title"):
+                               Temp = GetToken(F)
+                               Title = Temp
+                       elif (Temp == "required"):
+                               Temp = GetToken(F)
+                               Required = Temp
+                       elif (Temp == "multiple"):
+                               Temp = GetToken(F)
+                               Multiple = Temp
+                       Temp = GetToken(F)                      
+               if (Type == "capability.lock"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       if (Multiple != "" and Multiple == "true"):
+                               g = raw_input("Enter the number of locks to control: (1, 2, or 3)\n") 
+                               Out.write("//Global Object for class lock!\n")
+                               Out.write("@Field def %s = new locking(" % Object)
+                               Out.write("%s)\n" % g)
+                       elif (Multiple == "" or Multiple == "false"):
+                               Out.write("//Global Object for class lock!\n")
+                               Out.write("@Field def %s = new locking(1)\n" % Object)
+               #elif (Type == "capability.alarm"):
+
+               #elif (Type == "capability.battery"):
+
+               #elif (Type == "capability.beacon"):
+
+               #elif (Type == "capability.carbonMonoxideDetector"):
+
+               #elif (Type == "capability.colorControl"):
+
+               elif (Type == "capability.contactSensor"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       if (Multiple != "" and Multiple == "true"):
+                               g = raw_input("Enter the number of contactSensors to monitor: (1, 2, or 3)\n") 
+                               Out.write("//Global Object for class contactSensor!\n")
+                               Out.write("@Field def %s = new contacting(" % Object)
+                               Out.write("%s)\n" % g)
+                       elif (Multiple == "" or Multiple == "false"):
+                               Out.write("//Global Object for class contactSensor!\n")
+                               Out.write("@Field def %s = new contacting(1)\n" % Object)
+               #elif (Type == "capability.doorControl"):
+
+               #elif (Type == "capability.energyMeter"):
+
+               #elif (Type == "capability.illuminanceMeasurement"):
+
+               #elif (Type == "capability.accelerationSensor"):
+
+               #elif (Type == "capability.motionSensor"):
+
+               #elif (Type == "capability.musicPlayer"):
+
+               #elif (Type == "capability.powerMeter"):
+
+               #elif (Type == "capability.presenceSensor"):
+
+               #elif (Type == "capability.relativeHumidityMeasurement"):
+
+               #elif (Type == "capability.relaySwitch"):
+
+               #elif (Type == "capability.sleepSensor"):
+
+               #elif (Type == "capability.smokeDetector"):
+
+               #elif (Type == "capability.stepSensor"):
+
+               elif (Type == "capability.switch"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       if (Multiple != "" and Multiple == "true"):
+                               g = raw_input("Enter the number of switches to control: (1, 2, or 3)\n") 
+                               Out.write("//Global Object for class switch!\n")
+                               Out.write("@Field def %s = new switching(" % Object)
+                               Out.write("%s)\n" % g)
+                       elif (Multiple == "" or Multiple == "false"):
+                               Out.write("//Global Object for class switch!\n")
+                               Out.write("@Field def %s = new switching(1)\n" % Object)
+               #elif (Type == "capability.switchLevel"):
+
+               #elif (Type == "capability.temperatureMeasurement"):
+               
+               #elif (Type == "capability.thermostat"):
+                       
+               #elif (Type == "capability.valve"):
+
+               #elif (Type == "capability.waterSensor"):
+
+               #elif (Type == "capability.touchSensor"):
+
+               #elif (Type == "capability.imageCapture"):
+
+               #elif (Type == "device.mobilePresence"):
+
+               #elif (Type == "device.aeonKeyFob"):
+
+               elif (Type == "mode"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       g = raw_input("Enter the mode: ") 
+                       Out.write("//Global variable for mode!\n")
+                       Out.write("@Field def %s = " % Object)
+                       Out.write("\"%s\"\n" % g)
+               #elif (Type == "decimal"):
+
+               #elif (Type == "text"):
+                       
+               elif (Type == "number"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       g = raw_input("Enter the number: ") 
+                       Out.write("//Global variable for number!\n")
+                       Out.write("@Field def %s = " % Object)
+                       Out.write("%s\n" % g)
+               #elif (Type == "time"):
+
+               #elif (Type == "enum"):
+
+               #elif (Type == "bool"):
+
+               elif (Type == "phone"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       g = raw_input("Enter the number to send notification to:\n") 
+                       Out.write("//Global variable for phone number!\n")
+                       Out.write("@Field def %s = " % Object)
+                       Out.write("%s\n" % g)
+               elif (Type == "contact"):
+                       if (Title != ""):
+                               print(Object+", "+Title)
+                       g = raw_input("Enter the name of the recipients:\n") 
+                       Out.write("//Global variable for recipients!\n")
+                       g = g.split()
+                       Out.write("@Field def %s = " % Object)
+                       Out.write("%s\n" % g)
+       #Extract the global object for functions
+       elif (Temp == "def"):
+               Temp = GetToken(F)
+               NameofFunc = Temp
+               if (GetToken(F) != "="): #We have a function to create object for
+                       Out.write("//Global Object for functions in subscribe method!\n")       
+                       Out.write("@Field def %s = this.&" % NameofFunc)
+                       Out.write("%s\n" % NameofFunc)
+       if (Temp != "input"):
+               Temp = GetToken(F)
+
+
+F.close()
+Out.close()
diff --git a/GlobalVariables/GlobalVariables.groovy b/GlobalVariables/GlobalVariables.groovy
new file mode 100644 (file)
index 0000000..92ce8b9
--- /dev/null
@@ -0,0 +1,22 @@
+//create a location object to change the variable inside the class
+@Field def location = new locationVar()
+//Settings variable defined to settings on purpose
+@Field def settings = "Settings"
+//Global variable for state[mode]
+@Field def state = [home:[],away:[],night:[]]
+//Create a global logger object for methods
+@Field def log = new Logger()
+//Create a global object for app
+@Field def app = new Touch(1)
+//Create a global list for objects for events on subscribe methods
+@Field def ObjectList = []
+//Create a global list for events
+@Field def EventList = []
+//Create a global list for function calls based on corresponding events
+@Field def FunctionList = []
+//Create a global list for function schedulers
+@Field def ListofTimersFunc = []
+//Create a global list for timer schedulers
+@Field def ListofTimers = []
+
+
diff --git a/Location/Phrase.groovy b/Location/Phrase.groovy
new file mode 100644 (file)
index 0000000..f9f3081
--- /dev/null
@@ -0,0 +1,15 @@
+//Create a class for Phrase
+package Location
+
+class Phrase {
+       private LinkedHashMap Phrases
+       
+       Phrase() {
+               this.Phrases = [id:0, label:"Good Morning!"]
+       } 
+       def getPhrases() {
+               return Phrases
+       }
+}
+
+
diff --git a/Location/locationVar.groovy b/Location/locationVar.groovy
new file mode 100644 (file)
index 0000000..42e1f56
--- /dev/null
@@ -0,0 +1,21 @@
+//Create a class for location variable
+package Location
+
+class locationVar {
+    private String modes
+    private String mode
+    private int contactBookEnabled
+    private List CONTACTS
+    private List PhoneNums
+    
+    private Phrase helloHome
+
+    locationVar() {
+       this.modes = "'home', 'away', 'night'"
+       this.mode = "home"
+       this.helloHome = new Phrase()
+       this.contactBookEnabled = 1
+       this.CONTACTS = ['AJ']
+       this.PhoneNums = [9495379373]
+    }
+}
diff --git a/Lock/locking.groovy b/Lock/locking.groovy
new file mode 100644 (file)
index 0000000..e8ce9dd
--- /dev/null
@@ -0,0 +1,55 @@
+//Create a class for lock device
+package Lock
+
+public class locking{
+       List locks
+       int count
+
+       locking(int count) {
+               this.count = count
+               if (count == 1) {
+                       locks = [new locks(0, "lock0", "locked", "locked")]
+               } else if (count == 2) {
+                       locks = [new locks(0, "lock0", "locked", "locked"),new locks(1, "lock1", "locked", "locked")]
+               } else if (count == 3) {
+                       locks = [new locks(0, "lock0", "locked", "locked"),new locks(1, "lock1", "locked", "locked"),new locks(2, "lock2", "locked", "locked")]
+               }
+       }
+
+       def lock() {
+               if (count == 1) {
+                       locks[0].lock()
+               } else {
+                       locks*.lock()
+               }
+       }
+
+       def unlock() {
+               if (count == 1) {
+                       locks[0].unlock()
+               } else {
+                       locks*.unlock()
+               }
+       }
+
+       def currentValue(String S) {
+               if (count == 1) {
+                       locks[0].currentValue(S)
+               } else {
+                       locks*.currentValue(S)
+               }
+       }
+
+       def latestValue(String S) {
+               if (count == 1) {
+                       locks[0].latestValue(S)
+               } else {
+                       locks*.latestValue(S)
+               }
+       }
+
+       def getAt(int ix) {
+               locks[ix]
+       }
+}
+
diff --git a/Lock/locks.groovy b/Lock/locks.groovy
new file mode 100644 (file)
index 0000000..87671da
--- /dev/null
@@ -0,0 +1,40 @@
+//Create a class for lock device
+package Lock
+
+public class locks {
+       private int id = 0
+       private String displayName
+       private String currentLock
+       private String lockLatestValue
+
+       locks(int id, String displayName, String currentLock, String lockLatestValue) {
+               this.id = id
+               this.displayName = displayName
+               this.currentLock = currentLock
+               this.lockLatestValue = lockLatestValue
+       }
+
+       def lock() {
+               println("the door with id:$id is locked!")
+               this.lockLatestValue = this.currentLock
+               this.currentLock = "locked"
+       }
+       
+       def unlock() {
+               println("the door with id:$id is unlocked!")
+               this.lockLatestValue = this.currentLock
+               this.currentLock = "unlocked"
+       }
+       
+       def currentValue(String S) {
+               if (S == "lock") {
+                       return currentLock
+               }
+       }
+
+       def latestValue(String S) {
+               if (S == "lock") {
+                       return lockLatestValue
+               }
+       }
+}
diff --git a/Logger/Logger.groovy b/Logger/Logger.groovy
new file mode 100644 (file)
index 0000000..35ca850
--- /dev/null
@@ -0,0 +1,13 @@
+//Adding a Logger class for log.debug
+package Logger
+
+class Logger {
+    private boolean printToConsole = true
+
+    def methodMissing(String name, args) {
+        def messsage = args[0]
+        if (printToConsole) {
+            println messsage
+        }
+    }
+}
diff --git a/Methods/EventHandler.groovy b/Methods/EventHandler.groovy
new file mode 100644 (file)
index 0000000..a216725
--- /dev/null
@@ -0,0 +1,141 @@
+/////////////////////////////////////////////////////////////////////
+def EventHandler() {
+       while(true) {
+               List evt = []
+               print "Waiting for an event...\n"
+               def EVENT = System.in.newReader().readLine()
+               SepLine = EVENT.split()
+               for (int i = 0; i < EventList.size(); i++) {
+                       if (EventList[i] == SepLine[0]) {
+                               println("The following effect: \n")
+                               evt.add(new Event())
+                               switch(SepLine[0]) { 
+                                       case "Touched":
+                                               ObjectList[i].touched = 1
+                                               evt[-1].value = "Touched"
+                                               evt[-1].linkText = "touched by user"
+                                               evt[-1].name = "TouchSensor"
+                                               evt[-1].descriptionText = "Touching"
+                                               break
+                                       case "lock":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].lock()
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "locked"
+                                                       evt[-1].linkText = "lock0"
+                                                       evt[-1].displayName = "lock0"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "locking"
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].lock()
+                                                       evt[-1].deviceId = 1
+                                                       evt[-1].value = "locked"
+                                                       evt[-1].linkText = "lock1"
+                                                       evt[-1].displayName = "lock1"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "locking"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].lock()
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "locked"
+                                                       evt[-1].linkText = "lock2"
+                                                       evt[-1].displayName = "lock2"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "locking"
+                                               }
+                                               break
+                                       case "unlock":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].unlock()
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "unlocked"
+                                                       evt[-1].linkText = "lock0"
+                                                       evt[-1].displayName = "lock0"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "unlocking"   
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].unlock()
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "unlocked"
+                                                       evt[-1].linkText = "lock1"
+                                                       evt[-1].displayName = "lock1"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "unlocking"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].unlock()
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "unlocked"
+                                                       evt[-1].linkText = "lock2"
+                                                       evt[-1].displayName = "lock2"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "unlocking"
+                                               }
+                                               break
+                                       case "contact.open":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][0].currentContact = "open"
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "contact.open"
+                                                       evt[-1].linkText = "contact0"
+                                                       evt[-1].displayName = "contact0"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "opening"     
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][1].currentContact = "open"
+                                                       evt[-1].deviceId = 1
+                                                       evt[-1].value = "contact.open"
+                                                       evt[-1].linkText = "contact1"
+                                                       evt[-1].displayName = "contact1"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "opening"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][2].currentContact = "open"
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "contact.open"
+                                                       evt[-1].linkText = "contact2"
+                                                       evt[-1].displayName = "contact2"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "opening"
+                                               }
+                                               break
+                                       case "contact.closed":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][0].currentContact = "closed"
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "contact.closed"
+                                                       evt[-1].linkText = "contact0"
+                                                       evt[-1].displayName = "contact0"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "closing"
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][1].currentContact = "closed"
+                                                       evt[-1].deviceId = 1
+                                                       evt[-1].value = "contact.closed"
+                                                       evt[-1].linkText = "contact1"
+                                                       evt[-1].displayName = "contact1"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "closing"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][2].currentContact = "closed"
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "contact.closed"
+                                                       evt[-1].linkText = "contact2"
+                                                       evt[-1].displayName = "contact2"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "closing"
+                                               }
+                                               break
+                                       default:
+                                               break
+                               }
+                               FunctionList[i](evt[-1])
+                       }
+               }
+       }
+}
diff --git a/Methods/definition.groovy b/Methods/definition.groovy
new file mode 100644 (file)
index 0000000..a5cb5dd
--- /dev/null
@@ -0,0 +1,5 @@
+/////////////////////////////////////////////////////////////////////
+def definition(LinkedHashMap LHM) {
+       println("IGNORE -- JUST SOME DEFINITION")
+}
+
diff --git a/Methods/preferences.groovy b/Methods/preferences.groovy
new file mode 100644 (file)
index 0000000..8c98821
--- /dev/null
@@ -0,0 +1,4 @@
+/////////////////////////////////////////////////////////////////////
+def preferences(Closure Input) {
+       println("IGNORE -- JUST SOME DEFINITION")
+}
diff --git a/Methods/runIn.groovy b/Methods/runIn.groovy
new file mode 100644 (file)
index 0000000..ce056e3
--- /dev/null
@@ -0,0 +1,7 @@
+/////////////////////////////////////////////////////////////////////
+////runIn(time, func)
+def runIn(int seconds, Closure Input) {
+       ListofTimersFunc.add(Input)
+       ListofTimers.add(new Timer())
+       def task = ListofTimers[-1].runAfter(1000*seconds, Input)
+}
diff --git a/Methods/sendNotificationToContacts.groovy b/Methods/sendNotificationToContacts.groovy
new file mode 100644 (file)
index 0000000..cab016b
--- /dev/null
@@ -0,0 +1,11 @@
+/////////////////////////////////////////////////////////////////////
+////sendNotificationToContacts(text, recipients)
+def sendNotificationToContacts(String S, List recipients) {
+       for (int i = 0;i < recipients.size();i++) {
+               for (int j = 0;j < location.CONTACTS.size();j++) {
+                       if (recipients[i] == location.CONTACTS[j]) {
+                               println("Sending \""+S+"\" to "+location.PhoneNums[j].toString())
+                       }
+               }
+       }
+}
diff --git a/Methods/sendSms.groovy b/Methods/sendSms.groovy
new file mode 100644 (file)
index 0000000..f60a0a1
--- /dev/null
@@ -0,0 +1,5 @@
+/////////////////////////////////////////////////////////////////////
+////sendNotificationToContacts(text, recipients)
+def sendSms(long Phone, String S) {
+       println("Sending \""+S+"\" to "+Phone.toString())
+}
diff --git a/Methods/setLocationMode.groovy b/Methods/setLocationMode.groovy
new file mode 100644 (file)
index 0000000..d2dade1
--- /dev/null
@@ -0,0 +1,5 @@
+/////////////////////////////////////////////////////////////////////
+def setLocationMode(String mode) {
+       location.mode = mode
+}
+
diff --git a/Methods/subscribe.groovy b/Methods/subscribe.groovy
new file mode 100644 (file)
index 0000000..74200cb
--- /dev/null
@@ -0,0 +1,18 @@
+/////////////////////////////////////////////////////////////////////
+////subscribe(app, func)
+def subscribe(Object Obj, Closure Input) {
+       EventList.add("Touched")
+       FunctionList.add(Input)
+}
+////subscribe(obj, string, func)
+def subscribe(Object Obj, String S, Closure Input) {
+       ObjectList.add(Obj)
+       EventList.add(S)
+       FunctionList.add(Input)
+}
+////subscribe(obj, string, func, hashmap)
+def subscribe(Object Obj, String S, Closure Input, LinkedHashMap LHM) {
+       ObjectList.add(Obj)     
+       EventList.add(S)
+       FunctionList.add(Input)
+}
diff --git a/Methods/unschedule.groovy b/Methods/unschedule.groovy
new file mode 100644 (file)
index 0000000..8033606
--- /dev/null
@@ -0,0 +1,9 @@
+/////////////////////////////////////////////////////////////////////
+////unschedule(func)
+def unschedule(Closure Input) {
+       for (int i = 0;i < ListofTimersFunc.size();i++) {
+               if (ListofTimersFunc[i] == Input) {
+                       ListofTimers[i].cancel()
+               }
+       }
+}
diff --git a/README b/README
index d0c01ac30417723f738ec705c45bf8e603ae6c89..28554f78d4a964864bcfdbbed30429247f418ca6 100644 (file)
--- a/README
+++ b/README
@@ -1,2 +1,7 @@
 This is a new repository for the SmartThings execution infrastructure for Groovy.
 This project attempts to model-check SmartThings Groovy smart apps.
 This is a new repository for the SmartThings execution infrastructure for Groovy.
 This project attempts to model-check SmartThings Groovy smart apps.
+-------------------------------------------------------------------------------------------
+1. Put your groovy program in Extractor directory with the name App.groovy.
+2. Run the make command in smartthings-infrastructure directory.
+3. All the classes are created in the bin folder.
+-------------------------------------------------------------------------------------------
diff --git a/Runner.py b/Runner.py
new file mode 100644 (file)
index 0000000..86a4251
--- /dev/null
+++ b/Runner.py
@@ -0,0 +1,76 @@
+import os
+
+#Create directory for files to append in the main file
+Out = open("main.groovy", "w+")
+GlobalVariables = open("GlobalVariables/"+"GlobalVariables.groovy", "r")
+definition = open("Methods/"+"definition.groovy", "r")
+preferences = open("Methods/"+"preferences.groovy", "r")
+setLocationMode = open("Methods/"+"setLocationMode.groovy", "r")
+subscribe = open("Methods/"+"subscribe.groovy", "r")
+EventHandler = open("Methods/"+"EventHandler.groovy", "r")
+runIn = open("Methods/"+"runIn.groovy", "r")
+unschedule = open("Methods/"+"unschedule.groovy", "r")
+sendNotificationToContacts = open("Methods/"+"sendNotificationToContacts.groovy", "r")
+sendSms = open("Methods/"+"sendSms.groovy", "r")
+App = open("Extractor/"+"App.groovy", "r")
+ExtractedObjects = open("Extractor/"+"ExtractedObjects.groovy", "r")
+
+
+#Extract information from preferences and subscribe method to create required objects
+os.system("python Extractor/ExtractorScript.py")
+
+Out.write("//Infrastructure for SmartThings Application\n")
+Out.write("//Importing Libraries\n")
+Out.write("import groovy.transform.Field\n")
+Out.write("\n")
+Out.write("//Importing Classes\n")
+Out.write("import ContactSensor.contacting\n")
+Out.write("import ContactSensor.contacts\n")
+Out.write("import Lock.locking\n")
+Out.write("import Lock.locks\n")
+Out.write("import Switch.switching\n")
+Out.write("import Switch.switches\n")
+Out.write("import Event.Event\n")
+Out.write("import Logger.Logger\n")
+Out.write("import Location.locationVar\n")
+Out.write("import Location.Phrase\n")
+Out.write("import appTouch.Touch\n")
+Out.write("\n")
+Out.write("//GlobalVariables\n")
+for line in GlobalVariables:
+       Out.write(line)
+Out.write("\n")
+Out.write("//ExtractedObjects\n")
+for line in ExtractedObjects:
+       Out.write(line)
+Out.write("\n")
+Out.write("//Methods\n")
+for line in definition:
+       Out.write(line)
+for line in preferences:
+       Out.write(line)
+for line in setLocationMode:
+       Out.write(line)
+for line in subscribe:
+       Out.write(line)
+for line in EventHandler:
+       Out.write(line)
+for line in runIn:
+       Out.write(line)
+for line in unschedule:
+       Out.write(line)
+for line in sendNotificationToContacts:
+       Out.write(line)
+for line in sendSms:
+       Out.write(line)
+Out.write("\n")
+for line in App:
+       Out.write(line)
+Out.write("\n")
+Out.write("installed()\n")
+Out.write("EventHandler()\n")
+Out.close()
+
+
+
+
diff --git a/Switch/switches.groovy b/Switch/switches.groovy
new file mode 100644 (file)
index 0000000..359248d
--- /dev/null
@@ -0,0 +1,54 @@
+//Create a class for switch device
+package Switch
+
+public class switches {
+       private int id = 0
+       private String displayName
+       private String currentSwitch
+       private String switchLatestValue
+
+       switches(int id, String displayName, String currentSwitch, String switchLatestValue) {
+               this.id = id
+               this.displayName = displayName
+               this.currentSwitch = currentSwitch
+               this.switchLatestValue = switchLatestValue
+       }
+
+       def on() {
+               println("the switch with id:$id is on!")
+               this.switchLatestValue = this.currentSwitch
+               this.currentSwitch = "on"
+       }
+
+       def on(LinkedHashMap LHM) {
+               sleep(LHM["delay"])
+               println("the switch with id:$id is on!")
+               this.switchLatestValue = this.currentSwitch
+               this.currentSwitch = "on"
+       }
+
+       def off() {
+               println("the switch with id:$id is off!")
+               this.switchLatestValue = this.currentSwitch
+               this.currentSwitch = "off"
+       }
+
+       def off(LinkedHashMap LHM) {
+               sleep(LHM["delay"])
+               println("the switch with id:$id is off!")
+               this.switchLatestValue = this.currentSwitch
+               this.currentSwitch = "off"
+       }
+       
+       def currentValue(String S) {
+               if (S == "switch") {
+                       return currentSwitch
+               }
+       }
+
+       def latestValue(String S) {
+               if (S == "switch") {
+                       return switchLatestValue
+               }
+       }
+}
diff --git a/Switch/switching.groovy b/Switch/switching.groovy
new file mode 100644 (file)
index 0000000..da2f30c
--- /dev/null
@@ -0,0 +1,74 @@
+//Create a class for switch device
+package Switch
+
+public class switching{
+       List switches
+       int count
+
+       switching(int count) {
+               this.count = count
+               if (count == 1) {
+                       switches = [new switches(0, "switch0", "off", "off")]
+               } else if (count == 2) {
+                       switches = [new switches(0, "switch0", "off", "off"),new switches(1, "switch1", "off", "off")]
+               } else if (count == 3) {
+                       switches = [new switches(0, "switch0", "off", "off"),new switches(1, "switch1", "off", "off"),new switches(2, "switch2", "off", "off")]
+               }
+       }
+
+       def on() {
+               if (count == 1) {
+                       switches[0].on()
+               } else {
+                       switches*.on()
+               }
+       }
+
+       def on(LinkedHashMap LHM) {
+               if (count == 1) {
+                       sleep(LHM["delay"])
+                       switches[0].on()
+               } else {
+                       sleep(LHM["delay"])
+                       switches*.on()
+               }
+       }
+
+       def off() {
+               if (count == 1) {
+                       switches[0].off()       
+               } else {
+                       switches*.off()
+               }
+       }
+
+       def off(LinkedHashMap LHM) {
+               if (count == 1) {
+                       sleep(LHM["delay"])
+                       switches[0].off()
+               } else {
+                       sleep(LHM["delay"])
+                       switches*.off()
+               }
+       }
+
+       def currentValue(String S) {
+               if (count == 1) {
+                       switches[0].currentValue(S)
+               } else {
+                       switches*.currentValue(S)
+               }
+       }
+
+       def latestValue(String S) {
+               if (count == 1) {
+                       switches[0].latestValue(S)
+               } else {
+                       switches*.latestValue(S)
+               }
+       }
+
+       def getAt(int ix) {
+               switches[ix]
+       }
+}
diff --git a/appTouch/Touch.groovy b/appTouch/Touch.groovy
new file mode 100644 (file)
index 0000000..19e6816
--- /dev/null
@@ -0,0 +1,10 @@
+//Create a class for touch
+package appTouch
+
+public class Touch {
+       private int touched = 0
+
+       Touch(int touched) {
+               this.touched = touched
+       }
+}
diff --git a/main.groovy b/main.groovy
new file mode 100644 (file)
index 0000000..11d617c
--- /dev/null
@@ -0,0 +1,401 @@
+//Infrastructure for SmartThings Application
+//Importing Libraries
+import groovy.transform.Field
+
+//Importing Classes
+import ContactSensor.contacting
+import ContactSensor.contacts
+import Lock.locking
+import Lock.locks
+import Switch.switching
+import Switch.switches
+import Event.Event
+import Logger.Logger
+import Location.locationVar
+import Location.Phrase
+import appTouch.Touch
+
+//GlobalVariables
+//create a location object to change the variable inside the class
+@Field def location = new locationVar()
+//Settings variable defined to settings on purpose
+@Field def settings = "Settings"
+//Global variable for state[mode]
+@Field def state = [home:[],away:[],night:[]]
+//Create a global logger object for methods
+@Field def log = new Logger()
+//Create a global object for app
+@Field def app = new Touch(1)
+//Create a global list for objects for events on subscribe methods
+@Field def ObjectList = []
+//Create a global list for events
+@Field def EventList = []
+//Create a global list for function calls based on corresponding events
+@Field def FunctionList = []
+//Create a global list for function schedulers
+@Field def ListofTimersFunc = []
+//Create a global list for timer schedulers
+@Field def ListofTimers = []
+
+
+
+//ExtractedObjects
+//Global Object for class lock!
+@Field def lock1 = new locking(1)
+//Global Object for class contactSensor!
+@Field def contact = new contacting(1)
+//Global variable for number!
+@Field def minutesLater = 1
+//Global variable for number!
+@Field def secondsLater = 10
+//Global variable for recipients!
+@Field def recipients = ['AJ']
+//Global variable for phone number!
+@Field def phoneNumber = 9495379373
+//Global Object for functions in subscribe method!
+@Field def installed = this.&installed
+//Global Object for functions in subscribe method!
+@Field def updated = this.&updated
+//Global Object for functions in subscribe method!
+@Field def initialize = this.&initialize
+//Global Object for functions in subscribe method!
+@Field def lockDoor = this.&lockDoor
+//Global Object for functions in subscribe method!
+@Field def unlockDoor = this.&unlockDoor
+//Global Object for functions in subscribe method!
+@Field def doorHandler = this.&doorHandler
+
+//Methods
+/////////////////////////////////////////////////////////////////////
+def definition(LinkedHashMap LHM) {
+       println("IGNORE -- JUST SOME DEFINITION")
+}
+
+/////////////////////////////////////////////////////////////////////
+def preferences(Closure Input) {
+       println("IGNORE -- JUST SOME DEFINITION")
+}
+/////////////////////////////////////////////////////////////////////
+def setLocationMode(String mode) {
+       location.mode = mode
+}
+
+/////////////////////////////////////////////////////////////////////
+////subscribe(app, func)
+def subscribe(Object Obj, Closure Input) {
+       EventList.add("Touched")
+       FunctionList.add(Input)
+}
+////subscribe(obj, string, func)
+def subscribe(Object Obj, String S, Closure Input) {
+       ObjectList.add(Obj)
+       EventList.add(S)
+       FunctionList.add(Input)
+}
+////subscribe(obj, string, func, hashmap)
+def subscribe(Object Obj, String S, Closure Input, LinkedHashMap LHM) {
+       ObjectList.add(Obj)     
+       EventList.add(S)
+       FunctionList.add(Input)
+}
+/////////////////////////////////////////////////////////////////////
+def EventHandler() {
+       while(true) {
+               List evt = []
+               print "Waiting for an event...\n"
+               def EVENT = System.in.newReader().readLine()
+               SepLine = EVENT.split()
+               for (int i = 0; i < EventList.size(); i++) {
+                       if (EventList[i] == SepLine[0]) {
+                               println("The following effect: \n")
+                               evt.add(new Event())
+                               switch(SepLine[0]) { 
+                                       case "Touched":
+                                               ObjectList[i].touched = 1
+                                               evt[-1].value = "Touched"
+                                               evt[-1].linkText = "touched by user"
+                                               evt[-1].name = "TouchSensor"
+                                               evt[-1].descriptionText = "Touching"
+                                               break
+                                       case "lock":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].lock()
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "locked"
+                                                       evt[-1].linkText = "lock0"
+                                                       evt[-1].displayName = "lock0"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "locking"
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].lock()
+                                                       evt[-1].deviceId = 1
+                                                       evt[-1].value = "locked"
+                                                       evt[-1].linkText = "lock1"
+                                                       evt[-1].displayName = "lock1"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "locking"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].lock()
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "locked"
+                                                       evt[-1].linkText = "lock2"
+                                                       evt[-1].displayName = "lock2"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "locking"
+                                               }
+                                               break
+                                       case "unlock":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].unlock()
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "unlocked"
+                                                       evt[-1].linkText = "lock0"
+                                                       evt[-1].displayName = "lock0"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "unlocking"   
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].unlock()
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "unlocked"
+                                                       evt[-1].linkText = "lock1"
+                                                       evt[-1].displayName = "lock1"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "unlocking"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].unlock()
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "unlocked"
+                                                       evt[-1].linkText = "lock2"
+                                                       evt[-1].displayName = "lock2"
+                                                       evt[-1].name = "lock"
+                                                       evt[-1].descriptionText = "unlocking"
+                                               }
+                                               break
+                                       case "contact.open":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][0].currentContact = "open"
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "contact.open"
+                                                       evt[-1].linkText = "contact0"
+                                                       evt[-1].displayName = "contact0"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "opening"     
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][1].currentContact = "open"
+                                                       evt[-1].deviceId = 1
+                                                       evt[-1].value = "contact.open"
+                                                       evt[-1].linkText = "contact1"
+                                                       evt[-1].displayName = "contact1"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "opening"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][2].currentContact = "open"
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "contact.open"
+                                                       evt[-1].linkText = "contact2"
+                                                       evt[-1].displayName = "contact2"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "opening"
+                                               }
+                                               break
+                                       case "contact.closed":
+                                               if (SepLine[1] == "0") {
+                                                       ObjectList[i][0].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][0].currentContact = "closed"
+                                                       evt[-1].deviceId = 0
+                                                       evt[-1].value = "contact.closed"
+                                                       evt[-1].linkText = "contact0"
+                                                       evt[-1].displayName = "contact0"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "closing"
+                                               } else if (SepLine[1] == "1") {
+                                                       ObjectList[i][1].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][1].currentContact = "closed"
+                                                       evt[-1].deviceId = 1
+                                                       evt[-1].value = "contact.closed"
+                                                       evt[-1].linkText = "contact1"
+                                                       evt[-1].displayName = "contact1"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "closing"
+                                               } else if (SepLine[1] == "2") {
+                                                       ObjectList[i][2].contactLatestValue = ObjectList[i].currentContact
+                                                       ObjectList[i][2].currentContact = "closed"
+                                                       evt[-1].deviceId = 2
+                                                       evt[-1].value = "contact.closed"
+                                                       evt[-1].linkText = "contact2"
+                                                       evt[-1].displayName = "contact2"
+                                                       evt[-1].name = "ContactSensor"
+                                                       evt[-1].descriptionText = "closing"
+                                               }
+                                               break
+                                       default:
+                                               break
+                               }
+                               FunctionList[i](evt[-1])
+                       }
+               }
+       }
+}
+/////////////////////////////////////////////////////////////////////
+////runIn(time, func)
+def runIn(int seconds, Closure Input) {
+       ListofTimersFunc.add(Input)
+       ListofTimers.add(new Timer())
+       def task = ListofTimers[-1].runAfter(1000*seconds, Input)
+}
+/////////////////////////////////////////////////////////////////////
+////unschedule(func)
+def unschedule(Closure Input) {
+       for (int i = 0;i < ListofTimersFunc.size();i++) {
+               if (ListofTimersFunc[i] == Input) {
+                       ListofTimers[i].cancel()
+               }
+       }
+}
+/////////////////////////////////////////////////////////////////////
+////sendNotificationToContacts(text, recipients)
+def sendNotificationToContacts(String S, List recipients) {
+       for (int i = 0;i < recipients.size();i++) {
+               for (int j = 0;j < location.CONTACTS.size();j++) {
+                       if (recipients[i] == location.CONTACTS[j]) {
+                               println("Sending \""+S+"\" to "+location.PhoneNums[j].toString())
+                       }
+               }
+       }
+}
+/////////////////////////////////////////////////////////////////////
+////sendNotificationToContacts(text, recipients)
+def sendSms(long Phone, String S) {
+       println("Sending \""+S+"\" to "+Phone.toString())
+}
+
+///////////////////////////////////////////
+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"
+)
+
+preferences{
+    section("Select the door lock:") {
+        input "lock1", "capability.lock", required: true, multiple: 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){
+    log.debug evt.value
+    log.debug contact.latestValue("contact")
+    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
+       log.debug "1"
+        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...
+       log.debug "2"        
+       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...
+       log.debug "3"
+        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...
+       log.debug "4"
+       //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...
+       log.debug "5"
+        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
+       log.debug "6"
+        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!")
+        }
+    }
+}
+
+installed()
+EventHandler()
diff --git a/makefile b/makefile
new file mode 100644 (file)
index 0000000..5576b0a
--- /dev/null
+++ b/makefile
@@ -0,0 +1,15 @@
+PCC = python
+GCC = groovyc
+GFLAGS = -d
+RMFLAGS = -r
+
+default: Runner main
+
+Runner: Runner.py
+       $(PCC) Runner.py
+main: main.groovy
+       $(GCC) $(GFLAGS) bin/main main.groovy
+
+
+clean:
+       $(RM) $(RMFLAGS) bin/main