2 * Copyright 2015 Jesse Newland
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.
16 namespace: "jnewland",
17 author: "Jesse Newland",
18 description: "All the business logic for my crappy loft lives here",
19 category: "SmartThings Labs",
20 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
21 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
22 iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
25 page(name: "selectThings")
29 dynamicPage(name: "selectThings", title: "Select Things", install: true) {
30 section("Webhook URL"){
31 input "url", "text", title: "Webhook URL", description: "Your webhook URL", required: true
33 section("Things to monitor for events") {
34 input "monitor_switches", "capability.switch", title: "Switches", multiple: true, required: false
35 input "monitor_motion", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false
36 input "monitor_presence", "capability.presenceSensor", title: "Presence Sensors", multiple: true, required: false
38 section("Things to control") {
39 input "hues", "capability.colorControl", title: "Hue Bulbs", multiple: true, required: false
40 input "switches", "capability.switch", title: "Switches", multiple: true, required: false
41 input "dimmers", "capability.switchLevel", title: "Dimmers", multiple: true, required: false
44 input "voice", "capability.speechSynthesis", title: "Voice", required: false
61 subscribe(monitor_switches, "switch", eventHandler1)
62 subscribe(monitor_motion, "motion", eventHandler1)
63 subscribe(monitor_presence, "presence", eventHandler1)
64 subscribe(location, "mode", eventHandler1)
65 subscribe(location, "sunset", eventHandler1)
66 subscribe(location, "sunrise", eventHandler1)
70 def eventHandler1(evt) {
71 def everyone_here = presense_is_after(monitor_presence, "present", 10)
72 def everyone_gone = presense_is_after(monitor_presence, "not present", 10)
73 def current_count = monitor_presence.findAll { it.currentPresence == "present" }.size()
75 displayName: evt.displayName,
77 daytime: is_daytime(),
79 current_count: current_count,
80 everyone_here: everyone_here,
81 everyone_gone: everyone_gone
84 if (mode == "Pause") {
85 webhook([ at: 'paused' ])
86 log.info("No actions taken in Pause mode")
88 def lights = [switches, hues].flatten()
89 // turn on lights near stairs when motion is detected
90 if (evt.displayName == "motion@stairs" && evt.value == "active") {
91 webhook([ at: 'stair_motion_lights' ])
93 s.displayName == "stairs" ||
94 s.displayName == "loft" ||
95 s.displayName == "entry"
97 s.currentSwitch == "off"
99 if ("setLevel" in s.supportedCommands.collect { it.name }) {
100 if (location.mode == "Sleep") {
102 } else if (location.mode == "Home / Night") {
112 // Turn on some lights if one of us is up
113 if (evt.value == "Yawn") {
114 webhook([ at: 'yawn' ])
115 lights.findAll { s ->
116 s.displayName == "loft" ||
117 s.displayName == "entry" ||
118 s.displayName == "chandelier"
120 s.currentSwitch == "off"
122 if ("setLevel" in s.supportedCommands.collect { it.name }) {
129 // turn on all lights when entering day mode
130 if (evt.value == "Home / Day") {
131 webhook([ at: 'home_day' ])
133 if (s.currentSwitch == "off") {
136 if ("setLevel" in s.supportedCommands.collect { it.name }) {
142 // turn on night mode at sunset
143 if (evt.displayName == "sunset" && current_count > 0 && location.mode == "Home / Day") {
144 webhook([ at: 'sunset' ])
145 changeMode("Home / Night")
148 // dim lights at night
149 if (evt.value == "Home / Night") {
150 webhook([ at: 'home_night' ])
151 lights.findAll { s ->
152 "setLevel" in s.supportedCommands.collect { it.name }
154 log.info("Night mode enabled, dimming ${s.displayName}")
158 // turn off that light by the door downstairs entirely
159 lights.findAll { s ->
160 s.displayName == "downstairs door"
162 log.info("Night mode enabled, turning off ${s.displayName}")
167 // turn off all lights when entering sleep mode
168 if (evt.value == "Sleep") {
169 webhook([ at: 'sleep' ])
170 lights.findAll { s ->
171 s.currentSwitch == "on"
173 log.info("Sleep mode enabled, turning off ${s.displayName}")
178 // turn off all lights when everyone goes away
179 if (everyone_gone && location.mode != "Away") {
180 webhook([ at: 'away' ])
182 lights.findAll { s ->
183 s.currentSwitch == "on"
185 log.info("Away mode enabled, turning off ${s.displayName}")
190 // switch mode to Home when we return
191 if (current_count > 0 && location.mode == "Away") {
192 webhook([ at: 'home' ])
196 // Make home mode specific based on day / night
197 if (evt.value == "Home") {
198 webhook([ at: 'home_day_night' ])
200 changeMode("Home / Day")
202 changeMode("Home / Night")
209 webhook([ can_schedule: 'false' ])
210 log.error("can_schedule=false")
215 def changeMode(mode) {
216 //voice?.speak("changing mode to ${mode}")
217 setLocationMode(mode)
219 displayName: "changeMode",
232 def successClosure = { response ->
233 log.debug "Request was successful, $response"
238 success: successClosure,
241 httpPostJson(json_params)
245 private is_daytime() {
247 /*def data = getWeatherFeature("astronomy")
248 def sunset = "${data.moon_phase.sunset.hour}${data.moon_phase.sunset.minute}"
249 def sunrise = "${data.moon_phase.sunrise.hour}${data.moon_phase.sunrise.minute}"
250 def current = "${data.moon_phase.current_time.hour}${data.moon_phase.current_time.minute}"
251 if (current.toInteger() > sunrise.toInteger() && current.toInteger() < sunset.toInteger()) {
259 private presense_is_after(people, presence, minutes) {
261 for (person in people) {
262 if (person.currentPresence != presence) {
266 def threshold = 1000 * 60 * minutes
267 def elapsed = now() - person.currentState("presence").rawDateCreated.time
268 if (elapsed < threshold) {