import MobilePresence.MobilePresence
import MobilePresence.MobilePresences
import Event.Event
-import AtomicState.AtomicState
import Timer.SimulatedTimer
//JPF's Verify API
for (int i = 0;i < app2.eventList.size();i++) {
if (app2.eventList[i] == name) {
def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
- app2.functionList[i](event)
+ if (app2.functionList[i] instanceof String) {
+ String toCall = app2.functionList[i]
+ app2."$toCall"(event)
+ }
+ else
+ app2.functionList[i](event)
}
}
for (int i = 0;i < app1.eventList.size();i++) {
if (app1.eventList[i] == name) {
def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data)
- app1.functionList[i](event)
+ if (app1.functionList[i] instanceof String) {
+ String toCall = app1.functionList[i]
+ app1."$toCall"(event)
+ }
+ else
+ app1.functionList[i](event)
}
}
}
@Field def appObject = new Touched(sendEvent, 0)
//Create a global list for events
//@Field def evt = []
-//Global Object for class AtomicState!
-@Field def atomicState = new AtomicState()
//Global Object for class Touch Sensor!
@Field def touchSensorObject = new NfcTouch(sendEvent, 1)
//Global Object for class switch!
def reference
def location
def app
- def atomicState
//Extracted objects for App1
- //Object for class lock!
- def lock1
- //Object for class contactSensor!
- def contact
- //Global variable for number!
- def minutesLater = 70
- //Global variable for number!
- def secondsLater = 93
- //Global variable for contact!
- def recipients = "AJ"
- //Global variable for phone!
- def phoneNumber = 9495379373
+ //Object for class color control!
+ def master
+ //Object for class color control!
+ def slaves
+ //Global variable for boolean!
+ def randomYes = "1"
//Extracted objects for functions for App1
//Global Object for functions in subscribe method!
+ def mainPage = this.&mainPage
+ //Global Object for functions in subscribe method!
def installed = this.&installed
//Global Object for functions in subscribe method!
def updated = this.&updated
//Global Object for functions in subscribe method!
- def initialize = this.&initialize
+ def init = this.&init
+ //Global Object for functions in subscribe method!
+ def onOffHandler = this.&onOffHandler
+ //Global Object for functions in subscribe method!
+ def colorHandler = this.&colorHandler
+ //Global Object for functions in subscribe method!
+ def getRandomColorMaster = this.&getRandomColorMaster
+ //Global Object for functions in subscribe method!
+ def tempHandler = this.&tempHandler
+ //Global Object for functions in subscribe method!
+ def textAppName = this.&textAppName
+ //Global Object for functions in subscribe method!
+ def textVersion = this.&textVersion
//Global Object for functions in subscribe method!
- def lockDoor = this.&lockDoor
+ def textCopyright = this.&textCopyright
//Global Object for functions in subscribe method!
- def unlockDoor = this.&unlockDoor
+ def textLicense = this.&textLicense
//Global Object for functions in subscribe method!
- def doorHandler = this.&doorHandler
+ def textHelp = this.&textHelp
App1(Object obj) {
reference = obj
location = obj.locationObject
app = obj.appObject
- atomicState = obj.atomicState
- lock1 = obj.lockObject
- contact = obj.contactObject
+ master = obj.colorControlObject
+ slaves = obj.colorControlObject
//Global variable for settings!
- settings = [app:app, lock1:lock1, contact:contact, minutesLater:minutesLater, secondsLater:secondsLater, recipients:recipients, phoneNumber:phoneNumber]
+ settings = [app: app, master: master, slaves: slaves, randomYes: randomYes, END: "END"]
}
//Global variables for each app
//Global variable for state[mode]
def settings
//Zip code
def zipCode = 92617
+ //atomicState variable
+ def atomicState = [version: "1.01"]
//Methods
/////////////////////////////////////////////////////////////////////
def setLocationMode(String mode) {
- location.mode = mode
+ location.setValue([name: "Location", value: "$mode", deviceId: "locationID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+ location.setValue([name: "mode", value: "$mode", deviceId: "locationID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
}
/////////////////////////////////////////////////////////////////////
eventList.add(event)
functionList.add(FunctionToCall)
}
+ ////subscribe(obj, event, nameOfFunc)
+ def subscribe(Object obj, String event, String nameOfFunction) {
+ objectList.add(obj)
+ eventList.add(event)
+ functionList.add(nameOfFunction)
+ }
////subscribe(obj, event, func, data)
def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
objectList.add(obj)
}
}
+ def unschedule(String nameOfFunctionToUnschedule) {
+ for (int i = 0;i < timersFuncList.size();i++) {
+ if (timersFuncList[i] instanceof String) {
+ if (timersFuncList[i] == nameOfFunctionToUnschedule) {
+ if (timersList != null)
+ timersList[i].cancel()
+ }
+ }
+ }
+ }
+
def unschedule() {
for (int i = 0;i < timersFuncList.size();i++) {
}
}
}
+
+ def sendNotificationToContacts(String text, String recipients, LinkedHashMap metaData) {
+ for (int i = 0;i < recipients.size();i++) {
+ for (int j = 0;j < location.contacts.size();j++) {
+ if (recipients[i] == location.contacts[j]) {
+ println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
+ }
+ }
+ }
+ }
/////////////////////////////////////////////////////////////////////
////sendSms(phone, text)
def sendSms(long phoneNumber, String text) {
def canSchedule() {
return true
}
+ /////////////////////////////////////////////////////////////////////
+ def createAccessToken() {
+ state.accessToken = "accessToken"
+ return state.accessToken
+ }
+ /////////////////////////////////////////////////////////////////////
+ def runOnce(Date date, Closure methodToCall) {
+ methodTocall()
+ }
- def installed(){
- initialize()
+ 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() {
+ init()
}
def updated(){
- unsubscribe()
- unschedule()
- initialize()
+ unsubscribe()
+ init()
+ }
+
+ 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 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 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 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 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 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)
+ }
+ }
+ }
}
- 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!")
- }
+ //Version/Copyright/Information/Help
+
+ private def textAppName() {
+ def text = "Color Coordinator"
+ }
+
+ private def textVersion() {
+ def text = "Version 1.1.1 (12/13/2016)"
}
- 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!")
- }
- }
+ 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."
}
+
}
def reference
def location
def app
- def atomicState
//Extracted objects for App2
+ //Object for class contactSensor!
+ def deviceContactSensor
//Global variable for time!
- def starting = "15:00"
- //Global variable for time!
- def ending = "15:00"
- //Object for class beacon sensor!
- def beacons
- //Object for class mobile presence!
- def phones
- //Global variable for enum!
- def arrivalPhrase = "Good Night!"
- //Object for class switch!
- def arrivalOnSwitches
- //Object for class switch!
- def arrivalOffSwitches
- //Object for class lock!
- def arrivalLocks
- //Global variable for enum!
- def departPhrase = "Good Night!"
- //Object for class switch!
- def departOnSwitches
- //Object for class switch!
- def departOffSwitches
- //Object for class lock!
- def departLocks
- //Global variable for boolean!
- def pushNotification = "0"
- //Global variable for phone!
- def phone = 9495379373
- //Global variable for enum!
- def days = "Monday"
- //Global variable for mode!
- def modes = "night"
+ def reminderTime = "15:00"
+ //Object for class color control!
+ def deviceLight
//Extracted objects for functions for App2
//Global Object for functions in subscribe method!
- def mainPage = this.&mainPage
- //Global Object for functions in subscribe method!
def installed = this.&installed
//Global Object for functions in subscribe method!
def updated = this.&updated
//Global Object for functions in subscribe method!
def initialize = this.&initialize
//Global Object for functions in subscribe method!
- def beaconHandler = this.&beaconHandler
- //Global Object for functions in subscribe method!
- def arriveActions = this.&arriveActions
- //Global Object for functions in subscribe method!
- def departActions = this.&departActions
- //Global Object for functions in subscribe method!
- def prefix = this.&prefix
- //Global Object for functions in subscribe method!
- def listPhrases = this.&listPhrases
- //Global Object for functions in subscribe method!
- def executePhrase = this.&executePhrase
+ def contactHandler = this.&contactHandler
//Global Object for functions in subscribe method!
- def getBeaconName = this.&getBeaconName
+ def checkOpenDrawInPast = this.&checkOpenDrawInPast
//Global Object for functions in subscribe method!
- def getPhoneName = this.&getPhoneName
+ def checkOpenDrawAfterReminder = this.&checkOpenDrawAfterReminder
//Global Object for functions in subscribe method!
- def hideOptionsSection = this.&hideOptionsSection
+ def sendNotification = this.&sendNotification
//Global Object for functions in subscribe method!
- def getAllOk = this.&getAllOk
+ def isOpened = this.&isOpened
//Global Object for functions in subscribe method!
- def getModeOk = this.&getModeOk
+ def setLEDNotification = this.&setLEDNotification
//Global Object for functions in subscribe method!
- def getDaysOk = this.&getDaysOk
- //Global Object for functions in subscribe method!
- def getTimeOk = this.&getTimeOk
- //Global Object for functions in subscribe method!
- def hhmm = this.&hhmm
- //Global Object for functions in subscribe method!
- def timeIntervalLabel = this.&timeIntervalLabel
- //Global Object for functions in subscribe method!
- def list = this.&list
+ def resetLEDNotification = this.&resetLEDNotification
App2(Object obj) {
reference = obj
location = obj.locationObject
app = obj.appObject
- atomicState = obj.atomicState
- beacons = obj.beaconSensorObject
- phones = obj.mobilePresenceObject
- arrivalOnSwitches = obj.switchObject
- arrivalOffSwitches = obj.switchObject
- arrivalLocks = obj.lockObject
- departOnSwitches = obj.switchObject
- departOffSwitches = obj.switchObject
- departLocks = obj.lockObject
+ deviceContactSensor = obj.contactObject
+ deviceLight = obj.colorControlObject
//Global variable for settings!
- settings = [app:app, starting:starting, ending:ending, beacons:beacons, phones:phones, arrivalPhrase:arrivalPhrase, arrivalOnSwitches:arrivalOnSwitches, arrivalOffSwitches:arrivalOffSwitches, arrivalLocks:arrivalLocks, departPhrase:departPhrase, departOnSwitches:departOnSwitches, departOffSwitches:departOffSwitches, departLocks:departLocks, pushNotification:pushNotification, phone:phone, days:days, modes:modes]
+ settings = [app: app, deviceContactSensor: deviceContactSensor, reminderTime: reminderTime, deviceLight: deviceLight, END: "END"]
}
//Global variables for each app
//Global variable for state[mode]
def settings
//Zip code
def zipCode = 92617
+ //atomicState variable
+ def atomicState = [version: "1.01"]
//Methods
/////////////////////////////////////////////////////////////////////
def setLocationMode(String mode) {
- location.mode = mode
+ location.setValue([name: "Location", value: "$mode", deviceId: "locationID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+ location.setValue([name: "mode", value: "$mode", deviceId: "locationID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
}
/////////////////////////////////////////////////////////////////////
eventList.add(event)
functionList.add(FunctionToCall)
}
+ ////subscribe(obj, event, nameOfFunc)
+ def subscribe(Object obj, String event, String nameOfFunction) {
+ objectList.add(obj)
+ eventList.add(event)
+ functionList.add(nameOfFunction)
+ }
////subscribe(obj, event, func, data)
def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) {
objectList.add(obj)
}
}
+ def unschedule(String nameOfFunctionToUnschedule) {
+ for (int i = 0;i < timersFuncList.size();i++) {
+ if (timersFuncList[i] instanceof String) {
+ if (timersFuncList[i] == nameOfFunctionToUnschedule) {
+ if (timersList != null)
+ timersList[i].cancel()
+ }
+ }
+ }
+ }
+
def unschedule() {
for (int i = 0;i < timersFuncList.size();i++) {
}
}
}
+
+ def sendNotificationToContacts(String text, String recipients, LinkedHashMap metaData) {
+ for (int i = 0;i < recipients.size();i++) {
+ for (int j = 0;j < location.contacts.size();j++) {
+ if (recipients[i] == location.contacts[j]) {
+ println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString())
+ }
+ }
+ }
+ }
/////////////////////////////////////////////////////////////////////
////sendSms(phone, text)
def sendSms(long phoneNumber, String text) {
def canSchedule() {
return true
}
-
- def mainPage() {
- dynamicPage(name: "mainPage", install: true, uninstall: true) {
-
- section("Where do you want to watch?") {
- input name: "beacons", type: "capability.beacon", title: "Select your beacon(s)",
- multiple: true, required: true
- }
-
- section("Who do you want to watch for?") {
- input name: "phones", type: "device.mobilePresence", title: "Select your phone(s)",
- multiple: true, required: true
- }
-
- section("What do you want to do on arrival?") {
- input name: "arrivalPhrase", type: "enum", title: "Execute a phrase",
- options: listPhrases(), required: false
- input "arrivalOnSwitches", "capability.switch", title: "Turn on some switches",
- multiple: true, required: false
- input "arrivalOffSwitches", "capability.switch", title: "Turn off some switches",
- multiple: true, required: false
- input "arrivalLocks", "capability.lock", title: "Unlock the door",
- multiple: true, required: false
- }
-
- section("What do you want to do on departure?") {
- input name: "departPhrase", type: "enum", title: "Execute a phrase",
- options: listPhrases(), required: false
- input "departOnSwitches", "capability.switch", title: "Turn on some switches",
- multiple: true, required: false
- input "departOffSwitches", "capability.switch", title: "Turn off some switches",
- multiple: true, required: false
- input "departLocks", "capability.lock", title: "Lock the door",
- multiple: true, required: false
- }
-
- section("Do you want to be notified?") {
- input "pushNotification", "bool", title: "Send a push notification"
- input "phone", "phone", title: "Send a text message", description: "Tap to enter phone number",
- required: false
- }
-
- section {
- label title: "Give your automation a name", description: "e.g. Goodnight Home, Wake Up"
- }
-
- def timeLabel = timeIntervalLabel()
- section(title: "More options", hidden: hideOptionsSection(), hideable: true) {
- href "timeIntervalInput", title: "Only during a certain time",
- description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : "incomplete"
-
- input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
- options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
-
- input "modes", "mode", title: "Only when mode is", multiple: true, required: false
- }
- }
+ /////////////////////////////////////////////////////////////////////
+ def createAccessToken() {
+ state.accessToken = "accessToken"
+ return state.accessToken
}
-
- // Lifecycle management
+ /////////////////////////////////////////////////////////////////////
+ def runOnce(Date date, Closure methodToCall) {
+ methodTocall()
+ }
+
def installed() {
- log.debug "<beacon-control> Installed with settings: ${settings}"
+ log.debug "Installed with settings: ${settings}"
+
initialize()
}
def updated() {
- log.debug "<beacon-control> Updated with settings: ${settings}"
+ log.debug "Updated with settings: ${settings}"
+
unsubscribe()
+
initialize()
}
def initialize() {
- subscribe(beacons, "presence", beaconHandler)
- }
-
- // Event handlers
- def beaconHandler(evt) {
- log.debug "<beacon-control> beaconHandler: $evt"
-
- if (allOk) {
- def data = new groovy.json.JsonSlurper().parseText(evt.data)
- // removed logging of device names. can be added back for debugging
- //log.debug "<beacon-control> data: $data - phones: " + phones*.deviceNetworkId
-
- def beaconName = getBeaconName(evt)
- // removed logging of device names. can be added back for debugging
- //log.debug "<beacon-control> beaconName: $beaconName"
-
- def phoneName = getPhoneName(data)
- // removed logging of device names. can be added back for debugging
- //log.debug "<beacon-control> phoneName: $phoneName"
- if (phoneName != null) {
- def action = data.presence == "1" ? "arrived" : "left"
- def msg = "$phoneName has $action ${action == 'arrived' ? 'at ' : ''}the $beaconName"
-
- if (action == "arrived") {
- msg = arriveActions(msg)
- }
- else if (action == "left") {
- msg = departActions(msg)
- }
- log.debug "<beacon-control> msg: $msg"
- if (pushNotification || phone) {
- def options = [
- method: (pushNotification && phone) ? "both" : (pushNotification ? "push" : "sms"),
- phone: phone
- ]
- sendNotification(msg, options)
- }
+ // will stop LED notification incase it was set by med reminder
+ subscribe(deviceContactSensor, "contact", contactHandler)
+
+ // how many minutes to look in the past from the reminder time, for an open draw
+ state.minutesToCheckOpenDraw = 60
+
+ // is true when LED notification is set after exceeding 10 minutes past reminder time
+ state.ledNotificationTriggered = false
+
+ // Set a timer to run once a day to notify if draw wasn't opened yet
+ schedule(reminderTime, checkOpenDrawInPast)
+
+ }
+
+ // Should turn off any LED notification on OPEN state
+ def contactHandler(evt){
+ if (evt.value == "open") {
+ // if LED notification triggered, reset it.
+ log.debug "Cabinet opened"
+ if (state.ledNotificationTriggered) {
+ resetLEDNotification()
}
}
}
- // Helpers
- private arriveActions(msg) {
- if (arrivalPhrase || arrivalOnSwitches || arrivalOffSwitches || arrivalLocks) msg += ", so"
-
- if (arrivalPhrase) {
- log.debug "<beacon-control> executing: $arrivalPhrase"
- executePhrase(arrivalPhrase)
- msg += " ${prefix('executed')} $arrivalPhrase."
- }
- if (arrivalOnSwitches) {
- log.debug "<beacon-control> turning on: $arrivalOnSwitches"
- arrivalOnSwitches.on()
- msg += " ${prefix('turned')} ${list(arrivalOnSwitches)} on."
- }
- if (arrivalOffSwitches) {
- log.debug "<beacon-control> turning off: $arrivalOffSwitches"
- arrivalOffSwitches.off()
- msg += " ${prefix('turned')} ${list(arrivalOffSwitches)} off."
- }
- if (arrivalLocks) {
- log.debug "<beacon-control> unlocking: $arrivalLocks"
- arrivalLocks.unlock()
- msg += " ${prefix('unlocked')} ${list(arrivalLocks)}."
- }
- msg
- }
-
- private departActions(msg) {
- if (departPhrase || departOnSwitches || departOffSwitches || departLocks) msg += ", so"
-
- if (departPhrase) {
- log.debug "<beacon-control> executing: $departPhrase"
- executePhrase(departPhrase)
- msg += " ${prefix('executed')} $departPhrase."
- }
- if (departOnSwitches) {
- log.debug "<beacon-control> turning on: $departOnSwitches"
- departOnSwitches.on()
- msg += " ${prefix('turned')} ${list(departOnSwitches)} on."
- }
- if (departOffSwitches) {
- log.debug "<beacon-control> turning off: $departOffSwitches"
- departOffSwitches.off()
- msg += " ${prefix('turned')} ${list(departOffSwitches)} off."
- }
- if (departLocks) {
- log.debug "<beacon-control> unlocking: $departLocks"
- departLocks.lock()
- msg += " ${prefix('locked')} ${list(departLocks)}."
- }
- msg
- }
-
- private prefix(word) {
- def result
- def index = settings.prefixIndex == null ? 0 : settings.prefixIndex + 1
- switch (index) {
- case 0:
- result = "I $word"
- break
- case 1:
- result = "I also $word"
- break
- case 2:
- result = "And I $word"
- break
- default:
- result = "And $word"
- break
- }
-
- settings.prefixIndex = index
- log.trace "prefix($word'): $result"
- result
- }
-
- private listPhrases() {
- location.helloHome.getPhrases().label
- }
-
- private executePhrase(phraseName) {
- if (phraseName) {
- location.helloHome.execute(phraseName)
- log.debug "<beacon-control> executed phrase: $phraseName"
- }
- }
-
- private getBeaconName(evt) {
- def beaconName = beacons.find { b -> b.id == evt.deviceId }
- return beaconName
+ // If the draw was NOT opened within 60 minutes of the timer send notification out.
+ def checkOpenDrawInPast(){
+ log.debug "Checking past 60 minutes of activity from $reminderTime"
+
+ // check activity of sensor for past 60 minutes for any OPENED status
+ def cabinetOpened = isOpened(state.minutesToCheckOpenDraw)
+ log.debug "Cabinet found opened: $cabinetOpened"
+
+ // if it's opened, then do nothing and assume they took their meds
+ if (!cabinetOpened) {
+ sendNotification("Hi, please remember to take your meds in the cabinet")
+
+ // if no open activity, send out notification and set new reminder
+ def reminderTimePlus10 = new Date(now() + (10 * 60000))
+
+ // needs to be scheduled if draw wasn't already opened
+ runOnce(reminderTimePlus10, checkOpenDrawAfterReminder)
+ }
}
- private getPhoneName(data) {
- def phoneName = phones.find { phone ->
- // Work around DNI bug in data
- def pParts = phone.deviceNetworkId.split('\\|')
- def dParts = data.dni.split('\\|')
- pParts[0] == dParts[0]
+ // If the draw was NOT opened after 10 minutes past reminder, use LED notification
+ def checkOpenDrawAfterReminder(){
+ log.debug "Checking additional 10 minutes of activity from $reminderTime"
+
+ // check activity of sensor for past 10 minutes for any OPENED status
+ def cabinetOpened = isOpened(10)
+
+ log.debug "Cabinet found opened: $cabinetOpened"
+
+ // if no open activity, blink lights
+ if (!cabinetOpened) {
+ log.debug "Set LED to Notification color"
+ setLEDNotification()
+ }
+
+ }
+
+ // Helper function for sending out an app notification
+ def sendNotification(msg){
+ log.debug "Message Sent: $msg"
+ sendPush(msg)
+ }
+
+ // Check if the sensor has been opened since the minutes entered
+ // Return true if opened found, else false.
+ def isOpened(minutes){
+ // query last X minutes of activity log
+ def previousDateTime = new Date(now() - (minutes * 60000))
+
+ // capture all events recorded
+ def evts = deviceContactSensor.eventsSince(previousDateTime)
+ def cabinetOpened = false
+ if (evts.size() > 0) {
+ evts.each{
+ if(it.value == "open") {
+ cabinetOpened = true
+ }
+ }
}
- return phoneName
+
+ return cabinetOpened
}
- private hideOptionsSection() {
- (starting || ending || days || modes) ? false : true
- }
-
- private getAllOk() {
- modeOk && daysOk && timeOk
- }
+ // Saves current color and sets the light to RED
+ def setLEDNotification(){
- private getModeOk() {
- def result = !modes || modes.contains(location.mode)
- log.trace "<beacon-control> modeOk = $result"
- result
- }
+ state.ledNotificationTriggered = true
+
+ // turn light back off when reset is called if it was originally off
+ state.ledState = deviceLight.currentValue("switch")
- private getDaysOk() {
- def result = true
- if (days) {
- def df = new java.text.SimpleDateFormat("EEEE")
- if (location.timeZone) {
- df.setTimeZone(location.timeZone)
- }
- else {
- df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
- }
- def day = df.format(new Date())
- result = days.contains(day)
- }
- log.trace "<beacon-control> daysOk = $result"
- result
- }
+ // set light to RED and store original color until stopped
+ state.origColor = deviceLight.currentValue("hue")
+ deviceLight.on()
+ deviceLight.setHue(100)
+
+ log.debug "LED set to RED. Original color stored: $state.origColor"
- private getTimeOk() {
- def result = true
- if (starting && ending) {
- def currTime = now()
- def start = timeToday(starting, location?.timeZone).time
- def stop = timeToday(ending, location?.timeZone).time
- result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
- }
- log.trace "<beacon-control> timeOk = $result"
- result
}
- private hhmm(time, fmt = "h:mm a") {
- def t = timeToday(time, location.timeZone)
- def f = new java.text.SimpleDateFormat(fmt)
- f.setTimeZone(location.timeZone ?: timeZone(time))
- f.format(t)
- }
+ // Sets the color back to the original saved color
+ def resetLEDNotification(){
- private timeIntervalLabel() {
- (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
- }
+ state.ledNotificationTriggered = false
+
+ // return color to original
+ log.debug "Reset LED color to: $state.origColor"
+ if (state.origColor != null) {
+ deviceLight.setHue(state.origColor)
+ }
+
+ // if the light was turned on just for the notification, turn it back off now
+ if (state.ledState == "off") {
+ deviceLight.off()
+ }
- private list(Object names) {
- return names[0]
}
}
@Field def app1
@Field def app2
-def initOrder = Verify.getBoolean()
-if (initOrder) {
- app1 = new App1(this)
- app2 = new App2(this)
-} else {
- app2 = new App2(this)
- app1 = new App1(this)
-}
-def installOrder = Verify.getBoolean()
-if (installOrder) {
- app1.installed()
- app2.installed()
-} else {
- app2.installed()
- app1.installed()
-}
+app1 = new App1(this)
+app2 = new App2(this)
-while(true) {
- def eventNumber = Verify.getInt(0,4)
- switch(eventNumber) {
- case 0:
- lockObject.setValue([name: "lock", value: "locked", deviceId: "lockID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- break
- case 1:
- lockObject.setValue([name: "unlock", value: "unlocked ", deviceId: "lockID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- break
- case 2:
- contactObject.setValue([name: "contact.open", value: "open", deviceId: "contactSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- break
- case 3:
- contactObject.setValue([name: "contact.closed", value: "closed", deviceId: "contactSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- break
- case 4:
- def event = Verify.getInt(0,1)
- if (event == 0) {
- presenceSensorObject.setValue([name: "presence", value: "present", deviceId: "presenceSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"presence":"1","dni":"mobile0"}'])
- } else {
- presenceSensorObject.setValue([name: "presence", value: "not present", deviceId: "presenceSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"presence":"0","dni":"mobile0"}'])
- }
- break
- }
-}
+app1.installed()
+app2.installed()
+
+contactObject.setValue([name: "contact", value: "open", deviceId: "contactSensorID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+contactObject.setValue([name: "contact", value: "closed", deviceId: "contactSensorID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+contactObject.setValue([name: "contact", value: "open", deviceId: "contactSensorID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+
+colorControlObject.setValue([name: "hue", value: "32", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+colorControlObject.setValue([name: "saturation", value: "32", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+colorControlObject.setValue([name: "level", value: "32", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+colorControlObject.setValue([name: "switch", value: "on", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+colorControlObject.setValue([name: "switch", value: "off", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+colorControlObject.setValue([name: "switch", value: "on", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
+colorControlObject.setValue([name: "colorTemperature", value: "32", deviceId: "colorControlID0", descriptionText: "",
+displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])