How to queue a message on agent when device is sleeping?

How do you queue messages to be sent from the agent to the device?

In the agent code, I have a http.onrequest(http_handler) call that invokes device.send. However, the device cycles through 6-hour sleep periods. In my test code it seems that device.send just drops the message if it finds that the device is sleeping.

Please suggest an elegant and simple solution.

Thanks,
Abhinav

here is some code to try out. wrote it just now. it creates an empty table.

it adds slots to the table every time ‘testnewmessage’ runs.

it also shows how to remove the messages from the table and shows a test of that. I am not an expert so there may be others with better ideas…

`mynewtable <- {};

mymessagenumber <- 0;

function testnewmessage(msg){
mynewtable[mymessagenumber]<- msg;
mymessagenumber+=1;
}

testnewmessage(“hi”);
testnewmessage(“there”);
testnewmessage(“Abhinav”);

server.log(mynewtable.len());

foreach (index, value in mynewtable){
server.log ("i: " + index + " val: " + value);
}

mynewtable = {};

foreach (index, value in mynewtable){
server.log ("i: " + index + " val: " + value);
}

server.log(“done”);
`

The elegant solution would be to use a device.onconnect() handler in the agent to get notified when the device is online, then send it the messages. You may also want to send a special message when you’re done which triggers the device to go back to sleep.

Thanks for the reply.

However, seems like I am missing something in it’s implementation. I tried to send a message to the device within the device.onconnect handler. However, the corresponding device message handler never gets invoked. Please see the code below. What am I doing wrong?

Thanks,
Abhinav

==============================================
Device code

`imp.onidle (function () {
server.log (“Nothing to do so go to sleep”);
server.sleepfor(15);
})

function go_sleep(data)
{
server.sleepfor(15);
}

function set_config (config_data)
{
server.log(“Entered set_config ()”);
server.log("Received value: " + config_data);
}

agent.on(“CONFIG”, set_config);
agent.on(“GO_SLEEP”, go_sleep);`

==============================================
Agent code

`debug <- 1
imp_config <- null;
config_data <- null;

function petasense_log (message)
{
if (debug)
{
server.log (message);
}
}

function http_handler(request, response)
{
petasense_log (“Entered http_handler”);

if ("config_updated" in request.query)
{
    if (request.query["config_updated"].tointeger())
    {
        petasense_log ("Config updated. Fetching config.");

        if (device.isconnected())
        {
            petasense_log ("Oops, device is already connected.");
            update_imp();
        }
        else
        {
            petasense_log ("Ready to update_imp()");
            device.onconnect (update_imp);
        }

    }
}

}

function update_imp ()
{
local config_data = “New configuration is here!”;
petasense_log (“Entered update_imp()”);
device.send (“CONFIG”, config_data);
device.send (“GO_SLEEP”, null);
}

http.onrequest(http_handler);`

==============================================
Log

2014-05-21 12:21:24 UTC-7 [Status] Device booting; 2.37% program storage used 2014-05-21 12:21:24 UTC-7 [Device] Nothing to do so go to sleep 2014-05-21 12:21:24 UTC-7 [Device] sleeping until 1400700099000 2014-05-21 12:21:24 UTC-7 [Status] Device disconnected; 60 bytes sent, 0 received, 60 total 2014-05-21 12:21:29 UTC-7 [Agent] Entered http_handler 2014-05-21 12:21:29 UTC-7 [Agent] Config updated. Fetching config. 2014-05-21 12:21:29 UTC-7 [Agent] Ready to update_imp() 2014-05-21 12:21:40 UTC-7 [Agent] Entered update_imp() 2014-05-21 12:21:40 UTC-7 [Status] Device booting; 2.37% program storage used 2014-05-21 12:21:40 UTC-7 [Device] Nothing to do so go to sleep 2014-05-21 12:21:40 UTC-7 [Device] sleeping until 1400700115000 2014-05-21 12:21:40 UTC-7 [Status] Device disconnected; 60 bytes sent, 181 received, 241 total

To me it appears that the imp.onidle and the server.sleepfor is kicking in before the device is able to respond to the device.send from the agent. So how do I overcome this issue?

Abhinav

OK I learnt something more. The device message handler is responding when the device is powered on for the first time. It doesn’t invoke the handler subsequently when it comes up from deep sleep.

Deleted.

How about you change your sample code so that it clearly demonstrates the scenario. Does this cover it?

