--- /dev/null
+//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)
+ }
+ }
+}
--- /dev/null
+//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
+ }
+ }
+}
+
--- /dev/null
+//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 = ""
+ }
+}
--- /dev/null
+///////////////////////////////////////////
+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!")
+ }
+ }
+}
--- /dev/null
+//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
--- /dev/null
+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()
--- /dev/null
+//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 = []
+
+
--- /dev/null
+//Create a class for Phrase
+package Location
+
+class Phrase {
+ private LinkedHashMap Phrases
+
+ Phrase() {
+ this.Phrases = [id:0, label:"Good Morning!"]
+ }
+ def getPhrases() {
+ return Phrases
+ }
+}
+
+
--- /dev/null
+//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]
+ }
+}
--- /dev/null
+//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]
+ }
+}
+
--- /dev/null
+//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
+ }
+ }
+}
--- /dev/null
+//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
+ }
+ }
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+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])
+ }
+ }
+ }
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+def definition(LinkedHashMap LHM) {
+ println("IGNORE -- JUST SOME DEFINITION")
+}
+
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+def preferences(Closure Input) {
+ println("IGNORE -- JUST SOME DEFINITION")
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+////runIn(time, func)
+def runIn(int seconds, Closure Input) {
+ ListofTimersFunc.add(Input)
+ ListofTimers.add(new Timer())
+ def task = ListofTimers[-1].runAfter(1000*seconds, Input)
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+////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())
+ }
+ }
+ }
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+////sendNotificationToContacts(text, recipients)
+def sendSms(long Phone, String S) {
+ println("Sending \""+S+"\" to "+Phone.toString())
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+def setLocationMode(String mode) {
+ location.mode = mode
+}
+
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+////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)
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////
+////unschedule(func)
+def unschedule(Closure Input) {
+ for (int i = 0;i < ListofTimersFunc.size();i++) {
+ if (ListofTimersFunc[i] == Input) {
+ ListofTimers[i].cancel()
+ }
+ }
+}
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.
+-------------------------------------------------------------------------------------------
--- /dev/null
+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()
+
+
+
+
--- /dev/null
+//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
+ }
+ }
+}
--- /dev/null
+//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]
+ }
+}
--- /dev/null
+//Create a class for touch
+package appTouch
+
+public class Touch {
+ private int touched = 0
+
+ Touch(int touched) {
+ this.touched = touched
+ }
+}
--- /dev/null
+//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()
--- /dev/null
+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