1 //Infrastructure for SmartThings Application
3 import groovy.transform.Field
6 import ContactSensor.ContactSensor
7 import ContactSensor.ContactSensors
8 import DoorControl.DoorControl
9 import DoorControl.DoorControls
12 import Thermostat.Thermostat
13 import Thermostat.Thermostats
15 import Switch.Switches
16 import PresenceSensor.PresenceSensor
17 import PresenceSensor.PresenceSensors
19 import Location.LocationVar
20 import Location.Phrase
21 import appTouch.Touched
22 import NfcTouch.NfcTouch
23 import AeonKeyFob.AeonKeyFob
24 import AeonKeyFob.AeonKeyFobs
25 import MusicPlayer.MusicPlayer
26 import MusicPlayer.MusicPlayers
28 import Timer.SimulatedTimer
31 /////////////////////////////////////////////////////////////////////
32 def eventHandler(LinkedHashMap eventDataMap) {
33 def value = eventDataMap["value"]
34 def name = eventDataMap["name"]
35 def deviceId = eventDataMap["deviceId"]
36 def descriptionText = eventDataMap["descriptionText"]
37 def displayed = eventDataMap["displayed"]
38 def linkText = eventDataMap["linkText"]
39 def isStateChange = eventDataMap["isStateChange"]
40 def unit = eventDataMap["unit"]
41 def data = eventDataMap["data"]
43 for (int i = 0;i < app2.eventList.size();i++) {
44 if (app2.eventList[i] == name) {
45 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
47 app2.functionList[i](event)
51 for (int i = 0;i < app1.eventList.size();i++) {
52 if (app1.eventList[i] == name) {
53 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
55 app1.functionList[i](event)
60 //GlobalVariables for both Apps
61 //Create a global variable for send event
62 @Field def sendEvent = {eventDataMap ->
63 eventHandler(eventDataMap)
66 @Field def locationObject = new LocationVar()
67 //Object for touch to call function
68 @Field def appObject = new Touched(sendEvent, 0)
69 //Create a global list for events
71 //Global Object for class Touch Sensor!
72 @Field def touchSensorObject = new NfcTouch(sendEvent, 1)
73 //Global Object for class switch!
74 @Field def switchObject = new Switches(sendEvent, 1)
75 //Global Object for class lock!
76 @Field def lockObject = new Locks(sendEvent, 1)
77 //Global Object for class door control!
78 @Field def doorControlObject = new DoorControls(sendEvent, 1)
79 //Global Object for class contact sensor!
80 @Field def contactObject = new ContactSensors(sendEvent, 1)
81 //Global Object for class presence sensor!
82 @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1)
83 //Global Object for class thermostat!
84 @Field def thermostatObject = new Thermostats(sendEvent, 1)
85 //Global Object for class aeon key fob!
86 @Field def aeonKeyFobObject = new AeonKeyFobs(sendEvent, 1)
87 //Global Object for class music player!
88 @Field def musicPlayerObject = new MusicPlayers(sendEvent, 1)
96 //Extracted objects for App1
97 //Object for class lock!
99 //Global variable for number!
101 //Object for class contactSensor!
104 //Extracted objects for functions for App1
105 //Global Object for functions in subscribe method!
106 def installed = this.&installed
107 //Global Object for functions in subscribe method!
108 def updated = this.&updated
109 //Global Object for functions in subscribe method!
110 def initialize = this.&initialize
111 //Global Object for functions in subscribe method!
112 def lockDoor = this.&lockDoor
113 //Global Object for functions in subscribe method!
114 def doorOpen = this.&doorOpen
115 //Global Object for functions in subscribe method!
116 def doorClosed = this.&doorClosed
117 //Global Object for functions in subscribe method!
118 def doorHandler = this.&doorHandler
122 location = obj.locationObject
124 lock1 = obj.lockObject
125 openSensor = obj.contactObject
126 //Global variable for settings!
127 settings = [app:app, lock1:lock1, minutesLater:minutesLater, openSensor:openSensor]
129 //Global variables for each app
130 //Global variable for state[mode]
131 def state = [home:[],away:[],night:[]]
132 //Create a global logger object for methods
133 def log = new Logger()
134 //Create a global variable for Functions in Subscribe method
135 def functionList = []
136 //Create a global variable for Objects in Subscribe method
138 //Create a global variable for Events in Subscribe method
140 //Create a global list for function schedulers
141 def timersFuncList = []
142 //Create a global list for timer schedulers
144 //Create a global variable for settings
148 /////////////////////////////////////////////////////////////////////
149 def setLocationMode(String mode) {
153 /////////////////////////////////////////////////////////////////////
154 ////subscribe(obj, func)
155 def subscribe(Object obj, Closure FunctionToCall) {
158 eventList.add("Touched")
159 functionList.add(FunctionToCall)
160 } else if (obj == location) {
162 eventList.add("Location")
163 functionList.add(FunctionToCall)
166 ////subscribe(obj, event, func)
167 def subscribe(Object obj, String event, Closure FunctionToCall) {
170 functionList.add(FunctionToCall)
172 ////subscribe(obj, event, func, data)
173 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
176 functionList.add(FunctionToCall)
178 /////////////////////////////////////////////////////////////////////
179 ////runIn(time, func)
180 def runIn(int seconds, Closure functionToCall) {
181 if (timersFuncList.contains(functionToCall)) {
182 timersList[timersFuncList.indexOf(functionToCall)].cancel()
183 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
185 timersFuncList.add(functionToCall)
186 timersList.add(new SimulatedTimer())
187 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
190 /////////////////////////////////////////////////////////////////////
192 def unschedule(Closure functionToUnschedule) {
193 for (int i = 0;i < timersFuncList.size();i++) {
194 if (timersFuncList[i] == functionToUnschedule) {
195 if (timersList != null)
196 timersList[i].cancel()
203 for (int i = 0;i < timersFuncList.size();i++) {
204 if (timersList != null)
205 timersList[i].cancel()
208 /////////////////////////////////////////////////////////////////////
209 ////sendNotificationToContacts(text, recipients)
210 def sendNotificationToContacts(String text, String recipients) {
211 for (int i = 0;i < recipients.size();i++) {
212 for (int j = 0;j < location.contacts.size();j++) {
213 if (recipients[i] == location.contacts[j]) {
214 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
219 /////////////////////////////////////////////////////////////////////
220 ////sendSms(phone, text)
221 def sendSms(long phoneNumber, String text) {
222 println("Sending \""+text+"\" to "+phoneNumber.toString())
224 /////////////////////////////////////////////////////////////////////
226 def sendPush(String text) {
229 /////////////////////////////////////////////////////////////////////
230 ////schedule(time, nameOfFunction as String)
231 def schedule(String time, String nameOfFunction) {
232 def _inputTime = time.split(':')
233 Date date = new Date()
234 def _currentTime = date.format("HH:mm:ss").split(':')
236 //Convert input time and current time to minutes
237 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
238 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
241 if (inputTime < currentTime) {
242 delay = 24*60*60-inputTime+currentTime
244 delay = inputTime-currentTime
247 timersFuncList.add(nameOfFunction)
248 timersList.add(new SimulatedTimer())
249 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
253 ////schedule(time, nameOfFunction as Closure)
254 def schedule(String time, Closure nameOfFunction) {
255 def _inputTime = time.split(':')
256 Date date = new Date()
257 def _currentTime = date.format("HH:mm:ss").split(':')
259 //Convert input time and current time to minutes
260 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
261 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
264 if (inputTime < currentTime) {
265 delay = 24*60*60-inputTime+currentTime
267 delay = inputTime-currentTime
270 if (timersFuncList.contains(nameOfFunction)) {
271 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
272 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
274 timersFuncList.add(nameOfFunction)
275 timersList.add(new SimulatedTimer())
276 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
279 /////////////////////////////////////////////////////////////////////
281 return System.currentTimeMillis()
286 log.debug "Auto Lock Door installed. (URL: http://www.github.com/smartthings-users/smartapp.auto-lock-door)"
294 log.debug "Auto Lock Door updated."
300 log.debug "Settings: ${settings}"
301 subscribe(lock1, "lock", doorHandler)
302 subscribe(openSensor, "contact.closed", doorClosed)
303 subscribe(openSensor, "contact.open", doorOpen)
308 log.debug "Locking Door if Closed"
309 if((openSensor.latestValue("contact") == "closed")){
310 log.debug "Door Closed"
313 if ((openSensor.latestValue("contact") == "open")) {
314 def delay = minutesLater * 60
315 log.debug "Door open will try again in $minutesLater minutes"
316 runIn( delay, lockDoor )
322 log.debug "Door open reset previous lock task..."
323 unschedule( lockDoor )
324 def delay = minutesLater * 60
325 runIn( delay, lockDoor )
328 def doorClosed(evt) {
329 log.debug "Door Closed"
334 log.debug "Door ${openSensor.latestValue}"
335 log.debug "Lock ${evt.name} is ${evt.value}."
337 if (evt.value == "locked") { // If the human locks the door then...
338 log.debug "Cancelling previous lock task..."
339 unschedule( lockDoor ) // ...we don't need to lock it later.
341 else { // If the door is unlocked then...
342 def delay = minutesLater * 60 // runIn uses seconds
343 log.debug "Re-arming lock in ${minutesLater} minutes (${delay}s)."
344 runIn( delay, lockDoor ) // ...schedule to lock in x minutes.
356 //Extracted objects for App2
357 //Object for class Touch Sensor!
359 //Object for class switch!
361 //Object for class lock!
363 //Object for class door control!
365 //Global variable for enum!
366 def masterSwitch = "switchID0"
367 //Global variable for enum!
368 def masterLock = "lockID0"
369 //Global variable for enum!
370 def masterDoor = "DoorControlID0"
372 //Extracted objects for functions for App2
373 //Global Object for functions in subscribe method!
374 def pageTwo = this.&pageTwo
375 //Global Object for functions in subscribe method!
376 def installed = this.&installed
377 //Global Object for functions in subscribe method!
378 def updated = this.&updated
379 //Global Object for functions in subscribe method!
380 def initialize = this.&initialize
381 //Global Object for functions in subscribe method!
382 def currentStatus = this.¤tStatus
383 //Global Object for functions in subscribe method!
384 def touchHandler = this.&touchHandler
388 location = obj.locationObject
390 tag = obj.touchSensorObject
391 switch1 = obj.switchObject
392 lock = obj.lockObject
393 garageDoor = obj.doorControlObject
394 //Global variable for settings!
395 settings = [app:app, tag:tag, switch1:switch1, lock:lock, garageDoor:garageDoor, masterSwitch:masterSwitch, masterLock:masterLock, masterDoor:masterDoor]
397 //Global variables for each app
398 //Global variable for state[mode]
399 def state = [home:[],away:[],night:[]]
400 //Create a global logger object for methods
401 def log = new Logger()
402 //Create a global variable for Functions in Subscribe method
403 def functionList = []
404 //Create a global variable for Objects in Subscribe method
406 //Create a global variable for Events in Subscribe method
408 //Create a global list for function schedulers
409 def timersFuncList = []
410 //Create a global list for timer schedulers
412 //Create a global variable for settings
416 /////////////////////////////////////////////////////////////////////
417 def setLocationMode(String mode) {
421 /////////////////////////////////////////////////////////////////////
422 ////subscribe(obj, func)
423 def subscribe(Object obj, Closure FunctionToCall) {
426 eventList.add("Touched")
427 functionList.add(FunctionToCall)
428 } else if (obj == location) {
430 eventList.add("Location")
431 functionList.add(FunctionToCall)
434 ////subscribe(obj, event, func)
435 def subscribe(Object obj, String event, Closure FunctionToCall) {
438 functionList.add(FunctionToCall)
440 ////subscribe(obj, event, func, data)
441 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
444 functionList.add(FunctionToCall)
446 /////////////////////////////////////////////////////////////////////
447 ////runIn(time, func)
448 def runIn(int seconds, Closure functionToCall) {
449 if (timersFuncList.contains(functionToCall)) {
450 timersList[timersFuncList.indexOf(functionToCall)].cancel()
451 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
453 timersFuncList.add(functionToCall)
454 timersList.add(new SimulatedTimer())
455 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
458 /////////////////////////////////////////////////////////////////////
460 def unschedule(Closure functionToUnschedule) {
461 for (int i = 0;i < timersFuncList.size();i++) {
462 if (timersFuncList[i] == functionToUnschedule) {
463 if (timersList != null)
464 timersList[i].cancel()
471 for (int i = 0;i < timersFuncList.size();i++) {
472 if (timersList != null)
473 timersList[i].cancel()
476 /////////////////////////////////////////////////////////////////////
477 ////sendNotificationToContacts(text, recipients)
478 def sendNotificationToContacts(String text, String recipients) {
479 for (int i = 0;i < recipients.size();i++) {
480 for (int j = 0;j < location.contacts.size();j++) {
481 if (recipients[i] == location.contacts[j]) {
482 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
487 /////////////////////////////////////////////////////////////////////
488 ////sendSms(phone, text)
489 def sendSms(long phoneNumber, String text) {
490 println("Sending \""+text+"\" to "+phoneNumber.toString())
492 /////////////////////////////////////////////////////////////////////
493 ////schedule(time, nameOfFunction as String)
494 def schedule(String time, String nameOfFunction) {
495 def _inputTime = time.split(':')
496 Date date = new Date()
497 def _currentTime = date.format("HH:mm:ss").split(':')
499 //Convert input time and current time to minutes
500 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
501 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
504 if (inputTime < currentTime) {
505 delay = 24*60*60-inputTime+currentTime
507 delay = inputTime-currentTime
510 timersFuncList.add(nameOfFunction)
511 timersList.add(new SimulatedTimer())
512 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
516 ////schedule(time, nameOfFunction as Closure)
517 def schedule(String time, Closure nameOfFunction) {
518 def _inputTime = time.split(':')
519 Date date = new Date()
520 def _currentTime = date.format("HH:mm:ss").split(':')
522 //Convert input time and current time to minutes
523 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
524 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
527 if (inputTime < currentTime) {
528 delay = 24*60*60-inputTime+currentTime
530 delay = inputTime-currentTime
533 if (timersFuncList.contains(nameOfFunction)) {
534 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
535 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
537 timersFuncList.add(nameOfFunction)
538 timersList.add(new SimulatedTimer())
539 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
544 dynamicPage(name: "pageTwo") {
545 section("If set, the state of these devices will be toggled each time the tag is touched, " +
546 "e.g. a light that's on will be turned off and one that's off will be turned on, " +
547 "other devices of the same type will be set to the same state as their master device. " +
548 "If no master is designated then the majority of devices of the same type will be used " +
549 "to determine whether to turn on or off the devices.") {
551 if (switch1 || masterSwitch) {
552 input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
554 if (lock || masterLock) {
555 input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
557 if (garageDoor || masterDoor) {
558 input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
561 section([mobileOnly:true]) {
562 label title: "Assign a name", required: false
563 mode title: "Set for specific mode(s)", required: false
569 log.debug "Installed with settings: ${settings}"
575 log.debug "Updated with settings: ${settings}"
582 subscribe tag, "nfcTouch", touchHandler
583 subscribe app, touchHandler
586 private currentStatus(devices, master, attribute) {
587 log.trace "currentStatus($devices, $master, $attribute)"
590 result = devices.find{it.id == master}?.currentValue(attribute)
595 def value = it.currentValue(attribute)
596 map[value] = (map[value] ?: 0) + 1
597 log.trace "$it.displayName: $value"
600 result = map.collect{it}.sort{it.value}[-1].key
602 log.debug "$attribute = $result"
606 def touchHandler(evt) {
607 log.trace "touchHandler($evt.descriptionText)"
609 def status = currentStatus(switch1, masterSwitch, "switch")
611 if (status == "on") {
621 def status = currentStatus(lock, masterLock, "lock")
623 if (status == "locked") {
633 def status = currentStatus(garageDoor, masterDoor, "status")
635 if (status == "open") {
646 @Field def app1 = new App1(this)
647 @Field def app2 = new App2(this)
651 def events = [1,2,3,4,5,6,7]
652 def list = events.permutations()
653 int count = Verify.getInt(0,list.size()-1)
654 println "COUNT: " + count
659 appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "",
660 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
664 lockObject.setValue([name: "lock0", value: "locked", deviceId: 0, descriptionText: "",
665 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
669 lockObject.setValue([name: "lock0", value: "unlocked", deviceId: 0, descriptionText: "",
670 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
674 contactObject.setValue([name: "contact0", value: "open", deviceId: 0, descriptionText: "",
675 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
679 contactObject.setValue([name: "contact0", value: "closed", deviceId: 0, descriptionText: "",
680 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
684 switchObject.setValue([name: "switch0", value: "on", deviceId: 0, descriptionText: "",
685 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
689 switchObject.setValue([name: "switch0", value: "off", deviceId: 0, descriptionText: "",
690 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])