Device code:

`
function go_sleep(data)
{
server.log (“Nothing to do so go to sleep”);
imp.onidle (function () {
server.sleepfor(15);
})

function set_config (config_data)
{
server.log(“Entered set_config ()”);
server.log("Received value: " + config_data);
}

agent.on(“CONFIG”, set_config);
agent.on(“GO_SLEEP”, go_sleep);
`

Agent code:

function update_imp () { local config_data = "New configuration is here!"; server.log ("Entered update_imp()"); device.send ("CONFIG", config_data); device.send ("GO_SLEEP", null); } device.onconnect (update_imp);

Aron, I just ran your code. The problem with your device code is that it has no code to run when it wakes up from sleep. So it remains in sleep perennially. And it never invokes the device.onconnect handler.

Also, my use case is that my cloud app invokes some agent changes via the agent url which need to be propagated to the device when it wakes up. Device.onconnect doesn’t seem to be doing the job.

So no resolution yet. Can you describe how device.onconnect is supposed to work? The documentation is really short on details.

Hi, @montu17. @aron’s basic structure works for me: the function registered by device.onconnect() is called 15 seconds after the device runs server.sleepfor(15).

The very act of rebooting 15 seconds after executing server.sleepfor() causes the imp to connect[Edit: no it doesn’t; see @peter’s comment below], and therefore for device.onconnect()'s registered function to be called. Connecting to WiFi takes a second or so, so you won’t see log entries progress by exactly 15 seconds.

FWIW, I tested it with this code:

Agent

`function connected()
{
server.log(“Connected”);
device.send(“do.something”, saved_messages);
}

saved_messages <- [];

message1 <- {};
message1.a_key <- 999;
message1.b_key <- true;

message2 <- {};
message2.a_key <- “Hello”;

saved_messages.append(message1);
saved_messages.append(message2);

device.onconnect(connected);`

Device

`function zizz()
{
server.log(“Sleeping”);
server.sleepfor(15.0);
server.log(“Asleep”); // Should never appear in the log
}

function process_messages(messages)
{
server.log(“Messages received”);

foreach (i, item in messages)
{
    server.log("Message " + (i + 1) + " processed: " + item.a_key);
}

}

agent.on(“do.something”, process_messages);
imp.onidle(zizz);`

This is what I see in the logs:

2014-05-23 09:21:44 UTC+1 [Status] Device Booting; 2.44% program storage used 2014-05-23 09:21:44 UTC+1 [Device] Sleeping 2014-05-23 09:21:44 UTC+1 [Device] sleeping until 1400833319000 2014-05-23 09:22:02 UTC+1 [Status] Device disconnected 2014-05-23 09:22:02 UTC+1 [Agent] Connected 2014-05-23 09:22:02 UTC+1 [Status] Device Booting; 2.44% program storage used 2014-05-23 09:22:02 UTC+1 [Device] Messages received 2014-05-23 09:22:02 UTC+1 [Device] Message 1 processed: 999 2014-05-23 09:22:02 UTC+1 [Device] Message 2 processed: Hello 2014-05-23 09:22:02 UTC+1 [Status] Device Booting; 2.44% program storage used 2014-05-23 09:22:02 UTC+1 [Device] Sleeping 2014-05-23 09:22:02 UTC+1 [Device] sleeping until 1400833337000 2014-05-23 09:22:20 UTC+1 [Status] Device disconnected

Observations: I’m just not sure why I get “Device Booting…” right before “Sleeping” at line 10; I’m not sure why the agent doesn’t log the disconnection (line 4) until the device actually reconnects, but presumably this is a side-effect of the server.expectedonlineat() call implicit in server.sleepfor();

@smittytone Your device code is different from Aron’s because yours calls server.log(), which will bring the connection up following a wakeup. Aron’s doesn’t do anything that would bring the connection up.

Peter

So if I drop the server.log(“Sleeping”); from zizz(), then device.onconnect(); will not be called? So without that server.log(), I’d have to do a server.connect() to bring up the WiFi when the imp comes out of deep sleep?

One flaw in my code is that it assumes there’s time for the agent to get messages to the device after it wakes and reconnects but before it goes to sleep and drops off the WiFi. Any way to guarantee the imp doesn’t go idle (and this to sleep) before, or will it just work?

So if I drop the server.log(“Sleeping”); from zizz(), then device.onconnect(); will not be called?

