4 ////////////////////////////////////////
6 import groovy.transform.Field
11 import ContactSensor.ContactSensor
12 import ContactSensor.ContactSensors
13 import DoorControl.DoorControl
14 import DoorControl.DoorControls
17 import Thermostat.Thermostat
18 import Thermostat.Thermostats
20 import Switch.Switches
21 import PresenceSensor.PresenceSensor
22 import PresenceSensor.PresenceSensors
24 import Location.LocationVar
25 import Location.Phrase
26 import appTouch.Touched
27 import NfcTouch.NfcTouch
28 import AeonKeyFob.AeonKeyFob
29 import AeonKeyFob.AeonKeyFobs
30 import MusicPlayer.MusicPlayer
31 import MusicPlayer.MusicPlayers
32 import Timer.SimulatedTimer
35 @Field def location = new LocationVar()
36 //Settings variable defined to settings on purpose
37 @Field def settings = [app: "app"]
38 //Global variable for state[mode]
39 @Field def state = [home:[],away:[],night:[]]
40 //Create a global logger object for methods
41 @Field def log = new Logger()
44 //Global variables for files
45 @Field File extractedObjectsApp1 = new File("Extractor/App1/extractedObjectsApp1.groovy")
46 @Field File extractedObjectsApp2 = new File("Extractor/App2/extractedObjectsApp2.groovy")
47 @Field File extractedObjectsConstructorApp1 = new File("Extractor/App1/extractedObjectsConstructorApp1.groovy")
48 @Field File extractedObjectsConstructorApp2 = new File("Extractor/App2/extractedObjectsConstructorApp2.groovy")
53 extractedObjectsApp1.write("")
54 extractedObjectsConstructorApp1.write("")
55 } else if (App == "App2") {
56 extractedObjectsApp2.write("")
57 extractedObjectsConstructorApp2.write("")
65 //Global Object for class Touch Sensor!
66 @Field touchSensorObjects = 0
67 @Field def touchSensorObject0
68 @Field def touchSensorObject1
69 @Field def touchSensorObject2
70 //Global Object for class switch!
71 @Field switchObjects = 0
72 @Field def switchObject0
73 @Field def switchObject1
74 @Field def switchObject2
75 //Global Object for class lock!
76 @Field lockObjects = 0
77 @Field def lockObject0
78 @Field def lockObject1
79 @Field def lockObject2
80 //Global Object for class door control!
81 @Field doorControlObjects = 0
82 @Field def doorControlObject0
83 @Field def doorControlObject1
84 @Field def doorControlObject2
85 //Global Object for class contact sensor!
86 @Field contactObjects = 0
87 @Field def contactObject0
88 @Field def contactObject1
89 @Field def contactObject2
90 //Global Object for class presence sensor!
91 @Field presenceSensorObjects = 0
92 @Field def presenceSensorObject0
93 @Field def presenceSensorObject1
94 @Field def presenceSensorObject2
95 //Global Object for class thermostat!
96 @Field thermostatObjects = 0
97 @Field def thermostatObject0
98 @Field def thermostatObject1
99 @Field def thermostatObject2
100 //Global Object for class music player!
101 @Field musicPlayerObjects = 0
102 @Field def musicPlayerObject0
103 @Field def musicPlayerObject1
104 @Field def musicPlayerObject2
105 //Global Object for class music player!
106 @Field aeonKeyFobObjects = 0
107 @Field def aeonKeyFobObject0
108 @Field def aeonKeyFobObject1
109 @Field def aeonKeyFobObject2
114 @Field modeVariables = 0
122 @Field numberVariables = 0
130 @Field timeVariables = 0
138 @Field enumVariables = 0
146 @Field phoneVariables = 0
154 @Field contactVariables = 0
164 /////Input Methods/////
166 def input(String name, String type) {
167 LinkedHashMap metaData = []
168 metaData.put('name',name)
169 metaData.put('type',type)
173 //input "","",linkedHashMap
174 def input(LinkedHashMap metaData, String name, String type) {
175 metaData.put('name',name)
176 metaData.put('type',type)
180 //input linkedHashMap
181 def input(LinkedHashMap metaData) {
182 if (metaData.containsKey('title')) {
183 println metaData['title']
185 if (metaData.containsKey('options')) {
186 println "Options: "+metaData['options']
188 switch(metaData['type']) {
189 case "capability.lock":
190 if (lockObjects == 0) {
191 lockObject0 = metaData['name']
192 this[lockObject0] = new Locks({}, 1)
193 } else if (lockObjects == 1) {
194 lockObject1 = metaData['name']
195 this[lockObject1] = new Locks({}, 1)
196 } else if (lockObjects == 2) {
197 lockObject2 = metaData['name']
198 this[lockObject2] = new Locks({}, 1)
201 lockObjects=lockObjects+1
203 settings.put(metaData['name'], metaData['name'])
206 extractedObjectsApp1.append("//Object for class lock!\n")
207 extractedObjectsApp1.append("def "+metaData['name']+"\n")
208 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.lockObject\n")
210 extractedObjectsApp2.append("//Object for class lock!\n")
211 extractedObjectsApp2.append("def "+metaData['name']+"\n")
212 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.lockObject\n")
215 case "capability.alarm":
217 case "capability.battery":
219 case "capability.beacon":
221 case "capability.carbonMonoxideDetector":
223 case "capability.colorControl":
225 case "capability.contactSensor":
226 if (contactObjects == 0) {
227 contactObject0 = metaData['name']
228 this[contactObject0] = new ContactSensors({}, 1)
229 } else if (contactObjects == 1) {
230 contactObject1 = metaData['name']
231 this[contactObject1] = new ContactSensors({}, 1)
232 } else if (contactObjects == 2) {
233 contactObject2 = metaData['name']
234 this[contactObject2] = new ContactSensors({}, 1)
237 contactObjects=contactObjects+1
239 settings.put(metaData['name'], metaData['name'])
242 extractedObjectsApp1.append("//Object for class contactSensor!\n")
243 extractedObjectsApp1.append("def "+metaData['name']+"\n")
244 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.contactObject\n")
246 extractedObjectsApp2.append("//Object for class contactSensor!\n")
247 extractedObjectsApp2.append("def "+metaData['name']+"\n")
248 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.contactObject\n")
251 case "capability.doorControl":
252 if (doorControlObjects == 0) {
253 doorControlObject0 = metaData['name']
254 this[doorControlObject0] = new DoorControls({}, 1)
255 } else if (doorControlObjects == 1) {
256 doorControlObject1 = metaData['name']
257 this[doorControlObject1] = new DoorControls({}, 1)
258 } else if (doorControlObjects == 2) {
259 doorControlObject2 = metaData['name']
260 this[doorControlObject2] = new DoorControls({}, 1)
263 doorControlObjects=doorControlObjects+1
265 settings.put(metaData['name'], metaData['name'])
268 extractedObjectsApp1.append("//Object for class door control!\n")
269 extractedObjectsApp1.append("def "+metaData['name']+"\n")
270 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.doorControlObject\n")
272 extractedObjectsApp2.append("//Object for class door control!\n")
273 extractedObjectsApp2.append("def "+metaData['name']+"\n")
274 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.doorControlObject\n")
277 case "capability.energyMeter":
279 case "capability.illuminanceMeasurement":
281 case "capability.accelerationSensor":
283 case "capability.motionSensor":
285 case "capability.musicPlayer":
286 if (musicPlayerObjects == 0) {
287 musicPlayerObject0 = metaData['name']
288 this[musicPlayerObject0] = new MusicPlayers({}, 1)
289 } else if (musicPlayerObjects == 1) {
290 musicPlayerObject1 = metaData['name']
291 this[musicPlayerObject1] = new MusicPlayers({}, 1)
292 } else if (musicPlayerObjects == 2) {
293 musicPlayerObject2 = metaData['name']
294 this[musicPlayerObject2] = new MusicPlayers({}, 1)
297 musicPlayerObjects=musicPlayerObjects+1
299 settings.put(metaData['name'], metaData['name'])
302 extractedObjectsApp1.append("//Object for class music player!\n")
303 extractedObjectsApp1.append("def "+metaData['name']+"\n")
304 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.musicPlayerObject\n")
306 extractedObjectsApp2.append("//Object for class music player!\n")
307 extractedObjectsApp2.append("def "+metaData['name']+"\n")
308 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.musicPlayerObject\n")
311 case "capability.powerMeter":
313 case "capability.presenceSensor":
314 if (presenceSensorObjects == 0) {
315 presenceSensorObject0 = metaData['name']
316 this[presenceSensorObject0] = new PresenceSensors({}, 1)
317 } else if (presenceSensorObjects == 1) {
318 presenceSensorObject1 = metaData['name']
319 this[presenceSensorObject1] = new PresenceSensors({}, 1)
320 } else if (presenceSensorObjects == 2) {
321 presenceSensorObject2 = metaData['name']
322 this[presenceSensorObject2] = new PresenceSensors({}, 1)
325 presenceSensorObjects=presenceSensorObjects+1
327 settings.put(metaData['name'], metaData['name'])
330 extractedObjectsApp1.append("//Object for class presence sensor!\n")
331 extractedObjectsApp1.append("def "+metaData['name']+"\n")
332 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.presenceSensorObject\n")
334 extractedObjectsApp2.append("//Object for class presence sensor!\n")
335 extractedObjectsApp2.append("def "+metaData['name']+"\n")
336 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.presenceSensorObject\n")
339 case "capability.relativeHumidityMeasurement":
341 case "capability.relaySwitch":
343 case "capability.sleepSensor":
345 case "capability.smokeDetector":
347 case "capability.stepSensor":
349 case "capability.switch":
350 if (switchObjects == 0) {
351 switchObject0 = metaData['name']
352 this[switchObject0] = new Switches({}, 1)
353 } else if (switchObjects == 1) {
354 switchObject1 = metaData['name']
355 this[switchObject1] = new Switches({}, 1)
356 } else if (switchObjects == 2) {
357 switchObject2 = metaData['name']
358 this[switchObject2] = new Switches({}, 1)
361 switchObjects=switchObjects+1
363 settings.put(metaData['name'], metaData['name'])
366 extractedObjectsApp1.append("//Object for class switch!\n")
367 extractedObjectsApp1.append("def "+metaData['name']+"\n")
368 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.switchObject\n")
370 extractedObjectsApp2.append("//Object for class switch!\n")
371 extractedObjectsApp2.append("def "+metaData['name']+"\n")
372 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.switchObject\n")
375 case "capability.switchLevel":
377 case "capability.temperatureMeasurement":
379 case "capability.thermostat":
380 if (thermostatObjects == 0) {
381 thermostatObject0 = metaData['name']
382 this[thermostatObject0] = new Thermostats({}, 1)
383 } else if (thermostatObjects == 1) {
384 thermostatObject1 = metaData['name']
385 this[thermostatObject1] = new Thermostats({}, 1)
386 } else if (thermostatObjects == 2) {
387 thermostatObject2 = metaData['name']
388 this[thermostatObject2] = new Thermostats({}, 1)
391 thermostatObjects=thermostatObjects+1
393 settings.put(metaData['name'], metaData['name'])
396 extractedObjectsApp1.append("//Object for class thermostat!\n")
397 extractedObjectsApp1.append("def "+metaData['name']+"\n")
398 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.thermostatObject\n")
400 extractedObjectsApp2.append("//Object for class thermostat!\n")
401 extractedObjectsApp2.append("def "+metaData['name']+"\n")
402 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.thermostatObject\n")
405 case "capability.valve":
407 case "capability.waterSensor":
409 case "capability.touchSensor":
410 if (touchSensorObjects == 0) {
411 touchSensorObject0 = metaData['name']
412 this[touchSensorObject0] = new NfcTouch({}, 1)
413 } else if (touchSensorObjects == 1) {
414 touchSensorObject1 = metaData['name']
415 this[touchSensorObject1] = new NfcTouch({}, 1)
416 } else if (touchSensorObjects == 2) {
417 touchSensorObject2 = metaData['name']
418 this[touchSensorObject2] = new NfcTouch({}, 1)
421 touchSensorObjects=touchSensorObjects+1
423 settings.put(metaData['name'], metaData['name'])
426 extractedObjectsApp1.append("//Object for class Touch Sensor!\n")
427 extractedObjectsApp1.append("def "+metaData['name']+"\n")
428 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.touchSensorObject\n")
430 extractedObjectsApp2.append("//Object for class Touch Sensor!\n")
431 extractedObjectsApp2.append("def "+metaData['name']+"\n")
432 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.touchSensorObject\n")
435 case "capability.imageCapture":
437 case "device.mobilePresence":
439 case "device.aeonKeyFob":
440 if (aeonKeyFobObjects == 0) {
441 aeonKeyFobObject0 = metaData['name']
442 this[aeonKeyFobObject0] = new AeonKeyFobs({}, 1)
443 } else if (aeonKeyFobObjects == 1) {
444 aeonKeyFobObject1 = metaData['name']
445 this[aeonKeyFobObject1] = new AeonKeyFobs({}, 1)
446 } else if (aeonKeyFobObjects == 2) {
447 aeonKeyFobObject2 = metaData['name']
448 this[aeonKeyFobObject2] = new AeonKeyFobs({}, 1)
451 aeonKeyFobObjects=aeonKeyFobObjects+1
453 settings.put(metaData['name'], metaData['name'])
456 extractedObjectsApp1.append("//Object for class aeon key fob!\n")
457 extractedObjectsApp1.append("def "+metaData['name']+"\n")
458 extractedObjectsConstructorApp1.append(metaData['name']+" = obj.aeonKeyFobObject\n")
460 extractedObjectsApp2.append("//Object for class aeon key fob!\n")
461 extractedObjectsApp2.append("def "+metaData['name']+"\n")
462 extractedObjectsConstructorApp2.append(metaData['name']+" = obj.aeonKeyFobObject\n")
466 def userInput = System.console().readLine 'Enter the mode:'
468 if (modeVariables == 0) {
469 mode0 = metaData['name']
470 this[mode0] = userInput
471 } else if (modeVariables == 1) {
472 mode1 = metaData['name']
473 this[mode1] = userInput
474 } else if (modeVariables == 2) {
475 mode2 = metaData['name']
476 this[mode2] = userInput
477 } else if (modeVariables == 3) {
478 mode3 = metaData['name']
479 this[mode3] = userInput
480 } else if (modeVariables == 4) {
481 mode4 = metaData['name']
482 this[mode4] = userInput
483 } else if (modeVariables == 5) {
484 mode5 = metaData['name']
485 this[mode5] = userInput
488 modeVariables=modeVariables+1
490 settings.put(metaData['name'], metaData['name'])
493 extractedObjectsApp1.append("//Global variable for mode!\n")
494 extractedObjectsApp1.append("def "+metaData['name']+" = \""+userInput+"\"\n")
496 extractedObjectsApp2.append("//Global variable for mode!\n")
497 extractedObjectsApp2.append("def "+metaData['name']+" = \""+userInput+"\"\n")
505 def userInput = System.console().readLine 'Enter the number:'
507 if (numberVariables == 0) {
508 number0 = metaData['name']
509 this[number0] = userInput
510 } else if (numberVariables == 1) {
511 number1 = metaData['name']
512 this[number1] = userInput
513 } else if (numberVariables == 2) {
514 number2 = metaData['name']
515 this[number2] = userInput
516 } else if (numberVariables == 3) {
517 number3 = metaData['name']
518 this[number3] = userInput
519 } else if (numberVariables == 4) {
520 number4 = metaData['name']
521 this[number4] = userInput
522 } else if (numberVariables == 5) {
523 number5 = metaData['name']
524 this[number5] = userInput
527 numberVariables=numberVariables+1
529 settings.put(metaData['name'], metaData['name'])
532 extractedObjectsApp1.append("//Global variable for number!\n")
533 extractedObjectsApp1.append("def "+metaData['name']+" = "+userInput+"\n")
535 extractedObjectsApp2.append("//Global variable for number!\n")
536 extractedObjectsApp2.append("def "+metaData['name']+" = "+userInput+"\n")
540 def userInput = System.console().readLine 'Enter the time:'
542 if (timeVariables == 0) {
543 time0 = metaData['name']
544 this[time0] = userInput
545 } else if (timeVariables == 1) {
546 time1 = metaData['name']
547 this[time1] = userInput
548 } else if (timeVariables == 2) {
549 time2 = metaData['name']
550 this[time2] = userInput
551 } else if (timeVariables == 3) {
552 time3 = metaData['name']
553 this[time3] = userInput
554 } else if (timeVariables == 4) {
555 time4 = metaData['name']
556 this[time4] = userInput
557 } else if (timeVariables == 5) {
558 time5 = metaData['name']
559 this[time5] = userInput
562 timeVariables=timeVariables+1
564 settings.put(metaData['name'], metaData['name'])
567 extractedObjectsApp1.append("//Global variable for time!\n")
568 extractedObjectsApp1.append("def "+metaData['name']+" = \""+userInput+"\"\n")
570 extractedObjectsApp2.append("//Global variable for time!\n")
571 extractedObjectsApp2.append("def "+metaData['name']+" = \""+userInput+"\"\n")
575 def userInput = System.console().readLine 'Enter the enum:'
577 if (enumVariables == 0) {
578 enum0 = metaData['name']
579 this[enum0] = userInput
580 } else if (enumVariables == 1) {
581 enum1 = metaData['name']
582 this[enum1] = userInput
583 } else if (enumVariables == 2) {
584 enum2 = metaData['name']
585 this[enum2] = userInput
586 } else if (enumVariables == 3) {
587 enum3 = metaData['name']
588 this[enum3] = userInput
589 } else if (enumVariables == 4) {
590 enum4 = metaData['name']
591 this[enum4] = userInput
592 } else if (enumVariables == 5) {
593 enum5 = metaData['name']
594 this[enum5] = userInput
597 enumVariables=enumVariables+1
599 settings.put(metaData['name'], metaData['name'])
602 extractedObjectsApp1.append("//Global variable for enum!\n")
603 extractedObjectsApp1.append("def "+metaData['name']+" = \""+userInput+"\"\n")
605 extractedObjectsApp2.append("//Global variable for enum!\n")
606 extractedObjectsApp2.append("def "+metaData['name']+" = \""+userInput+"\"\n")
612 def userInput = System.console().readLine 'Enter the phone:'
614 if (phoneVariables == 0) {
615 phone0 = metaData['name']
616 this[phone0] = userInput
617 } else if (phoneVariables == 1) {
618 phone1 = metaData['name']
619 this[phone1] = userInput
620 } else if (phoneVariables == 2) {
621 phone2 = metaData['name']
622 this[phone2] = userInput
623 } else if (phoneVariables == 3) {
624 phone3 = metaData['name']
625 this[phone3] = userInput
626 } else if (phoneVariables == 4) {
627 phone4 = metaData['name']
628 this[phone4] = userInput
629 } else if (phoneVariables == 5) {
630 phone5 = metaData['name']
631 this[phone5] = userInput
634 phoneVariables=phoneVariables+1
636 settings.put(metaData['name'], metaData['name'])
639 extractedObjectsApp1.append("//Global variable for phone!\n")
640 extractedObjectsApp1.append("def "+metaData['name']+" = "+userInput+"\n")
642 extractedObjectsApp2.append("//Global variable for phone!\n")
643 extractedObjectsApp2.append("def "+metaData['name']+" = "+userInput+"\n")
647 def userInput = System.console().readLine 'Enter the metaData['name'] of the contact:'
649 if (contactVariables == 0) {
650 contact0 = metaData['name']
651 this[contact0] = userInput
652 } else if (contactVariables == 1) {
653 contact1 = metaData['name']
654 this[contact1] = userInput
655 } else if (contactVariables == 2) {
656 contact2 = metaData['name']
657 this[contact2] = userInput
658 } else if (contactVariables == 3) {
659 contact3 = metaData['name']
660 this[contact3] = userInput
661 } else if (contactVariables == 4) {
662 contact4 = metaData['name']
663 this[contact4] = userInput
664 } else if (contactVariables == 5) {
665 contact5 = metaData['name']
666 this[contact5] = userInput
669 contactVariables=contactVariables+1
671 settings.put(metaData['name'], metaData['name'])
674 extractedObjectsApp1.append("//Global variable for contact!\n")
675 extractedObjectsApp1.append("def "+metaData['name']+" = \""+userInput+"\"\n")
677 extractedObjectsApp2.append("//Global variable for contact!\n")
678 extractedObjectsApp2.append("def "+metaData['name']+" = \""+userInput+"\"\n")
686 def label(LinkedHashMap metaData) {
687 if (metaData.containsKey('title')) {
688 println metaData['title']
690 if (metaData.containsKey('options')) {
691 println "Options: "+metaData['options']
694 println("//IGNORE--ForMobileUse//")
697 def mode(LinkedHashMap metaData) {
698 if (metaData.containsKey('title')) {
699 println metaData['title']
701 if (metaData.containsKey('options')) {
702 println "Options: "+metaData['options']
705 println("//IGNORE--ForMobileUse//")
707 /////Input Methods/////
710 /////MethodsForExtraction/////
711 def definition(LinkedHashMap metaData) {
712 println("///Just some information///")
715 def preferences(Closure inputData) {
716 find(inputData) //Run the closure to extract pages/sections/inputMethods
718 extractedObjectsConstructorApp1.append("//Global variable for settings!\n")
719 extractedObjectsConstructorApp1.append("settings = $settings\n")
721 extractedObjectsConstructorApp2.append("//Global variable for settings!\n")
722 extractedObjectsConstructorApp2.append("settings = $settings\n")
726 def page(LinkedHashMap metaData, Closure inputData) {
727 if (metaData.containsKey('name'))
728 println(metaData['name'])
729 if (metaData.containsKey('title'))
730 println(metaData['title'])
732 find(inputData) //Run the closure to extract sections/inputMethods
735 def page(LinkedHashMap metaData) {
736 def nameOfFunction = metaData['name']
737 "$nameOfFunction"() //Call the page
740 def dynamicPage(LinkedHashMap metaData, Closure inputData) {
741 if (metaData.containsKey('name'))
742 println(metaData['name'])
743 if (metaData.containsKey('title'))
744 println(metaData['title'])
746 find(inputData) //Run the closure to extract sections/inputMethods
749 def section(String title, Closure inputData) {
751 find(inputData) //Run the closure to extract inputMethods
754 def section(Closure inputData) {
755 find(inputData) //Run the closure to extract inputMethods
758 def section(LinkedHashMap metaData, Closure inputData) {
759 find(inputData) //Run the closure to extract inputMethods
761 /////MethodsForExtraction/////
767 name: "NFC Tag Toggle",
768 namespace: "smartthings",
769 author: "SmartThings",
770 description: "Allows toggling of a switch, lock, or garage door based on an NFC Tag touch event",
771 category: "SmartThings Internal",
772 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Developers/nfc-tag-executor.png",
773 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Developers/nfc-tag-executor@2x.png",
774 iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Developers/nfc-tag-executor@2x.png")
778 page(name: "pageOne", title: "Device selection", uninstall: true, nextPage: "pageTwo") {
779 section("Select an NFC tag") {
780 input "tag", "capability.touchSensor", title: "NFC Tag"
782 section("Select devices to control") {
783 input "switch1", "capability.switch", title: "Light or switch", required: false, multiple: true
784 input "lock", "capability.lock", title: "Lock", required: false, multiple: true
785 input "garageDoor", "capability.doorControl", title: "Garage door controller", required: false, multiple: true
789 page(name: "pageTwo", title: "Master devices", install: true, uninstall: true)
793 dynamicPage(name: "pageTwo") {
794 section("If set, the state of these devices will be toggled each time the tag is touched, " +
795 "e.g. a light that's on will be turned off and one that's off will be turned on, " +
796 "other devices of the same type will be set to the same state as their master device. " +
797 "If no master is designated then the majority of devices of the same type will be used " +
798 "to determine whether to turn on or off the devices.") {
800 if (switch1 || masterSwitch) {
801 input "masterSwitch", "enum", title: "Master switch", options: switch1.collect{[(it.id): it.displayName]}, required: false
803 if (lock || masterLock) {
804 input "masterLock", "enum", title: "Master lock", options: lock.collect{[(it.id): it.displayName]}, required: false
806 if (garageDoor || masterDoor) {
807 input "masterDoor", "enum", title: "Master door", options: garageDoor.collect{[(it.id): it.displayName]}, required: false
810 section([mobileOnly:true]) {
811 label title: "Assign a name", required: false
812 mode title: "Set for specific mode(s)", required: false
818 log.debug "Installed with settings: ${settings}"
824 log.debug "Updated with settings: ${settings}"
831 subscribe tag, "nfcTouch", touchHandler
832 subscribe app, touchHandler
835 private currentStatus(devices, master, attribute) {
836 log.trace "currentStatus($devices, $master, $attribute)"
839 result = devices.find{it.id == master}?.currentValue(attribute)
844 def value = it.currentValue(attribute)
845 map[value] = (map[value] ?: 0) + 1
846 log.trace "$it.displayName: $value"
849 result = map.collect{it}.sort{it.value}[-1].key
851 log.debug "$attribute = $result"
855 def touchHandler(evt) {
856 log.trace "touchHandler($evt.descriptionText)"
858 def status = currentStatus(switch1, masterSwitch, "switch")
860 if (status == "on") {
870 def status = currentStatus(lock, masterLock, "lock")
872 if (status == "locked") {
882 def status = currentStatus(garageDoor, masterDoor, "status")
884 if (status == "open") {