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.
20 name: "Hue Mood Lighting",
21 namespace: "smartthings",
22 author: "SmartThings",
23 description: "Sets the colors and brightness level of your Philips Hue lights to match your mood.",
24 category: "SmartThings Labs",
25 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
26 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png"
30 page(name: "mainPage", title: "Adjust the color of your Hue lights to match your mood.", install: true, uninstall: true)
31 page(name: "timeIntervalInput", title: "Only during a certain time") {
33 input "starting", "time", title: "Starting", required: false
34 input "ending", "time", title: "Ending", required: false
39 // input "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
40 // input "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
41 // input "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
42 // input "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
43 // input "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
44 // input "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
45 // input "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
46 // input "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
47 // input "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
48 // input "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
49 // input "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
50 // input "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
51 // input "timeOfDay", "time", title: "At a Scheduled Time", required: false
54 dynamicPage(name: "mainPage") {
55 def anythingSet = anythingSet()
57 section("Set the lighting mood when..."){
58 ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
59 ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
60 ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
61 ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
62 ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
63 ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
64 ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
65 ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
66 ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
67 ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
68 ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
69 ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
70 ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
73 section(anythingSet ? "Select additional mood lighting triggers" : "Set the lighting mood when...", hideable: anythingSet, hidden: true){
74 ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
75 ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
76 ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
77 ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
78 ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
79 ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
80 ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
81 ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
82 ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
83 ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
84 ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
85 ifUnset "triggerModes", "mode", title: "System Changes Mode", description: "Select mode(s)", required: false, multiple: true
86 ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
88 section("Control these bulbs...") {
89 input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:true, multiple:true
91 section("Choose light effects...")
93 input "color", "enum", title: "Hue Color?", required: false, multiple:false, options: [
94 ["Soft White":"Soft White - Default"],
95 ["White":"White - Concentrate"],
96 ["Daylight":"Daylight - Energize"],
97 ["Warm White":"Warm White - Relax"],
98 "Red","Green","Blue","Yellow","Orange","Purple","Pink"]
99 input "lightLevel", "enum", title: "Light Level?", required: false, options: [10,20,30,40,50,60,70,80,90,100]
102 section("More options", hideable: true, hidden: true) {
103 input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
104 href "timeIntervalInput", title: "Only during a certain time"
105 input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
106 options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
107 input "modes", "mode", title: "Only when mode is", multiple: true, required: false
108 input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
110 section([mobileOnly:true]) {
111 label title: "Assign a name", required: false
112 mode title: "Set for specific mode(s)", required: false
116 private anythingSet() {
117 for (name in ["motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","triggerModes","timeOfDay"]) {
118 if (settings[name]) {
125 private ifUnset(Map options, String name, String capability) {
126 if (!settings[name]) {
127 input(options, name, capability)
131 private ifSet(Map options, String name, String capability) {
132 if (settings[name]) {
133 input(options, name, capability)
138 log.debug "Installed with settings: ${settings}"
143 log.debug "Updated with settings: ${settings}"
149 def subscribeToEvents() {
150 subscribe(app, appTouchHandler)
151 subscribe(contact, "contact.open", eventHandler1)
152 subscribe(contactClosed, "contact.closed", eventHandler1)
153 subscribe(acceleration, "acceleration.active", eventHandler1)
154 subscribe(motion, "motion.active", eventHandler1)
155 subscribe(mySwitch, "switch.on", eventHandler1)
156 subscribe(mySwitchOff, "switch.off", eventHandler1)
157 subscribe(arrivalPresence, "presence.present", eventHandler1)
158 subscribe(departurePresence, "presence.not present", eventHandler1)
159 subscribe(smoke, "smoke.detected", eventHandler1)
160 subscribe(smoke, "smoke.tested", eventHandler1)
161 subscribe(smoke, "carbonMonoxide.detected", eventHandler1)
162 subscribe(water, "water.wet", eventHandler1)
163 subscribe(button1, "button.pushed", eventHandler1)
166 subscribe(location, modeChangeHandler)
170 schedule(timeOfDay, scheduledTimeHandler)
174 def eventHandler1(evt=null) {
175 log.trace "Executing Mood Lighting"
178 def lastTime = state[frequencyKey(evt)]
179 if (oncePerDayOk(lastTime)) {
181 if (lastTime == null || now() - lastTime >= frequency * 60000) {
190 log.debug "Not taking action because it was already taken today"
195 def modeChangeHandler(evt) {
196 log.trace "modeChangeHandler $evt.name: $evt.value ($triggerModes)"
197 if (evt.value in triggerModes) {
202 def scheduledTimeHandler() {
203 log.trace "scheduledTimeHandler()"
207 def appTouchHandler(evt) {
211 private takeAction(evt) {
213 if (frequency || oncePerDay) {
214 state[frequencyKey(evt)] = now()
263 state.previous[it.id] = [
264 "switch": it.currentValue("switch"),
265 "level" : it.currentValue("level"),
266 "hue": it.currentValue("hue"),
267 "saturation": it.currentValue("saturation")
271 log.debug "current values = $state.previous"
273 def newValue = [hue: hueColor, saturation: saturation, level: lightLevel as Integer ?: 100]
274 log.debug "new value = $newValue"
276 hues*.setColor(newValue)
279 private frequencyKey(evt) {
280 "lastActionTimeStamp"
283 private dayString(Date date) {
284 def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
285 if (location.timeZone) {
286 df.setTimeZone(location.timeZone)
289 df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
295 private oncePerDayOk(Long lastTime) {
296 def result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
297 log.trace "oncePerDayOk = $result - $lastTime"
301 // TODO - centralize somehow
303 //modeOk && daysOk && timeOk
307 private getModeOk() {
308 def result = !modes || modes.contains(location.mode)
309 log.trace "modeOk = $result"
313 private getDaysOk() {
316 def df = new java.text.SimpleDateFormat("EEEE")
317 if (location.timeZone) {
318 df.setTimeZone(location.timeZone)
321 df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
323 def day = df.format(new Date())
324 result = days.contains(day)
326 log.trace "daysOk = $result"
330 private getTimeOk() {
332 if (starting && ending) {
334 def start = timeToday(starting, location?.timeZone).time
335 def stop = timeToday(ending, location?.timeZone).time
336 result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
338 log.trace "timeOk = $result"
342 private hhmm(time, fmt = "h:mm a")
344 def t = timeToday(time, location.timeZone)
345 def f = new java.text.SimpleDateFormat(fmt)
346 f.setTimeZone(location.timeZone ?: timeZone(time))
350 private timeIntervalLabel()
352 (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
354 // TODO - End Centralize