2 * Copyright 2015 SmartThings
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Monitors a set of presence detectors and triggers a mode change when everyone has left.
23 namespace: "smartthings",
24 author: "SmartThings",
25 description: "Monitors a set of SmartSense Presence tags or smartphones and triggers a mode change when everyone has left. Used in conjunction with Big Turn Off or Make It So to turn off lights, appliances, adjust the thermostat, turn on security apps, and more.",
26 category: "Mode Magic",
27 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/App-LightUpMyWorld.png",
28 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/App-LightUpMyWorld@2x.png"
32 section("When all of these people leave home") {
33 input "people", "capability.presenceSensor", multiple: true
35 section("Change to this mode") {
36 input "newMode", "mode", title: "Mode?"
38 section("False alarm threshold (defaults to 10 min)") {
39 input "falseAlarmThreshold", "decimal", title: "Number of minutes", required: false
41 section( "Notifications" ) {
42 input("recipients", "contact", title: "Send notifications to", required: false) {
43 input "sendPushMessage", "enum", title: "Send a push notification?", options: ["Yes", "No"], required: false
44 input "phone", "phone", title: "Send a Text Message?", required: false
51 log.debug "Installed with settings: ${settings}"
52 // commented out log statement because presence sensor label could contain user's name
53 //log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"
54 subscribe(people, "presence", presence)
55 // Input variable initialization
56 falseAlarmThreshold = 0
60 log.debug "Updated with settings: ${settings}"
61 // commented out log statement because presence sensor label could contain user's name
62 //log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"
64 subscribe(people, "presence", presence)
69 log.debug "evt.name: $evt.value"
70 if (evt.value == "not present") {
71 if (location.mode != newMode) {
72 log.debug "checking if everyone is away"
73 if (everyoneIsAway()) {
74 log.debug "starting sequence"
75 runIn(findFalseAlarmThreshold() * 60, "takeAction", [overwrite: false])
79 log.debug "mode is the same, not evaluating"
83 log.debug "present; doing nothing"
89 if (everyoneIsAway()) {
90 def threshold = 1000 * 60 * findFalseAlarmThreshold() - 1000
91 def awayLongEnough = people.findAll { person ->
92 def presenceState = person.currentState("presence")
94 // This device has yet to check in and has no presence state, treat it as not away long enough
97 def elapsed = now() - presenceState.rawDateCreated.time
100 log.debug "Found ${awayLongEnough.size()} out of ${people.size()} person(s) who were away long enough"
101 if (awayLongEnough.size() == people.size()) {
102 // TODO -- uncomment when app label is available
103 def message = "SmartThings changed your mode to '${newMode}' because everyone left home"
106 setLocationMode(newMode)
108 log.debug "not everyone has been away long enough; doing nothing"
111 log.debug "not everyone is away; doing nothing"
115 private everyoneIsAway()
118 for (person in people) {
119 if (person.currentPresence == "present") {
124 log.debug "everyoneIsAway: $result"
129 if (location.contactBookEnabled) {
130 log.debug("sending notifications to: ${recipients?.size()}")
131 sendNotificationToContacts(msg, recipients)
134 if (sendPushMessage != "No") {
135 log.debug("sending push message")
140 log.debug("sending text message")
147 private findFalseAlarmThreshold() {
148 (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold : 10