//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 MotionSensor.MotionSensor import MotionSensor.MotionSensors import ImageCapture.ImageCapture import ImageCapture.ImageCaptures import SmokeDetector.SmokeDetector import SmokeDetector.SmokeDetectors import Alarm.Alarm import Alarm.Alarms import SpeechSynthesis.SpeechSynthesis import SpeechSynthesis.SpeechSynthesises import Event.Event import Timer.SimulatedTimer //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(sendEvent) //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) //Global Object for class motion sensor! @Field def motionSensorObject = new MotionSensors(sendEvent, 1) //Global Object for class image capture! @Field def imageCaptureObject = new ImageCaptures(sendEvent, 1) //Global Object for class smoke detector! @Field def smokeDetectorObject = new SmokeDetectors(sendEvent, 1) //Global Object for class alarm! @Field def alarmObject = new Alarms(sendEvent, 1) //Global Object for class speech synthesis! @Field def speechSynthesisObject = new SpeechSynthesises(sendEvent, 1) //Application #1 class App1 { def reference def location def app //Extracted objects for App1 //Global variable for time! def time = "15:00" //Object for class lock! def lock //Object for class contactSensor! def contact //Global variable for enum! def sendPushMessage = "Yes" //Global variable for phone! def phone = 9495379373 //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 setTimeCallback = this.&setTimeCallback //Global Object for functions in subscribe method! def doorOpenCheck = this.&doorOpenCheck //Global Object for functions in subscribe method! def lockMessage = this.&lockMessage App1(Object obj) { reference = obj location = obj.locationObject app = obj.appObject lock = obj.lockObject contact = obj.contactObject //Global variable for settings! settings = [app:app, time:time, lock:lock, contact:contact, sendPushMessage:sendPushMessage, phone:phone] } //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 //Zip code def zipCode = 92617 //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*0, functionToCall) } else { timersFuncList.add(functionToCall) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall) } } def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) { runIn(seconds, functionToCall) } def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) { runIn(seconds, nameOfFunction) } def runIn(int seconds, String nameOfFunction) { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) { "$nameOfFunction"() } } ///////////////////////////////////////////////////////////////////// ////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()) } 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*0) { "$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*0, nameOfFunction) } else { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction) } } ///////////////////////////////////////////////////////////////////// def now() { return System.currentTimeMillis() } ///////////////////////////////////////////////////////////////////// def getTemperatureScale() { return 'C' //Celsius for now } ///////////////////////////////////////////////////////////////////// def getSunriseAndSunset(LinkedHashMap metaData) { def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]] return sunRiseSetInfo } def installed() { schedule(time, "setTimeCallback") } def updated(settings) { unschedule() schedule(time, "setTimeCallback") } def setTimeCallback() { if (contact) { doorOpenCheck() } else { lockMessage() lock.lock() } } def doorOpenCheck() { def currentState = contact.contactState if (currentState?.value == "open") { def msg = "${contact.displayName} is open. Scheduled lock failed." log.info msg if (sendPushMessage) { sendPush msg } if (phone) { sendSms phone, msg } } else { lockMessage() lock.lock() } } def lockMessage() { def msg = "Locking ${lock.displayName} due to scheduled lock." log.info msg if (sendPushMessage) { sendPush msg } if (phone) { sendSms phone, msg } } } //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 = "Yes" //Global variable for enum! def masterLock = "Yes" //Global variable for enum! def masterDoor = "Yes" //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 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 //Zip code def zipCode = 92617 //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*0, functionToCall) } else { timersFuncList.add(functionToCall) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall) } } def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) { runIn(seconds, functionToCall) } def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) { runIn(seconds, nameOfFunction) } def runIn(int seconds, String nameOfFunction) { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) { "$nameOfFunction"() } } ///////////////////////////////////////////////////////////////////// ////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()) } 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*0) { "$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*0, nameOfFunction) } else { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction) } } ///////////////////////////////////////////////////////////////////// def now() { return System.currentTimeMillis() } ///////////////////////////////////////////////////////////////////// def getTemperatureScale() { return 'C' //Celsius for now } ///////////////////////////////////////////////////////////////////// def getSunriseAndSunset(LinkedHashMap metaData) { def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]] return sunRiseSetInfo } 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()