Dealing with WiFi disconnection when waking from deep sleep

I’ve lifted some code from the dev guides to try and understand how I can both wake/deep-sleep and deal with wifi connection loss (keep executing code) when the device wakes.

This bit of code works fine:
imp.onidle(function() { server.connect(); //connect(); server.log("going to sleep now") server.sleepfor(15); });
With the default setsendtimeoutpolicy, the imp wakes up every 15 seconds, connects and logs, and goes back to sleep.

However, when I change the setsendtimeoutpolicy to enable the code to keep running with wifi connection loss, I can see the device waking up every 15 seconds because it’s current jumps from uA to 10s of mA, but it is not re-connecting to wifi and logging:
`
function connect()
{
// Check if we’re connected before calling server.connect()
// to avoid race condition

if (server.isconnected()) {
    // We're already connected, so execute the callback
    server.log("Already connected")
    onConnectedCallback(SERVER_CONNECTED);
}
else {
    // Otherwise, proceed as normal
    server.connect(onConnectedCallback, 30);
}

}

function onConnectedCallback(state)
{
// If we’re connected…
if (state == SERVER_CONNECTED) {
server.log(“onConnectedCallback”)
}
}

server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_FOR_ACK, 30);

imp.onidle(function() {
//server.connect();
connect();
server.log(“going to sleep now”)
server.sleepfor(15);
});`

I was expecting when it wakes up, it would execute code from the start, so the connect() function would be run and it would reconnect. Any clues on what I need to do here? What does the timeout parameter in setsendtimeoutpolicy (30) do - I don’t see the current rising for 30 seconds when it is trying to reconnect, only a fraction of a second?

With RETURN_ON_ERROR, calls to server.connect() return immediately while the connection is established in the background. Calls to server.log() can also fail with a send error code if the imp is not yet connected. So I think you’re calling server.sleepfor() while the connection is still coming up - try moving that to the onConnectedCallback function.

The setsendtimeoutpolicy timeout is described here.

Thanks Phil! Your suggestion of including the sleep command in the callback got it running. So the asynchronous in

If the RETURN_ON_ERROR policy is in effect, the connection proceeds asynchronously.
means that server.connect is occurring in the background, and my server.sleepfor statement didn't wait for the connect to finish. Makes sense.

Another question related to deep sleep.
I’m trying to work out how many values I can store in the nv table. My understanding is that floats and ints both use 4 bytes. The nv table is nominally 4kB. So it should be possible to store about 1000 floats/ints shouldn’t it?

I was storing 8 values in a table, then pushing the tables to an array in nv. This gave me about 250 values. That is, data is a table of 8 floats/ints in the below:
function write_data_to_nv(data) { if (!("nv" in getroottable() && "data_array" in nv )) { nv <- { data_array = [] }; } nv.data_array.insert(0,data); }

I’ve changed to storing 8 values in an array (data = array of 8 floats/ints), then pushing these arrays to nv. Now I can store 500 values.

But this is still less than the expected 1000. Is the nv 4kB space shared with something else (eg global variables) that could explain this? Or is there a more efficient way to store the values and get closer to the 1000 values I’m expecting?

Thanks,
James

When you were using an array of tables, you were seeing the overhead of the table (ie each element is named). With nested arrays you still have the array overhead multiple times.

If you can move this to multiple top level arrays, you remove this so it’s just the actual array entries taking most of the space, ie the nv table would be nv <- { a = [], b=[], c=[] } and have no deeper nesting than that.

The only thing to do which would be marginally more efficient would be to format the data yourself in a blob, and put the blob in the table - then you’re totally aware of the overheads.

If the values are samples from a source that changes slowly, you could consider encoding the values using a DPCM (Differential Pulse Code Modulation) technique. That might allow you to store each value in say 8 bits, instead of 4. But, as Hugo said, you’d still have to format the data into a blob to squeeze as much in.

Formatting the data into a blob and putting the blob in the “nv” table is definitely the easiest way to deal with NV. (If we’d realised this up front, “nv” would probably have been a blob not a table. Sometimes trying to make things easier for people actually makes it harder.) You could use the Serialiser library, or write your own routines for a more compact format such as Msgpack.

Peter

I’ve tried stuffing each reading into a blob, which is currently 18 bytes long. Then I’m pushing each reading blob into the nv data array. I’m not sure how to implement Hugo’s suggestion of removing the data array and putting the values straight into the nv table. Anyway, I’m getting 2628 bytes with the nv table = { data_array [blobs] }

Great idea coverdriven to use DPCM - that should work very nicely in my application (environmental sensors with slow changing data).

Peter, is there any advantage to using the serialiser library, over just creating the blob manually? I’d assume it’s less memory efficient because it has to also store the format of each of the items encoded into the blob?

Is it still true that there’s no way to programmatically find the total memory usage of the nv table?

I didn’t mean to put blobs in an array in the nv table, but to put just one blob in the nv table “nv = { b=blob }”, with all of your data packed into it. That means the overhead is small and constant: the “total memory usage of the nv table” will be a constant small amount (~20 bytes) plus the size of the blob.

Peter

Awesome, thanks. I’m serializing just by appending to the end of the top level blob, and now getting about 4010 bytes into the table.

Yet another related question…
If for some reason the imp loses power, and cold boots, I see it runs the previous squirrel code successfully when there is no wifi, and then I can gather data when wifi becomes available. One problem though, the clock is wrong:
2016-01-21 10:17:07 UTC+11 [Device] 946685168 0:7
2016-01-21 10:17:06 UTC+11 [Agent] Time: 2000-01-01 11:00:00
2016-01-21 10:17:07 UTC+11 [Device] sleeping until 1453334820000

‘946685168’ is returned by time() just before the device goes to sleep, so it thinks it’s 2000. I’m using server.sleepuntil. I guess it’s trying to wake up in the year 2000. But just before going to sleep, it looks like it’s getting the correct time from the server (1453334820000). So it never wakes up. Is there an explicit function that can be called to make sure the times are synchronised before issuing server.sleepuntil?

This is correct - it’s a cold boot, and unless you have an imp with a separate RTC supply pin (eg imp003) the RTC can’t run.

As you’re using server.sleepfor, it’s forcing a connect (to tell the server it’s going to sleep) before sleeping again; that connect should have updated the time that sleepfor/sleepuntil would reference and hence it should be waking ok. How long are you trying to sleep for?

Using imp.deepsleepfor would not force the connection to come up before sleeping, so you’d be sleeping on the 2000-referenced time.

I’m trying to sleep from 1 minute. The code is like this:
function next_loop() { local next_reading_time = time()+60*readings_minutes; local next_hour = date(next_reading_time).hour; //rounding to nearest multiple of readings_minutes local next_minute = (date(next_reading_time).min / readings_minutes) * readings_minutes; server.log(""+time() + " " + next_hour + ":" + next_minute); imp.onidle(function(){ server.sleepuntil(next_hour, next_minute); }); }

The server.log function is returning 946685168 0:7 (ie the year 2000)
But when going to sleep (next line of code with server.sleepuntil), it’s saying:
2016-01-21 10:17:07 UTC+11 [Device] sleeping until 1453334820000

So, I guess the imp is thinking it’s 2000, but it’s sleeping until 2016. So, any way to get it to update the imp time before server.sleepuntil? (note I’m using sleepuntil, not sleepfor).

My impression is that sleepuntil is for applications where the time you set is independent of the time you set it at. In your case, if you want it to wake up 1 minute from now, just try server.sleepfor(60)

Yes, this was just a test case. I generally want to wake up on the hour or at pre-determined intervals each hour. That’s why I want to use sleepuntil instead of sleepfor

On a side note, if you are developing a commercial application with high volume waking at specific times is generally a bad idea as it means all the devices hit your servers simultaneously. The more you can do to desynchronize the devices the better utilization you will get on your servers. For just a single device it doesn’t really matter.

Essentially here if you force the connection up before reading the time, then you’d get the correct time which you’d then do your sums on - simply adding a server.log before you read time() should do it.

As is, it won’t be sleeping until 2016, but will be sleeping to next_hour/next_minute which will match the 2000 00:00 time once per day and give the right behaviour :wink:

Hi Hugo. I tried adding an additional server.log():
function next_loop() { local next_reading_time = time()+60*readings_minutes; local next_hour = date(next_reading_time).hour; //rounding to nearest multiple of readings_minutes local next_minute = (date(next_reading_time).min / readings_minutes) * readings_minutes; server.log("Sync"); server.log(""+time() + " " + next_hour + ":" + next_minute); imp.onidle(function(){ server.sleepuntil(next_hour, next_minute); }); }

When I boot from cold with no wifi connection, and then later add a wifi connection, this is returning:
2016-01-22 06:56:37 UTC+11 [Device] sync 2016-01-22 06:56:37 UTC+11 [Device] 946684985 0:4 2016-01-22 06:56:37 UTC+11 [Device] sleeping until 1453421040000 2016-01-22 06:56:38 UTC+11 [Status] Device disconnected

So it looks like server.log isn’t successfully updating the imp’s time.
946684985/60/60/24/365 = 30, so the imp time is 1970+30 = 2000.
Then it’s saying "sleeping until 1453421040000"
1453421040000/60/60/24/365/1000 = 46 and a bit, or 1970+46 = 2016

So doesn’t that mean it’s not going to wake up for 16 years? I’m probably misunderstanding something!

Come to think of it, the server.log won’t cause the time to be set; it’ll cause a connectio, but the incoming data isn’t processed until your squirrel stops running (ie, you fall off the end of your code).

This is what happens before the onidle is fired. The solution is to put your time calculation within the onidle handler.

The actual hardware of the imp can’t sleep for more than a month (this is a limitation of the RTC hardware) so it’ll be sleeping to the hour and minute previously calculated, but in the actual day, vs the 2000-based time & date.