Adding a newline at the end of the code.
[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.ContactSensor
7 import ContactSensor.ContactSensors
8 import DoorControl.DoorControl
9 import DoorControl.DoorControls
10 import Lock.Lock
11 import Lock.Locks
12 import Thermostat.Thermostat
13 import Thermostat.Thermostats
14 import Switch.Switch
15 import Switch.Switches
16 import PresenceSensor.PresenceSensor
17 import PresenceSensor.PresenceSensors
18 import Logger.Logger
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
33 import Alarm.Alarm
34 import Alarm.Alarms
35 import SpeechSynthesis.SpeechSynthesis
36 import SpeechSynthesis.SpeechSynthesises
37 import Event.Event
38 import Timer.SimulatedTimer
39
40 //Global eventHandler
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"]
52
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)
56                         evt.add(event)
57                         app2.functionList[i](event)
58                 }
59         }
60
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)
64                         evt.add(event)
65                         app1.functionList[i](event)
66                 }
67         }
68 }
69
70 //GlobalVariables for both Apps
71 //Create a global variable for send event
72 @Field def sendEvent = {eventDataMap -> 
73                         eventHandler(eventDataMap)
74                         }
75 //Object for location
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
80 @Field def evt = []
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)
109
110 //Application #1
111 class App1 {
112         def reference
113         def location
114         def app
115
116         //Extracted objects for App1
117         //Object for class switch!
118         def switches
119         //Object for class thermostat!
120         def thermostats
121         //Object for class lock!
122         def locks
123
124         //Extracted objects for functions for App1
125         //Global Object for functions in subscribe method!
126         def installed = this.&installed
127         //Global Object for functions in subscribe method!
128         def updated = this.&updated
129         //Global Object for functions in subscribe method!
130         def appTouch = this.&appTouch
131         //Global Object for functions in subscribe method!
132         def changedLocationMode = this.&changedLocationMode
133         //Global Object for functions in subscribe method!
134         def restoreState = this.&restoreState
135         //Global Object for functions in subscribe method!
136         def saveState = this.&saveState
137         //Global Object for functions in subscribe method!
138         def getCurrentMode = this.&getCurrentMode
139
140         App1(Object obj) {
141                 reference = obj
142                 location = obj.locationObject
143                 app = obj.appObject
144                 switches = obj.switchObject
145                 thermostats = obj.thermostatObject
146                 locks = obj.lockObject
147                 //Global variable for settings!
148                 settings = [app:app, switches:switches, thermostats:thermostats, locks:locks]
149         }
150         //Global variables for each app
151         //Global variable for state[mode]
152         def state = [home:[],away:[],night:[]]
153         //Create a global logger object for methods
154         def log = new Logger()
155         //Create a global variable for Functions in Subscribe method
156         def functionList = []
157         //Create a global variable for Objects in Subscribe method
158         def objectList = []
159         //Create a global variable for Events in Subscribe method
160         def eventList = []
161         //Create a global list for function schedulers
162         def timersFuncList = []
163         //Create a global list for timer schedulers
164         def timersList = []
165         //Create a global variable for settings
166         def settings
167         //Zip code
168         def zipCode = 92617
169
170         //Methods
171         /////////////////////////////////////////////////////////////////////
172         def setLocationMode(String mode) {
173                 location.mode = mode
174         }
175         
176         /////////////////////////////////////////////////////////////////////
177         ////subscribe(obj, func)
178         def subscribe(Object obj, Closure FunctionToCall) {
179                 if (obj == app) {
180                         objectList.add(obj)
181                         eventList.add("Touched")
182                         functionList.add(FunctionToCall)
183                 } else if (obj == location) {
184                         objectList.add(obj)
185                         eventList.add("Location")
186                         functionList.add(FunctionToCall)
187                 }
188         }
189         ////subscribe(obj, event, func)
190         def subscribe(Object obj, String event, Closure FunctionToCall) {
191                 objectList.add(obj)
192                 eventList.add(event)
193                 functionList.add(FunctionToCall)
194         }
195         ////subscribe(obj, event, func, data)
196         def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
197                 objectList.add(obj)     
198                 eventList.add(event)
199                 functionList.add(FunctionToCall)
200         }
201         /////////////////////////////////////////////////////////////////////
202         ////runIn(time, func)
203         def runIn(int seconds, Closure functionToCall) {
204                 if (timersFuncList.contains(functionToCall)) {
205                         timersList[timersFuncList.indexOf(functionToCall)].cancel()
206                         def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
207                 } else {
208                         timersFuncList.add(functionToCall)
209                         timersList.add(new SimulatedTimer())
210                         def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
211                 }
212         }
213         
214         def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) {
215                 runIn(seconds, functionToCall)
216         }
217         
218         def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) {
219                 runIn(seconds, nameOfFunction)
220         }
221         
222         def runIn(int seconds, String nameOfFunction) {
223                 timersFuncList.add(nameOfFunction)
224                 timersList.add(new SimulatedTimer())
225                 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) {
226                         "$nameOfFunction"()
227                 }
228         }
229         /////////////////////////////////////////////////////////////////////
230         ////unschedule(func)
231         def unschedule(Closure functionToUnschedule) {
232                 for (int i = 0;i < timersFuncList.size();i++) {
233                         if (timersFuncList[i] == functionToUnschedule) {
234                                 if (timersList != null)
235                                         timersList[i].cancel()
236                         }
237                 }
238         }
239         
240         
241         def unschedule() {
242                 for (int i = 0;i < timersFuncList.size();i++) {
243                         if (timersList != null)
244                                 timersList[i].cancel()
245                 }
246         }
247         /////////////////////////////////////////////////////////////////////
248         ////sendNotificationToContacts(text, recipients)
249         def sendNotificationToContacts(String text, String recipients) {
250                 for (int i = 0;i < recipients.size();i++) {
251                         for (int j = 0;j < location.contacts.size();j++) {
252                                 if (recipients[i] == location.contacts[j]) {
253                                         println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
254                                 }
255                         }
256                 }
257         }
258         /////////////////////////////////////////////////////////////////////
259         ////sendSms(phone, text)
260         def sendSms(long phoneNumber, String text) {
261                 println("Sending \""+text+"\" to "+phoneNumber.toString())
262         }
263         
264         def sendSMS(long phoneNumber, String text) {
265                 println("Sending \""+text+"\" to "+phoneNumber.toString())
266         }
267         /////////////////////////////////////////////////////////////////////
268         ////sendPush(text)
269         def sendPush(String text) {
270                 println(text)
271         }
272         /////////////////////////////////////////////////////////////////////
273         ////schedule(time, nameOfFunction as String)
274         def schedule(String time, String nameOfFunction) {
275                 def _inputTime = time.split(':')
276                 Date date = new Date()  
277                 def _currentTime = date.format("HH:mm:ss").split(':')
278         
279                 //Convert input time and current time to minutes
280                 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
281                 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
282                 def delay
283         
284                 if (inputTime < currentTime) {
285                         delay = 24*60*60-inputTime+currentTime
286                 } else {
287                         delay = inputTime-currentTime
288                 }
289         
290                 timersFuncList.add(nameOfFunction)
291                 timersList.add(new SimulatedTimer())
292                 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) {
293                         "$nameOfFunction"()
294                 }
295         }
296         ////schedule(time, nameOfFunction as Closure)
297         def schedule(String time, Closure nameOfFunction) {
298                 def _inputTime = time.split(':')
299                 Date date = new Date()  
300                 def _currentTime = date.format("HH:mm:ss").split(':')
301         
302                 //Convert input time and current time to minutes
303                 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
304                 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
305                 def delay
306         
307                 if (inputTime < currentTime) {
308                         delay = 24*60*60-inputTime+currentTime
309                 } else {
310                         delay = inputTime-currentTime
311                 }
312         
313                 if (timersFuncList.contains(nameOfFunction)) {
314                         timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
315                         def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
316                 } else {
317                         timersFuncList.add(nameOfFunction)
318                         timersList.add(new SimulatedTimer())
319                         def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
320                 }
321         }
322         /////////////////////////////////////////////////////////////////////
323         def now() {
324                 return System.currentTimeMillis()
325         }
326         /////////////////////////////////////////////////////////////////////
327         def getTemperatureScale() {
328                 return 'C' //Celsius for now
329         }
330         
331         /////////////////////////////////////////////////////////////////////
332         def getSunriseAndSunset(LinkedHashMap metaData) {
333                 def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]]
334                 return sunRiseSetInfo
335         }
336
337         def installed() {
338                 subscribe(location, changedLocationMode)
339                 subscribe(app, appTouch)
340                 saveState()
341         }
342         
343         def updated() {
344                 unsubscribe()
345                 subscribe(location, changedLocationMode)
346                 subscribe(app, appTouch)
347                 saveState()
348         }
349         
350         def appTouch(evt)
351         {
352                 restoreState(currentMode)
353         }
354         
355         def changedLocationMode(evt)
356         {
357                 restoreState(evt.value)
358         }
359         
360         private restoreState(mode)
361         {
362                 log.info "restoring state for mode '$mode'"
363                 def map = state[mode] ?: [:]
364                 switches?.each {
365                         def value = map[it.id]
366                         if (value?.switch == "on") {
367                                 def level = value.level
368                                 if (level) {
369                                         log.debug "setting $it.label level to $level"
370                                         it.setLevel(level)
371                                 }
372                                 else {
373                                         log.debug "turning $it.label on"
374                                         it.on()
375                                 }
376                         }
377                         else if (value?.switch == "off") {
378                                 log.debug "turning $it.label off"
379                                 it.off()
380                         }
381                 }
382         
383                 thermostats?.each {
384                         def value = map[it.id]
385                         if (value?.coolingSetpoint) {
386                                 log.debug "coolingSetpoint = $value.coolingSetpoint"
387                                 it.setCoolingSetpoint(value.coolingSetpoint)
388                         }
389                         if (value?.heatingSetpoint) {
390                                 log.debug "heatingSetpoint = $value.heatingSetpoint"
391                                 it.setHeatingSetpoint(value.heatingSetpoint)
392                         }
393                 }
394         
395                 locks?.each {
396                         def value = map[it.id]
397                         if (value) {
398                                 if (value?.locked) {
399                                         it.lock()
400                                 }
401                                 else {
402                                         it.unlock()
403                                 }
404                         }
405                 }
406         }
407         
408         
409         private saveState()
410         {
411                 def mode = currentMode
412                 def map = state[mode] ?: [:]
413         
414                 switches?.each {
415                         map[it.id] = [switch: it.currentSwitch, level: it.currentLevel]
416                 }
417         
418                 thermostats?.each {
419                         map[it.id] = [coolingSetpoint: it.currentCoolingSetpoint, heatingSetpoint: it.currentHeatingSetpoint]
420                 }
421         
422                 locks?.each {
423                         map[it.id] = [locked: it.currentLock == "locked"]
424                 }
425         
426                 state[mode] = map
427                 log.debug "saved state for mode ${mode}: ${state[mode]}"
428                 log.debug "state: $state"
429         }
430         
431         private getCurrentMode()
432         {
433                 location.mode ?: "_none_"
434         }
435 }
436
437
438 //Application #2
439 class App2 {
440         def reference
441         def location
442         def app
443
444         //Extracted objects for App2
445         //Object for class Touch Sensor!
446         def tag
447         //Object for class switch!
448         def switch1
449         //Object for class lock!
450         def lock
451         //Object for class door control!
452         def garageDoor
453         //Global variable for enum!
454         def masterSwitch = "Yes"
455         //Global variable for enum!
456         def masterLock = "Yes"
457         //Global variable for enum!
458         def masterDoor = "No"
459
460         //Extracted objects for functions for App2
461         //Global Object for functions in subscribe method!
462         def pageTwo = this.&pageTwo
463         //Global Object for functions in subscribe method!
464         def installed = this.&installed
465         //Global Object for functions in subscribe method!
466         def updated = this.&updated
467         //Global Object for functions in subscribe method!
468         def initialize = this.&initialize
469         //Global Object for functions in subscribe method!
470         def touchHandler = this.&touchHandler
471
472         App2(Object obj) {
473                 reference = obj
474                 location = obj.locationObject
475                 app = obj.appObject
476                 tag = obj.touchSensorObject
477                 switch1 = obj.switchObject
478                 lock = obj.lockObject
479                 garageDoor = obj.doorControlObject
480                 //Global variable for settings!
481                 settings = [app:app, tag:tag, switch1:switch1, lock:lock, garageDoor:garageDoor, masterSwitch:masterSwitch, masterLock:masterLock, masterDoor:masterDoor]
482         }
483         //Global variables for each app
484         //Global variable for state[mode]
485         def state = [home:[],away:[],night:[]]
486         //Create a global logger object for methods
487         def log = new Logger()
488         //Create a global variable for Functions in Subscribe method
489         def functionList = []
490         //Create a global variable for Objects in Subscribe method
491         def objectList = []
492         //Create a global variable for Events in Subscribe method
493         def eventList = []
494         //Create a global list for function schedulers
495         def timersFuncList = []
496         //Create a global list for timer schedulers
497         def timersList = []
498         //Create a global variable for settings
499         def settings
500         //Zip code
501         def zipCode = 92617
502
503         //Methods
504         /////////////////////////////////////////////////////////////////////
505         def setLocationMode(String mode) {
506                 location.mode = mode
507         }
508         
509         /////////////////////////////////////////////////////////////////////
510         ////subscribe(obj, func)
511         def subscribe(Object obj, Closure FunctionToCall) {
512                 if (obj == app) {
513                         objectList.add(obj)
514                         eventList.add("Touched")
515                         functionList.add(FunctionToCall)
516                 } else if (obj == location) {
517                         objectList.add(obj)
518                         eventList.add("Location")
519                         functionList.add(FunctionToCall)
520                 }
521         }
522         ////subscribe(obj, event, func)
523         def subscribe(Object obj, String event, Closure FunctionToCall) {
524                 objectList.add(obj)
525                 eventList.add(event)
526                 functionList.add(FunctionToCall)
527         }
528         ////subscribe(obj, event, func, data)
529         def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
530                 objectList.add(obj)     
531                 eventList.add(event)
532                 functionList.add(FunctionToCall)
533         }
534         /////////////////////////////////////////////////////////////////////
535         ////runIn(time, func)
536         def runIn(int seconds, Closure functionToCall) {
537                 if (timersFuncList.contains(functionToCall)) {
538                         timersList[timersFuncList.indexOf(functionToCall)].cancel()
539                         def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
540                 } else {
541                         timersFuncList.add(functionToCall)
542                         timersList.add(new SimulatedTimer())
543                         def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall)
544                 }
545         }
546         
547         def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) {
548                 runIn(seconds, functionToCall)
549         }
550         
551         def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) {
552                 runIn(seconds, nameOfFunction)
553         }
554         
555         def runIn(int seconds, String nameOfFunction) {
556                 timersFuncList.add(nameOfFunction)
557                 timersList.add(new SimulatedTimer())
558                 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) {
559                         "$nameOfFunction"()
560                 }
561         }
562         /////////////////////////////////////////////////////////////////////
563         ////unschedule(func)
564         def unschedule(Closure functionToUnschedule) {
565                 for (int i = 0;i < timersFuncList.size();i++) {
566                         if (timersFuncList[i] == functionToUnschedule) {
567                                 if (timersList != null)
568                                         timersList[i].cancel()
569                         }
570                 }
571         }
572         
573         
574         def unschedule() {
575                 for (int i = 0;i < timersFuncList.size();i++) {
576                         if (timersList != null)
577                                 timersList[i].cancel()
578                 }
579         }
580         /////////////////////////////////////////////////////////////////////
581         ////sendNotificationToContacts(text, recipients)
582         def sendNotificationToContacts(String text, String recipients) {
583                 for (int i = 0;i < recipients.size();i++) {
584                         for (int j = 0;j < location.contacts.size();j++) {
585                                 if (recipients[i] == location.contacts[j]) {
586                                         println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
587                                 }
588                         }
589                 }
590         }
591         /////////////////////////////////////////////////////////////////////
592         ////sendSms(phone, text)
593         def sendSms(long phoneNumber, String text) {
594                 println("Sending \""+text+"\" to "+phoneNumber.toString())
595         }
596         
597         def sendSMS(long phoneNumber, String text) {
598                 println("Sending \""+text+"\" to "+phoneNumber.toString())
599         }
600         /////////////////////////////////////////////////////////////////////
601         ////schedule(time, nameOfFunction as String)
602         def schedule(String time, String nameOfFunction) {
603                 def _inputTime = time.split(':')
604                 Date date = new Date()  
605                 def _currentTime = date.format("HH:mm:ss").split(':')
606         
607                 //Convert input time and current time to minutes
608                 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
609                 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
610                 def delay
611         
612                 if (inputTime < currentTime) {
613                         delay = 24*60*60-inputTime+currentTime
614                 } else {
615                         delay = inputTime-currentTime
616                 }
617         
618                 timersFuncList.add(nameOfFunction)
619                 timersList.add(new SimulatedTimer())
620                 def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) {
621                         "$nameOfFunction"()
622                 }
623         }
624         ////schedule(time, nameOfFunction as Closure)
625         def schedule(String time, Closure nameOfFunction) {
626                 def _inputTime = time.split(':')
627                 Date date = new Date()  
628                 def _currentTime = date.format("HH:mm:ss").split(':')
629         
630                 //Convert input time and current time to minutes
631                 def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60
632                 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2])
633                 def delay
634         
635                 if (inputTime < currentTime) {
636                         delay = 24*60*60-inputTime+currentTime
637                 } else {
638                         delay = inputTime-currentTime
639                 }
640         
641                 if (timersFuncList.contains(nameOfFunction)) {
642                         timersList[timersFuncList.indexOf(nameOfFunction)].cancel()
643                         def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
644                 } else {
645                         timersFuncList.add(nameOfFunction)
646                         timersList.add(new SimulatedTimer())
647                         def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*seconds*0, nameOfFunction)
648                 }
649         }
650         /////////////////////////////////////////////////////////////////////
651         def now() {
652                 return System.currentTimeMillis()
653         }
654         /////////////////////////////////////////////////////////////////////
655         def getTemperatureScale() {
656                 return 'C' //Celsius for now
657         }
658         
659         /////////////////////////////////////////////////////////////////////
660         def getSunriseAndSunset(LinkedHashMap metaData) {
661                 def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]]
662                 return sunRiseSetInfo
663         }
664
665         def pageTwo() {
666                 dynamicPage(name: "pageTwo") {
667                 section("If set, the state of these devices will be toggled each time the tag is touched, " + 
668                         "e.g. a light that's on will be turned off and one that's off will be turned on, " +
669                         "other devices of the same type will be set to the same state as their master device. " +
670                         "If no master is designated then the majority of devices of the same type will be used " +
671                         "to determine whether to turn on or off the devices.") {
672                     
673                     if (switch1 || masterSwitch) {
674                         input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
675                     }
676                     if (lock || masterLock) {
677                         input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
678                     }
679                     if (garageDoor || masterDoor) {
680                         input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
681                     }            
682                         }
683                         section([mobileOnly:true]) {
684                                 label title: "Assign a name", required: false
685                                 mode title: "Set for specific mode(s)", required: false
686                         }        
687             }
688         }
689         
690         def installed() {
691                 log.debug "Installed with settings: ${settings}"
692         
693                 initialize()
694         }
695         
696         def updated() {
697                 log.debug "Updated with settings: ${settings}"
698         
699                 unsubscribe()
700                 initialize()
701         }
702         
703         def initialize() {
704                 subscribe tag, "nfcTouch", touchHandler
705             subscribe app, touchHandler
706         }
707         
708         private currentStatus(devices, master, attribute) {
709                 log.trace "currentStatus($devices, $master, $attribute)"
710                 def result = null
711                 if (master) {
712                 result = devices.find{it.id == master}?.currentValue(attribute)
713             }
714             else {
715                 def map = [:]
716                 devices.each {
717                         def value = it.currentValue(attribute)
718                     map[value] = (map[value] ?: 0) + 1
719                     log.trace "$it.displayName: $value"
720                 }
721                 log.trace map
722                 result = map.collect{it}.sort{it.value}[-1].key
723             }
724             log.debug "$attribute = $result"
725             result
726         }
727         
728         def touchHandler(evt) {
729                 log.trace "touchHandler($evt.descriptionText)"
730             if (switch1) {
731                 def status = currentStatus(switch1, masterSwitch, "switch")
732                 switch1.each {
733                     if (status == "on") {
734                         it.off()
735                     }
736                     else {
737                         it.on()
738                     }
739                 }
740             }
741             
742             if (lock) {
743                 def status = currentStatus(lock, masterLock, "lock")
744                 lock.each {
745                     if (status == "locked") {
746                         lock.unlock()
747                     }
748                     else {
749                         lock.lock()
750                     }
751                 }
752             }
753             
754             if (garageDoor) {
755                 def status = currentStatus(garageDoor, masterDoor, "status")
756                 garageDoor.each {
757                         if (status == "open") {
758                         it.close()
759                     }
760                     else {
761                         it.open()
762                     }
763                 }
764             }
765         }
766 }
767
768 @Field def app1 = new App1(this)
769 @Field def app2 = new App2(this)
770 app1.installed()
771 app2.installed()
772
773 appObject.setValue([name: "nfcTouch", value: "touched", deviceId: "nfcSensorID0", descriptionText: "",
774 displayed: true, linkText: "", isStateChange: false, unit: "", data: [info: "info"]])
775 appObject.setValue([name: "Touched", value: "touched", deviceId: "touchedSensorID0", descriptionText: "",
776 displayed: true, linkText: "", isStateChange: false, unit: "", data: [info: "info"]])
777 locationObject.setValue([name: "Location", value: "away", deviceId: "locationID0", descriptionText: "",
778 displayed: true, linkText: "", isStateChange: false, unit: "", data: [info: "info"]])
779 locationObject.setValue([name: "Location", value: "home", deviceId: "locationID0", descriptionText: "",
780 displayed: true, linkText: "", isStateChange: false, unit: "", data: [info: "info"]])
781 locationObject.setValue([name: "Location", value: "night", deviceId: "locationID0", descriptionText: "",
782 displayed: true, linkText: "", isStateChange: false, unit: "", data: [info: "info"]])