/**
* Dual Zone Smart Night Light
*
* Author: tslagle13
*
*/
definition(
name: "Dual Zone Smart Night Light",
namespace: "tslagle13",
author: "Tim Slagle",
description: "Turns on lights using motion and contact sensor. Both values must be closed/not active in order for lights to turn off.",
category: "Convenience",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/light_motion-outlet-luminance.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/light_motion-outlet-luminance@2x.png"
)
preferences {
section("Control these lights..."){
input "lights", "capability.switch", multiple: true
}
section("Turning on when a contact opens and there's movement..."){
input "motionSensor", "capability.motionSensor", title: "Where?"
input "contactSensor", "capability.contactSensor", title: "Which?"
}
section("And then off when it's light or there's been no movement for..."){
input "delayMinutes", "number", title: "Minutes?"
}
}
def installed() {
initialize()
}
def updated() {
unsubscribe()
unschedule()
initialize()
}
def initialize() {
subscribe(motionSensor, "motion", motionHandler)
subscribe(contactSensor, "contact.open", contactHandler)
subscribe(contactSensor, "contact.closed", contactHandler)
}
def motionHandler(evt) {
log.debug "$evt.name: $evt.value"
if (evt.value == "active") {
log.debug "turning on lights due to motion"
lights.on()
state.lastStatus = "on"
state.motionStopTime = null
}
else { // Motion has stoped
state.motionStopTime = now() // The on button was NOT pushed so...
if(delayMinutes) { // If the user set a delay then...
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false]) // Schedule the "lights off" for later.
} else { // Otherwise...
turnOffMotionAfterDelay() // Run the lights off now.
}
}
}
def contactHandler(evt) {
log.debug "$evt.name: $evt.value"
if (evt.value == "open") {
log.debug "turning on lights due to motion"
lights.on()
state.lastStatus = "on"
state.motionStopTime = null
}
else { // Motion has stoped
state.motionStopTime = now()
// The on button was NOT pushed so...
if(delayMinutes) { // If the user set a delay then...
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false]) // Schedule the "lights off" for later.
} else { // Otherwise...
turnOffMotionAfterDelay() // Run the lights off now.
}
}
}
def turnOffMotionAfterDelay(evt) {
log.debug "In turnOffMotionAfterDelay"
if (state.motionStopTime && state.lastStatus != "off") {
def elapsed = now() - state.motionStopTime
if (elapsed >= (delayMinutes ?: 0) * 60000L) {
lights.off()
state.lastStatus = "off"
}
}
}
Basically the contact sensor and motion use the same ādelay timerā the last event to happen will control the event timer. Basically the last contact closed or motion inactive call will start the turn off sequence.
@tslagle13 That is pretty close to what he wants. It still needs to take into account that a person might be in the shower with the door closed. In that scenario the lights could go off because of no motion and the door being closed.
I have pseudo-code on my whiteboard. I will try and build it tomorrow. I think you need to take into account the proximity of door opens and closures. If someone leaves out of the bathroom and does not close the door, the light should go off after a certain period of time. There are also other scenarios where this could end up with someone in the dark.
This is true. Iām wondering how you would account in a smart app for a āfakeā non-motion event though.
(iām not trying to prove my code or anything, i know it works in my home⦠nor am i trying disprove yours⦠i have a genuine interest in how you would account for this.)
My code would definitely work for the general someone is taking a pee or doing their hair scenario though⦠lol
If someone is motionless for large periods of time in the bathroom i canāt help you lol
I am just doing this as a challenge. I gave up on trying to figure it out once before, but this post has sparked my interest in it. I think I have a solution that might work, but I wonāt know until I get some actual code.
I think that the only way to stop a āfakeā non-motion would be to make it dependent on the door sensor being at the very least open a 2nd time in a specific time space.
Letās say a person went into the bathroom closed the door and is taking a bath, if the motion sensor doesnāt see motion but the door was never open again after being closed then it should not make an action
Hereās my philosophy when i write an app. I try not to assume for any variable. If i donāt have emperical data about a situation i tend to not write it into an app. This is what I would do.
You could custom make a trip sensor for the bath that would override all the different inputs for the smart app. SO when someone enters the shower the light stays on permanently.
2.You could use a moisture sensor in the bathtub that would also do the same thing when water is detected. Same thing here. It would over ride the other sensor inputs until no water is detected.
Agreed, but thatās why I have an absolute restart sequence timer for however long I think would be the minimum.
Most importantly as long as my wife doesnāt have the lights turn off on her which I think they wonāt, if the lights stay on because something out of normal occurred than no problem.
This bathroom occupancy thing was one thing I wanted to use ST for in the beginning but itās too complicated for our household. In the end, this simple motion switch did it for us and it still works when the internet goes bonkers. I just have to make sure to move the shower door a bit to reset the motion counter.