Update groveStreams.groovy
[smartapps.git] / official / good-night.groovy
1 /**
2  *  Copyright 2015 SmartThings
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  *  in compliance with the License. You may obtain a copy of the License at:
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
10  *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
11  *  for the specific language governing permissions and limitations under the License.
12  *
13  *  Good Night
14  *
15  *  Author: SmartThings
16  *  Date: 2013-03-07
17  */
18 definition(
19     name: "Good Night",
20     namespace: "smartthings",
21     author: "SmartThings",
22     description: "Changes mode when motion ceases after a specific time of night.",
23     category: "Mode Magic",
24     iconUrl: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/good-night.png",
25     iconX2Url: "https://s3.amazonaws.com/smartapp-icons/ModeMagic/good-night@2x.png"
26 )
27
28 preferences {
29         section("When there is no motion on any of these sensors") {
30                 input "motionSensors", "capability.motionSensor", title: "Where?", multiple: true
31         }
32         section("For this amount of time") {
33                 input "minutes", "number", title: "Minutes?"
34         }
35         section("After this time of day") {
36                 input "timeOfDay", "time", title: "Time?"
37         }
38         section("And (optionally) these switches are all off") {
39                 input "switches", "capability.switch", multiple: true, required: false
40         }
41         section("Change to this mode") {
42                 input "newMode", "mode", title: "Mode?"
43         }
44         section( "Notifications" ) {
45         input("recipients", "contact", title: "Send notifications to") {
46             input "sendPushMessage", "enum", title: "Send a push notification?", options: ["Yes", "No"], required: false
47             input "phoneNumber", "phone", title: "Send a Text Message?", required: false
48         }
49         }
50
51 }
52
53 def installed() {
54         log.debug "Current mode = ${location.mode}"
55         createSubscriptions()
56 }
57
58 def updated() {
59         log.debug "Current mode = ${location.mode}"
60         unsubscribe()
61         createSubscriptions()
62 }
63
64 def createSubscriptions()
65 {
66         subscribe(motionSensors, "motion.active", motionActiveHandler)
67         subscribe(motionSensors, "motion.inactive", motionInactiveHandler)
68         subscribe(switches, "switch.off", switchOffHandler)
69         subscribe(location, modeChangeHandler)
70
71         if (state.modeStartTime == null) {
72                 state.modeStartTime = 0
73         }
74 }
75
76 def modeChangeHandler(evt) {
77         state.modeStartTime = now()
78 }
79
80 def switchOffHandler(evt) {
81         if (correctMode() && correctTime()) {
82                 if (allQuiet() && switchesOk()) {
83                         takeActions()
84                 }
85         }
86 }
87
88 def motionActiveHandler(evt)
89 {
90         log.debug "Motion active"
91 }
92
93 def motionInactiveHandler(evt)
94 {
95         // for backward compatibility
96         if (state.modeStartTime == null) {
97                 subscribe(location, modeChangeHandler)
98                 state.modeStartTime = 0
99         }
100
101         if (correctMode() && correctTime()) {
102                 runIn(minutes * 60, scheduleCheck, [overwrite: false])
103         }
104 }
105
106 def scheduleCheck()
107 {
108         log.debug "scheduleCheck, currentMode = ${location.mode}, newMode = $newMode"
109         
110         if (correctMode() && correctTime()) {
111                 if (allQuiet() && switchesOk()) {
112                         takeActions()
113                 }
114         }
115 }
116
117 private takeActions() {
118         def message = "Goodnight! SmartThings changed the mode to '$newMode'"
119         send(message)
120         setLocationMode(newMode)
121         log.debug message
122 }
123
124 private correctMode() {
125         if (location.mode != newMode) {
126                 true
127         } else {
128                 log.debug "Location is already in the desired mode:  doing nothing"
129                 false
130         }
131 }
132
133 private correctTime() {
134         def t0 = now()
135         def modeStartTime = new Date(state.modeStartTime)
136         def startTime = timeTodayAfter(modeStartTime, timeOfDay, location.timeZone)
137         if (t0 >= startTime.time) {
138                 true
139         } else {
140                 log.debug "The current time of day (${new Date(t0)}), is not in the correct time window ($startTime):  doing nothing"
141                 false
142         }
143 }
144
145 private switchesOk() {
146         def result = true
147         for (it in (switches ?: [])) {
148                 if (it.currentSwitch == "on") {
149                         result = false
150                         break
151                 }
152         }
153         log.debug "Switches are all off: $result"
154         result
155 }
156
157 private allQuiet() {
158         def threshold = 1000 * 60 * minutes - 1000
159         def states = motionSensors.collect { it.currentState("motion") ?: [:] }.sort { a, b -> b.dateCreated <=> a.dateCreated }
160         if (states) {
161                 if (states.find { it.value == "active" }) {
162                         log.debug "Found active state"
163                         false
164                 } else {
165                         def sensor = states.first()
166                     def elapsed = now() - sensor.rawDateCreated.time
167                         if (elapsed >= threshold) {
168                                 log.debug "No active states, and enough time has passed"
169                                 true
170                         } else {
171                                 log.debug "No active states, but not enough time has passed"
172                                 false
173                         }
174                 }
175         } else {
176                 log.debug "No states to check for activity"
177                 true
178         }
179 }
180
181 private send(msg) {
182     if (location.contactBookEnabled) {
183         sendNotificationToContacts(msg, recipients)
184     }
185     else {
186         if (sendPushMessage != "No") {
187             log.debug("sending push message")
188             sendPush(msg)
189         }
190
191         if (phoneNumber) {
192             log.debug("sending text message")
193             sendSms(phoneNumber, msg)
194         }
195     }
196
197         log.debug msg
198 }