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
24 import Timer.SimulatedTimer
27 /////////////////////////////////////////////////////////////////////
28 def eventHandler(LinkedHashMap eventDataMap) {
29 def value = eventDataMap["value"]
30 def name = eventDataMap["name"]
31 def deviceId = eventDataMap["deviceId"]
32 def descriptionText = eventDataMap["descriptionText"]
33 def displayed = eventDataMap["displayed"]
34 def linkText = eventDataMap["linkText"]
35 def isStateChange = eventDataMap["isStateChange"]
36 def unit = eventDataMap["unit"]
37 def data = eventDataMap["data"]
39 for (int i = 0;i < app2.eventList.size();i++) {
40 if (app2.eventList[i] == name) {
41 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
43 app2.functionList[i](event)
47 for (int i = 0;i < app1.eventList.size();i++) {
48 if (app1.eventList[i] == name) {
49 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
51 app1.functionList[i](event)
56 //GlobalVariables for both Apps
57 //Create a global variable for send event
58 @Field def sendEvent = {eventDataMap ->
59 eventHandler(eventDataMap)
62 @Field def locationObject = new LocationVar()
63 //Object for touch to call function
64 @Field def appObject = new Touched(sendEvent, 0)
65 //Create a global list for events
67 //Global Object for class Touch Sensor!
68 @Field def touchSensorObject = new NfcTouch(sendEvent, 1)
69 //Global Object for class switch!
70 @Field def switchObject = new Switches(sendEvent, 1)
71 //Global Object for class lock!
72 @Field def lockObject = new Locks(sendEvent, 1)
73 //Global Object for class door control!
74 @Field def doorControlObject = new DoorControls(sendEvent, 1)
75 //Global Object for class contact sensor!
76 @Field def contactObject = new ContactSensors(sendEvent, 1)
77 //Global Object for class presence sensor!
78 @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1)
79 //Global Object for class thermostat!
80 @Field def thermostatObject = new Thermostats(sendEvent, 1)
88 //Extracted objects for App1
89 //Object for class Touch Sensor!
91 //Object for class switch!
93 //Object for class lock!
95 //Object for class door control!
97 //Global variable for enum!
98 def masterSwitch = "40"
99 //Global variable for enum!
100 def masterLock = "20"
101 //Global variable for enum!
102 def masterDoor = "40"
104 //Extracted objects for functions for App1
105 //Global Object for functions in subscribe method!
106 def pageTwo = this.&pageTwo
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 currentStatus = this.¤tStatus
115 //Global Object for functions in subscribe method!
116 def touchHandler = this.&touchHandler
120 location = obj.locationObject
122 tag = obj.touchSensorObject
123 switch1 = obj.switchObject
124 lock = obj.lockObject
125 garageDoor = obj.doorControlObject
127 //Global variables for each app
128 //Settings variable defined to settings on purpose
129 def settings = "Settings"
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
146 /////////////////////////////////////////////////////////////////////
147 def setLocationMode(String mode) {
151 /////////////////////////////////////////////////////////////////////
152 ////subscribe(obj, func)
153 def subscribe(Object obj, Closure FunctionToCall) {
156 eventList.add("Touched")
157 functionList.add(FunctionToCall)
158 } else if (obj == location) {
160 eventList.add("Location")
161 functionList.add(FunctionToCall)
164 ////subscribe(obj, event, func)
165 def subscribe(Object obj, String event, Closure FunctionToCall) {
168 functionList.add(FunctionToCall)
170 ////subscribe(obj, event, func, data)
171 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
174 functionList.add(FunctionToCall)
176 /////////////////////////////////////////////////////////////////////
177 ////runIn(time, func)
178 def runIn(int seconds, Closure functionToCall) {
179 if (timersFuncList.contains(functionToCall)) {
180 timersList[timersFuncList.indexOf(functionToCall)].cancel()
181 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
183 timersFuncList.add(functionToCall)
184 timersList.add(new SimulatedTimer())
185 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
188 /////////////////////////////////////////////////////////////////////
190 def unschedule(Closure functionToUnschedule) {
191 for (int i = 0;i < timersFuncList.size();i++) {
192 if (timersFuncList[i] == functionToUnschedule) {
193 if (timersList != null)
194 timersList[i].cancel()
201 for (int i = 0;i < timersFuncList.size();i++) {
202 if (timersList != null)
203 timersList[i].cancel()
206 /////////////////////////////////////////////////////////////////////
207 ////sendNotificationToContacts(text, recipients)
208 def sendNotificationToContacts(String text, String recipients) {
209 for (int i = 0;i < recipients.size();i++) {
210 for (int j = 0;j < location.contacts.size();j++) {
211 if (recipients[i] == location.contacts[j]) {
212 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
217 /////////////////////////////////////////////////////////////////////
218 ////sendSms(phone, text)
219 def sendSms(long phoneNumber, String text) {
220 println("Sending \""+text+"\" to "+phoneNumber.toString())
222 /////////////////////////////////////////////////////////////////////
224 def sendPush(String text) {
227 /////////////////////////////////////////////////////////////////////
228 ////schedule(time, nameOfFunction as String)
229 def schedule(String time, String nameOfFunction) {
230 def _inputTime = time.split(':')
231 Date date = new Date()
232 def _currentTime = date.format("HH:mm:ss").split(':')
234 //Convert input time and current time to minutes
235 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
236 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
239 if (inputTime < currentTime) {
240 delay = 24*60*60-inputTime+currentTime
242 delay = inputTime-currentTime
245 timersFuncList.add(nameOfFunction)
246 timersList.add(new SimulatedTimer())
247 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
251 ////schedule(time, nameOfFunction as Closure)
252 def schedule(String time, Closure nameOfFunction) {
253 def _inputTime = time.split(':')
254 Date date = new Date()
255 def _currentTime = date.format("HH:mm:ss").split(':')
257 //Convert input time and current time to minutes
258 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
259 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
262 if (inputTime < currentTime) {
263 delay = 24*60*60-inputTime+currentTime
265 delay = inputTime-currentTime
268 if (timersFuncList.contains(nameOfFunction)) {
269 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
270 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
272 timersFuncList.add(nameOfFunction)
273 timersList.add(new SimulatedTimer())
274 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
279 dynamicPage(name: "pageTwo") {
280 section("If set, the state of these devices will be toggled each time the tag is touched, " +
281 "e.g. a light that's on will be turned off and one that's off will be turned on, " +
282 "other devices of the same type will be set to the same state as their master device. " +
283 "If no master is designated then the majority of devices of the same type will be used " +
284 "to determine whether to turn on or off the devices.") {
286 if (switch1 || masterSwitch) {
287 input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
289 if (lock || masterLock) {
290 input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
292 if (garageDoor || masterDoor) {
293 input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
296 section([mobileOnly:true]) {
297 label title: "Assign a name", required: false
298 mode title: "Set for specific mode(s)", required: false
304 log.debug "Installed with settings: ${settings}"
310 log.debug "Updated with settings: ${settings}"
317 subscribe tag, "nfcTouch", touchHandler
318 subscribe app, touchHandler
321 private currentStatus(devices, master, attribute) {
322 log.trace "currentStatus($devices, $master, $attribute)"
325 result = devices.find{it.id == master}?.currentValue(attribute)
330 def value = it.currentValue(attribute)
331 map[value] = (map[value] ?: 0) + 1
332 log.trace "$it.displayName: $value"
335 result = map.collect{it}.sort{it.value}[-1].key
337 log.debug "$attribute = $result"
341 def touchHandler(evt) {
342 log.trace "touchHandler($evt.descriptionText)"
344 def status = currentStatus(switch1, masterSwitch, "switch")
346 if (status == "on") {
356 def status = currentStatus(lock, masterLock, "lock")
358 if (status == "locked") {
368 def status = currentStatus(garageDoor, masterDoor, "status")
370 if (status == "open") {
388 //Extracted objects for App2
389 //Object for class switch!
391 //Object for class switch!
393 //Object for class lock!
395 //Global variable for mode!
397 //Global variable for number!
400 //Extracted objects for functions for App2
401 //Global Object for functions in subscribe method!
402 def installed = this.&installed
403 //Global Object for functions in subscribe method!
404 def updated = this.&updated
405 //Global Object for functions in subscribe method!
406 def appTouch = this.&appTouch
410 location = obj.locationObject
412 switchesoff = obj.switchObject
413 switcheson = obj.switchObject
414 lock1 = obj.lockObject
416 //Global variables for each app
417 //Settings variable defined to settings on purpose
418 def settings = "Settings"
419 //Global variable for state[mode]
420 def state = [home:[],away:[],night:[]]
421 //Create a global logger object for methods
422 def log = new Logger()
423 //Create a global variable for Functions in Subscribe method
424 def functionList = []
425 //Create a global variable for Objects in Subscribe method
427 //Create a global variable for Events in Subscribe method
429 //Create a global list for function schedulers
430 def timersFuncList = []
431 //Create a global list for timer schedulers
435 /////////////////////////////////////////////////////////////////////
436 def setLocationMode(String mode) {
440 /////////////////////////////////////////////////////////////////////
441 ////subscribe(obj, func)
442 def subscribe(Object obj, Closure FunctionToCall) {
445 eventList.add("Touched")
446 functionList.add(FunctionToCall)
447 } else if (obj == location) {
449 eventList.add("Location")
450 functionList.add(FunctionToCall)
453 ////subscribe(obj, event, func)
454 def subscribe(Object obj, String event, Closure FunctionToCall) {
457 functionList.add(FunctionToCall)
459 ////subscribe(obj, event, func, data)
460 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
463 functionList.add(FunctionToCall)
465 /////////////////////////////////////////////////////////////////////
466 ////runIn(time, func)
467 def runIn(int seconds, Closure functionToCall) {
468 if (timersFuncList.contains(functionToCall)) {
469 timersList[timersFuncList.indexOf(functionToCall)].cancel()
470 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
472 timersFuncList.add(functionToCall)
473 timersList.add(new SimulatedTimer())
474 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
477 /////////////////////////////////////////////////////////////////////
479 def unschedule(Closure functionToUnschedule) {
480 for (int i = 0;i < timersFuncList.size();i++) {
481 if (timersFuncList[i] == functionToUnschedule) {
482 if (timersList != null)
483 timersList[i].cancel()
490 for (int i = 0;i < timersFuncList.size();i++) {
491 if (timersList != null)
492 timersList[i].cancel()
495 /////////////////////////////////////////////////////////////////////
496 ////sendNotificationToContacts(text, recipients)
497 def sendNotificationToContacts(String text, String recipients) {
498 for (int i = 0;i < recipients.size();i++) {
499 for (int j = 0;j < location.contacts.size();j++) {
500 if (recipients[i] == location.contacts[j]) {
501 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
506 /////////////////////////////////////////////////////////////////////
507 ////sendSms(phone, text)
508 def sendSms(long phoneNumber, String text) {
509 println("Sending \""+text+"\" to "+phoneNumber.toString())
511 /////////////////////////////////////////////////////////////////////
512 ////schedule(time, nameOfFunction as String)
513 def schedule(String time, String nameOfFunction) {
514 def _inputTime = time.split(':')
515 Date date = new Date()
516 def _currentTime = date.format("HH:mm:ss").split(':')
518 //Convert input time and current time to minutes
519 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
520 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
523 if (inputTime < currentTime) {
524 delay = 24*60*60-inputTime+currentTime
526 delay = inputTime-currentTime
529 timersFuncList.add(nameOfFunction)
530 timersList.add(new SimulatedTimer())
531 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
535 ////schedule(time, nameOfFunction as Closure)
536 def schedule(String time, Closure nameOfFunction) {
537 def _inputTime = time.split(':')
538 Date date = new Date()
539 def _currentTime = date.format("HH:mm:ss").split(':')
541 //Convert input time and current time to minutes
542 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
543 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
546 if (inputTime < currentTime) {
547 delay = 24*60*60-inputTime+currentTime
549 delay = inputTime-currentTime
552 if (timersFuncList.contains(nameOfFunction)) {
553 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
554 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
556 timersFuncList.add(nameOfFunction)
557 timersList.add(new SimulatedTimer())
558 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
564 log.debug "Installed with settings: ${settings}"
565 log.debug "Current mode = ${location.mode}"
566 subscribe(app, appTouch)
572 log.debug "Updated with settings: ${settings}"
573 log.debug "Current mode = ${location.mode}"
575 subscribe(app, appTouch)
579 log.debug "changeMode, location.mode = $location.mode, newMode = $newMode, location.modes = $location.modes"
580 if (location.mode != newMode) {
581 setLocationMode(newMode)
582 log.debug "Changed the mode to '${newMode}'"
584 log.debug "New mode is the same as the old mode, leaving it be"
586 log.debug "appTouch: $evt"
589 def delay = (waitfor != null && waitfor != "") ? waitfor * 1000 : 120000
590 switchesoff.off(delay: delay)
594 @Field def app1 = new App1(this)
595 @Field def app2 = new App2(this)
599 def events = [1,2,3,4,5,6,7]
600 def list = events.permutations()
601 int count = Verify.getInt(0,list.size()-1)
602 println "COUNT: " + count
607 appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "",
608 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
612 lockObject.setValue([name: "lock0", value: "locked", deviceId: 0, descriptionText: "",
613 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
617 lockObject.setValue([name: "lock0", value: "unlocked", deviceId: 0, descriptionText: "",
618 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
622 contactObject.setValue([name: "contact0", value: "open", deviceId: 0, descriptionText: "",
623 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
627 contactObject.setValue([name: "contact0", value: "closed", deviceId: 0, descriptionText: "",
628 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
632 switchObject.setValue([name: "switch0", value: "on", deviceId: 0, descriptionText: "",
633 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
637 switchObject.setValue([name: "switch0", value: "off", deviceId: 0, descriptionText: "",
638 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])