Imp doesn't wakeup when offline

Hi.
I’m looking to sync my imp’s clock with the Agent’s time() function. Seems like it’s working when the device is online. However, I would like the code to keep running even offline (for example, when the WiFi is dropped for some reason), until it reconnects. I would then like it to use the hardware.millis() function.
The problem is that my device doesn’t seem to wake when offline! Is there something I’m missing? Does imp.wakeup() on the device work only when connected to server?
I’m attaching a piece of the code. I hope it helps understand my problem:

The Device Code:

`server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 5);

function fdn2(value){
dtm2 = (value%1000000)1000-hardware.millis()+50;
hhh = (value%86400)/3600;
if ((lasthh == (hhh - 1))&&((hhh == 20)||(hhh == 8))) {do_stuff();}
lasthh = hhh;
minsleft = (60
60 - value%3600);
server.log(“Waking up in " + minsleft/60 + " minutes”);
imp.wakeup(minsleft,checkAgent);
}

function offline() {
local offlinevalue;

offlinevalue= dtm2 + hardware.millis();
hhh = (offlinevalue%86400)/3600;
if ((lasthh == (hhh - 1))&&((hhh == 20)||(hhh == 8))) {do_stuff();}
lasthh = hhh;
minsleft = (60*60 - offlinevalue%3600);
server.log("Waking up in " + minsleft/60 + " minutes");
imp.wakeup(minsleft,checkAgent);

}

function online() {
imp.onidle(agent.on(“dn”,fdn2));
agent.send(“trig”,0);
}

function checkAgent() {
agentup = 0;
imp.onidle(agent.on(“pong”,function(code){
agentup = 1; // Indicate Agent is up
}));
server.log(“Pinging agent…”);
agent.send(“ping”,0);
imp.wakeup(5,function(){if (!agentup) {server.log(“Imp offline”); offline()}
else {server.log(“Imp online”); online()}
})
};

checkAgent();`

The Agent code:

`function loop() {
imponline == false;
device.on(“ping”,function(code){
imponline == true;
server.log(“Ponging device…”);
device.send(“pong”,0);
});
device.on(“trig”,function(sendtime){
s = time();
while(s == time());
device.send(“dn”,(s+1));
}
}

loop();`

Thanks!

You need to implement an server.onunexpecteddisconnect handler.

As noted in the setsendtimeoutpolicy, if you set RETURN_ON_ERROR, you need a disconnect handler. The handler is the code that will run when it’s disconnected, and should have a server.connect in it somewhere (as that’s the only way the imp will try to reconnect).

Documentation around “off-line” mode is a little sparse - but it’s on our documentation todo list!

How do I do that? I’ve tried to add it at the end, after calling the checkAgent() function. Still didn’t work…
The line added is:

server.onunexpecteddisconnect(function(reason){offline();});

Thanks for the help!

The issue that you are never trying to reconnect. With server.setsendtimeoutpolicy(RETURN_ON_ERROR, …) you need to explicitly call server.connect() somewhere in your code (that runs while disconnected) or else your imp will never try to reconnect.

Edit: Here is some code to get you started:

`// set RETURN_ON_ERROR policy
server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT,30);

// create a connected variable to track connection state
connected <- false;
// if we’re currently connected, set connected to true at startup
if(server.isconnected()) connected = true;

function onConnectedCallback(state) {
if (state == SERVER_CONNECTED) {
// if we’re connected, set connected flag
connected = true;
server.log(“connected”);
} else {
// if this connection failed, try again in 30 seconds
imp.wakeup(30, connectionLoop)
}
}

function connectionLoop() {
if (!connected) {
// if we’re not connected, try connecting
// (onConnectCallback will call connectionLoop if the connection failed)
server.connect(onConnectCallback, 30);
}
}

// when we unexpectedly disconnect:
server.onunexpecteddisconnect(function(reason) {
// set the flag
connected = false;
// start the connection loop
connectionLoop();
});`

Thanks. I’ll try incorporating the code into my own.

The problem is that it seems like the imp doesn’t even wake up when offline. First, I can clearly see it does not light up. Second, the pins don’t trigger as scheduled. I would expect that to work even without the device attempting to reconnect, no?
Am I missing something?
Thanks again.

It’s not surprising that the imp doesn’t light up…

Unless otherwise specified (with imp.enableblinkup(true)), the imp only blinks for the first minute it is online (after that it shuts down the blinkup circuit to save batteries). You are using imp.wakeup, which doesn’t actually put the imp to sleep (it schedules the callback to run in x seconds).

I don’t see anything in the code you posted that would trigger pins… is that somewhere else? Are you certain your imp is following the code path you think it is?

A pin is triggered within the do_stuff() function, which I’ve spared you for simplicity… sorry, I should have mentioned.

I’m pretty certain the code path is correct, because when I cancel out the device.send(“pong”,0); line in the agent code, everything works great and the offline() function is called upon. The pin is then triggered, as expected.

Is there anything else I should try out?
Thanks.

Oh, actually - I didn’t really look at your agent code. So you need to change a few things:

`function loop() {
imponline == false;
device.on(“ping”,function(code){
imponline == true;
server.log(“Ponging device…”);
device.send(“pong”,0);
});
device.on(“trig”,function(sendtime){
s = time();
while(s == time());
device.send(“dn”,(s+1));
}
}

loop();`

You don’t actually need the loop function. When you create an agent.on/device.handler, it sets up a “listener” for that event - once you’ve setup the trigger, you don’t need to do anything else (it gets triggered automatically).

There’s a couple other issues with the agent code:

  1. imponline == false; and imponline == true; compares imponline to false/true, it doesn’t set it. To set the variable you need to use: imponline=false; and imponline=true;

Your agent code should look like this:

`//agent code
imponline <- false;

device.on(“ping”, function(code) {
imponline = true;
server.log(“Ponging device…”);
device.send(“pong”,0);
});

device.on(“trig”,function(sendtime) {
s = time();
while(s == time());
device.send(“dn”,(s+1));
});`

Finally - your second device.on has some blocking code in it (the while (s == time()) loop). This isn’t the end of the world, but best practice is to code with events wherever possible - in this case, you could use something like the following:

device.on("trig", function(sendtime) { s = time(); // wait a second, then execute this function imp.wakeup(1, function() { device.send("dn", (s+1)); }); });

Thanks!
That did the trick!
I guess the loop() thing solved it, although I don’t quite understand why…

@spicymeatball - Give this article on event driven programming a read.

It explains how events and event handling with Electric Imp works (any why you don’t need the loop function you had). If it still doesn’t make sense come back and I’ll try to explain a bit more in here.