X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=main.groovy;h=d8f3667539d5a478345ea263835084017281e3a6;hb=c16421586f6281bce41fb42a22befbbb7d099745;hp=d0d579664406ff6254a92e6a19b2d419b996152a;hpb=bd07590976e1951bd9f3cb48b02b0f8644b16662;p=smartthings-infrastructure.git diff --git a/main.groovy b/main.groovy index d0d5796..d8f3667 100644 --- a/main.groovy +++ b/main.groovy @@ -3,16 +3,37 @@ import groovy.transform.Field //Importing Classes -import ContactSensor.Contacting -import ContactSensor.Contacts -import Lock.Locking +import ContactSensor.ContactSensor +import ContactSensor.ContactSensors +import DoorControl.DoorControl +import DoorControl.DoorControls +import Lock.Lock import Lock.Locks -import Switch.Switching +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 @@ -52,19 +73,39 @@ def eventHandler(LinkedHashMap eventDataMap) { eventHandler(eventDataMap) } //Object for location -@Field def locationObject = new LocationVar() -//Object for touch +@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 = [] - -//Extracted global objects for both Apps -//Global Object for class lock! -@Field def lockObject = new Locking(sendEvent,1) -//Global Object for class contactSensor! -@Field def contactObject = new Contacting(sendEvent,1) +//Global Object for class Touch Sensor! +@Field def touchSensorObject = new NfcTouch(sendEvent, 1) //Global Object for class switch! -@Field def switchObject = new Switching(sendEvent, 1) +@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 { @@ -73,18 +114,16 @@ class App1 { def app //Extracted objects for App1 + //Global variable for time! + def time = "15:00" //Object for class lock! - def lock1 + def lock //Object for class contactSensor! def contact - //Global variable for number! - def minutesLater = 1 - //Global variable for number! - def secondsLater = 10 - //Global variable for contact! - def recipients = "AJ" + //Global variable for enum! + def sendPushMessage = "Yes" //Global variable for phone! - def phoneNumber = 9495379373 + def phone = 9495379373 //Extracted objects for functions for App1 //Global Object for functions in subscribe method! @@ -92,24 +131,22 @@ class App1 { //Global Object for functions in subscribe method! def updated = this.&updated //Global Object for functions in subscribe method! - def initialize = this.&initialize + def setTimeCallback = this.&setTimeCallback //Global Object for functions in subscribe method! - def lockDoor = this.&lockDoor + def doorOpenCheck = this.&doorOpenCheck //Global Object for functions in subscribe method! - def unlockDoor = this.&unlockDoor - //Global Object for functions in subscribe method! - def doorHandler = this.&doorHandler + def lockMessage = this.&lockMessage App1(Object obj) { reference = obj location = obj.locationObject app = obj.appObject - lock1 = obj.lockObject + 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 - //Settings variable defined to settings on purpose - def settings = "Settings" //Global variable for state[mode] def state = [home:[],away:[],night:[]] //Create a global logger object for methods @@ -124,6 +161,10 @@ class App1 { 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 ///////////////////////////////////////////////////////////////////// @@ -134,9 +175,15 @@ class App1 { ///////////////////////////////////////////////////////////////////// ////subscribe(obj, func) def subscribe(Object obj, Closure FunctionToCall) { - objectList.add(obj) - eventList.add("Touched") - functionList.add(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) { @@ -155,11 +202,27 @@ class App1 { 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) + 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, functionToCall) + 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"() } } ///////////////////////////////////////////////////////////////////// @@ -196,6 +259,10 @@ class App1 { 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) { @@ -221,7 +288,7 @@ class App1 { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) - def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) { + def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) { "$nameOfFunction"() } } @@ -244,98 +311,72 @@ class App1 { if (timersFuncList.contains(nameOfFunction)) { timersList[timersFuncList.indexOf(nameOfFunction)].cancel() - def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction) + 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, nameOfFunction) + def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction) } } - - def installed(){ - initialize() + ///////////////////////////////////////////////////////////////////// + def now() { + return System.currentTimeMillis() + } + ///////////////////////////////////////////////////////////////////// + def getTemperatureScale() { + return 'C' //Celsius for now } - def updated(){ - unsubscribe() - unschedule() - initialize() + ///////////////////////////////////////////////////////////////////// + def getSunriseAndSunset(LinkedHashMap metaData) { + def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]] + return sunRiseSetInfo } + + def installed() { + schedule(time, "setTimeCallback") - 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 updated(settings) { + unschedule() + schedule(time, "setTimeCallback") } - 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) - } + 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 ( phoneNumber ) { - log.debug("Sending text message...") - sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!") + if (phone) { + sendSms phone, msg } + } else { + lockMessage() + lock.lock() + } } - def doorHandler(evt){ - if ((contact.latestValue("contact") == "open") && (evt.value == "locked")) { // If the door is open and a person locks the door then... - //def delay = (secondsLater) // runIn uses seconds - runIn( secondsLater, unlockDoor ) // ...schedule (in minutes) to unlock... We don't want the door to be closed while the lock is engaged. - } - else if ((contact.latestValue("contact") == "open") && (evt.value == "unlocked")) { // If the door is open and a person unlocks it then... - unschedule( unlockDoor ) // ...we don't need to unlock it later. - } - else if ((contact.latestValue("contact") == "closed") && (evt.value == "locked")) { // If the door is closed and a person manually locks it then... - unschedule( lockDoor ) // ...we don't need to lock it later. - } - else if ((contact.latestValue("contact") == "closed") && (evt.value == "unlocked")) { // If the door is closed and a person unlocks it then... - //def delay = (minutesLater * 60) // runIn uses seconds - runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock. - } - else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "open")) { // If a person opens an unlocked door... - unschedule( lockDoor ) // ...we don't need to lock it later. - } - else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "closed")) { // If a person closes an unlocked door... - //def delay = (minutesLater * 60) // runIn uses seconds - runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock. - } - else { //Opening or Closing door when locked (in case you have a handle lock) - log.debug "Unlocking the door." - lock1.unlock() - if(location.contactBookEnabled) { - if ( recipients ) { - log.debug ( "Sending Push Notification..." ) - sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!", recipients) - } - } - if ( phoneNumber ) { - log.debug("Sending text message...") - sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!") - } - } + def lockMessage() { + def msg = "Locking ${lock.displayName} due to scheduled lock." + log.info msg + if (sendPushMessage) { + sendPush msg + } + if (phone) { + sendSms phone, msg + } } } @@ -347,36 +388,45 @@ class App2 { def app //Extracted objects for App2 + //Object for class Touch Sensor! + def tag //Object for class switch! - def switchesoff - //Object for class switch! - def switcheson + def switch1 //Object for class lock! - def lock1 - //Global variable for mode! - def newMode = "away" - //Global variable for number! - def waitfor = 4 + 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 appTouch = this.&appTouch + 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 - switchesoff = obj.switchObject - switcheson = obj.switchObject - lock1 = obj.lockObject + 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 - //Settings variable defined to settings on purpose - def settings = "Settings" //Global variable for state[mode] def state = [home:[],away:[],night:[]] //Create a global logger object for methods @@ -391,6 +441,10 @@ class App2 { 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 ///////////////////////////////////////////////////////////////////// @@ -401,9 +455,15 @@ class App2 { ///////////////////////////////////////////////////////////////////// ////subscribe(obj, func) def subscribe(Object obj, Closure FunctionToCall) { - objectList.add(obj) - eventList.add("Touched") - functionList.add(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) { @@ -422,11 +482,27 @@ class App2 { 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) + 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, functionToCall) + 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"() } } ///////////////////////////////////////////////////////////////////// @@ -463,6 +539,10 @@ class App2 { 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) { @@ -483,7 +563,7 @@ class App2 { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) - def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) { + def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) { "$nameOfFunction"() } } @@ -506,43 +586,128 @@ class App2 { if (timersFuncList.contains(nameOfFunction)) { timersList[timersFuncList.indexOf(nameOfFunction)].cancel() - def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction) + 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, nameOfFunction) + 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() - { - log.debug "Installed with settings: ${settings}" - log.debug "Current mode = ${location.mode}" - subscribe(app, appTouch) + 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() - { + def updated() { log.debug "Updated with settings: ${settings}" - log.debug "Current mode = ${location.mode}" + unsubscribe() - subscribe(app, appTouch) - } - - def appTouch(evt) { - log.debug "changeMode, location.mode = $location.mode, newMode = $newMode, location.modes = $location.modes" - if (location.mode != newMode) { - setLocationMode(newMode) - log.debug "Changed the mode to '${newMode}'" - } else { - log.debug "New mode is the same as the old mode, leaving it be" - } - log.debug "appTouch: $evt" - lock1.lock() - switcheson.on() - def delay = (waitfor != null && waitfor != "") ? waitfor * 1000 : 120000 - switchesoff.off(delay: delay) + 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() + } + } + } } } @@ -551,71 +716,3 @@ class App2 { app1.installed() app2.installed() - // Generate a random variable - Random random = new Random(1131) - int nextRandom = 10 - - // Touch events - new Thread() { - @Override - public void run() { - while(true) { - appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "", - displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) - Thread.sleep(random.nextInt(nextRandom)); - - } - } - }.start() - - // Lock events - new Thread() { - - @Override - public void run() { - while(true) { - lockObject.setValue([name: "lock", value: "locked", deviceId: 0, descriptionText: "", - displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) - Thread.sleep(random.nextInt(nextRandom)); - } - } - }.start() - - new Thread() { - - @Override - public void run() { - while(true) { - lockObject.setValue([name: "unlock", value: "unlocked", deviceId: 0, descriptionText: "", - displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) - Thread.sleep(random.nextInt(nextRandom)); - } - } - }.start() - - // Contact sensor events - new Thread() { - - @Override - public void run() { - while(true) { - contactObject.setValue([name: "contact.open", value: "open", deviceId: 0, descriptionText: "", - displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) - Thread.sleep(random.nextInt(nextRandom)); - - } - } - }.start() - - new Thread() { - - @Override - public void run() { - while(true) { - contactObject.setValue([name: "contact.closed", value: "closed", deviceId: 0, descriptionText: "", - displayed: true, linkText: "", isStateChange: false, unit: "", data: []]) - Thread.sleep(random.nextInt(nextRandom)); - - } - } - }.start()