LoRaWAN not sending after wakeup

Issue: Trying to send after wake up from sleep mode

Setup: Serial commands sent to chip

Server: TTN

Details:
Hello, I have a simple sleep, send sleep setup. The rak chip will check the config to see if it is joined and if it is, there should be no need to join again using AT+JOIN, I am checking the status with the at status command and i get this:

OK Work Mode: LoRaWAN
Region: AS923
MulticastEnable: false
DutycycleEnable: false
Send_repeat_cnt: 0
Join_mode: OTAA
DevEui: 0000000000101001
AppEui: 0000000000000001
AppKey: 603315472BA5DF9399A7E19D1363FF3D
Class: A
Joined Network:true
IsConfirm: unconfirm
AdrEnable: true
EnableRepeaterSupport: false
RX2_CHANNEL_FREQUENCY: 923200000, RX2_CHANNEL_DR:2
RX_WINDOW_DURATION: 3000ms
RECEIVE_DELAY_1: 5000ms
RECEIVE_DELAY_2: 6000ms
JOIN_ACCEPT_DELAY_1: 5000ms
JOIN_ACCEPT_DELAY_2: 6000ms
Current Datarate: 5
Primeval Datarate: 5
ChannelsTxPower: 0
UpLinkCounter: 4
DownLinkCounter: 1

HAS DEV_EUI
HAS APP_EUI
HAS APP_KEY
JOINED ALREADY!!!
at+send=lora:1:01
COMMAND FAILED!

Joined Network:true is showing, so I believe I should be able to just call at+send=lora:1:01 correct? but this fails.
The only way i can get it to send is if I do AT+JOIN again, that doesn’t seem right.

Any help would be greatly appreciated!

Hi @Kevin192291 ,

Can we try to isolate the issue if it is on the RAK4270 side or on the code of your microcontroller host.

I checked it here in my RAK4270 and it behaves the way you expect.

Here’s my log:

Will it be possible if you try manually sending the AT command first to the RAK4270?

yes, that is what I am doing. I am wondering if i can simply get a true/false value back showing if i am already connected to the gateway? Or do I need to do the long parse of all that text?

Hmm. Consistent connection to the gateway is not a LoRaWAN principle.

Being joined (status of the End-Device) doesn’t mean you are within a reach of a gateway. If you join yesterday then the gateway is down today, you are still joined in status.

Probably you can send a confirmed packet once in a while to see if you are still within the gateway. If you see no confirmed downlink coming from the Network Server, it means you are out of reach of the gateway.

I can garentee that I will always be in range, this is not a mobile application. Possibly I am not being clear. I simply want the Joined Network field from the status message, nothing else. Is this possible? or do I need to parse a long string?

Yes. You need to get it from the long string.

Sadly, that’s the drawback of having a single command for checking the status.

We changed this approach in RAK3172. You can check the join status just by a single at command query.

I would love to see that come back at some point

There is no concept of being joined to a gateway, only having joined a network server. There is a mechanism for a LoRaWAN stack to do a link check but that’s usually set to around 64 uplinks!

So your device that joins may report it is joined, because it is, but for whatever reason the uplinks aren’t heard (interference or something attenuates the signal) or the gateway is just not there, turned off, rebooting, has no back-haul etc etc

For situations where waiting 64 uplinks before checking the link isn’t appropriate I have a variety of schemes, but mostly I end up with devices in an area that has reasonable coverage that join and then just send and send and send.

Is there any possibility that there is a brown-out on the radio - so it’s all good to go but as soon as the mA’s are called upon the voltage dips and causes some issue?

Hello Nick,
I guess the root of the issue is that I am trying to avoid calling at+join everytime I wake from sleep, as to the best of my knowledge this is not technically correct and may cause issues with too many devices connected. Am I mistaken? If I were to call at+join each wake, it would simplify my workflow, but I think it is not necessary is it?

You are entirely correct, there should be no need to join after every wake and it’s not something I’ve found I’ve had to do with the RAK modules using AT commands.

And you are totally correct about the arising issues with the network if you join on wake - apart from potential clashes with other radios doing the same & the gateway going deaf to uplinks (including other join requests) whilst sending the join accept, you will run in to other potential issues with JoinNonces, an extra security mechanism that the network server will track to make sure the join request isn’t a replay attack.

Have you looked at your power arrangements.

As I only run the modules at 9600 to give me flexibility to use a soft serial implementation if I choose, if you are running at full tilt and as unscientific as this is, it may be that you need to introduce a small delay between the wake up call and the send request. And that prompts me to mention, are you just sending the AT+SEND or are you waking the module first? If the baud rate is high, the module has to detect the incoming bits on the Rx line, have the wake interrupt triggered and processed and then go on to read the message, get the radio in to the right state which needs a few uS to set itself up etc etc, so again, rather unscientific, but it may be worth adding a wake up call in with a very short delay before hitting it with the send request.

What is the MCU and what baud rate are you connected at?

Hello Nick,
My MCU is the ESP32-WROOM Not on a dev board, it is a custom design. The baud rate is 115200.
I am waking the up the chip before anything, and then delaying a full second before doing anything else.

My original plan was like this:

  1. Wake Up
  2. Init Serial2, setTimeout of 10 seconds
  3. Wake up RAK chip, delay 1 second for everything to stabilize.
  4. Check if rak chip has DEV_EUI, APP_EUI, and APP_KEY set, If no, load it from SD card
  5. Check if already joined to gateway, If no, issue an AT+JOIN call
  6. Send Data & check at+recv= response for a : and parse downlink if necessary.
  7. Sleep RAK chip, sleep 1 second for things to stabilize and END Serial2 connection.

