Well, that’s important.
Trying again.
/**
*/
definition(
name: “LightsFollowMeConditionally”,
namespace: “mikelupo”,
author: “michael lupo”,
description: “Detected motion turns on switch devices (for a duration, in seconds) when the detected light falls below a given level.”,
category: “Safety & Security”,
iconUrl: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png”,
iconX2Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”,
iconX3Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”)
preferences {
section(“When motion is detected on …”) {
input “motionSensor”,“capability.motionSensor”, title: “Select a motion sensor”, multiple: true
}
section ("…and sample the light value from (Sensor)") {
input “lightSensor”, “capability.illuminanceMeasurement”, title: “Select an illuminance sensor”
input “lightValue”, “number”, title: “Lux Value is darker than”, required: true
}
section ("…and turn on if one of these peeps becomes present") {
input “presenceSensor”, “capability.presenceSensor”, title: “people”, required: false, multiple:true
}
section(“Turn on the following…”) {
input “lights”, “capability.switch”, title: “Turn on?”, required: false, multiple: true
input “offset”, “number”, title: “Turn on this many minutes before sunset”
}
section(“When turned on by motion, turn it off after…”){
input “seconds”, “number”, title: “Seconds”, required: true
}
section(“Turn off lights at…”) {
input “timeToRun”, “time”
}
}
//this code is becoming a bit rotton. It might be time to remove it.
def myIlluminanceHandler(evt) {
def currentIlluminance = “{evt.integerValue}"
def lastKnownIlluminance = state.lastKnownIlluminance
log.debug "The current illumanance sent by the event is: {evt.integerValue}”
log.debug “The last known illuminance was: {lastKnownIlluminance}"
log.debug "Your selected LUX value is: {lightValue}”
//now update the persisted stored value (state) to hold the new value.
state.lastKnownIlluminance = evt.integerValue
def lastStatus = state.lastStatus
}
//Turn on the lights by motion. Ignore the event if the lights are in the “sticky” on routine.
//otherwise, we turn the lights on if the illuminance is low enough. (i.e. before sunset but it’s dark enough, or after midnight)
//Be advised: that the sensor samples one per hour. So we could possibly miss the first events of the hour. Hopefully though,
//the sticky routine will workaround this for us as the lights should be on at sunset.
def myMotionHandler(evt) {
if (state.isTurnedOnBySunset == true) {
log.debug (“myMotionHandler: Lights are operated by Cron right now. Ignoring motion events”)
return
}
def motionValue = "${evt.value}"
log.debug "The motion sent by the event is: ${motionValue}"
def lastKnownIlluminanceValue = state.lastKnownIlluminance
log.debug "Last known illuminance is: ${lastKnownIlluminanceValue}"
def lastStatus = "${state.lastStatus}"
log.debug "Last status: ${lastStatus}"
if ( "${motionValue}" == "active" && lastKnownIlluminanceValue.intValue() < lightValue && lastStatus != "on") {
log.debug("Turning the light on")
lights.on()
state.lastStatus = "on"
log.debug "Updating last status from ${lastStatus} to ${state.lastStatus}"
state.isTurnedOnByMotion = true
//turn off the light after motion is stopped and the given delay is expired if the light was turned on by motion.
} else if ("${motionValue}" == "inactive" && lastStatus == "on" && state.isTurnedOnByMotion == true) {
//This sets a timer to call the "scheduledTurnOff" method when the light comes on as a result of motion.
//def delay = seconds * 60 //use this if we decide to use minutes instead of seconds.
def delay = seconds
log.debug "Will turn off the light in ${delay} seconds"
runIn(delay, "scheduledTurnOff")
} else if ("${motionValue}" == "active" && lastStatus == "on" && state.isTurnedOnByMotion == true) {
def delay = seconds
} else if ("${motionValue}" == "active" && lastStatus == "on" && state.isTurnedOnByMotion == false) {
log.debug "The light was turned on manually, we will not turn it off by timer."
}
}
//TODO: create a status.motionDetected map to know whether the light was turned on as a result of motion, or as a result of a manual toggle.
def mySwitchHandler(evt) {
log.debug("-----------------------------------------------------------")
for (myLight in lights) {
log.debug “mySwitchHandler: The light: {myLight} has been turned {myLight.latestValue(“switch”)}”
}
log.debug("-----------------------------------------------------------")
//this handles the case where we may have turned the light off manually or via the timer.
if ("${evt.value}" == "off"){
state.isTurnedOnByMotion = false
}
state.lastStatus = "${evt.value}"
}
def myPresenceHandler(evt) {
//if the lights are on because of the sunset -> 23:59, then let’s ignore the event…because the lights are already on.
if (state.isTurnedOnBySunset == true) {
log.debug (“myPresenceHandler: Lights are operated by Cron right now. Ignoring presence events”)
return
}
def lastKnownIlluminanceValue = state.lastKnownIlluminance
log.debug "Last known illuminance is: ${lastKnownIlluminanceValue}"
def lastStatus = "${state.lastStatus}"
log.debug "Last status: ${lastStatus}"
if ("${evt.value}" == "present") {
log.debug("Someone came home")
if ( lastKnownIlluminanceValue.intValue() < lightValue && lastStatus != "on") {
log.debug("Turning the light on because someone came home")
lights.on()
state.lastStatus = "on"
log.debug "Updating last status from ${lastStatus} to ${state.lastStatus}"
state.isTurnedOnByPresence = true
def delay = seconds
log.debug "Will turn off the light in ${delay} seconds"
runIn(delay, "scheduledTurnOff")
//turn off the light after motion is stopped and the given delay is expired if the light was turned on by motion.
} else if (lastStatus == "on" && state.isTurnedOnByPresence == true) {
//This sets a timer to call the "scheduledTurnOff" method when the light comes on as a result of motion.
//def delay = seconds * 60 //use this if we decide to use minutes instead of seconds.
def delay = seconds
log.debug "Will turn off the light in ${delay} seconds"
runIn(delay, "scheduledTurnOff")
} else if (lastStatus == "on" && state.isTurnedOnByPresence == true) {
def delay = seconds
} else if (lastStatus == "on" && state.isTurnedOnByPresence == false) {
log.debug "The light was already turned on and therefore we will not turn it off by timer."
}
} else {
log.debug("Someone left. Buh bye!")
}
}
def installed() {
//state is a persistently stored map.
state.lastKnownIlluminance = 0;
log.debug “Installed with settings: ${settings}”
subscribe(lightSensor, “illuminance”, myIlluminanceHandler)
subscribe(motionSensor, “motion”, myMotionHandler)
subscribe(lights, “switch.on”, mySwitchHandler)
subscribe(lights, “switch.off”, mySwitchHandler)
subscribe(presenceSensor, “presence”, myPresenceHandler)
//By adding the sunset/sunrise handlers, we have new handlers that can help us set states.
//subscribe(location, "sunset", sunsetHandler)
//subscribe(location, "sunrise", sunriseHandler)
//this is only here to test since I only get one sunset per day. Maybe I can use this with an offset?
def sunset = getSunriseAndSunset(zipCode: "02769").sunset
//calculate the offset
def timeBeforeSunset = new Date(sunset.time - (offset * 60 * 1000))
log.debug "Scheduling for: $timeBeforeSunset (sunset is $sunset)"
//schedule this to run daily at a specific time.
schedule(timeBeforeSunset, turnOnLightsByCronHandler)
//this is the handler that should turn off the lights when we hit the specified hard-coded time.
schedule(timeToRun, turnOffLightsByCronHandler)
//this is intended to turn the lights back on if we're in the between Sunset and 23:59 routine.
runEvery1Minute(stickyLightsOnHandler)
//initializing this state.
state.isTurnedOnByMotion = false
state.isTurnedOnBySunset = false
}
def updated() {
log.debug “Updated with settings: ${settings}”
unsubscribe()
installed()
}
//if the lights are supposed to be turned on, and someone accidentally turned them off, we turn them back on.
def stickyLightsOnHandler() {
def sunset = getSunriseAndSunset(zipCode: “02769”).sunset
log.debug “Today’s sunset will be at: ${sunset}”
if (state.isTurnedOnBySunset == true) {
//there is something wrong here. I am getting NPE in the if statement. TODO: figure out how to detect the current light value.
// for (myLight in lights) {
// if ({myLight.latestValue("switch")} == "off") {
// myLight.on()
// log.debug "stickyLightsOnHandler: The light: {myLight} has been turned ${myLight.latestValue(“switch”)} because it was off and they should be on because of CRON!"
// }
// }
//just shotgun approach. I liked the for loop approach better, but I can’t figure out what is wrong.
lights.on()
}
}
def turnOffLightsByCronHandler() {
state.isTurnedOnBySunset = false
lights.off()
}
def turnOnLightsByCronHandler() {
state.isTurnedOnBySunset = true
lights.on()
}
//def sunsetHandler(evt) {
// log.debug “Sun has set!”
// state.isTurnedOnBySunset = true
// lights.on()
//}
//def sunriseHandler(evt) {
// log.debug "Sun has risen!"
// lights.off()
//}
def scheduledTurnOff() {
lights.off()
}