Working offline is not working

Hi,

I’m planning to write a code that in case the imp went offline, saves readings to an external memory. I’m trying to accomplish that using server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 30.0) and server.onunexpecteddisconnect(disconnectionHandler);
I have a deepsleep part of the code to save power, and it’s looping using the deepsleep.
However, when the imp searches for WiFi and doesn’t find it, it doesn’t loop, it’s like it doesn’t wake up from the deepsleep… it just freezes.

Now I simplified the code, just to get loop on the deepsleep and continue to work offline if the wifi was disconnected, and I’m using a led to confirm that is working offline… And also here, nothing happens, the led doesn’t blink constantly as it is supposed to if it goes offline when I disconnect the wifi and I have to do a hard reset to get it back to work and sometimes I need to switch imps to get it to work (I’m using imp001 on April board).
Here is my device code below. Please let me know what is it that I’m doing wrong? I’d really appreciate your help…

// This function is called if the agent link is lost
function disconnectionHandler(reason) {
flashLed();
}

function flashLed() {
// Turn the LED on (write a HIGH value)
led.write(1);

}

function flashLed2() {
// Turn the LED on (write a HIGH value)
led.write(1);

// Pause for half a second
imp.sleep(0.5);

// Turn the LED off
led.write(0);

}

function sleep(){
imp.onidle(function(){ imp.deepsleepfor(10); });
}

// PROGRAM STARTS HERE

//Do don’t terminate the program if the the wifi was disconnected
server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 30.0);
// Configure the LED (on pin 2) as digital out with 0 start state
led <- hardware.pin2;
led.configure(DIGITAL_OUT, 0);

server.onunexpecteddisconnect(disconnectionHandler);

if (server.isconnected()) {server.log(“server is connected”)};
function flashLed2();
sleep();

Thanks,
Perla

I do not see any server.connect calls in your code. When you use return_on_error you must explicitly have a function to reconnect somewhere. Also, looking at your code it looks like it is doing exactly what you tell it to. On boot (if connected) run flashled2, then sleep. When you wake from deep sleep, it is not connected because you never tell it to connect, so it doesn’t run flashled2, then repeats the sleep cycle. Try adding the server.log outside the if connected logic (i believe this forces a connect). This is how I interpret your code flow. [Ahh… you are trying to run offline :slight_smile: ]

Also, try putting your last sleep() at the end of the flashled2 function. More syncronous flow. The imp will definitely run offline, my guess is that it may be going to sleep before finishing your flashled2 function.

Also see https://electricimp.com/docs/resources/disconnecteddebugging/ - adding a serial port for debug when you’re not connected is really helpful.

“function flashled2();” is not calling flashLed2(), it’s redefining the function, I think.

But, as @physicsnole notes, you’re never calling connect. The code will start from a cold boot connected, and then appear to just to go sleep without logging anything. This is because you’re doing the log, but then not flushing the link before you sleep, so the packet likely never escapes onto wifi.

If you add a server.flush() after the log, you should at least see the message, though I don’t believe you’ll see the flash (see above).

On the next wake, you won’t see the log (as server.isconnected() is false), won’t flash the LED, and will sleep again. It will look dead until you power cycle it.

You may also want to consider using connectionmanager: the nice thing about this is that it can log messages when offline, and will output them when it gets reconnected. They’re lost on a sleep though.

Hi,

Thanks for you responses… I updated the code with your notes as you can see below and now the behaviour is:

While the WiFi is on:

  • I need to do a hard reset so that it would download the updated code
  • It logs the server messages for the first time it connects only
  • It flashes, the loop works

While the WiFi is off:

  • I don’t see the queued messages as described in the connectionmanager class doc.
  • it doesn’t execute the offline behaviour, it keeps flashing the online flash
    I can only see the offline flash if I’m doing a hard reset and it didn’t pickup the connection right away.

Changing the sleep() location to inside the flash functions, didn’t affect the behaviour.
Also I have a question, I thought that the deepsleep itself would be causing a loop, that the imp would wakeup and re-execute the program without the need for a server connect, no? and if there is a server.log would it try to connect every 9 min (the default settings) instead of the time I set it to sleep for?

