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
26 import gov.nasa.jpf.vm.Verify
29 /////////////////////////////////////////////////////////////////////
30 def eventHandler(LinkedHashMap eventDataMap) {
31 def value = eventDataMap["value"]
32 def name = eventDataMap["name"]
33 def deviceId = eventDataMap["deviceId"]
34 def descriptionText = eventDataMap["descriptionText"]
35 def displayed = eventDataMap["displayed"]
36 def linkText = eventDataMap["linkText"]
37 def isStateChange = eventDataMap["isStateChange"]
38 def unit = eventDataMap["unit"]
39 def data = eventDataMap["data"]
41 for (int i = 0;i < app2.eventList.size();i++) {
42 if (app2.eventList[i] == name) {
43 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
45 app2.functionList[i](event)
49 for (int i = 0;i < app1.eventList.size();i++) {
50 if (app1.eventList[i] == name) {
51 def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
53 app1.functionList[i](event)
58 //GlobalVariables for both Apps
59 //Create a global variable for send event
60 @Field def sendEvent = {eventDataMap ->
61 eventHandler(eventDataMap)
64 @Field def locationObject = new LocationVar()
65 //Object for touch to call function
66 @Field def appObject = new Touched(sendEvent, 0)
67 //Create a global list for events
69 //Global Object for class Touch Sensor!
70 @Field def touchSensorObject = new NfcTouch(sendEvent, 1)
71 //Global Object for class switch!
72 @Field def switchObject = new Switches(sendEvent, 1)
73 //Global Object for class lock!
74 @Field def lockObject = new Locks(sendEvent, 1)
75 //Global Object for class door control!
76 @Field def doorControlObject = new DoorControls(sendEvent, 1)
77 //Global Object for class contact sensor!
78 @Field def contactObject = new ContactSensors(sendEvent, 1)
79 //Global Object for class presence sensor!
80 @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1)
81 //Global Object for class thermostat!
82 @Field def thermostatObject = new Thermostats(sendEvent, 1)
90 //Extracted objects for App1
91 //Object for class Touch Sensor!
93 //Object for class switch!
95 //Object for class lock!
97 //Object for class door control!
99 //Global variable for enum!
100 def masterSwitch = "40"
101 //Global variable for enum!
102 def masterLock = "20"
103 //Global variable for enum!
104 def masterDoor = "40"
106 //Extracted objects for functions for App1
107 //Global Object for functions in subscribe method!
108 def pageTwo = this.&pageTwo
109 //Global Object for functions in subscribe method!
110 def installed = this.&installed
111 //Global Object for functions in subscribe method!
112 def updated = this.&updated
113 //Global Object for functions in subscribe method!
114 def initialize = this.&initialize
115 //Global Object for functions in subscribe method!
116 def currentStatus = this.¤tStatus
117 //Global Object for functions in subscribe method!
118 def touchHandler = this.&touchHandler
122 location = obj.locationObject
124 tag = obj.touchSensorObject
125 switch1 = obj.switchObject
126 lock = obj.lockObject
127 garageDoor = obj.doorControlObject
129 //Global variables for each app
130 //Settings variable defined to settings on purpose
131 def settings = "Settings"
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
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)
281 dynamicPage(name: "pageTwo") {
282 section("If set, the state of these devices will be toggled each time the tag is touched, " +
283 "e.g. a light that's on will be turned off and one that's off will be turned on, " +
284 "other devices of the same type will be set to the same state as their master device. " +
285 "If no master is designated then the majority of devices of the same type will be used " +
286 "to determine whether to turn on or off the devices.") {
288 if (switch1 || masterSwitch) {
289 input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
291 if (lock || masterLock) {
292 input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
294 if (garageDoor || masterDoor) {
295 input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
298 section([mobileOnly:true]) {
299 label title: "Assign a name", required: false
300 mode title: "Set for specific mode(s)", required: false
306 log.debug "Installed with settings: ${settings}"
312 log.debug "Updated with settings: ${settings}"
319 subscribe tag, "nfcTouch", touchHandler
320 subscribe app, touchHandler
323 private currentStatus(devices, master, attribute) {
324 log.trace "currentStatus($devices, $master, $attribute)"
327 result = devices.find{it.id == master}?.currentValue(attribute)
332 def value = it.currentValue(attribute)
333 map[value] = (map[value] ?: 0) + 1
334 log.trace "$it.displayName: $value"
337 result = map.collect{it}.sort{it.value}[-1].key
339 log.debug "$attribute = $result"
343 def touchHandler(evt) {
344 log.trace "touchHandler($evt.descriptionText)"
346 def status = currentStatus(switch1, masterSwitch, "switch")
348 if (status == "on") {
358 def status = currentStatus(lock, masterLock, "lock")
360 if (status == "locked") {
370 def status = currentStatus(garageDoor, masterDoor, "status")
372 if (status == "open") {
390 //Extracted objects for App2
391 //Object for class switch!
393 //Object for class switch!
395 //Object for class lock!
397 //Global variable for mode!
399 //Global variable for number!
402 //Extracted objects for functions for App2
403 //Global Object for functions in subscribe method!
404 def installed = this.&installed
405 //Global Object for functions in subscribe method!
406 def updated = this.&updated
407 //Global Object for functions in subscribe method!
408 def appTouch = this.&appTouch
412 location = obj.locationObject
414 switchesoff = obj.switchObject
415 switcheson = obj.switchObject
416 lock1 = obj.lockObject
418 //Global variables for each app
419 //Settings variable defined to settings on purpose
420 def settings = "Settings"
421 //Global variable for state[mode]
422 def state = [home:[],away:[],night:[]]
423 //Create a global logger object for methods
424 def log = new Logger()
425 //Create a global variable for Functions in Subscribe method
426 def functionList = []
427 //Create a global variable for Objects in Subscribe method
429 //Create a global variable for Events in Subscribe method
431 //Create a global list for function schedulers
432 def timersFuncList = []
433 //Create a global list for timer schedulers
437 /////////////////////////////////////////////////////////////////////
438 def setLocationMode(String mode) {
442 /////////////////////////////////////////////////////////////////////
443 ////subscribe(obj, func)
444 def subscribe(Object obj, Closure FunctionToCall) {
447 eventList.add("Touched")
448 functionList.add(FunctionToCall)
449 } else if (obj == location) {
451 eventList.add("Location")
452 functionList.add(FunctionToCall)
455 ////subscribe(obj, event, func)
456 def subscribe(Object obj, String event, Closure FunctionToCall) {
459 functionList.add(FunctionToCall)
461 ////subscribe(obj, event, func, data)
462 def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
465 functionList.add(FunctionToCall)
467 /////////////////////////////////////////////////////////////////////
468 ////runIn(time, func)
469 def runIn(int seconds, Closure functionToCall) {
470 if (timersFuncList.contains(functionToCall)) {
471 timersList[timersFuncList.indexOf(functionToCall)].cancel()
472 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
474 timersFuncList.add(functionToCall)
475 timersList.add(new SimulatedTimer())
476 def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds, functionToCall)
479 /////////////////////////////////////////////////////////////////////
481 def unschedule(Closure functionToUnschedule) {
482 for (int i = 0;i < timersFuncList.size();i++) {
483 if (timersFuncList[i] == functionToUnschedule) {
484 if (timersList != null)
485 timersList[i].cancel()
492 for (int i = 0;i < timersFuncList.size();i++) {
493 if (timersList != null)
494 timersList[i].cancel()
497 /////////////////////////////////////////////////////////////////////
498 ////sendNotificationToContacts(text, recipients)
499 def sendNotificationToContacts(String text, String recipients) {
500 for (int i = 0;i < recipients.size();i++) {
501 for (int j = 0;j < location.contacts.size();j++) {
502 if (recipients[i] == location.contacts[j]) {
503 println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
508 /////////////////////////////////////////////////////////////////////
509 ////sendSms(phone, text)
510 def sendSms(long phoneNumber, String text) {
511 println("Sending \""+text+"\" to "+phoneNumber.toString())
513 /////////////////////////////////////////////////////////////////////
514 ////schedule(time, nameOfFunction as String)
515 def schedule(String time, String nameOfFunction) {
516 def _inputTime = time.split(':')
517 Date date = new Date()
518 def _currentTime = date.format("HH:mm:ss").split(':')
520 //Convert input time and current time to minutes
521 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
522 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
525 if (inputTime < currentTime) {
526 delay = 24*60*60-inputTime+currentTime
528 delay = inputTime-currentTime
531 timersFuncList.add(nameOfFunction)
532 timersList.add(new SimulatedTimer())
533 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000) {
537 ////schedule(time, nameOfFunction as Closure)
538 def schedule(String time, Closure nameOfFunction) {
539 def _inputTime = time.split(':')
540 Date date = new Date()
541 def _currentTime = date.format("HH:mm:ss").split(':')
543 //Convert input time and current time to minutes
544 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
545 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
548 if (inputTime < currentTime) {
549 delay = 24*60*60-inputTime+currentTime
551 delay = inputTime-currentTime
554 if (timersFuncList.contains(nameOfFunction)) {
555 timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
556 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
558 timersFuncList.add(nameOfFunction)
559 timersList.add(new SimulatedTimer())
560 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds, nameOfFunction)
566 log.debug "Installed with settings: ${settings}"
567 log.debug "Current mode = ${location.mode}"
568 subscribe(app, appTouch)
574 log.debug "Updated with settings: ${settings}"
575 log.debug "Current mode = ${location.mode}"
577 subscribe(app, appTouch)
581 log.debug "changeMode, location.mode = $location.mode, newMode = $newMode, location.modes = $location.modes"
582 if (location.mode != newMode) {
583 setLocationMode(newMode)
584 log.debug "Changed the mode to '${newMode}'"
586 log.debug "New mode is the same as the old mode, leaving it be"
588 log.debug "appTouch: $evt"
591 def delay = (waitfor != null && waitfor != "") ? waitfor * 1000 : 120000
592 switchesoff.off(delay: delay)
596 @Field def app1 = new App1(this)
597 @Field def app2 = new App2(this)
601 def events = [1,2,3,4,5,6,7]
602 def list = events.permutations()
603 int count = Verify.getInt(0,list.size()-1)
604 println "COUNT: " + count
609 appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "",
610 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
614 lockObject.setValue([name: "lock0", value: "locked", deviceId: 0, descriptionText: "",
615 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
619 lockObject.setValue([name: "lock0", value: "unlocked", deviceId: 0, descriptionText: "",
620 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
624 contactObject.setValue([name: "contact0", value: "open", deviceId: 0, descriptionText: "",
625 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
629 contactObject.setValue([name: "contact0", value: "closed", deviceId: 0, descriptionText: "",
630 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
634 switchObject.setValue([name: "switch0", value: "on", deviceId: 0, descriptionText: "",
635 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
639 switchObject.setValue([name: "switch0", value: "off", deviceId: 0, descriptionText: "",
640 displayed: true, linkText: "", isStateChange: false, unit: "", data: []])