Turn Light Off After X Amount Of Time Unless Triggered

Yes that is exactly what I am looking for, just couldn’t figure it out. It would be greatly appreciated.

OK, it’s done, same file as above. Just follow the link above to get the updated copy, then copy/paste into IDE to install. Let me know if it works for you! :grinning:

Okay cool I will definitely test this out here after awhile when I can. Thanks again for the help. I will post back with the results.

The “Optional switch to cancel” is looking for text input like assigning a name, but you can’t choose a switch.

Must be a typo. Give me a minute…

Haha, I found where the typo was after I went back and looked at the code.

I give, what’s the typo?

input “cancel”, “capabiity.switch”, title: “Optional switch to cancel”, required: false, multiple: false

Ya, I found it just now too. I’ll fix the Github copy. Thanks! :grinning:

1 Like

Alright, appreciate it as this should be exactly what I’m looking for. Not a problem.

1 Like

Welcome back!

20 char…you missed all the fun…

Tested it and it worked perfectly. Thank you very much for the help in getting this going with your app.

You’re welcome!

Question for you: Will you actually use both parts of the automation? That is, sometimes the light will just turn off after x minutes, but sometimes, you’ll turn on the other switch to keep the light on? I’m just curious.

Yes I will. There are times where I open my garage door, but need my lights to stay on so simply tapping the switch will keep the lights on for me instead of turning off and leaving me in the dark. Very useful.

1 Like

Well somehow I can’t seem to get this to work now. I deleted everything to better organize things and simplify things. It worked fine using this app but now it doesn’t

I need the lights to come on for 5 minutes when the garage door opens unless already on.

Any help would be appreciated. I am assuming this will require virtual switches.

If your garage door includes a contact sensor, you could do this with Rule Machine.

Conditions would be garage-lights off, garage-door open. Rule would be garage-lights off AND garage-door open, and the actions for true would be turn on the lights and turn-off after delay of 5 minutes.

So, if the lights are off, and the door opens, the lights would come on and then turn off 5 minutes later. But, if the lights are on when the door opens, the rule fails, and it doesn’t turn the lights off after 5 minutes.

It does have a contact sensor. I thought about using rule machine, but unfortunately it does not have the press switch to cancel timer ability.

Wasn’t sure if that would be possible, or if it works by checking if the contact state has changed to open.

Tried it with rule machine, but if the garage door is open it will turn the lights off after X amount of minutes then turn them right back on.

Here’s the latest version of Smart Timer X

/**

  • Smart Timer
  • Loosely based on “Light Follows Me”
  • This prevent them from turning off when the timer expires, if they were already turned on
  • If the switch is already on, if won’t be affected by the timer (Must be turned of manually)
  • If the switch is toggled while in timeout-mode, it will remain on and ignore the timer (Must be turned of manually)
  • The timeout perid begins when the contact is closed, or motion stops, so leaving a door open won’t start the timer until it’s closed.
  • Author: andersheie@gmail.com
  • Date: 2015-10-30
    */

