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
293 private getModeOk() {
294 def result = !modes || modes.contains(location.mode)
295 log.trace "modeOk = $result"
299 private getDaysOk() {
302 def df = new java.text.SimpleDateFormat("EEEE")
303 if (location.timeZone) {
304 df.setTimeZone(location.timeZone)
307 df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
309 def day = df.format(new Date())
310 result = days.contains(day)
312 log.trace "daysOk = $result"
316 private getTimeOk() {
318 if (starting && ending) {
320 def start = timeToday(starting, location?.timeZone).time
321 def stop = timeToday(ending, location?.timeZone).time
322 result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
324 log.trace "timeOk = $result"
328 private hhmm(time, fmt = "h:mm a")
330 def t = timeToday(time, location.timeZone)
331 def f = new java.text.SimpleDateFormat(fmt)
332 f.setTimeZone(location.timeZone ?: timeZone(time))
336 private timeIntervalLabel()
338 (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
340 // TODO - End Centralize