Can someone help me understand runIn() and unschedule()?


(Yk Chen) #1

Hi, all,

I am new here. I tried to write my own SmartApp as shown below. The goal of the code is to lock the door 3-5 minutes after the door is closed. I have a separate contact sensor from the lock.

Here are my troubles:
(1) Currently, runIn() does not seem to work. If I understand correctly, runIn should trigger the lockDoor() 3-5 minutes after the door is closed. However, my door always lock immediately after the door is closed.
(2) Currently, unschedule() does not seem to work. If I understand correctly, if I schedule an action to the lock door 3-5 minutes later, but the door is open 1 minute later, then the contactHandler will be called and the unschedule() should cancel the lock action. However, my lcok still extends the latch (which is incorrect).

Suggestions/comments are strongly appreciated.


preferences
{
    section("When a door unlocks...") {
        input "lock1", "capability.lock"
    }
    section("When the door closes..."){
		input "contact1", "capability.contactSensor", title: "Where?"
	}
    section("Lock it how many minutes after the door is closed?") {
        input "minutesAfterClosed", "number", title: "When?"
    }
}

def installed()
{
    log.debug "Auto Lock Door installed."
    initialize()
}

def updated()
{
    unsubscribe()
    unschedule()
    log.debug "Auto Lock Door updated."
    initialize()
}

def initialize()
{
    log.debug "Settings: ${settings}"
    subscribe(contact1, "contact", contactHandler) 
}

def lockDoor()
{
    log.debug "Locking the door"
	lock1.lock()
}

def contactHandler(evt) 							// This procedure runs when the door sensor reports closed.
{
	log.debug "The event is trigger by ${evt.displayName} with value ${evt.value}"
	
	unschedule()
    if (evt.value == "closed") { 					// If the door is closed
    	def secondsAfterClosed = minutesAfterClosed * 60
        log.debug "Schedule to lock in ${secondsAfterClosed} seconds"
		runIn ( secondsAfterClosed, lockDoor())	// Schedule to lock the door
	}
}


(Steve S) #2

@ykchen913 - try not putting the () in your runIn call. Make it like so:

runIn ( secondsAfterClosed, lockDoor) // Schedule to lock the door

Also, you can just subscribe to the closed event if you want - that way you don’t have to check in your contactHandler if it was a closed event:

subscribe(contact1, "contact.closed", contactHandler)

Finally, in Unschedule, I typically also supply the name of the handler I want to unschedule - it might not make a difference in your app, but if you write one where you have multiple things scheduled and you only want to unschedule some of them, you can specify like so:

unschedule(lockDoor)

I hope that helps some.


(Ryan) #3

@ykchen913 - Did you get it to work? I tried something similar and found that unschedule() failed to prevent the function within runIn from being called.


(Yk Chen) #4

Yes, it works for me. I am a little confused about the difference between runIn ( secondsAfterClosed, lockDoor) and runIn ( secondsAfterClosed, lockDoor()). @Steve, can you share your insight why “()” makes the difference? Thanks.


(Tony Gutierrez) #5

How do you pass a parameter to the function you are calling in runIn? Shit, actually now it says I cant even use runin. Am I missing an import?


(Ron S) #6

I think the proper way of using runIn is (somebody can correct me…):
runIn(60, “sendPresenceMessage”, [overwrite: false]);

def presenceHandler(evt)
{
    log.debug "evt.name: $evt.value";
	if (evt.value == "not present"){
		log.debug "Check if everybody is away.";
		if (everyoneIsAway()){
        	log.debug "Everybody is away. Sceheduling runIn...";
                        //60 seconds. Setting below 60 seconds may not work.
			runIn(60, "sendPresenceMessage", [overwrite: false]);
		} else {
			log.debug "Somebody is home. Not sending text message or push.";
		}			
	}
}

private everyoneIsAway()
{
    def result = true;
    for (person in people) {
        if (person.currentPresence == "present") {
            log.debug person.displayName + " is present.";
            result = false;
            break;
        } else {
        	log.debug person.displayName + " is not present.";
        }
    }
    log.debug "everyoneIsAway: $result";
    return result;
}

def sendPresenceMessage()
{
	def msg = null;
    msg = "Everybody is away. Confirmed home is now in ${location.mode} mode";
	if (phone){
		log.debug( "Sending text message" )
        log.debug (msg);
		sendSms( phone, msg );
	}
	if (sendPushMessage != "No") {
    	log.debug( "Sending push message" )
    	log.debug (msg);
        sendPush( msg );
    }
}

(Tony Gutierrez) #7

Turns out you cant use runin in a device type.