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
40 dynamicPage(name: "mainPage") {
41 def anythingSet = anythingSet()
43 section("Set the lighting mood when..."){
44 ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
45 ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
46 ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
47 ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
48 ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
49 ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
50 ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
51 ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
52 ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
53 ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
54 ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
55 ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
56 ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
59 section(anythingSet ? "Select additional mood lighting triggers" : "Set the lighting mood when...", hideable: anythingSet, hidden: true){
60 ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
61 ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
62 ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
63 ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
64 ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
65 ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
66 ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
67 ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
68 ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
69 ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
70 ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
71 ifUnset "triggerModes", "mode", title: "System Changes Mode", description: "Select mode(s)", required: false, multiple: true
72 ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
74 section("Control these bulbs...") {
75 input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:true, multiple:true
77 section("Choose light effects...")
79 input "color", "enum", title: "Hue Color?", required: false, multiple:false, options: [
80 ["Soft White":"Soft White - Default"],
81 ["White":"White - Concentrate"],
82 ["Daylight":"Daylight - Energize"],
83 ["Warm White":"Warm White - Relax"],
84 "Red","Green","Blue","Yellow","Orange","Purple","Pink"]
85 input "lightLevel", "enum", title: "Light Level?", required: false, options: [10,20,30,40,50,60,70,80,90,100]
88 section("More options", hideable: true, hidden: true) {
89 input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
90 href "timeIntervalInput", title: "Only during a certain time"
91 input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
92 options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
93 input "modes", "mode", title: "Only when mode is", multiple: true, required: false
94 input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
96 section([mobileOnly:true]) {
97 label title: "Assign a name", required: false
98 mode title: "Set for specific mode(s)", required: false
102 private anythingSet() {
103 for (name in ["motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","triggerModes","timeOfDay"]) {
104 if (settings[name]) {
111 private ifUnset(Map options, String name, String capability) {
112 if (!settings[name]) {
113 input(options, name, capability)
117 private ifSet(Map options, String name, String capability) {
118 if (settings[name]) {
119 input(options, name, capability)
124 log.debug "Installed with settings: ${settings}"
129 log.debug "Updated with settings: ${settings}"
135 def subscribeToEvents() {
136 subscribe(app, appTouchHandler)
137 subscribe(contact, "contact.open", eventHandler1)
138 subscribe(contactClosed, "contact.closed", eventHandler1)
139 subscribe(acceleration, "acceleration.active", eventHandler1)
140 subscribe(motion, "motion.active", eventHandler1)
141 subscribe(mySwitch, "switch.on", eventHandler1)
142 subscribe(mySwitchOff, "switch.off", eventHandler1)
143 subscribe(arrivalPresence, "presence.present", eventHandler1)
144 subscribe(departurePresence, "presence.not present", eventHandler1)
145 subscribe(smoke, "smoke.detected", eventHandler1)
146 subscribe(smoke, "smoke.tested", eventHandler1)
147 subscribe(smoke, "carbonMonoxide.detected", eventHandler1)
148 subscribe(water, "water.wet", eventHandler1)
149 subscribe(button1, "button.pushed", eventHandler1)
152 subscribe(location, modeChangeHandler)
156 schedule(timeOfDay, scheduledTimeHandler)
160 def eventHandler1(evt=null) {
161 log.trace "Executing Mood Lighting"
164 def lastTime = state[frequencyKey(evt)]
165 if (oncePerDayOk(lastTime)) {
167 if (lastTime == null || now() - lastTime >= frequency * 60000) {
176 log.debug "Not taking action because it was already taken today"
181 def modeChangeHandler(evt) {
182 log.trace "modeChangeHandler $evt.name: $evt.value ($triggerModes)"
183 if (evt.value in triggerModes) {
188 def scheduledTimeHandler() {
189 log.trace "scheduledTimeHandler()"
193 def appTouchHandler(evt) {
197 private takeAction(evt) {
199 if (frequency || oncePerDay) {
200 state[frequencyKey(evt)] = now()
249 state.previous[it.id] = [
250 "switch": it.currentValue("switch"),
251 "level" : it.currentValue("level"),
252 "hue": it.currentValue("hue"),
253 "saturation": it.currentValue("saturation")
257 log.debug "current values = $state.previous"
259 def newValue = [hue: hueColor, saturation: saturation, level: lightLevel as Integer ?: 100]
260 log.debug "new value = $newValue"
262 hues*.setColor(newValue)
265 private frequencyKey(evt) {
266 "lastActionTimeStamp"
269 private dayString(Date date) {
270 def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
271 if (location.timeZone) {
272 df.setTimeZone(location.timeZone)
275 df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
281 private oncePerDayOk(Long lastTime) {
282 def result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
283 log.trace "oncePerDayOk = $result - $lastTime"
287 // TODO - centralize somehow
289 modeOk && daysOk && timeOk
292 private getModeOk() {
293 def result = !modes || modes.contains(location.mode)
294 log.trace "modeOk = $result"
298 private getDaysOk() {
301 def df = new java.text.SimpleDateFormat("EEEE")
302 if (location.timeZone) {
303 df.setTimeZone(location.timeZone)
306 df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
308 def day = df.format(new Date())
309 result = days.contains(day)
311 log.trace "daysOk = $result"
315 private getTimeOk() {
317 if (starting && ending) {
319 def start = timeToday(starting, location?.timeZone).time
320 def stop = timeToday(ending, location?.timeZone).time
321 result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
323 log.trace "timeOk = $result"
327 private hhmm(time, fmt = "h:mm a")
329 def t = timeToday(time, location.timeZone)
330 def f = new java.text.SimpleDateFormat(fmt)
331 f.setTimeZone(location.timeZone ?: timeZone(time))
335 private timeIntervalLabel()
337 (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
339 // TODO - End Centralize