Changes in classes: new concept for latest value + all types of events generated...
[smartthings-infrastructure.git] / Extractor / App1 / App1.groovy
index 94ec37c73a6ba5e5fbec131bfd6c9a90f29bedae..b41e7a6be0e0f7dffcca08fbf330f51c8ea43130 100644 (file)
+/**
+ *     Color Coordinator 
+ *  Version 1.1.1 - 11/9/16
+ *  By Michael Struck
+ *
+ *  1.0.0 - Initial release
+ *  1.1.0 - Fixed issue where master can be part of slaves. This causes a loop that impacts SmartThings. 
+ *  1.1.1 - Fix NPE being thrown for slave/master inputs being empty.
+ *
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ *  in compliance with the License. You may obtain a copy of the License at:
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
+ *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
+ *  for the specific language governing permissions and limitations under the License.
+ *
+ */
 definition(
-    name: "Enhanced Auto Lock Door",
-    namespace: "Lock Auto Super Enhanced",
-    author: "Arnaud",
-    description: "Automatically locks a specific door after X minutes when closed  and unlocks it when open after X seconds.",
-    category: "Safety & Security",
-    iconUrl: "http://www.gharexpert.com/mid/4142010105208.jpg",
-    iconX2Url: "http://www.gharexpert.com/mid/4142010105208.jpg"
+       name: "Color Coordinator",
+       namespace: "MichaelStruck",
+       author: "Michael Struck",
+       description: "Ties multiple colored lights to one specific light's settings",
+       category: "Convenience",
+       iconUrl: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/ColorCoordinator/CC.png",
+       iconX2Url: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/ColorCoordinator/CC@2x.png"
 )
 
