Update WorkingFromHome.groovy
[smartapps.git] / official / forgiving-security.groovy
1 /**
2  *  Forgiving Security
3  *
4  *  Author: brian@bevey.org
5  *  Date: 10/25/13
6  *
7  *  Arm a simple security system based on mode.  Has a grace period to allow an
8  *  ever present lag in presence detection.
9  */
10
11 definition(
12   name: "Forgiving Security",
13   namespace: "imbrianj",
14   author: "brian@bevey.org",
15   description: "Alerts you if something happens while you're away.  Has a settable grace period to compensate for presence sensors that may take a few seconds to be noticed.",
16   category: "Safety & Security",
17   iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
18   iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
19 )
20
21 preferences {
22   section("Things to secure?") {
23     input "contacts", "capability.contactSensor", title: "Contact Sensors", multiple: true, required: false
24     input "motions",  "capability.motionSensor",  title: "Motion Sensors",  multiple: true, required: false
25   }
26
27   section("Alarms to go off?") {
28     input "alarms", "capability.alarm",  title: "Which Alarms?",         multiple: true, required: false
29     input "lights", "capability.switch", title: "Turn on which lights?", multiple: true, required: false
30   }
31
32   section("Delay for presence lag?") {
33     input name: "presenceDelay", type: "number", title: "Seconds (defaults to 15s)", required: false
34   }
35
36   section("Notifications?") {
37     input "sendPushMessage", "enum", title: "Send a push notification?", metadata: [values: ["Yes", "No"]], required: false
38     input "phone", "phone", title: "Send a Text Message?", required: false
39   }
40
41   section("Message interval?") {
42     input name: "messageDelay", type: "number", title: "Minutes (default to every message)", required: false
43   }
44 }
45
46 def installed() {
47   init()
48 }
49
50 def updated() {
51   unsubscribe()
52   init()
53 }
54
55 def init() {
56   state.lastTrigger    = now()
57   state.deviceTriggers = []
58   subscribe(contacts, "contact.open",  triggerAlarm)
59   subscribe(motions,  "motion.active", triggerAlarm)
60 }
61
62 def triggerAlarm(evt) {
63   def presenceDelay = presenceDelay ?: 15
64
65   if(now() - (presenceDelay * 1000) > state.lastTrigger) {
66     log.warn("Stale event - ignoring")
67
68     state.deviceTriggers = []
69   }
70
71   state.deviceTriggers.add(evt.displayName)
72   state.triggerMode = location.mode
73   state.lastTrigger = now()
74
75   log.info(evt.displayName + " triggered an alarm.  Waiting for presence lag.")
76   runIn(presenceDelay, "fireAlarm")
77 }
78
79 def fireAlarm() {
80   if(state.deviceTriggers.size() > 0) {
81     def devices = state.deviceTriggers.unique().join(", ")
82
83     if(location.mode == state.triggerMode) {
84       log.info(devices + " alarm triggered and mode hasn't changed.")
85       send(devices + " alarm has been triggered!")
86       lights?.on()
87       alarms?.both()
88     }
89
90     else {
91       log.info(devices + " alarm triggered, but it looks like you were just coming home.  Ignoring.")
92     }
93   }
94
95   state.deviceTriggers = []
96 }
97
98 private send(msg) {
99   def delay = (messageDelay != null && messageDelay != "") ? messageDelay * 60 * 1000 : 0
100
101   if(now() - delay > state.lastMessage) {
102     state.lastMessage = now()
103     if(sendPushMessage == "Yes") {
104       log.debug("Sending push message.")
105       sendPush(msg)
106     }
107
108     if(phone) {
109       log.debug("Sending text message.")
110       sendSms(phone, msg)
111     }
112
113     log.debug(msg)
114   }
115
116   else {
117     log.info("Have a message to send, but user requested to not get it.")
118   }
119 }