2 name: "Bright When Dark And/Or Bright After Sunset",
5 description: "Turn ON light(s) and/or dimmer(s) when there's movement and the room is dark with illuminance threshold and/or between sunset and sunrise. Then turn OFF after X minute(s) when the brightness of the room is above the illuminance threshold or turn OFF after X minute(s) when there is no movement.",
6 category: "Convenience",
7 iconX2Url: "http://neiloseman.com/wp-content/uploads/2013/08/stockvault-bulb128619.jpg"
12 page(name: "timeIntervalInput", title: "Only during a certain time...")
16 input "starting", "time", title: "Starting", required: false
17 input "ending", "time", title: "Ending", required: false
21 page(name: "configurations")
27 dynamicPage(name: "configurations", title: "Configurations...", uninstall: true, nextPage: "options")
29 section(title: "Turn ON lights on movement when...")
31 input "dark", "bool", title: "It is dark?", required: true
32 input "sun", "bool", title: "Between sunset and surise?", required: true
34 section(title: "More options...", hidden: hideOptionsSection(), hideable: true)
36 def timeLabel = timeIntervalLabel()
37 href "timeIntervalInput", title: "Only during a certain time:", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : null
38 input "days", "enum", title: "Only on certain days of the week:", multiple: true, required: false, options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
39 input "modes", "mode", title: "Only when mode is:", multiple: true, required: false
41 section ("Assign a name")
43 label title: "Assign a name", required: false
50 if (dark == true && sun == true)
52 dynamicPage(name: "options", title: "Lights will turn ON on movement when it is dark and between sunset and sunrise...", install: true, uninstall: true)
54 section("Control these light(s)...")
56 input "lights", "capability.switch", title: "Light(s)?", multiple: true, required: false
58 section("Control these dimmer(s)...")
60 input "dimmers", "capability.switchLevel", title: "Dimmer(s)?", multiple: true, required:false
61 input "level", "number", title: "How bright?", required:false, description: "0% to 100%"
63 section("Turning ON when it's dark and there's movement...")
65 input "motionSensor", "capability.motionSensor", title: "Where?", multiple: true, required: true
67 section("And then OFF when it's light or there's been no movement for...")
69 input "delayMinutes", "number", title: "Minutes?", required: false
71 section("Using this light sensor...")
73 input "lightSensor", "capability.illuminanceMeasurement",title: "Light Sensor?", multiple: false, required: true
74 input "luxLevel", "number", title: "Illuminance threshold? (default 50 lux)",defaultValue: "50", required: false
76 section ("And between sunset and sunrise...")
78 input "sunriseOffsetValue", "text", title: "Sunrise offset", required: false, description: "00:00"
79 input "sunriseOffsetDir", "enum", title: "Before or After", required: false, metadata: [values: ["Before","After"]]
80 input "sunsetOffsetValue", "text", title: "Sunset offset", required: false, description: "00:00"
81 input "sunsetOffsetDir", "enum", title: "Before or After", required: false, metadata: [values: ["Before","After"]]
83 section ("Zip code (optional, defaults to location coordinates when location services are enabled)...")
85 input "zipCode", "text", title: "Zip Code?", required: false, description: "Local Zip Code"
89 else if (dark == true && sun == false)
91 dynamicPage(name: "options", title: "Lights will turn ON on movement when it is dark...", install: true, uninstall: true)
93 section("Control these light(s)...")
95 input "lights", "capability.switch", title: "Light(s)?", multiple: true, required: false
97 section("Control these dimmer(s)...")
99 input "dimmers", "capability.switchLevel", title: "Dimmer(s)?", multiple: true, required:false
100 input "level", "number", title: "How bright?", required:false, description: "0% to 100%"
102 section("Turning ON when it's dark and there's movement...")
104 input "motionSensor", "capability.motionSensor", title: "Where?", multiple: true, required: true
106 section("And then OFF when it's light or there's been no movement for...")
108 input "delayMinutes", "number", title: "Minutes?", required: false
110 section("Using this light sensor...")
112 input "lightSensor", "capability.illuminanceMeasurement",title: "Light Sensor?", multiple: false, required: true
113 input "luxLevel", "number", title: "Illuminance threshold? (default 50 lux)",defaultValue: "50", required: false
117 else if (sun == true && dark == false)
119 dynamicPage(name: "options", title: "Lights will turn ON on movement between sunset and sunrise...", install: true, uninstall: true)
121 section("Control these light(s)...")
123 input "lights", "capability.switch", title: "Light(s)?", multiple: true, required: false
125 section("Control these dimmer(s)...")
127 input "dimmers", "capability.switchLevel", title: "Dimmer(s)?", multiple: true, required:false
128 input "level", "number", title: "How bright?", required:false, description: "0% to 100%"
130 section("Turning ON there's movement...")
132 input "motionSensor", "capability.motionSensor", title: "Where?", multiple: true, required: true
134 section("And then OFF there's been no movement for...")
136 input "delayMinutes", "number", title: "Minutes?", required: false
138 section ("Between sunset and sunrise...")
140 input "sunriseOffsetValue", "text", title: "Sunrise offset", required: false, description: "00:00"
141 input "sunriseOffsetDir", "enum", title: "Before or After", required: false, metadata: [values: ["Before","After"]]
142 input "sunsetOffsetValue", "text", title: "Sunset offset", required: false, description: "00:00"
143 input "sunsetOffsetDir", "enum", title: "Before or After", required: false, metadata: [values: ["Before","After"]]
145 section ("Zip code (optional, defaults to location coordinates when location services are enabled)...")
147 input "zipCode", "text", title: "Zip Code?", required: false, description: "Local Zip Code"
153 dynamicPage(name: "options", title: "Lights will turn ON on movement...", install: true, uninstall: true)
155 section("Control these light(s)...")
157 input "lights", "capability.switch", title: "Light(s)?", multiple: true, required: false
159 section("Control these dimmer(s)...")
161 input "dimmers", "capability.switchLevel", title: "Dimmer(s)?", multiple: true, required:false
162 input "level", "number", title: "How bright?", required:false, description: "0% to 100%"
164 section("Turning ON when there's movement...")
166 input "motionSensor", "capability.motionSensor", title: "Where?", multiple: true, required: true
168 section("And then OFF when there's been no movement for...")
170 input "delayMinutes", "number", title: "Minutes?", required: false
178 log.debug "Installed with settings: ${settings}."
184 log.debug "Updated with settings: ${settings}."
192 subscribe(motionSensor, "motion", motionHandler)
193 if (lights != null && lights != "" && dimmers != null && dimmers != "")
195 log.debug "$lights subscribing..."
196 subscribe(lights, "switch", lightsHandler)
197 log.debug "$dimmers subscribing..."
198 subscribe(dimmers, "switch", dimmersHandler)
199 if (dark == true && lightSensor != null && lightSensor != "")
201 log.debug "$lights and $dimmers will turn ON when movement detected and when it is dark..."
202 subscribe(lightSensor, "illuminance", illuminanceHandler, [filterEvents: false])
206 log.debug "$lights and $dimmers will turn ON when movement detected between sunset and sunrise..."
208 subscribe(location, "position", locationPositionChange)
209 subscribe(location, "sunriseTime", sunriseSunsetTimeHandler)
210 subscribe(location, "sunsetTime", sunriseSunsetTimeHandler)
212 else if (dark != true && sun != true)
214 log.debug "$lights and $dimmers will turn ON when movement detected..."
217 else if (lights != null && lights != "")
219 log.debug "$lights subscribing..."
220 subscribe(lights, "switch", lightsHandler)
221 if (dark == true && lightSensor != null && lightSensor != "")
223 log.debug "$lights will turn ON when movement detected and when it is dark..."
224 subscribe(lightSensor, "illuminance", illuminanceHandler, [filterEvents: false])
228 log.debug "$lights will turn ON when movement detected between sunset and sunrise..."
230 subscribe(location, "position", locationPositionChange)
231 subscribe(location, "sunriseTime", sunriseSunsetTimeHandler)
232 subscribe(location, "sunsetTime", sunriseSunsetTimeHandler)
234 else if (dark != true && sun != true)
236 log.debug "$lights will turn ON when movement detected..."
239 else if (dimmers != null && dimmers != "")
241 log.debug "$dimmers subscribing..."
242 subscribe(dimmers, "switch", dimmersHandler)
243 if (dark == true && lightSensor != null && lightSensor != "")
245 log.debug "$dimmers will turn ON when movement detected and when it is dark..."
246 subscribe(lightSensor, "illuminance", illuminanceHandler, [filterEvents: false])
250 log.debug "$dimmers will turn ON when movement detected between sunset and sunrise..."
252 subscribe(location, "position", locationPositionChange)
253 subscribe(location, "sunriseTime", sunriseSunsetTimeHandler)
254 subscribe(location, "sunsetTime", sunriseSunsetTimeHandler)
256 else if (dark != true && sun != true)
258 log.debug "$dimmers will turn ON when movement detected..."
261 log.debug "Determinating lights and dimmers current value..."
262 if (lights != null && lights != "")
264 if (lights.currentValue("switch").toString().contains("on"))
266 state.lightsState = "on"
267 log.debug "Lights $state.lightsState."
269 else if (lights.currentValue("switch").toString().contains("off"))
271 state.lightsState = "off"
272 log.debug "Lights $state.lightsState."
279 if (dimmers != null && dimmers != "")
281 if (dimmers.currentValue("switch").toString().contains("on"))
283 state.dimmersState = "on"
284 log.debug "Dimmers $state.dimmersState."
286 else if (dimmers.currentValue("switch").toString().contains("off"))
288 state.dimmersState = "off"
289 log.debug "Dimmers $state.dimmersState."
298 def locationPositionChange(evt)
300 log.trace "locationChange()"
304 def sunriseSunsetTimeHandler(evt)
306 state.lastSunriseSunsetEvent = now()
307 log.debug "SmartNightlight.sunriseSunsetTimeHandler($app.id)"
311 def motionHandler(evt)
313 log.debug "$evt.name: $evt.value"
314 if (evt.value == "active")
316 unschedule(turnOffLights)
317 unschedule(turnOffDimmers)
318 if (dark == true && sun == true)
320 if (darkOk == true && sunOk == true)
322 log.debug "Lights and Dimmers will turn ON because $motionSensor detected motion and $lightSensor was dark or because $motionSensor detected motion between sunset and sunrise..."
323 if (lights != null && lights != "")
325 log.debug "Lights: $lights will turn ON..."
328 if (dimmers != null && dimmers != "")
330 log.debug "Dimmers: $dimmers will turn ON..."
334 else if (darkOk == true && sunOk != true)
336 log.debug "Lights and Dimmers will turn ON because $motionSensor detected motion and $lightSensor was dark..."
337 if (lights != null && lights != "")
339 log.debug "Lights: $lights will turn ON..."
342 if (dimmers != null && dimmers != "")
344 log.debug "Dimmers: $dimmers will turn ON..."
348 else if (darkOk != true && sunOk == true)
350 log.debug "Lights and dimmers will turn ON because $motionSensor detected motion between sunset and sunrise..."
351 if (lights != null && lights != "")
353 log.debug "Lights: $lights will turn ON..."
356 if (dimmers != null && dimmers != "")
358 log.debug "Dimmers: $dimmers will turn ON..."
364 log.debug "Lights and dimmers will not turn ON because $lightSensor is too bright or because time not between sunset and surise."
367 else if (dark == true && sun != true)
371 log.debug "Lights and dimmers will turn ON because $motionSensor detected motion and $lightSensor was dark..."
372 if (lights != null && lights != "")
374 log.debug "Lights: $lights will turn ON..."
377 if (dimmers != null && dimmers != "")
379 log.debug "Dimmers: $dimmers will turn ON..."
385 log.debug "Lights and dimmers will not turn ON because $lightSensor is too bright."
388 else if (dark != true && sun == true)
392 log.debug "Lights and dimmers will turn ON because $motionSensor detected motion between sunset and sunrise..."
393 if (lights != null && lights != "")
395 log.debug "Lights: $lights will turn ON..."
398 if (dimmers != null && dimmers != "")
400 log.debug "Dimmers: $dimmers will turn ON..."
406 log.debug "Lights and dimmers will not turn ON because time not between sunset and surise."
409 else if (dark != true && sun != true)
411 log.debug "Lights and dimmers will turn ON because $motionSensor detected motion..."
412 if (lights != null && lights != "")
414 log.debug "Lights: $lights will turn ON..."
417 if (dimmers != null && dimmers != "")
419 log.debug "Dimmers: $dimmers will turn ON..."
424 else if (evt.value == "inactive")
426 unschedule(turnOffLights)
427 unschedule(turnOffDimmers)
428 if (state.lightsState != "off" || state.dimmersState != "off")
430 log.debug "Lights and/or dimmers are not OFF."
433 def delay = delayMinutes * 60
434 if (dark == true && sun == true)
436 log.debug "Lights and dimmers will turn OFF in $delayMinutes minute(s) after turning ON when dark or between sunset and sunrise..."
437 if (lights != null && lights != "")
439 log.debug "Lights: $lights will turn OFF in $delayMinutes minute(s)..."
440 runIn(delay, turnOffLights)
442 if (dimmers != null && dimmers != "")
444 log.debug "Dimmers: $dimmers will turn OFF in $delayMinutes minute(s)..."
445 runIn(delay, turnOffDimmers)
448 else if (dark == true && sun != true)
450 log.debug "Lights and dimmers will turn OFF in $delayMinutes minute(s) after turning ON when dark..."
451 if (lights != null && lights != "")
453 log.debug "Lights: $lights will turn OFF in $delayMinutes minute(s)..."
454 runIn(delay, turnOffLights)
456 if (dimmers != null && dimmers != "")
458 log.debug "Dimmers: $dimmers will turn OFF in $delayMinutes minute(s)..."
459 runIn(delay, turnOffDimmers)
462 else if (dark != true && sun == true)
464 log.debug "Lights and dimmers will turn OFF in $delayMinutes minute(s) between sunset and sunrise..."
465 if (lights != null && lights != "")
467 log.debug "Lights: $lights will turn OFF in $delayMinutes minute(s)..."
468 runIn(delay, turnOffLights)
470 if (dimmers != null && dimmers != "")
472 log.debug "Dimmers: $dimmers will turn OFF in $delayMinutes minute(s)..."
473 runIn(delay, turnOffDimmers)
476 else if (dark != true && sun != true)
478 log.debug "Lights and dimmers will turn OFF in $delayMinutes minute(s)..."
479 if (lights != null && lights != "")
481 log.debug "Lights: $lights will turn OFF in $delayMinutes minute(s)..."
482 runIn(delay, turnOffLights)
484 if (dimmers != null && dimmers != "")
486 log.debug "Dimmers: $dimmers will turn OFF in $delayMinutes minute(s)..."
487 runIn(delay, turnOffDimmers)
493 log.debug "Lights and dimmers will stay ON because no turn OFF delay was set..."
496 else if (state.lightsState == "off" && state.dimmersState == "off")
498 log.debug "Lights and dimmers are already OFF and will not turn OFF in $delayMinutes minute(s)."
503 def lightsHandler(evt)
505 log.debug "Lights Handler $evt.name: $evt.value"
506 if (evt.value == "on")
508 log.debug "Lights: $lights now ON."
509 unschedule(turnOffLights)
510 state.lightsState = "on"
512 else if (evt.value == "off")
514 log.debug "Lights: $lights now OFF."
515 unschedule(turnOffLights)
516 state.lightsState = "off"
520 def dimmersHandler(evt)
522 log.debug "Dimmer Handler $evt.name: $evt.value"
523 if (evt.value == "on")
525 log.debug "Dimmers: $dimmers now ON."
526 unschedule(turnOffDimmers)
527 state.dimmersState = "on"
529 else if (evt.value == "off")
531 log.debug "Dimmers: $dimmers now OFF."
532 unschedule(turnOffDimmers)
533 state.dimmersState = "off"
537 def illuminanceHandler(evt)
539 log.debug "$evt.name: $evt.value, lastStatus lights: $state.lightsState, lastStatus dimmers: $state.dimmersState, motionStopTime: $state.motionStopTime"
540 unschedule(turnOffLights)
541 unschedule(turnOffDimmers)
542 if (evt.integerValue > 999)
544 log.debug "Lights and dimmers will turn OFF because illuminance is superior to 999 lux..."
545 if (lights != null && lights != "")
547 log.debug "Lights: $lights will turn OFF..."
550 if (dimmers != null && dimmers != "")
552 log.debug "Dimmers: $dimmers will turn OFF..."
556 else if (evt.integerValue > ((luxLevel != null && luxLevel != "") ? luxLevel : 50))
558 log.debug "Lights and dimmers will turn OFF because illuminance is superior to $luxLevel lux..."
559 if (lights != null && lights != "")
561 log.debug "Lights: $lights will turn OFF..."
564 if (dimmers != null && dimmers != "")
566 log.debug "Dimmers: $dimmers will turn OFF..."
576 if (state.lightsState != "on")
578 log.debug "Turning ON lights: $lights..."
580 state.lightsState = "on"
584 log.debug "Lights: $lights already ON."
589 log.debug "Time, days of the week or mode out of range! $lights will not turn ON."
597 if (state.dimmersState != "on")
599 log.debug "Turning ON dimmers: $dimmers..."
600 settings.dimmers?.setLevel(level)
601 state.dimmersState = "on"
605 log.debug "Dimmers: $dimmers already ON."
610 log.debug "Time, days of the week or mode out of range! $dimmers will not turn ON."
619 if (state.lightsState != "off")
621 log.debug "Turning OFF lights: $lights..."
623 state.lightsState = "on"
627 log.debug "Lights: $lights already OFF."
632 log.debug "Time, day of the week or mode out of range! $lights will not turn OFF."
640 if (state.dimmersState != "off")
642 log.debug "Turning OFF dimmers: $dimmers..."
644 state.dimmersState = "off"
648 log.debug "Dimmers: $dimmers already OFF."
653 log.debug "Time, day of the week or mode out of range! $dimmers will not turn OFF."
659 def s = getSunriseAndSunset(zipCode: zipCode, sunriseOffset: sunriseOffset, sunsetOffset: sunsetOffset)
660 state.riseTime = s.sunrise.time
661 state.setTime = s.sunset.time
662 log.debug "Sunrise: ${new Date(state.riseTime)}($state.riseTime), Sunset: ${new Date(state.setTime)}($state.setTime)"
668 if (dark == true && lightSensor != null && lightSensor != "")
670 result = lightSensor.currentIlluminance < ((luxLevel != null && luxLevel != "") ? luxLevel : 50)
672 log.trace "darkOk = $result"
682 result = t < state.riseTime || t > state.setTime
684 log.trace "sunOk = $result"
688 private getSunriseOffset()
690 sunriseOffsetValue ? (sunriseOffsetDir == "Before" ? "-$sunriseOffsetValue" : sunriseOffsetValue) : null
693 private getSunsetOffset()
695 sunsetOffsetValue ? (sunsetOffsetDir == "Before" ? "-$sunsetOffsetValue" : sunsetOffsetValue) : null
700 modeOk && daysOk && timeOk
705 def result = !modes || modes.contains(location.mode)
706 log.trace "modeOk = $result"
715 def df = new java.text.SimpleDateFormat("EEEE")
716 if (location.timeZone)
718 df.setTimeZone(location.timeZone)
722 df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
724 def day = df.format(new Date())
725 result = days.contains(day)
727 log.trace "daysOk = $result"
734 if (starting && ending)
737 def start = timeToday(starting).time
738 def stop = timeToday(ending).time
739 result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
741 log.trace "timeOk = $result"
745 private hhmm(time, fmt = "h:mm a")
747 def t = timeToday(time, location.timeZone)
748 def f = new java.text.SimpleDateFormat(fmt)
749 f.setTimeZone(location.timeZone ?: timeZone(time))
753 private hideOptionsSection()
755 (starting || ending || days || modes) ? false : true
758 private timeIntervalLabel()
760 (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""