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
27 import MotionSensor.MotionSensor
28 import MotionSensor.MotionSensors
29 import ImageCapture.ImageCapture
30 import ImageCapture.ImageCaptures
31 import SmokeDetector.SmokeDetector
32 import SmokeDetector.SmokeDetectors
35 import SpeechSynthesis.SpeechSynthesis
36 import SpeechSynthesis.SpeechSynthesises
38 import Timer.SimulatedTimer
41 /////////////////////////////////////////////////////////////////////
42 def eventHandler(LinkedHashMap eventDataMap) {
43 def value = eventDataMap["value"]
44 def name = eventDataMap["name"]
45 def deviceId = eventDataMap["deviceId"]
46 def descriptionText = eventDataMap["descriptionText"]
47 def displayed = eventDataMap["displayed"]
48 def linkText = eventDataMap["linkText"]
49 def isStateChange = eventDataMap["isStateChange"]
50 def unit = eventDataMap["unit"]
51 def data = eventDataMap["data"]
53 for (int i = 0;i < app2.eventList.size();i++) {
54 if (app2.eventList[i] == name) {
55 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
57 app2.functionList[i](event)
61 for (int i = 0;i < app1.eventList.size();i++) {
62 if (app1.eventList[i] == name) {
63 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
65 app1.functionList[i](event)
70 //GlobalVariables for both Apps
71 //Create a global variable for send event
72 @Field def sendEvent = {eventDataMap ->
73 eventHandler(eventDataMap)
76 @Field def locationObject = new LocationVar(sendEvent)
77 //Object for touch to call function
78 @Field def appObject = new Touched(sendEvent, 0)
79 //Create a global list for events
81 //Global Object for class Touch Sensor!
82 @Field def touchSensorObject = new NfcTouch(sendEvent, 1)
83 //Global Object for class switch!
84 @Field def switchObject = new Switches(sendEvent, 1)
85 //Global Object for class lock!
86 @Field def lockObject = new Locks(sendEvent, 1)
87 //Global Object for class door control!
88 @Field def doorControlObject = new DoorControls(sendEvent, 1)
89 //Global Object for class contact sensor!
90 @Field def contactObject = new ContactSensors(sendEvent, 1)
91 //Global Object for class presence sensor!
92 @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1)
93 //Global Object for class thermostat!
94 @Field def thermostatObject = new Thermostats(sendEvent, 1)
95 //Global Object for class aeon key fob!
96 @Field def aeonKeyFobObject = new AeonKeyFobs(sendEvent, 1)
97 //Global Object for class music player!
98 @Field def musicPlayerObject = new MusicPlayers(sendEvent, 1)
99 //Global Object for class motion sensor!
100 @Field def motionSensorObject = new MotionSensors(sendEvent, 1)
101 //Global Object for class image capture!
102 @Field def imageCaptureObject = new ImageCaptures(sendEvent, 1)
103 //Global Object for class smoke detector!
104 @Field def smokeDetectorObject = new SmokeDetectors(sendEvent, 1)
105 //Global Object for class alarm!
106 @Field def alarmObject = new Alarms(sendEvent, 1)
107 //Global Object for class speech synthesis!
108 @Field def speechSynthesisObject = new SpeechSynthesises(sendEvent, 1)
116 //Extracted objects for App1
117 //Global variable for time!
119 //Object for class lock!
121 //Object for class contactSensor!
123 //Global variable for enum!
124 def sendPushMessage = "Yes"
125 //Global variable for phone!
126 def phone = 9495379373
128 //Extracted objects for functions for App1
129 //Global Object for functions in subscribe method!
130 def installed = this.&installed
131 //Global Object for functions in subscribe method!
132 def updated = this.&updated
133 //Global Object for functions in subscribe method!
134 def setTimeCallback = this.&setTimeCallback
135 //Global Object for functions in subscribe method!
136 def doorOpenCheck = this.&doorOpenCheck
137 //Global Object for functions in subscribe method!
138 def lockMessage = this.&lockMessage
142 location = obj.locationObject
144 lock = obj.lockObject
145 contact = obj.contactObject
146 //Global variable for settings!
147 settings = [app:app, time:time, lock:lock, contact:contact, sendPushMessage:sendPushMessage, phone:phone]
149 //Global variables for each app
150 //Global variable for state[mode]
151 def state = [home:[],away:[],night:[]]
152 //Create a global logger object for methods
153 def log = new Logger()
154 //Create a global variable for Functions in Subscribe method
155 def functionList = []
156 //Create a global variable for Objects in Subscribe method
158 //Create a global variable for Events in Subscribe method
160 //Create a global list for function schedulers
161 def timersFuncList = []
162 //Create a global list for timer schedulers
164 //Create a global variable for settings
170 /////////////////////////////////////////////////////////////////////
171 def setLocationMode(String mode) {
175 /////////////////////////////////////////////////////////////////////
176 ////subscribe(obj, func)
177 def subscribe(Object obj, Closure FunctionToCall) {
180 eventList.add("Touched")
181 functionList.add(FunctionToCall)
182 } else if (obj == location) {
184 eventList.add("Location")
185 functionList.add(FunctionToCall)
188 ////subscribe(obj, event, func)
189 def subscribe(Object obj, String event, Closure FunctionToCall) {
192 functionList.add(FunctionToCall)
194 ////subscribe(obj, event, func, data)
195 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
198 functionList.add(FunctionToCall)
200 /////////////////////////////////////////////////////////////////////
201 ////runIn(time, func)
202 def runIn(int seconds, Closure functionToCall) {
203 if (timersFuncList.contains(functionToCall)) {
204 timersList[timersFuncList.indexOf(functionToCall)].cancel()
205 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
207 timersFuncList.add(functionToCall)
208 timersList.add(new SimulatedTimer())
209 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
213 def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) {
214 runIn(seconds, functionToCall)
217 def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) {
218 runIn(seconds, nameOfFunction)
221 def runIn(int seconds, String nameOfFunction) {
222 timersFuncList.add(nameOfFunction)
223 timersList.add(new SimulatedTimer())
224 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) {
228 /////////////////////////////////////////////////////////////////////
230 def unschedule(Closure functionToUnschedule) {
231 for (int i = 0;i < timersFuncList.size();i++) {
232 if (timersFuncList[i] == functionToUnschedule) {
233 if (timersList != null)
234 timersList[i].cancel()
241 for (int i = 0;i < timersFuncList.size();i++) {
242 if (timersList != null)
243 timersList[i].cancel()
246 /////////////////////////////////////////////////////////////////////
247 ////sendNotificationToContacts(text, recipients)
248 def sendNotificationToContacts(String text, String recipients) {
249 for (int i = 0;i < recipients.size();i++) {
250 for (int j = 0;j < location.contacts.size();j++) {
251 if (recipients[i] == location.contacts[j]) {
252 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
257 /////////////////////////////////////////////////////////////////////
258 ////sendSms(phone, text)
259 def sendSms(long phoneNumber, String text) {
260 println("Sending \""+text+"\" to "+phoneNumber.toString())
263 def sendSMS(long phoneNumber, String text) {
264 println("Sending \""+text+"\" to "+phoneNumber.toString())
266 /////////////////////////////////////////////////////////////////////
268 def sendPush(String text) {
271 /////////////////////////////////////////////////////////////////////
272 ////schedule(time, nameOfFunction as String)
273 def schedule(String time, String nameOfFunction) {
274 def _inputTime = time.split(':')
275 Date date = new Date()
276 def _currentTime = date.format("HH:mm:ss").split(':')
278 //Convert input time and current time to minutes
279 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
280 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
283 if (inputTime < currentTime) {
284 delay = 24*60*60-inputTime+currentTime
286 delay = inputTime-currentTime
289 timersFuncList.add(nameOfFunction)
290 timersList.add(new SimulatedTimer())
291 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) {
295 ////schedule(time, nameOfFunction as Closure)
296 def schedule(String time, Closure nameOfFunction) {
297 def _inputTime = time.split(':')
298 Date date = new Date()
299 def _currentTime = date.format("HH:mm:ss").split(':')
301 //Convert input time and current time to minutes
302 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
303 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
306 if (inputTime < currentTime) {
307 delay = 24*60*60-inputTime+currentTime
309 delay = inputTime-currentTime
312 if (timersFuncList.contains(nameOfFunction)) {
313 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
314 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
316 timersFuncList.add(nameOfFunction)
317 timersList.add(new SimulatedTimer())
318 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
321 /////////////////////////////////////////////////////////////////////
323 return System.currentTimeMillis()
325 /////////////////////////////////////////////////////////////////////
326 def getTemperatureScale() {
327 return 'C' //Celsius for now
330 /////////////////////////////////////////////////////////////////////
331 def getSunriseAndSunset(LinkedHashMap metaData) {
332 def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]]
333 return sunRiseSetInfo
337 schedule(time, "setTimeCallback")
341 def updated(settings) {
343 schedule(time, "setTimeCallback")
346 def setTimeCallback() {
354 def doorOpenCheck() {
355 def currentState = contact.contactState
356 if (currentState?.value == "open") {
357 def msg = "${contact.displayName} is open. Scheduled lock failed."
359 if (sendPushMessage) {
372 def msg = "Locking ${lock.displayName} due to scheduled lock."
374 if (sendPushMessage) {
390 //Extracted objects for App2
391 //Object for class Touch Sensor!
393 //Object for class switch!
395 //Object for class lock!
397 //Object for class door control!
399 //Global variable for enum!
400 def masterSwitch = "Yes"
401 //Global variable for enum!
402 def masterLock = "Yes"
403 //Global variable for enum!
404 def masterDoor = "Yes"
406 //Extracted objects for functions for App2
407 //Global Object for functions in subscribe method!
408 def pageTwo = this.&pageTwo
409 //Global Object for functions in subscribe method!
410 def installed = this.&installed
411 //Global Object for functions in subscribe method!
412 def updated = this.&updated
413 //Global Object for functions in subscribe method!
414 def initialize = this.&initialize
415 //Global Object for functions in subscribe method!
416 def touchHandler = this.&touchHandler
420 location = obj.locationObject
422 tag = obj.touchSensorObject
423 switch1 = obj.switchObject
424 lock = obj.lockObject
425 garageDoor = obj.doorControlObject
426 //Global variable for settings!
427 settings = [app:app, tag:tag, switch1:switch1, lock:lock, garageDoor:garageDoor, masterSwitch:masterSwitch, masterLock:masterLock, masterDoor:masterDoor]
429 //Global variables for each app
430 //Global variable for state[mode]
431 def state = [home:[],away:[],night:[]]
432 //Create a global logger object for methods
433 def log = new Logger()
434 //Create a global variable for Functions in Subscribe method
435 def functionList = []
436 //Create a global variable for Objects in Subscribe method
438 //Create a global variable for Events in Subscribe method
440 //Create a global list for function schedulers
441 def timersFuncList = []
442 //Create a global list for timer schedulers
444 //Create a global variable for settings
450 /////////////////////////////////////////////////////////////////////
451 def setLocationMode(String mode) {
455 /////////////////////////////////////////////////////////////////////
456 ////subscribe(obj, func)
457 def subscribe(Object obj, Closure FunctionToCall) {
460 eventList.add("Touched")
461 functionList.add(FunctionToCall)
462 } else if (obj == location) {
464 eventList.add("Location")
465 functionList.add(FunctionToCall)
468 ////subscribe(obj, event, func)
469 def subscribe(Object obj, String event, Closure FunctionToCall) {
472 functionList.add(FunctionToCall)
474 ////subscribe(obj, event, func, data)
475 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
478 functionList.add(FunctionToCall)
480 /////////////////////////////////////////////////////////////////////
481 ////runIn(time, func)
482 def runIn(int seconds, Closure functionToCall) {
483 if (timersFuncList.contains(functionToCall)) {
484 timersList[timersFuncList.indexOf(functionToCall)].cancel()
485 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
487 timersFuncList.add(functionToCall)
488 timersList.add(new SimulatedTimer())
489 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
493 def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) {
494 runIn(seconds, functionToCall)
497 def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) {
498 runIn(seconds, nameOfFunction)
501 def runIn(int seconds, String nameOfFunction) {
502 timersFuncList.add(nameOfFunction)
503 timersList.add(new SimulatedTimer())
504 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) {
508 /////////////////////////////////////////////////////////////////////
510 def unschedule(Closure functionToUnschedule) {
511 for (int i = 0;i < timersFuncList.size();i++) {
512 if (timersFuncList[i] == functionToUnschedule) {
513 if (timersList != null)
514 timersList[i].cancel()
521 for (int i = 0;i < timersFuncList.size();i++) {
522 if (timersList != null)
523 timersList[i].cancel()
526 /////////////////////////////////////////////////////////////////////
527 ////sendNotificationToContacts(text, recipients)
528 def sendNotificationToContacts(String text, String recipients) {
529 for (int i = 0;i < recipients.size();i++) {
530 for (int j = 0;j < location.contacts.size();j++) {
531 if (recipients[i] == location.contacts[j]) {
532 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
537 /////////////////////////////////////////////////////////////////////
538 ////sendSms(phone, text)
539 def sendSms(long phoneNumber, String text) {
540 println("Sending \""+text+"\" to "+phoneNumber.toString())
543 def sendSMS(long phoneNumber, String text) {
544 println("Sending \""+text+"\" to "+phoneNumber.toString())
546 /////////////////////////////////////////////////////////////////////
547 ////schedule(time, nameOfFunction as String)
548 def schedule(String time, String nameOfFunction) {
549 def _inputTime = time.split(':')
550 Date date = new Date()
551 def _currentTime = date.format("HH:mm:ss").split(':')
553 //Convert input time and current time to minutes
554 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
555 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
558 if (inputTime < currentTime) {
559 delay = 24*60*60-inputTime+currentTime
561 delay = inputTime-currentTime
564 timersFuncList.add(nameOfFunction)
565 timersList.add(new SimulatedTimer())
566 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) {
570 ////schedule(time, nameOfFunction as Closure)
571 def schedule(String time, Closure nameOfFunction) {
572 def _inputTime = time.split(':')
573 Date date = new Date()
574 def _currentTime = date.format("HH:mm:ss").split(':')
576 //Convert input time and current time to minutes
577 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
578 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
581 if (inputTime < currentTime) {
582 delay = 24*60*60-inputTime+currentTime
584 delay = inputTime-currentTime
587 if (timersFuncList.contains(nameOfFunction)) {
588 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
589 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
591 timersFuncList.add(nameOfFunction)
592 timersList.add(new SimulatedTimer())
593 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
596 /////////////////////////////////////////////////////////////////////
598 return System.currentTimeMillis()
600 /////////////////////////////////////////////////////////////////////
601 def getTemperatureScale() {
602 return 'C' //Celsius for now
605 /////////////////////////////////////////////////////////////////////
606 def getSunriseAndSunset(LinkedHashMap metaData) {
607 def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]]
608 return sunRiseSetInfo
612 dynamicPage(name: "pageTwo") {
613 section("If set, the state of these devices will be toggled each time the tag is touched, " +
614 "e.g. a light that's on will be turned off and one that's off will be turned on, " +
615 "other devices of the same type will be set to the same state as their master device. " +
616 "If no master is designated then the majority of devices of the same type will be used " +
617 "to determine whether to turn on or off the devices.") {
619 if (switch1 || masterSwitch) {
620 input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
622 if (lock || masterLock) {
623 input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
625 if (garageDoor || masterDoor) {
626 input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
629 section([mobileOnly:true]) {
630 label title: "Assign a name", required: false
631 mode title: "Set for specific mode(s)", required: false
637 log.debug "Installed with settings: ${settings}"
643 log.debug "Updated with settings: ${settings}"
650 subscribe tag, "nfcTouch", touchHandler
651 subscribe app, touchHandler
654 private currentStatus(devices, master, attribute) {
655 log.trace "currentStatus($devices, $master, $attribute)"
658 result = devices.find{it.id == master}?.currentValue(attribute)
663 def value = it.currentValue(attribute)
664 map[value] = (map[value] ?: 0) + 1
665 log.trace "$it.displayName: $value"
668 result = map.collect{it}.sort{it.value}[-1].key
670 log.debug "$attribute = $result"
674 def touchHandler(evt) {
675 log.trace "touchHandler($evt.descriptionText)"
677 def status = currentStatus(switch1, masterSwitch, "switch")
679 if (status == "on") {
689 def status = currentStatus(lock, masterLock, "lock")
691 if (status == "locked") {
701 def status = currentStatus(garageDoor, masterDoor, "status")
703 if (status == "open") {
714 @Field def app1 = new App1(this)
715 @Field def app2 = new App2(this)