Thanks,
Perla

My device code:

#require “ConnectionManager.class.nut:1.0.1”

// This function is called if the agent link is lost
function disconnectionHandler(reason) {
flashLed();
}

function flashLed() {
// Turn the LED on (write a HIGH value)
cm.log(“Working offline”)
led.write(1);
imp.sleep(5);
sleep();

}

function flashLed2() {

cm.log("server is connected");
server.flush(10) 
// Turn the LED on (write a HIGH value)
led.write(1);

// Pause for half a second
imp.sleep(0.5);

// Turn the LED off
led.write(0);

}

function sleep(){
imp.onidle(function(){ imp.deepsleepfor(15); });
}

// PROGRAM STARTS HERE

//Do don’t terminate the program if the the wifi was disconnected
server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 30.0);
// Configure the LED (on pin 2) as digital out with 0 start state
led <- hardware.pin2;
led.configure(DIGITAL_OUT, 0);

// Instantiate ConnectionManager so BlinkUp is always enabled,
// and we automatically agressively try to reconnect on disconnect
cm <- ConnectionManager({
“blinkupBehavior” : ConnectionManager.BLINK_ALWAYS,
“stayConnected” : false
});

// Set the recommended buffer size (see note below)
imp.setsendbuffersize(8096);
cm.connect();
cm.log(“server is connected - from main”);
flashLed2();
cm.disconnect();

sleep();

server.onunexpecteddisconnect(disconnectionHandler);

Why do I have to do a hard reboot so that the code can be downloaded? not just power reset, I take out the imp completely and then put back in, sometimes several times…

The imp in deep sleep uses such little power that it can survive off the capacitor for a few seconds while power is removed.

are you commenting on the hard reboot thing?

Yes. For your offline testing you are disconnected. So when you push a program update, it won’t receive until you power cycle. But, I think your imp is staying in deep sleep even after you remove power, hence you having to remove from board.

yes, why do you think this is happening?

Note The ConnectionManager class stores log messages in memory but doesn’t persist log messages across deep sleeps and cold boots.

cm.log is not persisted across deep sleep. the reason why you have to power cycle for update is because you are not letting the imp have enough time to connect before sleeping. Look at this structure. Here i set a onConnect handler in which I put the flashled2 function and then the next sleep.

`#require “ConnectionManager.class.nut:1.0.1”

// Instantiate ConnectionManager so BlinkUp is always enabled,
// and we automatically agressively try to reconnect on disconnect
cm <- ConnectionManager({
“blinkupBehavior” : ConnectionManager.BLINK_ALWAYS,
“stayConnected” : false
});

// This function is called if the agent link is lost
cm.onDisconnect(function(expected) {
if (expected) {
// Log a regular message that we disconnected as expected
cm.log(“Expected Disconnection”);
flashLed();
} else {
// Log an error message that we unexpectedly disconnected
cm.error(“Unexpected Disconnection”);
}
});

cm.onConnect(function() {
cm.log(“server is connected - from main”);
flashLed2();
cm.disconnect();
sleep();
});

function flashLed() {
// Turn the LED on (write a HIGH value)
cm.log(“Working offline”)
led.write(1);
imp.sleep(5);
sleep();
}

function flashLed2() {
cm.log(“server is connected”);
server.flush(10)
// Turn the LED on (write a HIGH value)
led.write(1);
// Pause for half a second
imp.sleep(0.5);
// Turn the LED off
led.write(0);
}

function sleep(){
imp.onidle(function(){ imp.deepsleepfor(15); });
}

// PROGRAM STARTS HERE

//Do don’t terminate the program if the the wifi was disconnected
server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 30.0);
// Configure the LED (on pin 2) as digital out with 0 start state
led <- hardware.pin2;
led.configure(DIGITAL_OUT, 0);

// Set the recommended buffer size (see note below)
imp.setsendbuffersize(8096);
cm.connect();`

The flash was working becasue this was before the sleep. The connect function takes some time to process, and runs “in the background” so your main function continues to process before the connection is complete. Thus, cm.disconnect and sleep was being called after the led flash, but before the connection was made. It is important to structure your code utilizing callbacks or promises. This helps the code flow as designed.

