Update influxdb-logger.groovy
[smartapps.git] / official / smart-light-timer-x-minutes-unless-already-on.groovy
1 /**
2  *  Smart Timer
3  *  Loosely based on "Light Follows Me"
4  *
5  *  This prevent them from turning off when the timer expires, if they were already turned on
6  *
7  *  If the switch is already on, if won't be affected by the timer  (Must be turned of manually)
8  *  If the switch is toggled while in timeout-mode, it will remain on and ignore the timer (Must be turned of manually)
9  *
10  *  The timeout perid begins when the contact is closed, or motion stops, so leaving a door open won't start the timer until it's closed.
11  *
12  *  Author: andersheie@gmail.com
13  *  Date: 2014-08-31
14  */
15
16 definition(
17     name: "Smart Light Timer, X minutes unless already on",
18     namespace: "Pope",
19     author: "listpope@cox.net",
20     description: "Turns on a switch for X minutes, then turns it off. Unless, the switch is already on, in which case it stays on. If the switch is toggled while the timer is running, the timer is canceled.",
21     category: "Convenience",
22     iconUrl: "http://upload.wikimedia.org/wikipedia/commons/6/6a/Light_bulb_icon_tips.svg",
23     iconX2Url: "http://upload.wikimedia.org/wikipedia/commons/6/6a/Light_bulb_icon_tips.svg")
24
25 preferences {
26         section("Turn on when there's movement..."){
27                 input "motions", "capability.motionSensor", multiple: true, title: "Select motion detectors", required: false
28         }
29         section("Or, turn on when one of these contacts opened"){
30                 input "contacts", "capability.contactSensor", multiple: true, title: "Select Contacts", required: false
31         }
32         section("And off after no more triggers after..."){
33                 input "minutes1", "number", title: "Minutes?", defaultValue: "5"
34         }
35         section("Turn on/off light(s)..."){
36                 input "switches", "capability.switch", multiple: true, title: "Select Lights"
37         }
38 }
39
40
41 def installed()
42 {
43         subscribe(switches, "switch", switchChange)
44         subscribe(motions, "motion", motionHandler)
45         subscribe(contacts, "contact", contactHandler)
46         schedule("0 * * * * ?", "scheduleCheck")
47     state.myState = "ready"
48 }
49
50
51 def updated()
52 {
53         unsubscribe()
54         subscribe(motions, "motion", motionHandler)
55     subscribe(switches, "switch", switchChange)
56         subscribe(contacts, "contact", contactHandler)
57
58     state.myState = "ready"
59     log.debug "state: " + state.myState
60 }
61
62 def switchChange(evt) {
63         log.debug "SwitchChange: $evt.name: $evt.value"
64     
65     if(evt.value == "on") {
66         // Slight change of Race condition between motion or contact turning the switch on,
67         // versus user turning the switch on. Since we can't pass event parameters :-(, we rely
68         // on the state and hope the best.
69         if(state.myState == "activating") {
70             // OK, probably an event from Activating something, and not the switch itself. Go to Active mode.
71             state.myState = "active"
72         } else if(state.myState != "active") {
73                 state.myState = "already on"
74         }
75     } else {
76         // If active and switch is turned of manually, then stop the schedule and go to ready state
77         if(state.myState == "active" || state.myState == "activating") {
78                 unschedule()
79         }
80                 state.myState = "ready"
81     }
82     log.debug "state: " + state.myState
83 }
84
85 def contactHandler(evt) {
86         log.debug "contactHandler: $evt.name: $evt.value"
87     
88     if (evt.value == "open") {
89         if(state.myState == "ready") {
90             log.debug "Turning on lights by contact opening"
91             switches.on()
92             state.inactiveAt = null
93             state.myState = "activating"
94         }
95     } else if (evt.value == "closed") {
96         if (!state.inactiveAt && state.myState == "active" || state.myState == "activating") {
97                         // When contact closes, we reset the timer if not already set
98             setActiveAndSchedule()
99         }
100     }
101     log.debug "state: " + state.myState
102 }
103
104 def motionHandler(evt) {
105         log.debug "motionHandler: $evt.name: $evt.value"
106
107     if (evt.value == "active") {
108         if(state.myState == "ready" || state.myState == "active" || state.myState == "activating" ) {
109             log.debug "turning on lights"
110             switches.on()
111             state.inactiveAt = null
112             state.myState = "activating"
113         }
114     } else if (evt.value == "inactive") {
115         if (!state.inactiveAt && state.myState == "active" || state.myState == "activating") {
116                         // When Motion ends, we reset the timer if not already set
117            setActiveAndSchedule()
118         }
119     }
120     log.debug "state: " + state.myState
121 }
122
123 def setActiveAndSchedule() {
124     unschedule()
125         state.myState = "active"
126     state.inactiveAt = now()
127         schedule("0 * * * * ?", "scheduleCheck")
128 }
129
130 def scheduleCheck() {
131         log.debug "schedule check, ts = ${state.inactiveAt}"
132     if(state.myState != "already on") {
133         if(state.inactiveAt != null) {
134                 def elapsed = now() - state.inactiveAt
135             log.debug "${elapsed / 1000} sec since motion stopped"
136                 def threshold = 1000 * 60 * minutes1
137                 if (elapsed >= threshold) {
138                     if (state.myState == "active") {
139                         log.debug "turning off lights"
140                         switches.off()
141                     }
142                     state.inactiveAt = null
143                     state.myState = "ready"
144                 }
145         }
146     }
147     log.debug "state: " + state.myState
148 }