RAK811 not using Class C correctly

When using OTAA on the RAK811 LoRa Node pHat does not provide true Class C functionality because there is only a small window of time(maybe a second or two?) after an uplink has been sent that allows immediate downlinks from my private Chirpstack (on the RAK2245 RPI gateway) to be read. Class C is supposed to keep listening after transmission until the next packet needs to be sent. It seems to act more like Class A. Chirpstack has already been configured to work with Class C, so it transmits the downlinks almost immediately. Where I have gone wrong? I already configured the node to run in Class C by typing rak811 set-config class=2.
Here is my code:

#!/usr/bin/env python3

from random import randint
from sys import exit
from time import sleep

from rak811 import Mode, Rak811

lora = Rak811()

# Most of the setup should happen only once...
print('Setup')
lora.hard_reset()
lora.mode = Mode.LoRaWan
lora.band = 'EU868'
DEV_EUI = ' '
APP_KEY = ' '
lora.set_config(dev_eui=DEV_EUI,
                app_key=APP_KEY)

print('Joining')
lora.join_otaa()
# Note that DR is different from SF and depends on the region
# See: https://docs.exploratory.engineering/lora/dr_sf/
# Set Data Rate to 5 which is SF7/125kHz for EU868
sleep(10)
lora.dr = 5

print('Sending packets every minute - Interrupt to cancel loop')
print('You can send downlinks from the TTN console')
try:
    while True:
        print("Sending packet")
        lora.send("Hello World")

        while lora.nb_downlinks:
            print("Received", lora.get_downlink()['data'])

        sleep(60)
except Exception as e:  # noqa: E722
    print(e)
    pass

print('Cleaning up')
lora.close()
exit(0)

You’ve not actually told the device to use Class C …

RAK811 Class C is proven to work on ChirpStack.

I am not really familiar with pHat and the python code you use but can you confirm first that your class A works? And a downlink is working with class A setup? We start on that.

If that is working, it means your RX2 is setup properly and moving to class C should not be really difficult. Just enable Class C on Device-profile in ChirpStack then enable RAK811 to class C.

On your python script, why are the keys DEV_EUI and APP_KEY empty then you execute lora.set_config()? Also, you want to use class C so that you can receive immediate downlinks but you perform sleep(60) in your while loop.

The python code is from [https://github.com/AmedeeBulle/pyrak811]. Already used class A beforehand and it works as expected. Once the uplink has been transmitted the gateway will transmit a downlink message if there are any queued for it. The downlink was received with no problems.

Class C has already been enabled.

The keys are only empty as I don’t want to post them here. Regardless, establishing connection with OTAA is not a problem. Changed the code to not go to sleep and only listen in the while loop. However, it still doesn’t listen for more than a second or two.
Code:
#!/usr/bin/env python3

from random import randint
from sys import exit
from time import sleep

from rak811 import Mode, Rak811

lora = Rak811()

# Most of the setup should happen only once...
print('Setup')
lora.hard_reset()
lora.mode = Mode.LoRaWan
lora.band = 'EU868'
DEV_EUI = ' '
APP_KEY = ' '
lora.set_config(dev_eui=DEV_EUI,
                app_key=APP_KEY)

print('Joining')
lora.join_otaa()
# Note that DR is different from SF and depends on the region
# See: https://docs.exploratory.engineering/lora/dr_sf/
# Set Data Rate to 5 which is SF7/125kHz for EU868
sleep(10)
lora.dr = 5

print('Sending packets every minute - Interrupt to cancel loop')
print('You can send downlinks from the TTN console')
print("Sending packet")
lora.send("Hello World")
try:
    while True:
        while lora.nb_downlinks:
            print("Received", lora.get_downlink()['data'])

except Exception as e:  # noqa: E722
    print(e)
    pass

print('Cleaning up')
lora.close()
exit(0)

I also used the pyrak811’s command line interface to try out Class C on OTAA. When inputting the commands;
rak811 join-otaa
rak811 send ‘Hello World’
Then send this command on the rak gateway for the downlink within 100 seconds before the end node timeouts;
mosquitto_pub -t application/1/device/[Insert Device_EUI]/tx -m '{"confirmed": false, "fport": 13, "data": "SGVsbG8gTm9kZQ==" }'
The end node was able to listen to the downlink anytime for up to 100 seconds(seems to be library’s timeout) after the uplink has been transmitted. It seems the problem has to be my python code or the library itself. Anyway to fix this?
(https://github.com/AmedeeBulle/pyrak811)

If you look at the commands for the RAK811, you’ll see there is a set class option …

@nmcc I did this in the command line terminal.

However trying to do this in Python, class is a keyword meaning it is a reserved word that cannot be used as a variable/function name. Could not get this to run:

CLASS = '2'
lora.set_config(dev_eui=DEV_EUI,
                        app_key=APP_KEY,
                        class=CLASS)

When executing the code I got this:

File "otaa.py", line 44
   class=CLASS)
       ^
SyntaxError: invalid syntax

It seems like the library did not take that into account…

I think you have to check the implementation of the python library. My RAK811 works like a charm on Class C using the built-in ChirpStack network server of my Rak gateway. Btw, the firmware of my RAK811 is the latest V3.0.0.14.

If your Class A works, then you are few steps away to be on Class C. You just need to at+set_config=lora:class:2, reset the power then at+join.

If you have a USB to UART converter around, I suggest you connect your pHat RAK811 directly to your PC and manually input the command. Then you can also check your status using at+get_config=lora:status. You can even test if Class C work right away by waiting for real time downlinks. This way you can isolate where is the real issue. But most probably it is the library.

You could call it something else other than CLASS! If it was a different name, it would work a treat:

I’d be reluctant to end up with code that sets just part of a devices config as down the line (months, maybe years later) it won’t be clear what’s actually going on.

The best approach initially is @carlrowan’s “use a serial tool” - so you can see exactly what’s going on with the module. Then you can layer a library & some code over the top knowing it’s not the module, but the library or code or just a bad hair day.