Commit #7: eventHandler and event queue are unique between two apps now. (Similar...
[smartthings-infrastructure.git] / main.groovy
1 //Infrastructure for SmartThings Application
2 //Importing Libraries
3 import groovy.transform.Field
4
5 //Importing Classes
6 import ContactSensor.Contacting
7 import ContactSensor.Contacts
8 import Lock.Locking
9 import Lock.Locks
10 import Switch.Switching
11 import Switch.Switches
12 import Logger.Logger
13 import Location.LocationVar
14 import Location.Phrase
15 import appTouch.Touched
16 import Event.Event
17
18 //Global eventHandler
19 /////////////////////////////////////////////////////////////////////
20 def eventHandler(LinkedHashMap eventDataMap) {
21         def value = eventDataMap["value"]
22         def name = eventDataMap["name"]
23         def deviceId = eventDataMap["deviceId"]
24         def descriptionText = eventDataMap["descriptionText"]
25         def displayed = eventDataMap["displayed"]
26         def linkText = eventDataMap["linkText"]
27         def isStateChange = eventDataMap["isStateChange"]
28         def unit = eventDataMap["unit"]
29         def data = eventDataMap["data"]
30         def minSize
31         def smallest
32
33         //make search efficient
34         if (app1.eventList.size() == app2.eventList.size()) {
35                 minSize = app1.eventList.size()
36                 smallest = "equal"
37         } else if (app1.eventList.size() < app2.eventList.size()) {
38                 minSize = app1.eventList.size()
39                 smallest = "app1"
40         } else {
41                 minSize = app2.eventList.size()
42                 smallest = "app2"
43         }
44
45         for (int i = 0;i < minSize;i++) {
46                 if (app1.eventList[i] == name) {
47                         evt.add(new Event())
48                         evt[-1].value = value
49                         evt[-1].name = name
50                         evt[-1].deviceId = deviceId
51                         evt[-1].descriptionText = descriptionText
52                         evt[-1].displayed = displayed
53                         evt[-1].linkText = linkText
54                         evt[-1].displayName = linkText
55                         evt[-1].isStateChange = isStateChange
56                         evt[-1].unit = unit
57                         evt[-1].data = data
58                         app1.functionList[i](evt[-1])
59                 }
60                 if (app2.eventList[i] == name) {
61                         evt.add(new Event())
62                         evt[-1].value = value
63                         evt[-1].name = name
64                         evt[-1].deviceId = deviceId
65                         evt[-1].descriptionText = descriptionText
66                         evt[-1].displayed = displayed
67                         evt[-1].linkText = linkText
68                         evt[-1].displayName = linkText
69                         evt[-1].isStateChange = isStateChange
70                         evt[-1].unit = unit
71                         evt[-1].data = data
72                         app2.functionList[i](evt[-1])
73                 }
74         }
75
76         if (smallest == "app1") {
77                 for (int i = minSize;i < app2.eventList.size();i++) {
78                         if (app2.eventList[i] == name) {
79                                 evt.add(new Event())
80                                 evt[-1].value = value
81                                 evt[-1].name = name
82                                 evt[-1].deviceId = deviceId
83                                 evt[-1].descriptionText = descriptionText
84                                 evt[-1].displayed = displayed
85                                 evt[-1].linkText = linkText
86                                 evt[-1].displayName = linkText
87                                 evt[-1].isStateChange = isStateChange
88                                 evt[-1].unit = unit
89                                 evt[-1].data = data
90                                 app2.functionList[i](evt[-1])
91                         }
92                 }
93         } else if (smallest == "app2") {
94                 for (int i = minSize;i < app1.eventList.size();i++) {
95                         if (app1.eventList[i] == name) {
96                                 evt.add(new Event())
97                                 evt[-1].value = value
98                                 evt[-1].name = name
99                                 evt[-1].deviceId = deviceId
100                                 evt[-1].descriptionText = descriptionText
101                                 evt[-1].displayed = displayed
102                                 evt[-1].linkText = linkText
103                                 evt[-1].displayName = linkText
104                                 evt[-1].isStateChange = isStateChange
105                                 evt[-1].unit = unit
106                                 evt[-1].data = data
107                                 app1.functionList[i](evt[-1])
108                         }
109                 }
110         }       
111 }
112
113 //GlobalVariables for both Apps
114 //Create a global variable for send event
115 @Field def sendEvent = {eventDataMap -> 
116                         eventHandler(eventDataMap)
117                         }
118 //Object for location
119 @Field def locationObject = new LocationVar()
120 //Object for touch
121 @Field def appObject = new Touched(sendEvent, 0)
122 //Create a global list for events
123 @Field def evt = []
124
125 //Extracted global objects for both Apps
126 //Global Object for class lock!
127 @Field def lockObject = new Locking(sendEvent, 1)
128 //Global Object for class contactSensor!
129 @Field def contactObject = new Contacting(sendEvent, 1)
130 //Global Object for class Switch!
131 @Field def switchObject = new Switching(sendEvent, 1)
132
133 //Application #1
134 class App1 {
135         def reference
136         def location
137         def app
138
139         //Extracted objects for App1
140         //Object for class lock!
141         def lock1
142         //Object for class contactSensor!
143         def contact
144         //Global variable for number!
145         def minutesLater = 1
146         //Global variable for number!
147         def secondsLater = 1
148         //Global variable for recipients!
149         def recipients = ['AJ']
150         //Global variable for phone number!
151         def phoneNumber = 9495379373
152         //Global Object for functions in subscribe method!
153         def installed = this.&installed
154         //Global Object for functions in subscribe method!
155         def updated = this.&updated
156         //Global Object for functions in subscribe method!
157         def initialize = this.&initialize
158         //Global Object for functions in subscribe method!
159         def lockDoor = this.&lockDoor
160         //Global Object for functions in subscribe method!
161         def unlockDoor = this.&unlockDoor
162         //Global Object for functions in subscribe method!
163         def doorHandler = this.&doorHandler
164
165         App1(Object obj) {
166                 reference = obj
167                 location = obj.locationObject
168                 app = obj.appObject
169                 lock1 = obj.lockObject
170                 contact = obj.contactObject
171         }
172         //Global variables for each app
173         //Settings variable defined to settings on purpose
174         def settings = "Settings"
175         //Global variable for state[mode]
176         def state = [home:[],away:[],night:[]]
177         //Create a global logger object for methods
178         def log = new Logger()
179         //Create a global variable for Functions in Subscribe method
180         def functionList = []
181         //Create a global variable for Objects in Subscribe method
182         def objectList = []
183         //Create a global variable for Events in Subscribe method
184         def eventList = []
185         //Create a global list for function schedulers
186         def timersFuncList = []
187         //Create a global list for timer schedulers
188         def timersList = []
189
190         //Methods
191         /////////////////////////////////////////////////////////////////////
192         def setLocationMode(String mode) {
193                 location.mode = mode
194         }
195         
196         /////////////////////////////////////////////////////////////////////
197         ////subscribe(obj, func)
198         def subscribe(Object obj, Closure FunctionToCall) {
199                 objectList.add(obj)
200                 eventList.add("Touched")
201                 functionList.add(FunctionToCall)
202         }
203         ////subscribe(obj, event, func)
204         def subscribe(Object obj, String event, Closure FunctionToCall) {
205                 objectList.add(obj)
206                 eventList.add(event)
207                 functionList.add(FunctionToCall)
208         }
209         ////subscribe(obj, event, func, data)
210         def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
211                 objectList.add(obj)     
212                 eventList.add(event)
213                 functionList.add(FunctionToCall)
214         }
215         /////////////////////////////////////////////////////////////////////
216         ////runIn(time, func)
217         def runIn(int seconds, Closure functionToCall) {
218                 timersFuncList.add(functionToCall)
219                 timersList.add(new Timer())
220                 def task = timersList[-1].runAfter(1000*seconds, functionToCall)
221         }
222         /////////////////////////////////////////////////////////////////////
223         ////unschedule(func)
224         def unschedule(Closure functionToUnschedule) {
225                 for (int i = 0;i < timersFuncList.size();i++) {
226                         if (timersFuncList[i] == functionToUnschedule) {
227                                 timersList[i].cancel()
228                         }
229                 }
230         }
231         /////////////////////////////////////////////////////////////////////
232         ////sendNotificationToContacts(text, recipients)
233         def sendNotificationToContacts(String text, List recipients) {
234                 for (int i = 0;i < recipients.size();i++) {
235                         for (int j = 0;j < location.contacts.size();j++) {
236                                 if (recipients[i] == location.contacts[j]) {
237                                         println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
238                                 }
239                         }
240                 }
241         }
242         /////////////////////////////////////////////////////////////////////
243         ////sendSms(phone, text)
244         def sendSms(long phoneNumber, String text) {
245                 println("Sending \""+text+"\" to "+phoneNumber.toString())
246         }
247
248         def installed(){
249             initialize()
250         }
251         
252         def updated(){
253             unsubscribe()
254             unschedule()
255             initialize()
256         }
257         
258         def initialize(){
259             log.debug "Settings: ${settings}"
260             subscribe(lock1, "lock", doorHandler, [filterEvents: false])
261             subscribe(lock1, "unlock", doorHandler, [filterEvents: false])  
262             subscribe(contact, "contact.open", doorHandler)
263             subscribe(contact, "contact.closed", doorHandler)
264         }
265         
266         def lockDoor(){
267             log.debug "Locking the door."
268             lock1.lock()
269             if(location.contactBookEnabled) {
270                 if ( recipients ) {
271                     log.debug ( "Sending Push Notification..." ) 
272                     sendNotificationToContacts( "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!", recipients)
273                 }
274             }
275             if (phoneNumber) {
276                 log.debug("Sending text message...")
277                 sendSms( phoneNumber, "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!")
278             }
279         }
280         
281         def unlockDoor(){
282             log.debug "Unlocking the door."
283             lock1.unlock()
284             if(location.contactBookEnabled) {
285                 if ( recipients ) {
286                     log.debug ( "Sending Push Notification..." ) 
287                     sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!", recipients)
288                 }
289             }
290             if ( phoneNumber ) {
291                 log.debug("Sending text message...")
292                 sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!")
293             }
294         }
295         
296         def doorHandler(evt){
297             if ((contact.latestValue("contact") == "open") && (evt.value == "locked")) { // If the door is open and a person locks the door then...  
298                 //def delay = (secondsLater) // runIn uses seconds
299                 runIn( secondsLater, unlockDoor )   // ...schedule (in minutes) to unlock...  We don't want the door to be closed while the lock is engaged. 
300             }
301             else if ((contact.latestValue("contact") == "open") && (evt.value == "unlocked")) { // If the door is open and a person unlocks it then...
302                 unschedule( unlockDoor ) // ...we don't need to unlock it later.
303             }
304             else if ((contact.latestValue("contact") == "closed") && (evt.value == "locked")) { // If the door is closed and a person manually locks it then...
305                 unschedule( lockDoor ) // ...we don't need to lock it later.
306             }   
307             else if ((contact.latestValue("contact") == "closed") && (evt.value == "unlocked")) { // If the door is closed and a person unlocks it then...
308                //def delay = (minutesLater * 60) // runIn uses seconds
309                 runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
310             }
311             else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "open")) { // If a person opens an unlocked door...
312                 unschedule( lockDoor ) // ...we don't need to lock it later.
313             }
314             else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "closed")) { // If a person closes an unlocked door...
315                 //def delay = (minutesLater * 60) // runIn uses seconds
316                 runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
317             }
318             else { //Opening or Closing door when locked (in case you have a handle lock)
319                 log.debug "Unlocking the door."
320                 lock1.unlock()
321                 if(location.contactBookEnabled) {
322                     if ( recipients ) {
323                         log.debug ( "Sending Push Notification..." ) 
324                         sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!", recipients)
325                     }
326                 }
327                 if ( phoneNumber ) {
328                     log.debug("Sending text message...")
329                     sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!")
330                 }
331             }
332         }
333 }
334
335
336 //Application #2
337 class App2 {
338         def reference
339         def location
340         def app
341
342         //Extracted objects for App2
343         //Object for class Switch!
344         def switchesoff
345         //Object for class Switch!
346         def switcheson
347         //Object for class lock!
348         def lock1
349         //Global variable for mode!
350         def newMode = "away"
351         //Global variable for number!
352         def waitfor = 1
353         //Global Object for functions in subscribe method!
354         def installed = this.&installed
355         //Global Object for functions in subscribe method!
356         def updated = this.&updated
357         //Global Object for functions in subscribe method!
358         def appTouch = this.&appTouch
359
360         App2(Object obj) {
361                 reference = obj
362                 location = obj.locationObject
363                 app = obj.appObject
364                 switchesoff = obj.switchObject
365                 switcheson = obj.switchObject
366                 lock1 = obj.lockObject
367         }
368         //Global variables for each app
369         //Settings variable defined to settings on purpose
370         def settings = "Settings"
371         //Global variable for state[mode]
372         def state = [home:[],away:[],night:[]]
373         //Create a global logger object for methods
374         def log = new Logger()
375         //Create a global variable for Functions in Subscribe method
376         def functionList = []
377         //Create a global variable for Objects in Subscribe method
378         def objectList = []
379         //Create a global variable for Events in Subscribe method
380         def eventList = []
381         //Create a global list for function schedulers
382         def timersFuncList = []
383         //Create a global list for timer schedulers
384         def timersList = []
385
386         //Methods
387         /////////////////////////////////////////////////////////////////////
388         def setLocationMode(String mode) {
389                 location.mode = mode
390         }
391         
392         /////////////////////////////////////////////////////////////////////
393         ////subscribe(obj, func)
394         def subscribe(Object obj, Closure FunctionToCall) {
395                 objectList.add(obj)
396                 eventList.add("Touched")
397                 functionList.add(FunctionToCall)
398         }
399         ////subscribe(obj, event, func)
400         def subscribe(Object obj, String event, Closure FunctionToCall) {
401                 objectList.add(obj)
402                 eventList.add(event)
403                 functionList.add(FunctionToCall)
404         }
405         ////subscribe(obj, event, func, data)
406         def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
407                 objectList.add(obj)     
408                 eventList.add(event)
409                 functionList.add(FunctionToCall)
410         }
411         /////////////////////////////////////////////////////////////////////
412         ////runIn(time, func)
413         def runIn(int seconds, Closure functionToCall) {
414                 timersFuncList.add(functionToCall)
415                 timersList.add(new Timer())
416                 def task = timersList[-1].runAfter(1000*seconds, functionToCall)
417         }
418         /////////////////////////////////////////////////////////////////////
419         ////unschedule(func)
420         def unschedule(Closure functionToUnschedule) {
421                 for (int i = 0;i < timersFuncList.size();i++) {
422                         if (timersFuncList[i] == functionToUnschedule) {
423                                 timersList[i].cancel()
424                         }
425                 }
426         }
427         /////////////////////////////////////////////////////////////////////
428         ////sendNotificationToContacts(text, recipients)
429         def sendNotificationToContacts(String text, List recipients) {
430                 for (int i = 0;i < recipients.size();i++) {
431                         for (int j = 0;j < location.contacts.size();j++) {
432                                 if (recipients[i] == location.contacts[j]) {
433                                         println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
434                                 }
435                         }
436                 }
437         }
438         /////////////////////////////////////////////////////////////////////
439         ////sendSms(phone, text)
440         def sendSms(long phoneNumber, String text) {
441                 println("Sending \""+text+"\" to "+phoneNumber.toString())
442         }
443
444         def installed()
445         {
446                 log.debug "Installed with settings: ${settings}"
447                 log.debug "Current mode = ${location.mode}"
448                 subscribe(app, appTouch)
449         }
450         
451         
452         def updated()
453         {
454                 log.debug "Updated with settings: ${settings}"
455                 log.debug "Current mode = ${location.mode}"
456                 unsubscribe()
457                 subscribe(app, appTouch)
458         }
459         
460         def appTouch(evt) {
461                 log.debug "changeMode, location.mode = $location.mode, newMode = $newMode, location.modes = $location.modes"
462             if (location.mode != newMode) {
463                                 setLocationMode(newMode)
464                                 log.debug "Changed the mode to '${newMode}'"
465             }   else {
466                 log.debug "New mode is the same as the old mode, leaving it be"
467                 }
468             log.debug "appTouch: $evt"
469             lock1.lock()
470             switcheson.on()
471             def delay = (waitfor != null && waitfor != "") ? waitfor * 1000 : 120000
472                 switchesoff.off(delay: delay)
473         }
474 }
475
476 @Field def app1 = new App1(this)
477 @Field def app2 = new App2(this)
478 app1.installed()
479 app2.installed()
480 appObject.setValue([name: "Touched", value: "Touched", deviceId: 0, descriptionText: "",
481            displayed: true, linkText: "", isStateChange: false, unit: "", data: []])
482