-preferences{
-    section("Select the door lock:") {
-        input "lock1", "capability.lock", required: true
-    }
-    section("Select the door contact sensor:") {
-        input "contact", "capability.contactSensor", required: true
-    }   
-    section("Automatically lock the door when closed...") {
-        input "minutesLater", "number", title: "Delay (in minutes):", required: true
-    }
-    section("Automatically unlock the door when open...") {
-        input "secondsLater", "number", title: "Delay (in seconds):", required: true
-    }
-    section( "Notifications" ) {
-        input("recipients", "contact", title: "Send notifications to", required: false) {
-            input "phoneNumber", "phone", title: "Warn with text message (optional)", description: "Phone Number", required: false
+preferences {
+       page name: "mainPage"
+}
+
+def mainPage() {
+       section("Master Light") {
+               input "master", "capability.colorControl", title: "Colored Light", required: true
+       }
+       section("Lights that follow the master settings") {
+               input "slaves", "capability.colorControl", title: "Colored Lights",  multiple: true, required: true, submitOnChange: true
+       }
+       section([mobileOnly:true], "Options") {
+               input "randomYes", "bool",title: "When Master Turned On, Randomize Color", defaultValue: false
+               href "pageAbout", title: "About ${textAppName()}", description: "Tap to get application version, license and instructions"
+        }
+       
+       dynamicPage(name: "mainPage", title: "", install: true, uninstall: false) {
+       def masterInList = slaves?.id?.find{it==master?.id}
+        if (masterInList) {
+               section ("**WARNING**"){
+                       paragraph "You have included the Master Light in the Slave Group. This will cause a loop in execution. Please remove this device from the Slave Group.", image: "https://raw.githubusercontent.com/MichaelStruck/SmartThingsPublic/master/img/caution.png"
+               }
         }
-    }
+        
+       page(name: "pageAbout", title: "About ${textAppName()}", uninstall: true) {
+                       section {
+                               paragraph "${textVersion()}\n${textCopyright()}\n\n${textLicense()}\n"
+                       }
+                       section("Instructions") {
+                               paragraph textHelp()
+                       }
+                       section("Tap button below to remove application"){
+                       }
+               }
+               
+       }
 }
 
-def installed(){
-    initialize()
+def installed() {   
+       init() 
 }
 
 def updated(){
-    unsubscribe()
-    unschedule()
-    initialize()
+       unsubscribe()
+    init()
 }
 
-def initialize(){
-    log.debug "Settings: ${settings}"
-    subscribe(lock1, "lock", doorHandler, [filterEvents: false])
-    subscribe(lock1, "unlock", doorHandler, [filterEvents: false])  
-    subscribe(contact, "contact.open", doorHandler)
-    subscribe(contact, "contact.closed", doorHandler)
+def init() {
+    subscribe(master, "switch", onOffHandler)
+    subscribe(master, "level", colorHandler)
+    subscribe(master, "hue", colorHandler)
+    subscribe(master, "saturation", colorHandler)
+    subscribe(master, "colorTemperature", tempHandler)
+}
+//-----------------------------------
+def onOffHandler(evt){
+       if (slaves && master) {
+               if (!slaves?.id.find{it==master?.id}){
+               if (master?.currentValue("switch") == "on"){
+                   if (randomYes) getRandomColorMaster()
+                               else slaves?.on()
+               }
+               else {
+                   slaves?.off()  
+               }
+               }
+       }
 }
 
-def lockDoor(){
-    log.debug "Locking the door."
-    lock1.lock()
-    if(location.contactBookEnabled) {
-        if ( recipients ) {
-            log.debug ( "Sending Push Notification..." ) 
-            sendNotificationToContacts( "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!", recipients)
-        }
-    }
-    if (phoneNumber) {
-        log.debug("Sending text message...")
-        sendSms( phoneNumber, "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!")
-    }
+def colorHandler(evt) {
+       if (slaves && master) {
+               if (!slaves?.id?.find{it==master?.id} && master?.currentValue("switch") == "on"){
+                       log.debug "Changing Slave units H,S,L"
+               def dimLevel = master?.currentValue("level")
+               def hueLevel = master?.currentValue("hue")
+               def saturationLevel = master.currentValue("saturation")
+                       def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
+               slaves?.setColor(newValue)
+               try {
+                       log.debug "Changing Slave color temp"
+                       def tempLevel = master?.currentValue("colorTemperature")
+                       slaves?.setColorTemperature(tempLevel)
+               }
+                       catch (e){
+                       log.debug "Color temp for master --"
+               }
+               }
+       }
 }
 
-def unlockDoor(){
-    log.debug "Unlocking the door."
-    lock1.unlock()
-    if(location.contactBookEnabled) {
-        if ( recipients ) {
-            log.debug ( "Sending Push Notification..." ) 
-            sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!", recipients)
-        }
-    }
-    if ( phoneNumber ) {
-        log.debug("Sending text message...")
-        sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!")
-    }
+def getRandomColorMaster(){
+    def hueLevel = Math.floor(Math.random() *1000)
+    def saturationLevel = Math.floor(Math.random() * 100)
+    def dimLevel = master?.currentValue("level")
+       def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
+    log.debug hueLevel
+    log.debug saturationLevel
+    master.setColor(newValue)
+    slaves?.setColor(newValue)   
 }
 
-def doorHandler(evt){
-    if ((contact.latestValue("contact") == "open") && (evt.value == "locked")) { // If the door is open and a person locks the door then...  
-        //def delay = (secondsLater) // runIn uses seconds
-        runIn( secondsLater, unlockDoor )   // ...schedule (in minutes) to unlock...  We don't want the door to be closed while the lock is engaged. 
-    }
-    else if ((contact.latestValue("contact") == "open") && (evt.value == "unlocked")) { // If the door is open and a person unlocks it then...
-        unschedule( unlockDoor ) // ...we don't need to unlock it later.
-    }
-    else if ((contact.latestValue("contact") == "closed") && (evt.value == "locked")) { // If the door is closed and a person manually locks it then...
-        unschedule( lockDoor ) // ...we don't need to lock it later.
-    }   
-    else if ((contact.latestValue("contact") == "closed") && (evt.value == "unlocked")) { // If the door is closed and a person unlocks it then...
-       //def delay = (minutesLater * 60) // runIn uses seconds
-        runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
-    }
-    else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "open")) { // If a person opens an unlocked door...
-        unschedule( lockDoor ) // ...we don't need to lock it later.
-    }
-    else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "closed")) { // If a person closes an unlocked door...
-        //def delay = (minutesLater * 60) // runIn uses seconds
-        runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
-    }
-    else { //Opening or Closing door when locked (in case you have a handle lock)
-        log.debug "Unlocking the door."
-        lock1.unlock()
-        if(location.contactBookEnabled) {
-            if ( recipients ) {
-                log.debug ( "Sending Push Notification..." ) 
-                sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!", recipients)
-            }
-        }
-        if ( phoneNumber ) {
-            log.debug("Sending text message...")
-            sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!")
-        }
-    }
+def tempHandler(evt){
+       if (slaves && master) {
+           if (!slaves?.id?.find{it==master?.id} && master?.currentValue("switch") == "on"){
+               if (evt.value != "--") {
+                   log.debug "Changing Slave color temp based on Master change"
+                   def tempLevel = master.currentValue("colorTemperature")
+                   slaves?.setColorTemperature(tempLevel)
+               }
+               }
+       }
 }
+
+//Version/Copyright/Information/Help
+
+private def textAppName() {
+       def text = "Color Coordinator"
+}      
+
+private def textVersion() {
+    def text = "Version 1.1.1 (12/13/2016)"
+}
+
+private def textCopyright() {
+    def text = "Copyright © 2016 Michael Struck"
+}
+
+private def textLicense() {
+    def text =
+               "Licensed under the Apache License, Version 2.0 (the 'License'); "+
+               "you may not use this file except in compliance with the License. "+
+               "You may obtain a copy of the License at"+
+               "\n\n"+
+               "    http://www.apache.org/licenses/LICENSE-2.0"+
+               "\n\n"+
+               "Unless required by applicable law or agreed to in writing, software "+
+               "distributed under the License is distributed on an 'AS IS' BASIS, "+
+               "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. "+
+               "See the License for the specific language governing permissions and "+
+               "limitations under the License."
+}
+
+private def textHelp() {
+       def text =
+       "This application will allow you to control the settings of multiple colored lights with one control. " +
+        "Simply choose a master control light, and then choose the lights that will follow the settings of the master, "+
+        "including on/off conditions, hue, saturation, level and color temperature. Also includes a random color feature."
+}
+