Ok I agree that the structure must be what is wrong with my code, makes complete sense… this code is looping and writing to the server “server is connected” but it doesn’t blink as indicated by flashled2 it’s doing the offline led flashing on every wake up from the deepsleep.

Also, it is not working offline. Did you remove the “server.onunexpecteddisconnect(disconnectionHandler);” on purpose?

Yes, I replaced it with the cm.onDisconnect. From there you can make decisions on whether is was expected or not.

What is it you are trying to do exactly? If you give me some idea on what you want the program to do I can help. I am just confused exactly what you are trying to achieve. Your flashled function turns the led on, sleeps for 5 seconds, then deepsleeps for 15… confusing :slight_smile:

If you are planning a large development where offline behaviour is an important part of the functionality, Hugo’s suggestion of a debugging serial port is absolutely worthwhile.

With it, you can quickly determine what’s happening and what state the imp is in. I have been developing various embedded products for years, and it’s always my fallback position should other debugging methods fall short. If pins are in short supply, the other option would be using spi-flash to record stuff (that can be downloaded later), but that requires more effort to work reliably.

The reason you need to cold boot to get the imp to pick up new code is that you connect, then disconnect immediately. On the imp, your code runs in preference to everything else in the system, including processing incoming data from the connection.

So, whilst you can connect and log something, your imp (at your command) is ignoring the server telling it there’s new code available.

If you removed the cm.disconnect() line from your code, then I believe you would be picking up new code from the server on each wake. Why? Because sleep uses imp.onidle(), which allows the imp to process the received messages from the server before firing, hence it will get the new code before calling the handler.

As it is, cm.disconnect() disconnects and throws away all the messages from the server, THEN (when there’s nothing there to process) calls sleep() which fires the onidle handler after your server.onunexpecteddisconnect() is called - which itself doesn’t do anything useful as you’ve just disconnected then told the imp to go to sleep at the earliest possible opportunity.

I know this is off topic @hugo, but is there a way to merge agent and device code? Meaning, is there a way to have a single “model” code, and have the agent <-> device comm an abstact layer that is intrinsically mutual? I guess some method that precludes any data transmission inherit to EI “libraries” which takes some work out of developers?

I think any sort it chucker function should not be required. Bind the device to the agent, and “inherently” handle the data comms…

You can certainly call device methods fairly transparently from the agent (think @coverdriven has been doing this for years), but I’m not really sure what you’re asking for beyond RPC?

Abstracting comms too much is painful, because the real world (which lies between agent and device) is very much not an abstract world.

I just spend alot of time sending data from device to agent. There has to be a way to bind the data, like angular!

Hey thanks for sticking around and helping on this…
What I’m trying to achieve originally is to get the imp to work offline, so that it would store data to an eeprom in case the the connection was lost. After several failures, I simplified the code and used the led as an indicator of what happening…

So, I’m using a quick flash (faslhled2) in case it was online and a long flash (flashled()) if it was offline. And I’m using the deepsleep because I need to save power and loop the program.
So the logic and the behaviour I’m targeting is that the imp is on connects, flashes the led and goes into deepsleep, then repeats unless the connection was lost. In that case, it should give long flashes to indicate the connection loss…

I’ve tried different approaches using your hints above but I just couldn’t get it to work offline… I used the sample code with the LED example here it’s working offline but when I added the deepsleep it stopped…
And now I’m facing a new serious challenge shown in the screenshot, the code is not being updated properly although it is indicating that it did, so I might have run a code that actually works but it wasn’t updated…
Any idea what is going on

If code isn’t downloading, a power cycle will always get the new code. If it’s not downloading when running your code, it’s because you are disconnecting or sleeping before you let the imp check the input data, as I have said.

I’m afraid we really can’t help you debug more. There are no issues with offline working, lots of commercial products do this. It is tricky because you can’t see what the imp is doing when offline, which is why we recommend you get a serial cable and hook it up.

I suggest you get one then use it to debug your code?