Recursion ok with imp.wakeup()

I am having several issues with some code I have written to control my garage door. Since the door button just reverses the door direction from the last time, I want to ensure that an end switch is closed after 30 seconds so I call doorClose from within the doorClose function via imp.wakeup(30.0, doorClose). the program doesn’t seem to wait for the wakeup time (30 sec) to pass before calling itself again. Full code and devise log below:
`// create a global variable called door,
// and assign pin1 to it
door ← hardware.pin1;
endSwitch ← hardware.pin2;

// configure door to be a digital output
door.configure(DIGITAL_OUT);

// function to “push” door button
function buttonPush() {
server.log(“button pushed”);
door.write(1);
}

// function to release door button
function buttonRelease() {
server.log(“button released”);
door.write(0);
}

// function to push and release door button
function buttonToggle(anything) {
buttonPush();
imp.wakeup(1.0, buttonRelease);
}

//create a variable to store the endSwitch Status
local switchStatus = 3;

//function to test endswitch status
function endSwitchStatus() {
switchStatus = endSwitch.read();
server.log("switch Statuss: ");
}

// function to open the door
function openDoor(anything) {
server.log(“open button pushed”);
switchStatus = endSwitch.read();
server.log("switch Status: " + switchStatus);
// if switch closed (pin LOW), toggle the door button
if (switchStatus == 0) {
buttonToggle(1);
// wait 30 seconds, call function again to test to make sure end switch is open
imp.wakeup(30.0, openDoor(1))
}
}

// function to close door
function closeDoor(anything) {
server.log(“close button pushed”);
switchStatus = endSwitch.read();
//server.log("switch Status: ", + switchStatus);
// if switch open (pin HIGH), toggle the door button
if (switchStatus == 1) {
buttonToggle(1);
// wait 30 seconds, call function again to test to make sure end switch is closed
imp.wakeup(30, closeDoor(1))
}
}

// configure endSwitch to be a digital input
endSwitch.configure(DIGITAL_IN);

// register a handler for “button” messages from the agent
agent.on(“close”, closeDoor);
agent.on(“open”, openDoor);
agent.on(“button”, buttonToggle)`

Devise log:

2014-11-09 19:19:36 UTC-8 [Status] Downloading new code; 3.93% program storage used 2014-11-09 20:19:07 UTC-8 [Device] close button pushed 2014-11-09 20:19:07 UTC-8 [Device] switch Status: 1 2014-11-09 20:19:07 UTC-8 [Device] button pushed 2014-11-09 20:19:07 UTC-8 [Device] close button pushed 2014-11-09 20:19:07 UTC-8 [Device] switch Status: 1 2014-11-09 20:19:07 UTC-8 [Device] button pushed 2014-11-09 20:19:07 UTC-8 [Device] close button pushed 2014-11-09 20:19:07 UTC-8 [Device] switch Status: 1 2014-11-09 20:19:07 UTC-8 [Device] button pushed . . . . 2014-11-09 20:19:09 UTC-8 [Device] close button pushed 2014-11-09 20:19:09 UTC-8 [Device] switch Status: 1 2014-11-09 20:19:09 UTC-8 [Device] button pushed 2014-11-09 20:19:09 UTC-8 [Device] close button pushed 2014-11-09 20:19:10 UTC-8 [Device] switch Status: 1 2014-11-09 20:19:10 UTC-8 [Device] button pushed 2014-11-09 20:19:10 UTC-8 [Device] close button pushed 2014-11-09 20:19:10 UTC-8 [Device] switch Status: 1 2014-11-09 20:19:17 UTC-8 [Exit Code] imp restarted, reason: out of memory 2014-11-09 20:19:17 UTC-8 [Status] Device Booting; 3.99% program storage used

What is going on?
Also I have added the “anything” parameter because it seems that the agent devise.send() wants functions to have parameters. Is that right?

Yes, agent.on accepts a string, followed by an event handler function with exactly one parameter. The string and the parameters correspond to those sent by device.send.

Your use of imp.wakeup is not quite correct.

imp.wakeup(30, closeDoor(1))
This line calls closeDoor() immediately and passes the result to imp.wakeup().

You could try one of the following:

imp.wakeup(30, function() { closeDoor(1) })

or

function closeDoor(anything=1){ ... imp.wakeup(30, closeDoor) } }

Thank you!

You may find this interesting. I recently completed the automation of my garage door. I used it as a starting point for mine…

You might want to simplify your code by merging the push & release functions into your toggle function like so:

function buttonToggle() { server.log("button pushed"); door.write(1); imp.sleep(1.0); server.log("button released"); door.write(0); }

Makes your code smaller and easier to troubleshoot. I noticed that your relatively simple code takes up 4% of your program storage area.

@dheadrickdheadrick Thanks for the simplification. The examples I had looked at all used imp.wakeup() as the means for delaying. But wakeup() requires a function (though in way I clearly don’t understand). Thus the separate functions for push and release. I will definitely simplify.

Also I found that instructable after I made my code. I find his code confusing but will probably dive into it as I want my garage door to send me notifications as well and I think the cashed web interface a brilliant idea for faking an iPhone app.

FYI, I am using the existing garage door closed limit switch interfaced to the imp via an opto-isolator, likewise for triggering the door button. So no relay or extra switches.

Ah… my garage door didn’t have any limit switches to use, so I had to add my own.

Don’t let the code on instructables discourage you. If you can divide it up into manageable independent bites, then you only have to look at each smaller part to try and understand it. The agent code has a ton of bits I don’t understand or use, but left in because they were for the use of twitter (which I might want to try in the future).

Once you get your program working, definitely debug it while you’re home in case something goes wrong. Some of my mistakes caused the door to trigger open and close repeatedly every 10 seconds. Also, try powering up your program while the door is in different states. I found another bug which only appeared if the IMP was powered on while the door was not closed.

Re. imp.wakeup(), @charlesowers, the way to think of it is that the function you provide to this method - whether it’s an inline function or one declared elsewhere for which you’re just supplying the name - is that you’re telling the imp to call that function when it wakes. To do that, the imp needs a reference to that function’s location in memory, and this is what imp.wakeup() takes, ie.

imp.wakeup(20.0, myFunction)

You’re not saying ‘when you wake, run the bit of code that comes next’, which is why you don’t use

imp.wakeup(20.0, myFunction() )

which embeds an immediate call to myFunction(). The ‘callback’ syntax above embeds a delayed call, ie. it tells the imp to run the code at the address of myFunction() when it wakes - a subtle, but crucial difference.

Now the situation is actually slightly more complicated than I’ve just described, but that’s the best way to think of what’s going on, I think.

@smittytone Thanks, that does help me understand it.