Update laundry-monitor.groovy
[smartapps.git] / official / medicine-management-contact-sensor.groovy
1 /**
2  *  Medicine Management - Contact Sensor
3  *
4  *  Copyright 2016 Jim Mangione
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7  *  in compliance with the License. You may obtain a copy of the License at:
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
12  *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
13  *  for the specific language governing permissions and limitations under the License.
14  *
15  * Logic: 
16  * --- Send notification at the medicine reminder time IF draw wasn't alread opened in past 60 minutes
17  * --- If draw still isn't open 10 minutes AFTER reminder time, LED will turn RED.
18  * --- ----- Once draw IS open, LED will return back to it's original color
19  *
20  */
21 import groovy.time.TimeCategory 
22
23 definition(
24     name: "Medicine Management - Contact Sensor",
25     namespace: "MangioneImagery",
26     author: "Jim Mangione",
27     description: "This supports devices with capabilities of ContactSensor and ColorControl (LED). It sends an in-app and ambient light notification if you forget to open the drawer or cabinet where meds are stored. A reminder will be set to a single time per day. If the draw or cabinet isn't opened within 60 minutes of that reminder, an in-app message will be sent. If the draw or cabinet still isn't opened after an additional 10 minutes, then an LED light turns red until the draw or cabinet is opened",
28     category: "Health & Wellness",
29     iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
30     iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
31     iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
32
33
34 preferences {
35
36         section("My Medicine Draw/Cabinet"){
37                 input "deviceContactSensor", "capability.contactSensor", title: "Opened Sensor" 
38         } 
39
40     section("Remind me to take my medicine at"){
41         input "reminderTime", "time", title: "Time"
42     }
43     
44     // NOTE: Use REAL device - virtual device causes compilation errors
45     section("My LED Light"){
46         input "deviceLight", "capability.colorControl", title: "Smart light"
47     }
48
49 }
50
51 def installed() {
52         log.debug "Installed with settings: ${settings}"
53         
54         initialize()
55 }
56
57 def updated() {
58         log.debug "Updated with settings: ${settings}"
59
60         unsubscribe()
61         
62         initialize()
63 }
64
65 def initialize() {
66
67     // will stop LED notification incase it was set by med reminder
68     subscribe(deviceContactSensor, "contact", contactHandler)
69
70     // how many minutes to look in the past from the reminder time, for an open draw
71     state.minutesToCheckOpenDraw = 60
72     
73     // is true when LED notification is set after exceeding 10 minutes past reminder time
74     state.ledNotificationTriggered = false
75     
76     // Set a timer to run once a day to notify if draw wasn't opened yet
77     schedule(reminderTime, checkOpenDrawInPast)
78    
79 }
80
81 // Should turn off any LED notification on OPEN state
82 def contactHandler(evt){
83         if (evt.value == "open") {
84         // if LED notification triggered, reset it.
85         log.debug "Cabinet opened"
86         if (state.ledNotificationTriggered) {
87             resetLEDNotification()
88         }
89         }
90 }
91
92 // If the draw was NOT opened within 60 minutes of the timer send notification out.
93 def checkOpenDrawInPast(){
94         log.debug "Checking past 60 minutes of activity from $reminderTime"
95     
96     // check activity of sensor for past 60 minutes for any OPENED status
97     def cabinetOpened = isOpened(state.minutesToCheckOpenDraw)
98         log.debug "Cabinet found opened: $cabinetOpened"
99     
100     // if it's opened, then do nothing and assume they took their meds
101     if (!cabinetOpened) {    
102         sendNotification("Hi, please remember to take your meds in the cabinet")
103        
104        // if no open activity, send out notification and set new reminder    
105         def reminderTimePlus10 = new Date(now() + (10 * 60000))
106
107         // needs to be scheduled if draw wasn't already opened
108         runOnce(reminderTimePlus10, checkOpenDrawAfterReminder)
109     }
110 }
111
112 // If the draw was NOT opened after 10 minutes past reminder, use LED notification
113 def checkOpenDrawAfterReminder(){
114         log.debug "Checking additional 10 minutes of activity from $reminderTime"
115     
116     // check activity of sensor for past 10 minutes for any OPENED status
117     def cabinetOpened = isOpened(10)    
118     
119         log.debug "Cabinet found opened: $cabinetOpened"
120         
121     // if no open activity, blink lights
122     if (!cabinetOpened) {
123         log.debug "Set LED to Notification color"
124         setLEDNotification()
125     }
126     
127 }
128
129 // Helper function for sending out an app notification
130 def sendNotification(msg){
131         log.debug "Message Sent: $msg"
132         sendPush(msg)
133 }
134
135 // Check if the sensor has been opened since the minutes entered
136 // Return true if opened found, else false.
137 def isOpened(minutes){
138     // query last X minutes of activity log    
139     def previousDateTime = new Date(now() - (minutes * 60000))
140     
141     // capture all events recorded
142     def evts = deviceContactSensor.eventsSince(previousDateTime)   
143     def cabinetOpened = false
144     if (evts.size() > 0) {
145         evts.each{
146             if(it.value == "open") {
147                 cabinetOpened = true 
148             }
149         }
150         }
151     
152     return cabinetOpened
153 }
154
155 // Saves current color and sets the light to RED
156 def setLEDNotification(){
157
158         state.ledNotificationTriggered = true
159     
160         // turn light back off when reset is called if it was originally off
161         state.ledState = deviceLight.currentValue("switch")
162
163         // set light to RED and store original color until stopped    
164     state.origColor = deviceLight.currentValue("hue")
165     deviceLight.on()
166     deviceLight.setHue(100)
167     
168     log.debug "LED set to RED. Original color stored: $state.origColor"
169
170 }
171
172 // Sets the color back to the original saved color
173 def resetLEDNotification(){
174
175         state.ledNotificationTriggered = false
176     
177     // return color to original
178     log.debug "Reset LED color to: $state.origColor"
179     if (state.origColor != null) {
180         deviceLight.setHue(state.origColor)
181     }
182     
183     // if the light was turned on just for the notification, turn it back off now
184     if (state.ledState == "off") {
185         deviceLight.off()
186     }
187
188 }