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
30 import gov.nasa.jpf.vm.Verify
33 /////////////////////////////////////////////////////////////////////
34 def eventHandler(LinkedHashMap eventDataMap) {
35 def value = eventDataMap["value"]
36 def name = eventDataMap["name"]
37 def deviceId = eventDataMap["deviceId"]
38 def descriptionText = eventDataMap["descriptionText"]
39 def displayed = eventDataMap["displayed"]
40 def linkText = eventDataMap["linkText"]
41 def isStateChange = eventDataMap["isStateChange"]
42 def unit = eventDataMap["unit"]
43 def data = eventDataMap["data"]
45 for (int i = 0;i < app2.eventList.size();i++) {
46 if (app2.eventList[i] == name) {
47 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
49 app2.functionList[i](event)
53 for (int i = 0;i < app1.eventList.size();i++) {
54 if (app1.eventList[i] == name) {
55 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
57 app1.functionList[i](event)
62 //GlobalVariables for both Apps
63 //Create a global variable for send event
64 @Field def sendEvent = {eventDataMap ->
65 eventHandler(eventDataMap)
68 @Field def locationObject = new LocationVar()
69 //Object for touch to call function
70 @Field def appObject = new Touched(sendEvent, 0)
71 //Create a global list for events
73 //Global Object for class Touch Sensor!
74 @Field def touchSensorObject = new NfcTouch(sendEvent, 1)
75 //Global Object for class switch!
76 @Field def switchObject = new Switches(sendEvent, 1)
77 //Global Object for class lock!
78 @Field def lockObject = new Locks(sendEvent, 1)
79 //Global Object for class door control!
80 @Field def doorControlObject = new DoorControls(sendEvent, 1)
81 //Global Object for class contact sensor!
82 @Field def contactObject = new ContactSensors(sendEvent, 1)
83 //Global Object for class presence sensor!
84 @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1)
85 //Global Object for class thermostat!
86 @Field def thermostatObject = new Thermostats(sendEvent, 1)
87 //Global Object for class aeon key fob!
88 @Field def aeonKeyFobObject = new AeonKeyFobs(sendEvent, 1)
89 //Global Object for class music player!
90 @Field def musicPlayerObject = new MusicPlayers(sendEvent, 1)
98 //Extracted objects for App1
99 //Object for class lock!
101 //Global variable for number!
103 //Object for class contactSensor!
106 //Extracted objects for functions for App1
107 //Global Object for functions in subscribe method!
108 def installed = this.&installed
109 //Global Object for functions in subscribe method!
110 def updated = this.&updated
111 //Global Object for functions in subscribe method!
112 def initialize = this.&initialize
113 //Global Object for functions in subscribe method!
114 def lockDoor = this.&lockDoor
115 //Global Object for functions in subscribe method!
116 def doorOpen = this.&doorOpen
117 //Global Object for functions in subscribe method!
118 def doorClosed = this.&doorClosed
119 //Global Object for functions in subscribe method!
120 def doorHandler = this.&doorHandler
124 location = obj.locationObject
126 lock1 = obj.lockObject
127 openSensor = obj.contactObject
128 //Global variable for settings!
129 settings = [app:app, lock1:lock1, minutesLater:minutesLater, openSensor:openSensor]
131 //Global variables for each app
132 //Global variable for state[mode]
133 def state = [home:[],away:[],night:[]]
134 //Create a global logger object for methods
135 def log = new Logger()
136 //Create a global variable for Functions in Subscribe method
137 def functionList = []
138 //Create a global variable for Objects in Subscribe method
140 //Create a global variable for Events in Subscribe method
142 //Create a global list for function schedulers
143 def timersFuncList = []
144 //Create a global list for timer schedulers
146 //Create a global variable for settings
150 /////////////////////////////////////////////////////////////////////
151 def setLocationMode(String mode) {
155 /////////////////////////////////////////////////////////////////////
156 ////subscribe(obj, func)
157 def subscribe(Object obj, Closure FunctionToCall) {
160 eventList.add("Touched")
161 functionList.add(FunctionToCall)
162 } else if (obj == location) {
164 eventList.add("Location")
165 functionList.add(FunctionToCall)
168 ////subscribe(obj, event, func)
169 def subscribe(Object obj, String event, Closure FunctionToCall) {
172 functionList.add(FunctionToCall)
174 ////subscribe(obj, event, func, data)
175 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
178 functionList.add(FunctionToCall)
180 /////////////////////////////////////////////////////////////////////
181 ////runIn(time, func)
182 def runIn(int seconds, Closure functionToCall) {
183 if (timersFuncList.contains(functionToCall)) {
184 timersList[timersFuncList.indexOf(functionToCall)].cancel()
185 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
187 timersFuncList.add(functionToCall)
188 timersList.add(new SimulatedTimer())
189 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
192 /////////////////////////////////////////////////////////////////////
194 def unschedule(Closure functionToUnschedule) {
195 for (int i = 0;i < timersFuncList.size();i++) {
196 if (timersFuncList[i] == functionToUnschedule) {
197 if (timersList != null)
198 timersList[i].cancel()
205 for (int i = 0;i < timersFuncList.size();i++) {
206 if (timersList != null)
207 timersList[i].cancel()
210 /////////////////////////////////////////////////////////////////////
211 ////sendNotificationToContacts(text, recipients)
212 def sendNotificationToContacts(String text, String recipients) {
213 for (int i = 0;i < recipients.size();i++) {
214 for (int j = 0;j < location.contacts.size();j++) {
215 if (recipients[i] == location.contacts[j]) {
216 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
221 /////////////////////////////////////////////////////////////////////
222 ////sendSms(phone, text)
223 def sendSms(long phoneNumber, String text) {
224 println("Sending \""+text+"\" to "+phoneNumber.toString())
226 /////////////////////////////////////////////////////////////////////
228 def sendPush(String text) {
231 /////////////////////////////////////////////////////////////////////
232 ////schedule(time, nameOfFunction as String)
233 def schedule(String time, String nameOfFunction) {
234 def _inputTime = time.split(':')
235 Date date = new Date()
236 def _currentTime = date.format("HH:mm:ss").split(':')
238 //Convert input time and current time to minutes
239 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
240 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
243 if (inputTime < currentTime) {
244 delay = 24*60*60-inputTime+currentTime
246 delay = inputTime-currentTime
249 timersFuncList.add(nameOfFunction)
250 timersList.add(new SimulatedTimer())
251 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
255 ////schedule(time, nameOfFunction as Closure)
256 def schedule(String time, Closure nameOfFunction) {
257 def _inputTime = time.split(':')
258 Date date = new Date()
259 def _currentTime = date.format("HH:mm:ss").split(':')
261 //Convert input time and current time to minutes
262 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
263 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
266 if (inputTime < currentTime) {
267 delay = 24*60*60-inputTime+currentTime
269 delay = inputTime-currentTime
272 if (timersFuncList.contains(nameOfFunction)) {
273 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
274 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
276 timersFuncList.add(nameOfFunction)
277 timersList.add(new SimulatedTimer())
278 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
281 /////////////////////////////////////////////////////////////////////
283 return System.currentTimeMillis()
288 log.debug "Auto Lock Door installed. (URL: http://www.github.com/smartthings-users/smartapp.auto-lock-door)"
296 log.debug "Auto Lock Door updated."
302 log.debug "Settings: ${settings}"
303 subscribe(lock1, "lock", doorHandler)
304 subscribe(openSensor, "contact.closed", doorClosed)
305 subscribe(openSensor, "contact.open", doorOpen)
310 log.debug "Locking Door if Closed"
311 if((openSensor.latestValue("contact") == "closed")){
312 log.debug "Door Closed"
315 if ((openSensor.latestValue("contact") == "open")) {
316 def delay = minutesLater * 60
317 log.debug "Door open will try again in $minutesLater minutes"
318 runIn( delay, lockDoor )
324 log.debug "Door open reset previous lock task..."
325 unschedule( lockDoor )
326 def delay = minutesLater * 60
327 runIn( delay, lockDoor )
330 def doorClosed(evt) {
331 log.debug "Door Closed"
336 log.debug "Door ${openSensor.latestValue}"
337 log.debug "Lock ${evt.name} is ${evt.value}."
339 if (evt.value == "locked") { // If the human locks the door then...
340 log.debug "Cancelling previous lock task..."
341 unschedule( lockDoor ) // ...we don't need to lock it later.
343 else { // If the door is unlocked then...
344 def delay = minutesLater * 60 // runIn uses seconds
345 log.debug "Re-arming lock in ${minutesLater} minutes (${delay}s)."
346 runIn( delay, lockDoor ) // ...schedule to lock in x minutes.
358 //Extracted objects for App2
359 //Object for class Touch Sensor!
361 //Object for class switch!
363 //Object for class lock!
365 //Object for class door control!
367 //Global variable for enum!
368 def masterSwitch = "switchID0"
369 //Global variable for enum!
370 def masterLock = "lockID0"
371 //Global variable for enum!
372 def masterDoor = "DoorControlID0"
374 //Extracted objects for functions for App2
375 //Global Object for functions in subscribe method!
376 def pageTwo = this.&pageTwo
377 //Global Object for functions in subscribe method!
378 def installed = this.&installed
379 //Global Object for functions in subscribe method!
380 def updated = this.&updated
381 //Global Object for functions in subscribe method!
382 def initialize = this.&initialize
383 //Global Object for functions in subscribe method!
384 def currentStatus = this.¤tStatus
385 //Global Object for functions in subscribe method!
386 def touchHandler = this.&touchHandler
390 location = obj.locationObject
392 tag = obj.touchSensorObject
393 switch1 = obj.switchObject
394 lock = obj.lockObject
395 garageDoor = obj.doorControlObject
396 //Global variable for settings!
397 settings = [app:app, tag:tag, switch1:switch1, lock:lock, garageDoor:garageDoor, masterSwitch:masterSwitch, masterLock:masterLock, masterDoor:masterDoor]
399 //Global variables for each app
400 //Global variable for state[mode]
401 def state = [home:[],away:[],night:[]]
402 //Create a global logger object for methods
403 def log = new Logger()
404 //Create a global variable for Functions in Subscribe method
405 def functionList = []
406 //Create a global variable for Objects in Subscribe method
408 //Create a global variable for Events in Subscribe method
410 //Create a global list for function schedulers
411 def timersFuncList = []
412 //Create a global list for timer schedulers
414 //Create a global variable for settings
418 /////////////////////////////////////////////////////////////////////
419 def setLocationMode(String mode) {
423 /////////////////////////////////////////////////////////////////////
424 ////subscribe(obj, func)
425 def subscribe(Object obj, Closure FunctionToCall) {
428 eventList.add("Touched")
429 functionList.add(FunctionToCall)
430 } else if (obj == location) {
432 eventList.add("Location")
433 functionList.add(FunctionToCall)
436 ////subscribe(obj, event, func)
437 def subscribe(Object obj, String event, Closure FunctionToCall) {
440 functionList.add(FunctionToCall)
442 ////subscribe(obj, event, func, data)
443 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
446 functionList.add(FunctionToCall)
448 /////////////////////////////////////////////////////////////////////
449 ////runIn(time, func)
450 def runIn(int seconds, Closure functionToCall) {
451 if (timersFuncList.contains(functionToCall)) {
452 timersList[timersFuncList.indexOf(functionToCall)].cancel()
453 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
455 timersFuncList.add(functionToCall)
456 timersList.add(new SimulatedTimer())
457 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
460 /////////////////////////////////////////////////////////////////////
462 def unschedule(Closure functionToUnschedule) {
463 for (int i = 0;i < timersFuncList.size();i++) {
464 if (timersFuncList[i] == functionToUnschedule) {
465 if (timersList != null)
466 timersList[i].cancel()
473 for (int i = 0;i < timersFuncList.size();i++) {
474 if (timersList != null)
475 timersList[i].cancel()
478 /////////////////////////////////////////////////////////////////////
479 ////sendNotificationToContacts(text, recipients)
480 def sendNotificationToContacts(String text, String recipients) {
481 for (int i = 0;i < recipients.size();i++) {
482 for (int j = 0;j < location.contacts.size();j++) {
483 if (recipients[i] == location.contacts[j]) {
484 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
489 /////////////////////////////////////////////////////////////////////
490 ////sendSms(phone, text)
491 def sendSms(long phoneNumber, String text) {
492 println("Sending \""+text+"\" to "+phoneNumber.toString())
494 /////////////////////////////////////////////////////////////////////
495 ////schedule(time, nameOfFunction as String)
496 def schedule(String time, String nameOfFunction) {
497 def _inputTime = time.split(':')
498 Date date = new Date()
499 def _currentTime = date.format("HH:mm:ss").split(':')
501 //Convert input time and current time to minutes
502 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
503 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
506 if (inputTime < currentTime) {
507 delay = 24*60*60-inputTime+currentTime
509 delay = inputTime-currentTime
512 timersFuncList.add(nameOfFunction)
513 timersList.add(new SimulatedTimer())
514 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
518 ////schedule(time, nameOfFunction as Closure)
519 def schedule(String time, Closure nameOfFunction) {
520 def _inputTime = time.split(':')
521 Date date = new Date()
522 def _currentTime = date.format("HH:mm:ss").split(':')
524 //Convert input time and current time to minutes
525 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
526 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
529 if (inputTime < currentTime) {
530 delay = 24*60*60-inputTime+currentTime
532 delay = inputTime-currentTime
535 if (timersFuncList.contains(nameOfFunction)) {
536 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
537 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
539 timersFuncList.add(nameOfFunction)
540 timersList.add(new SimulatedTimer())
541 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
546 dynamicPage(name: "pageTwo") {
547 section("If set, the state of these devices will be toggled each time the tag is touched, " +
548 "e.g. a light that's on will be turned off and one that's off will be turned on, " +
549 "other devices of the same type will be set to the same state as their master device. " +
550 "If no master is designated then the majority of devices of the same type will be used " +
551 "to determine whether to turn on or off the devices.") {
553 if (switch1 || masterSwitch) {
554 input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
556 if (lock || masterLock) {
557 input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
559 if (garageDoor || masterDoor) {
560 input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
563 section([mobileOnly:true]) {
564 label title: "Assign a name", required: false
565 mode title: "Set for specific mode(s)", required: false
571 log.debug "Installed with settings: ${settings}"
577 log.debug "Updated with settings: ${settings}"
584 subscribe tag, "nfcTouch", touchHandler
585 subscribe app, touchHandler
588 private currentStatus(devices, master, attribute) {
589 log.trace "currentStatus($devices, $master, $attribute)"
592 result = devices.find{it.id == master}?.currentValue(attribute)
597 def value = it.currentValue(attribute)
598 map[value] = (map[value] ?: 0) + 1
599 log.trace "$it.displayName: $value"
602 result = map.collect{it}.sort{it.value}[-1].key
604 log.debug "$attribute = $result"
608 def touchHandler(evt) {
609 log.trace "touchHandler($evt.descriptionText)"
611 def status = currentStatus(switch1, masterSwitch, "switch")
613 if (status == "on") {
623 def status = currentStatus(lock, masterLock, "lock")
625 if (status == "locked") {
635 def status = currentStatus(garageDoor, masterDoor, "status")
637 if (status == "open") {
648 @Field def app1 = new App1(this)
649 @Field def app2 = new App2(this)
653 def events = [1,2,3,4,5,6,7]
654 def list = events.permutations()
655 int count = Verify.getInt(0,list.size()-1)
656 println "COUNT: " + count
661 appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "",
662 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
666 lockObject.setValue([name: "lock0", value: "locked", deviceId: 0, descriptionText: "",
667 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
671 lockObject.setValue([name: "lock0", value: "unlocked", deviceId: 0, descriptionText: "",
672 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
676 contactObject.setValue([name: "contact0", value: "open", deviceId: 0, descriptionText: "",
677 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
681 contactObject.setValue([name: "contact0", value: "closed", deviceId: 0, descriptionText: "",
682 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
686 switchObject.setValue([name: "switch0", value: "on", deviceId: 0, descriptionText: "",
687 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
691 switchObject.setValue([name: "switch0", value: "off", deviceId: 0, descriptionText: "",
692 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])