computenodes / dragino

LoRaWAN implementation in python
GNU Affero General Public License v3.0
27 stars 11 forks source link

Support SF12 & RX2 #12

Open theopieri opened 3 years ago

theopieri commented 3 years ago

Hi,

I will like to ask if the code can support SF12 (Spreading Factor)?

Also i testing Downlink code is working perfect in the RX1 windows but if the gateway send in RX2 windows can not receive downlink why??

BNNorman commented 3 years ago

The Dragino code only listens on RX1. See on_tx_done(), line 203, in dragino.py. So you would have to implement listening on RX2 in your code after sending an uplink.

For OTAA RX1 is upto 5 seconds and RX2 occurs 1 second after that - according to what I've read.

dragino.py inherits methods from SX127x/LoRA.py which include routines to set the spreading factor and frequency etc.

Before changing frequency you need to call set_mode(MODE.SLEEP) or MODE.STDBY first. Then set_mode(MODE.RXCONT) when ready to listen on RX2.

There are other inherited methods: set_bw(bandwidth), set_coding_rate(cr) and set_spreading_factor(sf) which will help.

So I would suggest using something (untested) like this :-

import logging
import time
from dragino.SX127x.constants import MODE
from dragino import Dragino
import RPi.GPIO as GPIO

GPIO.setwarnings(false)

D = Dragino("dragino.ini", logging_level=logging.DEBUG)
D.join()
start=time.time()

while not D.registered():

    if time.time()-start>=5:
       # switch to listening on RX2
    D.set_mode(MODE.STDBY)
    # RX2 is 869.525 SF9BW125 in europe
        D.set_freq(869.25)
        D.set_spreading_factor(9)
        D.set_bw(7) # BW125 I think
        D.set_mode(MODE.RXCONT)

    if time()-start>6:
        print("JOIN failed")
    break

    sleep(1)

Hope that helps. (for now).

It might be worth requesting that on_tx_done() switches to RX2 after a timeout but it would be blocking for 5 seconds with OTAA,. I think I would prefer to handle the RX1/RX2 myself.

theopieri commented 3 years ago

Thank you, i will try and let you know!!!

pjb304 commented 3 years ago

I think there are issues with clock drift on the RFM95 module when using SF 11 & SF12. As it's not something we needed for our use case (this code was written for a specific application and then made public in case it was useful to others). I wasn't able to spend any time investigating in depth to see what was going. If it's something that you need please can you investigate and let us know how you get on.

BNNorman commented 3 years ago

I had a go at this but (despite what I read about timing RX1 at 5s max + RX2 at 5 to 6s). It didn't work as expected. I.e the RX1 join accept arrived at 5.16 seconds not within 5 seconds - my TTN gateway is only 30 feet away. Switching to RX2 too soon can result in missing the RX1 reply. Waiting too long can result in missing the RX2 reply.

I modified my code above to this modification of test.py:-

#!/usr/bin/env python3
"""
    Test harness for dragino module - sends hello world out over LoRaWAN 5 times
"""
import logging
from time import sleep,time
import RPi.GPIO as GPIO
from dragino import Dragino
from dragino.SX127x.constants import MODE

GPIO.setwarnings(False)

# add logfile
logLevel=logging.DEBUG
logging.basicConfig(filename="test.log", format='%(asctime)s - %(funcName)s - %(lineno)d - %(levelname)s - %(message)s', level=logLevel)

D = Dragino("dragino.ini", logging_level=logLevel)

print("Waiting for JOIN ACCEPT")
RX1=True

D.join()
start=time()

while not D.registered():

    if RX1 and (time()-start)>5:
        print("JOIN failed in RX1 waiting for RX2")
        RX1=False
        D.set_mode(MODE.STDBY)
        D.set_freq(869.525)
        D.set_spreading_factor(9)
        D.set_bw(7)
        D.set_mode(MODE.RXCONT)

    if not RX1 and (time()-start)>6:
        print("JOIN failed in RX2 - retrying")
        RX1=True
        D.join()
        start=time()

if RX1:
    print("JOINED in RX1 after",time()-start)
else:
    print("JOINED in RX2 after",time()-start)

One possible reason for the join accept arriving at 5.16s might be all the python code - that would need investigating but not today.

When testing this you need to remove the cached entries at the end of dragino.ini to force dragino.py to send a join request otherwise it just uses the cached values next time you run the code.

It would be interesting to see what times you get. Also, how you can force an RX2 response for testing.

EDIT: I moved the start=time() to after the D.join() because D.join() could take significant time. However, my join still took 5.22 seconds. If anyone knows how to benchmark the code we could fine tune the 'if' statements inside the loop. I guess we are at the mercy of a non-realtime OS here.