Steps 4 and 5 are causing me trouble.
Joining everytime makes things easy and things just work, but this feels very very wrong. This is why I am looking for a way to check the config and join status. to @carlrowan point, my lorawan device is within range of a gateway, and immobile so I do believe there is less need to attempt a fresh join.

Do you know how to change the baud rate to 9600? That sounds good to me.
Also, in terms of steps 4 and 5, I would love to get these to work, OR I would love to know if I am going about this in the wrong way. I know I may be over complicating it, but I want to make many of these devices and having the config on an SD card is very nice (btw, the loading of the sd card stuff is all working just fine). Getting the RAK chip to let me know if it has been previously configured is the real holdup for me right now.

Incase anyone is interested, Here is my code for the LoRaWAN part of things in full (It joins every wake and is suboptimal):

#include "lorawan.h"
bool hasJoined = false;
bool hasSettings = false;

bool rk_recvData(void)
{
    String ret = Serial2.readStringUntil('\0');
    if (ret.length() > 0)
    {
        if (ret.indexOf("OK") >= 0)
        {
            Serial.println("Command Result: " + ret);
            return true;
        }
        if (ret.indexOf("at+recv=") >= 0)
        {
            if (ret.indexOf(":") >= 0)
            {
                Serial.println("Send Command Result: " + ret);
                ret = ret.substring(ret.indexOf(":") + 1, ret.length());
                Serial.println("Downlink Recieved Result: " + ret);
                return true;
            }
            else
            {
                Serial.println("Send Command Result: " + ret);
                return true;
            }
        }
        else
        {
            Serial.println("Command BAD: " + ret);
            return false;
        }
    }
}

// Function: status will return lorawan status
// OK Work Mode: LoRaWAN
// Region: AS923
// MulticastEnable: false
// DutycycleEnable: false
// Send_repeat_cnt: 0
// Join_mode: OTAA
// DevEui: 0000000000101001
// AppEui: 0000000000000001
// AppKey: 603315472BA5DF9399A7E19D1363FF3D
// Class: A
// Joined Network:false
// IsConfirm: unconfirm
// AdrEnable: true
// EnableRepeaterSupport: false
// RX2_CHANNEL_FREQUENCY: 923200000, RX2_CHANNEL_DR:2
// RX_WINDOW_DURATION: 3000ms
// RECEIVE_DELAY_1: 1000ms
// RECEIVE_DELAY_2: 2000ms
// JOIN_ACCEPT_DELAY_1: 5000ms
// JOIN_ACCEPT_DELAY_2: 6000ms
// Current Datarate: 5
// Primeval Datarate: 5
// ChannelsTxPower: 0
// UpLinkCounter: 0
// DownLinkCounter: 0

void LORAWAN_status(String dev_eui_to_check, String app_eui_to_check, String app_key_to_check)
{
    Serial2.println("at+get_config=lora:status");
    String ret = Serial2.readStringUntil('\0');
    if (ret.length() > 0)
    {
        Serial.println(ret.indexOf("DevEui: " + dev_eui_to_check) > 0);
        if (ret.indexOf("DevEui: " + dev_eui_to_check) > 0)
        {
            Serial.println("HAS SETTINGS ALREADY");
            hasSettings = true;
        }

        if (ret.indexOf("Joined Network:true") > 0)
        {
            Serial.println("JOINED ALREADY!!!");
            hasJoined = true;
        }
        else
        {
            Serial.println("Error config is here:");
            Serial.println(ret);
        }
        return;
    }
}

void LORAWAN_Setup(String DEV_EUI, String APP_EUI, String APP_KEY)
{
    Serial2.begin(115200);
    Serial2.setTimeout(10000);
    delay(100);
    Serial2.println("at+set_config=device:sleep:0");
    delay(1000);
    rk_recvData();

    LORAWAN_status(DEV_EUI, APP_EUI, APP_KEY);
    if (hasSettings == false)
    {
        Serial2.println("at+set_config=lora:region:AS923");
        Serial.println("Config Region resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:2:0");
        Serial.println("Config Channel resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:3:0");
        Serial.println("Config Channel resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:4:0");
        Serial.println("Config Channel resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:5:0");
        Serial.println("Config Channel resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:6:0");
        Serial.println("Config Channel resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:7:0");
        Serial.println("Config Channel resp: " + rk_recvData());
        Serial2.println("at+set_config=lora:ch_mask:8:0");
        Serial.println("Config Channel resp: " + rk_recvData());

        Serial2.println("at+set_config=lora:dev_eui:" + DEV_EUI);
        Serial.println("Config dev eui: " + rk_recvData());
        Serial2.println("at+set_config=lora:app_eui:" + APP_EUI);
        Serial.println("Config app eui: " + rk_recvData());
        Serial2.println("at+set_config=lora:app_key:" + APP_KEY);
        Serial.println("Config app key: " + rk_recvData());
    }
}

void LORAWAN_Join()
{
    Serial.println("JOINING GATEWAY...");
    Serial2.println("at+join");
    rk_recvData();
}

void LORAWAN_Send(int channel, String data)
{
    Serial.println("SENDING DATA TO GATEWAY...");
    String payload = "at+send=lora:" + String(channel) + ":" + data;
    Serial2.println(payload);
    rk_recvData();
}

void LORAWAN_Sleep(bool sleep)
{
    String payload = "at+set_config=device:sleep:" + String((int)sleep);
    rk_recvData();
    delay(1000);
}

String convertByteArrayToHexString(byte* data, String &hex)
{
    String hexstring = "";
    for (int i = 0; i < 5; i++)
    {
        if (data[i] < 0x10)
        {
        hexstring += '0';
        }
        hexstring += String(data[i], HEX);
    }
    Serial.println("Byte Array Converted to: " + hexstring);
    return hexstring;
}