definition(
name: “Smart Light Timer, X minutes unless already on”,
namespace: “Pope”,
author: "listpope@cox.net",
description: “Turns on a switch for X minutes, then turns it off. Unless, the switch is already on, in which case it stays on. If the switch is toggled while the timer is running, the timer is canceled.”,
category: “Convenience”,
iconUrl: “http://upload.wikimedia.org/wikipedia/commons/6/6a/Light_bulb_icon_tips.svg”,
iconX2Url: “http://upload.wikimedia.org/wikipedia/commons/6/6a/Light_bulb_icon_tips.svg”)

preferences {
section(“Turn on when there is movement…”){
input “motions”, “capability.motionSensor”, multiple: true, title: “Select motion detectors”, required: false
}
section(“Or, turn on when one of these contacts opened”){
input “contacts”, “capability.contactSensor”, multiple: true, title: “Select Contacts”, required: false
}
section(“Or, turn on when any of these people come home”) {
input “peoplearrive”, “capability.presenceSensor”, multiple: true, required: false
}
section(“Or, turn on when any of these people leave”) {
input “peopleleave”, “capability.presenceSensor”, multiple: true, required: false
}
section(“And off after no more triggers after…”){
input “minutes1”, “number”, title: “Minutes?”, defaultValue: “5”
}
section(“Turn on/off light(s)…”){
input “switches”, “capability.switch”, multiple: true, title: “Select Lights”
}
}

def installed()
{
log.debug "installed()"
initialize()
}

def updated()
{
log.debug "updated()"
initialize()
}

def initialize()
{
log.debug “initialize()”
// Reset to new set of Switches, just in case.
unsubscribe()

state.switches = [:]

switches.each { 
  // log.debug "ID: $it.id" 
    // Set ready state for each switch
    state.switches["$it.id"] = "ready"
}
logStates()

subscribe(motions, “motion”, motionHandler)
subscribe(switches, “switch”, switchChange)
subscribe(contacts, “contact”, contactHandler)
subscribe(peoplearrive, “presence.present”, presencePresentHandler)
subscribe(peopleleave, “presence.not present”, presenceNotPresentHandler)
state.lastAction = null
schedule(“0 * * * * ?”, “scheduleCheck”)

}

def logStates() {
if(state.switches == null) {
state.switches = [:]
}
state.switches.each {
log.debug “State: $it.key = $it.value”
}
}

def turnSwitchOn(id) {
for(S in switches) {
if(S.id == id) {
S.on()
}
}
}

def turnSwitchOff(id) {
for(S in switches) {
if(S.id == id) {
S.off()
}
}
}

def initState(deviceID) {
// Have to add this so existing apps that are neither updated nor initiated can slowly get ‘reset’ with states.
// Smartthings doesn’t call any specific method when new version is published.

if(state.switches == null) {
state.switches = [:]
}
if(state.switches[deviceID] == null) {
state.switches[deviceID] = “ready”
}

}

def switchChange(evt) {
def deviceID = evt.device.id
log.debug "SwitchChange: $evt.name: $evt.value $evt.device.id current state = " + state.switches[deviceID]
initState(deviceID)

if(evt.value == “on”) {
if(state.switches[deviceID] == “activating”) {
// OK, probably an event from Activating something, and not the switch itself. Go to Active mode.
log.debug "$deviceID = " + state.switches[deviceID] + " -> active"
state.switches[deviceID] = “active”
} else if(state.switches[deviceID] != “active”) {
log.debug "$deviceID = " + state.switches[deviceID] + " -> already on"
state.switches[deviceID] = “already on”
}
} else {
// If active and switch is turned of manually, then stop the schedule and go to ready state
state.switches[deviceID] = “ready”
}
logStates()

}

def contactHandler(evt) {
log.debug “contactHandler: $evt.name: $evt.value”

state.switches.each { thisswitch ->
	 initState(thisswitch.key)
     //log.debug "Looking for $thisswitch.key"
     if (evt.value == "open") {
        if(state.switches[thisswitch.key] == "ready") {
            log.debug "Turning on lights by contact opening: $thisswitch"
            log.debug "$thisswitch.key = " + state.switches[thisswitch.key] + " -> activating"
            state.switches[thisswitch.key] = "activating"
            turnSwitchOn(thisswitch.key)
            setActiveAndSchedule()
            
        }
    } else if (evt.value == "closed") {
        if (!state.lastAction && (state.switches[thisswitch.key] == "active" 
        					   || state.switches[thisswitch.key] == "activating")) {
            // When contact closes, we reset the timer if not already set
            log.debug "$thisswitch.key = " + state.switches[thisswitch.key] + " -> active"
            state.switches[thisswitch.key] = "active"
            setActiveAndSchedule()
        }
    }
}
logStates()

}

def scheduleCheck() {
log.debug "schedule check, ts = ${state.lastAction}"
boolean resetInactive = false
state.switches.each { thisswitch ->
initState(thisswitch.key)
if(state.switches[thisswitch.key] != “already on”) {
if(state.lastAction != null) {
def elapsed = now() - state.lastAction
log.debug "${elapsed / 1000} sec since events stopped"
def threshold = 1000 * 60 * minutes1
if (elapsed >= threshold) {
if (state.switches[thisswitch.key] == “active”
|| state.switches[thisswitch.key] == “activating”) {
state.switches[thisswitch.key] = "ready"
log.debug "Turning off lights by switch closing: $thisswitch"
turnSwitchOff(thisswitch.key)
}
resetInactive = true
}
}
}
}
if(resetInactive) {
state.lastAction = null
unschedule()
}
logStates()
}

/**********************************************************************/

def motionHandler(evt) {
log.debug "motionHandler: $evt.name: $evt.value (current state: " + state.myState + “)”

state.switches.each { thisswitch ->
initState(thisswitch.key)
if (evt.value == “active”) {
if(state.switches[thisswitch.key] == “ready”
|| state.switches[thisswitch.key] == “active”
|| state.switches[thisswitch.key] == “activating” ) {
log.debug "$thisswitch.key = " + state.switches[thisswitch.key] + " -> activating"
state.switches[thisswitch.key] = "activating"
turnSwitchOn(thisswitch.key)
setActiveAndSchedule()
}
} else if (evt.value == “inactive”) {
if (state.switches[thisswitch.key] == “active” || state.switches[thisswitch.key] == “activating”) {
// When Motion ends, we reset the timer if not already set
log.debug "$thisswitch.key = " + state.switches[thisswitch.key] + " -> active"
state.switches[thisswitch.key] = "active"
setActiveAndSchedule()
}
}
}
logStates()
}

def presencePresentHandler(evt) {
log.debug “presence: $evt.linkText is now $evt.value”

state.switches.each { thisswitch ->
	initState(thisswitch.key)
    if (evt.value == "present") {
        if(state.switches[thisswitch.key] == "ready" 
        	|| state.switches[thisswitch.key] == "active" 
            || state.switches[thisswitch.key] == "activating" ) {
            log.debug "Presence turning on switch $thisswitch"
            state.switches[thisswitch.key] = "active"
            turnSwitchOn(thisswitch.key)
            // We don't wait until the person leave, but instead start timer immediately.
            setActiveAndSchedule()
            
        }
    } 
}
logStates()

}

def presenceNotPresentHandler(evt) {
log.debug “presence: $evt.linkText is now $evt.value”

state.switches.each { thisswitch ->
	initState(thisswitch.key)
    if (evt.value == "not present") {
        if(state.switches[thisswitch.key] == "ready" 
        	|| state.switches[thisswitch.key] == "active" 
            || state.switches[thisswitch.key] == "activating" ) {
            log.debug "No Presence turning on lights $thisswitch"
            state.switches[thisswitch.key] = "active"
            turnSwitchOn(thisswitch.key)
            // We don't wait until the person arrive back, but instead start timer immediately.
            setActiveAndSchedule()
        }
    } 
}
logStates()

}

def setActiveAndSchedule() {
unschedule()
state.lastAction = now()
schedule(“0 * * * * ?”, “scheduleCheck”)
log.debug “Scheduled new timer”
}