//Infrastructure for SmartThings Application //Importing Libraries import groovy.transform.Field //Importing Classes import ContactSensor.ContactSensor import ContactSensor.ContactSensors import DoorControl.DoorControl import DoorControl.DoorControls import Lock.Lock import Lock.Locks import Thermostat.Thermostat import Thermostat.Thermostats import Switch.Switch import Switch.Switches import PresenceSensor.PresenceSensor import PresenceSensor.PresenceSensors import Logger.Logger import Location.LocationVar import Location.Phrase import appTouch.Touched import NfcTouch.NfcTouch import AeonKeyFob.AeonKeyFob import AeonKeyFob.AeonKeyFobs import MusicPlayer.MusicPlayer import MusicPlayer.MusicPlayers import Event.Event import Timer.SimulatedTimer import gov.nasa.jpf.vm.Verify //Global eventHandler ///////////////////////////////////////////////////////////////////// def eventHandler(LinkedHashMap eventDataMap) { def value = eventDataMap["value"] def name = eventDataMap["name"] def deviceId = eventDataMap["deviceId"] def descriptionText = eventDataMap["descriptionText"] def displayed = eventDataMap["displayed"] def linkText = eventDataMap["linkText"] def isStateChange = eventDataMap["isStateChange"] def unit = eventDataMap["unit"] def data = eventDataMap["data"] for (int i = 0;i < app2.eventList.size();i++) { if (app2.eventList[i] == name) { def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data) evt.add(event) app2.functionList[i](event) } } for (int i = 0;i < app1.eventList.size();i++) { if (app1.eventList[i] == name) { def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data) evt.add(event) app1.functionList[i](event) } } } //GlobalVariables for both Apps //Create a global variable for send event @Field def sendEvent = {eventDataMap -> eventHandler(eventDataMap) } //Object for location @Field def locationObject = new LocationVar() //Object for touch to call function @Field def appObject = new Touched(sendEvent, 0) //Create a global list for events @Field def evt = [] //Global Object for class Touch Sensor! @Field def touchSensorObject = new NfcTouch(sendEvent, 1) //Global Object for class switch! @Field def switchObject = new Switches(sendEvent, 1) //Global Object for class lock! @Field def lockObject = new Locks(sendEvent, 1) //Global Object for class door control! @Field def doorControlObject = new DoorControls(sendEvent, 1) //Global Object for class contact sensor! @Field def contactObject = new ContactSensors(sendEvent, 1) //Global Object for class presence sensor! @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1) //Global Object for class thermostat! @Field def thermostatObject = new Thermostats(sendEvent, 1) //Global Object for class aeon key fob! @Field def aeonKeyFobObject = new AeonKeyFobs(sendEvent, 1) //Global Object for class music player! @Field def musicPlayerObject = new MusicPlayers(sendEvent, 1) //Application #1 class App1 { def reference def location def app //Extracted objects for App1 //Object for class lock! def lock1 //Global variable for number! def minutesLater = 1 //Object for class contactSensor! def openSensor //Extracted objects for functions for App1 //Global Object for functions in subscribe method! def installed = this.&installed //Global Object for functions in subscribe method! def updated = this.&updated //Global Object for functions in subscribe method! def initialize = this.&initialize //Global Object for functions in subscribe method! def lockDoor = this.&lockDoor //Global Object for functions in subscribe method! def doorOpen = this.&doorOpen //Global Object for functions in subscribe method! def doorClosed = this.&doorClosed //Global Object for functions in subscribe method! def doorHandler = this.&doorHandler App1(Object obj) { reference = obj location = obj.locationObject app = obj.appObject lock1 = obj.lockObject openSensor = obj.contactObject //Global variable for settings! settings = [app:app, lock1:lock1, minutesLater:minutesLater, openSensor:openSensor] } //Global variables for each app //Global variable for state[mode] def state = [home:[],away:[],night:[]] //Create a global logger object for methods def log = new Logger() //Create a global variable for Functions in Subscribe method def functionList = [] //Create a global variable for Objects in Subscribe method def objectList = [] //Create a global variable for Events in Subscribe method def eventList = [] //Create a global list for function schedulers def timersFuncList = [] //Create a global list for timer schedulers def timersList = [] //Create a global variable for settings def settings //Methods ///////////////////////////////////////////////////////////////////// def setLocationMode(String mode) { location.mode = mode } ///////////////////////////////////////////////////////////////////// ////subscribe(obj, func) def subscribe(Object obj, Closure FunctionToCall) { if (obj == app) { objectList.add(obj) eventList.add("Touched") functionList.add(FunctionToCall) } else if (obj == location) { objectList.add(obj) eventList.add("Location") functionList.add(FunctionToCall) } } ////subscribe(obj, event, func) def subscribe(Object obj, String event, Closure FunctionToCall) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ////subscribe(obj, event, func, data) def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ///////////////////////////////////////////////////////////////////// ////runIn(time, func) def runIn(int seconds, Closure functionToCall) { if (timersFuncList.contains(functionToCall)) { timersList[timersFuncList.indexOf(functionToCall)].cancel() def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall) } else { timersFuncList.add(functionToCall) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall) } } ///////////////////////////////////////////////////////////////////// ////unschedule(func) def unschedule(Closure functionToUnschedule) { for (int i = 0;i < timersFuncList.size();i++) { if (timersFuncList[i] == functionToUnschedule) { if (timersList != null) timersList[i].cancel() } } } def unschedule() { for (int i = 0;i < timersFuncList.size();i++) { if (timersList != null) timersList[i].cancel() } } ///////////////////////////////////////////////////////////////////// ////sendNotificationToContacts(text, recipients) def sendNotificationToContacts(String text, String 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 \""+text+"\" to "+location.phoneNumbers[j].toString()) } } } } ///////////////////////////////////////////////////////////////////// ////sendSms(phone, text) def sendSms(long phoneNumber, String text) { println("Sending \""+text+"\" to "+phoneNumber.toString()) } ///////////////////////////////////////////////////////////////////// ////sendPush(text) def sendPush(String text) { println(text) } ///////////////////////////////////////////////////////////////////// ////schedule(time, nameOfFunction as String) def schedule(String time, String nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) { "$nameOfFunction"() } } ////schedule(time, nameOfFunction as Closure) def schedule(String time, Closure nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } if (timersFuncList.contains(nameOfFunction)) { timersList[timersFuncList.indexOf(nameOfFunction)].cancel() def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction) } else { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction) } } ///////////////////////////////////////////////////////////////////// def now() { return System.currentTimeMillis() } def installed() { log.debug "Auto Lock Door installed. (URL: http://www.github.com/smartthings-users/smartapp.auto-lock-door)" initialize() } def updated() { unsubscribe() unschedule() log.debug "Auto Lock Door updated." initialize() } def initialize() { log.debug "Settings: ${settings}" subscribe(lock1, "lock", doorHandler) subscribe(openSensor, "contact.closed", doorClosed) subscribe(openSensor, "contact.open", doorOpen) } def lockDoor() { log.debug "Locking Door if Closed" if((openSensor.latestValue("contact") == "closed")){ log.debug "Door Closed" lock1.lock() } else { if ((openSensor.latestValue("contact") == "open")) { def delay = minutesLater * 60 log.debug "Door open will try again in $minutesLater minutes" runIn( delay, lockDoor ) } } } def doorOpen(evt) { log.debug "Door open reset previous lock task..." unschedule( lockDoor ) def delay = minutesLater * 60 runIn( delay, lockDoor ) } def doorClosed(evt) { log.debug "Door Closed" } def doorHandler(evt) { log.debug "Door ${openSensor.latestValue}" log.debug "Lock ${evt.name} is ${evt.value}." if (evt.value == "locked") { // If the human locks the door then... log.debug "Cancelling previous lock task..." unschedule( lockDoor ) // ...we don't need to lock it later. } else { // If the door is unlocked then... def delay = minutesLater * 60 // runIn uses seconds log.debug "Re-arming lock in ${minutesLater} minutes (${delay}s)." runIn( delay, lockDoor ) // ...schedule to lock in x minutes. } } } //Application #2 class App2 { def reference def location def app //Extracted objects for App2 //Object for class Touch Sensor! def tag //Object for class switch! def switch1 //Object for class lock! def lock //Object for class door control! def garageDoor //Global variable for enum! def masterSwitch = "switchID0" //Global variable for enum! def masterLock = "lockID0" //Global variable for enum! def masterDoor = "DoorControlID0" //Extracted objects for functions for App2 //Global Object for functions in subscribe method! def pageTwo = this.&pageTwo //Global Object for functions in subscribe method! def installed = this.&installed //Global Object for functions in subscribe method! def updated = this.&updated //Global Object for functions in subscribe method! def initialize = this.&initialize //Global Object for functions in subscribe method! def currentStatus = this.¤tStatus //Global Object for functions in subscribe method! def touchHandler = this.&touchHandler App2(Object obj) { reference = obj location = obj.locationObject app = obj.appObject tag = obj.touchSensorObject switch1 = obj.switchObject lock = obj.lockObject garageDoor = obj.doorControlObject //Global variable for settings! settings = [app:app, tag:tag, switch1:switch1, lock:lock, garageDoor:garageDoor, masterSwitch:masterSwitch, masterLock:masterLock, masterDoor:masterDoor] } //Global variables for each app //Global variable for state[mode] def state = [home:[],away:[],night:[]] //Create a global logger object for methods def log = new Logger() //Create a global variable for Functions in Subscribe method def functionList = [] //Create a global variable for Objects in Subscribe method def objectList = [] //Create a global variable for Events in Subscribe method def eventList = [] //Create a global list for function schedulers def timersFuncList = [] //Create a global list for timer schedulers def timersList = [] //Create a global variable for settings def settings //Methods ///////////////////////////////////////////////////////////////////// def setLocationMode(String mode) { location.mode = mode } ///////////////////////////////////////////////////////////////////// ////subscribe(obj, func) def subscribe(Object obj, Closure FunctionToCall) { if (obj == app) { objectList.add(obj) eventList.add("Touched") functionList.add(FunctionToCall) } else if (obj == location) { objectList.add(obj) eventList.add("Location") functionList.add(FunctionToCall) } } ////subscribe(obj, event, func) def subscribe(Object obj, String event, Closure FunctionToCall) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ////subscribe(obj, event, func, data) def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ///////////////////////////////////////////////////////////////////// ////runIn(time, func) def runIn(int seconds, Closure functionToCall) { if (timersFuncList.contains(functionToCall)) { timersList[timersFuncList.indexOf(functionToCall)].cancel() def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall) } else { timersFuncList.add(functionToCall) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall) } } ///////////////////////////////////////////////////////////////////// ////unschedule(func) def unschedule(Closure functionToUnschedule) { for (int i = 0;i < timersFuncList.size();i++) { if (timersFuncList[i] == functionToUnschedule) { if (timersList != null) timersList[i].cancel() } } } def unschedule() { for (int i = 0;i < timersFuncList.size();i++) { if (timersList != null) timersList[i].cancel() } } ///////////////////////////////////////////////////////////////////// ////sendNotificationToContacts(text, recipients) def sendNotificationToContacts(String text, String 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 \""+text+"\" to "+location.phoneNumbers[j].toString()) } } } } ///////////////////////////////////////////////////////////////////// ////sendSms(phone, text) def sendSms(long phoneNumber, String text) { println("Sending \""+text+"\" to "+phoneNumber.toString()) } ///////////////////////////////////////////////////////////////////// ////schedule(time, nameOfFunction as String) def schedule(String time, String nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) { "$nameOfFunction"() } } ////schedule(time, nameOfFunction as Closure) def schedule(String time, Closure nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } if (timersFuncList.contains(nameOfFunction)) { timersList[timersFuncList.indexOf(nameOfFunction)].cancel() def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction) } else { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction) } } def pageTwo() { dynamicPage(name: "pageTwo") { section("If set, the state of these devices will be toggled each time the tag is touched, " + "e.g. a light that's on will be turned off and one that's off will be turned on, " + "other devices of the same type will be set to the same state as their master device. " + "If no master is designated then the majority of devices of the same type will be used " + "to determine whether to turn on or off the devices.") { if (switch1 || masterSwitch) { input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false } if (lock || masterLock) { input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false } if (garageDoor || masterDoor) { input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false } } section([mobileOnly:true]) { label title: "Assign a name", required: false mode title: "Set for specific mode(s)", required: false } } } def installed() { log.debug "Installed with settings: ${settings}" initialize() } def updated() { log.debug "Updated with settings: ${settings}" unsubscribe() initialize() } def initialize() { subscribe tag, "nfcTouch", touchHandler subscribe app, touchHandler } private currentStatus(devices, master, attribute) { log.trace "currentStatus($devices, $master, $attribute)" def result = null if (master) { result = devices.find{it.id == master}?.currentValue(attribute) } else { def map = [:] devices.each { def value = it.currentValue(attribute) map[value] = (map[value] ?: 0) + 1 log.trace "$it.displayName: $value" } log.trace map result = map.collect{it}.sort{it.value}[-1].key } log.debug "$attribute = $result" result } def touchHandler(evt) { log.trace "touchHandler($evt.descriptionText)" if (switch1) { def status = currentStatus(switch1, masterSwitch, "switch") switch1.each { if (status == "on") { it.off() } else { it.on() } } } if (lock) { def status = currentStatus(lock, masterLock, "lock") lock.each { if (status == "locked") { lock.unlock() } else { lock.lock() } } } if (garageDoor) { def status = currentStatus(garageDoor, masterDoor, "status") garageDoor.each { if (status == "open") { it.close() } else { it.open() } } } } } @Field def app1 = new App1(this) @Field def app2 = new App2(this) app1.installed() app2.installed() def events = [1,2,3,4,5,6,7] def list = events.permutations() int count = Verify.getInt(0,list.size()-1) println "COUNT: " + count list[count].each { switch(it) { case 1: appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println "1" break case 2: lockObject.setValue([name: "lock0", value: "locked", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println " 2" break case 3: lockObject.setValue([name: "lock0", value: "unlocked", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println " 3" break case 4: contactObject.setValue([name: "contact0", value: "open", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println " 4" break case 5: contactObject.setValue([name: "contact0", value: "closed", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println " 5" break case 6: switchObject.setValue([name: "switch0", value: "on", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println " 6" break case 7: switchObject.setValue([name: "switch0", value: "off", deviceId: 0, descriptionText: "", displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) println " 7" default: break } }