Low power sketch - sending data to a sleeping device

Started by fgomes, May 11, 2015, 06:44:21 PM

fgomes

I have a couple of sensors working for a long time, reporting temperature, humidity and pressure to the gateway each minute, sleeping most of the time to save the batteries. The nodes use SendWithRetry and then turn off the radio and put the ATMEGA sleeping using the LowPower lib. This is running very well for more than one year. Now for a similar system I have to be able to remotely configure the sensor nodes, sending some alarm level parameters. Since the nodes are mostly sleeping, this has to be synchronized somehow. The simplest way could be to send these parameters together with the Ack message, since this is the only (short) time the sensor node is listening. But as far as I know the library doesn't support an Ack with payload. Do you have any other suggestion for this problem? Of course this could also be implemented with 'application level' acknowledgements, the sensor send a message until it receives other message, that carries the configuration payload. I'm open to other ideas :-)

Best regards

Fernando

TomWS

Quote from: fgomes on May 11, 2015, 06:44:21 PM
I have a couple of sensors working for a long time, reporting temperature, humidity and pressure to the gateway each minute, sleeping most of the time to save the batteries. The nodes use SendWithRetry and then turn off the radio and put the ATMEGA sleeping using the LowPower lib. This is running very well for more than one year. Now for a similar system I have to be able to remotely configure the sensor nodes, sending some alarm level parameters. Since the nodes are mostly sleeping, this has to be synchronized somehow. The simplest way could be to send these parameters together with the Ack message, since this is the only (short) time the sensor node is listening. But as far as I know the library doesn't support an Ack with payload.
TOTALLY incorrect assumption!  The beauty of this library is that you can essentially send a full payload with an Ack!

Now, you need to make sure you're code is properly checking the Ack as soon as you return from sendWithRetry().
The secret, if there is one, is to immediately save the result on return from sendWithRetry().  For example:

/******************************************************************************
*
*   sendDescriptor() - common task, saves typing...
*
******************************************************************************/
bool  sendDescriptor(byte to, bool retry) {
  bool rc;
  if (to==0)
    to = GATEWAYID;
  if (retry && to != RF69_BROADCAST_ADDR)
  {
    rc = radio.sendWithRetry(to, &devDescriptor, devDescriptor.h.len);
    return AckCheck(rc);
  }
  else
    radio.send(to, &devDescriptor, devDescriptor.h.len);
    return true;

}

/******************************************************************************
*
*   AckCheck() - local method to check to see if there is any AckData and save it locally if there is.
*
******************************************************************************/
bool AckCheck(bool rc)
{
  if (rc) 
  {
    noInterrupts();
    // tranmission ok, see if any data was Ack'd
    if (radio.DATALEN && radio.DATALEN==radio.DATA[0]) // got a valid packet?
    {
      // yup, save it
      for (int i=0; i<radio.DATALEN; i++) 
        sendAckData[i] = radio.DATA[i];
    }
      else
        sendAckData[0]=0;
    interrupts();
  }
  return rc;
}

/******************************************************************************
*
*   getAckData() - return ptr to locally saved ack data
*
******************************************************************************/
byte *getAckData(void)
{
  if (sendAckData[0]) return &sendAckData[0];
  return NULL;
}

Do you have any other suggestion for this problem? Of course this could also be implemented with 'application level' acknowledgements, the sensor send a message until it receives other message, that carries the configuration payload. I'm open to other ideas :-)

Best regards

Fernando
[/quote]
I'll post the gateway side of the code shortly...
Tom
UPDATED: fixed typo in getAckData definition...

TomWS

Here's the gateway side of the code.  Note that the receive data is saved immediately so that subsequent receives don't overwrite the data.  In this case the gateway is doing exactly what you want to do, check to see if the previously sleeping mote, which is now checking in, has to receive anything from the Gateway side.

  // now see if there is any data from a client...
  if (radio.receiveDone())   
  {
    byte
      sender,
      target,
      datalen,
      ackReq;
    int 
      rssi;

    memcpy(rcvBuf,(const void *)radio.DATA,radio.DATALEN);  // save data from device
    sender  = radio.SENDERID;
    target  = radio.TARGETID;
    rssi     = radio.RSSI;
    datalen = radio.DATALEN;
    ackReq  = radio.ACKRequested();

     if (ackReq && target == MY_DEVICE_ID)
    {
      // check to see if we have a request pending for this device
      int i =checkGotSomething(sender);
      if (i>=0) 
      {
        if (bVerboseOn) {Serial.print(F( "Processing GotSomething..." ));}
        reqSomething.request = TM_GOT_SOMETHING;
        reqSomething.data[0] = gotSomethingList[i].something;
        radio.sendACK(&reqSomething,reqSomething.h.len);
        if (bVerboseOn) {Serial.print(F( " - ACK with gotSomething=" )); Serial.println(reqSomething.data[0],HEX);}
      } else 
      {
        radio.sendACK();
        if (bVerboseOn) {Serial.print(F( " - ACK sent" )); }
      }
    }
    Blink(5);
    if (bVerboseOn) {Serial.println();}

Enjoy...
Tom
UPDATED: fixed typo in my device id test.

fgomes

Hi Tom

Thanks for the example! Sorry for the question but I really didn't noticed the possibility of sending the payload with the Ack, I tried also to check the examples and didn't find it, so this was the reason of posting the question in the forum. Anyway, thanks again for your help, and for such a good library for the RFM69HW radio, I been using it for more than 1 year without problems.

Best regards

Fernando


TomWS

Quote from: fgomes on May 12, 2015, 05:33:52 AM
<snip> Sorry for the question but I really didn't noticed the possibility of sending the payload with the Ack,<snip>
No problem!   I was just teasing you.  NO ONE gets this! Which is probably why I exaggerated my response.  Of course, it might be that no one gets this because there aren't any examples (he said sheepishly)...

You can ask any question you want, all we want in return is to know that someone is sincerely trying to find an answer and learn.

Tom

fgomes

Quote from: TomWS on May 12, 2015, 07:37:56 AM
No problem!   I was just teasing you.  NO ONE gets this! Which is probably why I exaggerated my response.  Of course, it might be that no one gets this because there aren't any examples (he said sheepishly)...
You can ask any question you want, all we want in return is to know that someone is sincerely trying to find an answer and learn.
Tom
Hi Tom

I knew you were teasing me   ;D
But I am typically careful not asking the obvious, checking the examples and previous posts about my doubts, so you hit me in the face, it was obvious if I just checked the sendaAck function declaration or implementation  :)

Best regards

Fernando

TomWS

Quote from: fgomes on May 12, 2015, 02:56:35 PM
<snip>so you hit me in the face <snip>
I find that I need a 'hit in the face' every now and then... it keeps me on my toes (or off my backside)...

I like that you recognized the value of this capability.  It really is essential to get messages to long term sleeping motes and it takes very little logic on the part of the gateway.

Tom