That’s right, yes.

So without that server.log(), I’d have to do a server.connect() to bring up the WiFi when the imp comes out of deep sleep?

Either server.connect(), or some other call that tries to send something to the server, such as server.log() or agent.send(). (But agent.on() doesn’t itself send anything, so won’t cause a connection.)

[Edited to clarify:] If you’re using the default SUSPEND_ON_ERROR, that is; if you’re using RETURN_ON_ERROR, then yes only server.connect() will bring up the WiFi.

Peter

Ah, I get it. It’s because the freshly wakened imp (post deep sleep) is in the ACTIVE-OFFLINE state not, as I incorrectly assumed, an ACTIVE state. My code makes it ACTIVE by calling server.log().

Which makes perfect sense because the imp doesn’t always need WiFi when it wakes, so it’s better to leave it off until it’s needed.

Question: does telling the agent that the imp will be asleep for x time units do anything more than simply stop the agent sending messages to the imp when code tells it to during that period?

It doesn’t even do that; it’s informational only. You can wake before that point (eg a pin1 wakeup) and get messages from the agent.

@peter @hugo I haven’t yet been able to get an answer to my question that I started the thread with. I have tried the device.onconnect as suggested by @hugo (see my code in the above post). The behavior I am seeing is that when the device comes up from deep sleep (not power on), the agent side handler is being called. However, the device side agent is not being invoked. Can you please help me with any pointers?

PS: However, the device message handler IS invoked when the device is powered on. The problem is observed only when it’s waking up from deep sleep.

Thanks,
Abhinav

As I have said in the past, I don’t truly understand the behaviour of device.onconnect() so I would avoid using it. Your mileage may vary but here is an alternative way.

Device code:

`
function go_sleep(data)
{
server.log (“Nothing to do so go to sleep”);
imp.onidle (function () {
server.sleepfor(15);
})
}

function set_config (config_data)
{
server.log(“Entered set_config ()”);
server.log("Received value: " + config_data);
}

agent.on(“CONFIG”, set_config);
agent.on(“GO_SLEEP”, go_sleep);
device.send(“status”, “boot”);
`

Agent code:

function update_imp (status) { local config_data = "New configuration is here!"; server.log ("Entered update_imp()"); device.send ("CONFIG", config_data); device.send ("GO_SLEEP", null); } device.on("status", update_imp);

@montu17 smittytone’s code appears to show this working. Have you tried running this yourself?

The device side code he posted is correct, if slightly hard to follow because after the imp wakes from sleep, the wifi isn’t connected. It’s not until the onidle() handler fires, whose main job it is to go back to sleep, that the connection comes up - forced by the server.log() - and that then causes the pending messages to be delivered.

This might be a little clearer:

agent:
`function connected()
{
server.log(“Connected”);
device.send(“do.something”, saved_messages);
}

saved_messages <- [];

message1 <- {};
message1.a_key <- 999;
message1.b_key <- true;

message2 <- {};
message2.a_key <- “Hello”;

saved_messages.append(message1);
saved_messages.append(message2);

// when we get this from the device, clear our pending queue and queue another message for its next wake
device.on(“ack”, function(v) {
saved_messages <- [];
saved_messages.append(message1);
});

// when the device connects, send the saved messages to it
device.onconnect(connected);
`

`function zizz()
{
server.log(“Sleeping”);
server.sleepfor(15.0);
server.log(“Asleep”); // Should never appear in the log
}

function process_messages(messages)
{
server.log(“Messages received”);

foreach (i, item in messages)
{
    server.log("Message " + (i + 1) + " processed: " + item.a_key);
}

// ask server for some more
agent.send("ack", 0);

}

// set up handler to deal with messages from the server
agent.on(“do.something”, process_messages);

// force the connection up (if we’ve woken from sleep, wifi isn’t up yet)
server.log(“imp online”);

// Wait online a couple of seconds to ensure any pending messages arrive, then go to sleep
imp.wakeup(2, function() {
imp.onidle(zizz);
});
`

…this may be a bit more explicit.

As I have said in the past, I don’t truly understand the behaviour of device.onconnect() so I would avoid using it …

Can certainly +1 this comment @aron … there seems to be some long standing funky behavior related to both device.onconnect() and device.ondisconnect() I’ve never been able to figure out either. I typically also use alternate means now determine device status.

  • Larry