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 name: "Garage Door Monitor",
19 namespace: "smartthings",
20 author: "SmartThings",
21 description: "Monitor your garage door and get a text message if it is open too long",
22 category: "Safety & Security",
23 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/garage_contact.png",
24 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/garage_contact@2x.png"
28 section("When the garage door is open...") {
29 input "multisensor", "capability.threeAxis", title: "Which?"
31 section("For too long...") {
32 input "maxOpenTime", "number", title: "Minutes?"
34 section("Text me at (optional, sends a push notification if not specified)...") {
35 input("recipients", "contact", title: "Notify", description: "Send notifications to") {
36 input "phone", "phone", title: "Phone number?", required: false
43 subscribe(multisensor, "acceleration", accelerationHandler)
49 subscribe(multisensor, "acceleration", accelerationHandler)
52 def accelerationHandler(evt) {
53 def latestThreeAxisState = multisensor.threeAxisState // e.g.: 0,0,-1000
54 if (latestThreeAxisState) {
55 def isOpen = Math.abs(latestThreeAxisState.xyzValue.z) > 250 // TODO: Test that this value works in most cases...
56 def isNotScheduled = state.status != "scheduled"
63 if (isOpen && isNotScheduled) {
64 runIn(maxOpenTime * 60, takeAction, [overwrite: false])
65 state.status = "scheduled"
70 log.warn "COULD NOT FIND LATEST 3-AXIS STATE FOR: ${multisensor}"
75 if (state.status == "scheduled")
77 def deltaMillis = 1000 * 60 * maxOpenTime
78 def timeAgo = new Date(now() - deltaMillis)
79 def openTooLong = multisensor.threeAxisState.dateCreated.toSystemDate() < timeAgo
81 def recentTexts = state.smsHistory.find { it.sentDate.toSystemDate() > timeAgo }
86 runIn(maxOpenTime * 60, takeAction, [overwrite: false])
88 log.trace "Status is no longer scheduled. Not sending text."
92 def sendTextMessage() {
93 log.debug "$multisensor was open too long, texting phone"
96 def openMinutes = maxOpenTime * (state.smsHistory?.size() ?: 1)
97 def msg = "Your ${multisensor.label ?: multisensor.name} has been open for more than ${openMinutes} minutes!"
98 if (location.contactBookEnabled) {
99 sendNotificationToContacts(msg, recipients)
110 def updateSmsHistory() {
111 if (!state.smsHistory) state.smsHistory = []
113 if(state.smsHistory.size() > 9) {
114 log.debug "SmsHistory is too big, reducing size"
115 state.smsHistory = state.smsHistory[-9..-1]
117 state.smsHistory << [sentDate: new Date().toSystemFormat()]
120 def clearSmsHistory() {
121 state.smsHistory = null