Has anyone successfully used lora.nvram_save() and restore?



  • Re: How to accomplish lora.nvram_restore() ?

    I have tried many variations, but no luck for me. If anyone has been successful, would you please post your code?



  • @jcaron The issue has been worked out and it works quite well now! Thanks a lot!



  • @jcaron Thanks for responsing so quick! I have tried your suggestion and it works now. And I will experiment further to eusure the stability. Now the code is:

    # pysense sensor part
    from pysense import Pysense
    from LTR329ALS01 import LTR329ALS01
    from LIS2HH12 import LIS2HH12
    
    # FiPy part
    from network import LoRa
    import socket
    import time
    import pycom
    import ubinascii
    import machine
    
    # pysense machine part
    from machine import RTC
    from machine import SD
    import os
    
    from network import WLAN, Bluetooth,LTE
    
    # set parameters for sensor function
    py = Pysense()
    lt = LTR329ALS01(py)  # only use light sensor
    
    lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)   # itialise LoRa in LORAWAN mode.
    lora.nvram_restore()
    #-------------------------------- if never join before -------------------------------------#
    if not lora.has_joined():
        print("Firstly join")
        #-------------------- use OTAA to connect with TTN ------------------------------#
        app_eui = ubinascii.unhexlify('70B3D57ED0013E78')
        app_key = ubinascii.unhexlify('5D87FAB0BC66A45FB0DA07453ED2BC2B')
        lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0) # join a network using OTAA (Over the Air Activation)
        while not lora.has_joined():    # wait until the module has joined the network
            time.sleep(2.5)
            print('Not yet joined...')
        # join in
        print('Successfully join in!')
    
        #---------- Set LoRa parameters ----------------#
        # create a LoRa socket
        s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        # set the LoRaWAN data rate
        s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
    
        #---------- Send uplink & Stroe uplink data ----------------#
        uplink_payload = ("Light: " + str(lt.light()))
        s.setblocking(True)
        s.send(uplink_payload)
    
        #--------- Receive downlink & Stroe downlink data ----------#
        s.setblocking(False)
        downlink_message = s.recv(64) # bytes form     and     n is typically < 64 bytes
        #time.sleep(1)
        print(downlink_message)
        print(type(downlink_message))
        lora.nvram_save()   # store in flush to judge next time
    
        #----------- Jugde whether there is a downlink -------------#
        if downlink_message == b'':
            print("There is no downlink")
        else:
            downlink_payload = downlink_message.decode('ascii') # string form
            print("Downlink message: " + downlink_payload)
            #-------- Judge downlink message & operate -------------#
            if downlink_message == b'2': # if ==2, it will light green for 5 seconds
                print("Hi, Green!")
                pycom.heartbeat(False)
                pycom.rgbled(0x007f00) # green
                time.sleep(3)
                pycom.heartbeat(True)
            if downlink_message == b'4': # if ==4, it will light yellow for 5 seconds
                print("Hi, Yellow!")
                pycom.heartbeat(False)
                pycom.rgbled(0x7f7f00) # yellow
                time.sleep(3)
                pycom.heartbeat(True)
        print("####################################")
        print("\n")
    
    #-------------------------------- if already join -------------------------------------#
    else:
        '''
        #--------- Remove default channels ----------#
        for index in range(0, 15):
            lora.remove_channel(index)
        lora.add_channel(3, frequency=867100000, dr_min=0, dr_max=5)
        lora.add_channel(4, frequency=867300000, dr_min=0, dr_max=5)
        lora.add_channel(5, frequency=867500000, dr_min=0, dr_max=5)
        lora.add_channel(6, frequency=867700000, dr_min=0, dr_max=5)
        lora.add_channel(7, frequency=867900000, dr_min=0, dr_max=5)
    
        lora.add_channel(8, frequency=868100000, dr_min=0, dr_max=5)
        lora.add_channel(9, frequency=868300000, dr_min=0, dr_max=5)
        lora.add_channel(10, frequency=868500000, dr_min=0, dr_max=5)
        lora.add_channel(11, frequency=868700000, dr_min=0, dr_max=5)
        lora.add_channel(12, frequency=868900000, dr_min=0, dr_max=5)
    
        lora.add_channel(13, frequency=869100000, dr_min=0, dr_max=5)
        lora.add_channel(14, frequency=869300000, dr_min=0, dr_max=5)
        lora.add_channel(15, frequency=869500000, dr_min=0, dr_max=5)
        '''
        print("Join already")
        #---------------------------Set LoRa parameters-------------------------------------#
        # create a LoRa socket
        s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        # set the LoRaWAN data rate
        s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
    
        #---------- Send uplink & Stroe uplink data ----------------#
        uplink_payload = ("Light: " + str(lt.light()))
        s.setblocking(True)
        s.send(uplink_payload)
        print("send finish")
    
        #--------- Receive downlink & Stroe downlink data ----------#
        s.setblocking(False)
        downlink_message = s.recv(64) # bytes form     and     n is typically < 64 bytes
        time.sleep(1)
        print(downlink_message)
        print(type(downlink_message))
        lora.nvram_save()
        print("Receive finish")
    
        #----------- Jugde whether there is a downlink -------------#
        if downlink_message == b'':
            print("There is no downlink")
        else:
            downlink_payload = downlink_message.decode('ascii') # string form
            print("Downlink message: " + downlink_payload)
    
            #-------- Judge downlink message & operate -------------#
            if downlink_message == b'2': # if ==2, it will light green for 5 seconds
                print("Hi, Green!")
                pycom.heartbeat(False)
                pycom.rgbled(0x007f00) # green
                time.sleep(3)
                pycom.heartbeat(True)
            if downlink_message == b'4': # if ==4, it will light yellow for 5 seconds
                print("Hi, Yellow!")
                pycom.heartbeat(False)
                pycom.rgbled(0x7f7f00) # yellow
                time.sleep(3)
                pycom.heartbeat(True)
        print("####################################")
        print("\n")
    
    print("Deep sleep begin!")
    # time sleep
    py.setup_sleep(9)   # setup a 10 seconds sleep time
    py.go_to_sleep()
    #machine.deepsleep(9000)  # machine.deepsleep([milli_sec])
    

    Thanks a lot!



  • @Bismarck501 You should factorise your code a lot, it would make things a lot easier to maintain.

    You shouldn't rely on an additional NVRAM variable to determine your LoRaWAN state.

    Instead, just call nvram_restore, then has_joined. If not true, you need to join. Otherwise, you can go ahead and send/receive.

    Also, I would call nvram_save after any interaction with the LoRaWAN stack is finished including the recv part. Not sure it currently causes any issues, but it's better to be consistent.



  • @jmarcelino Hello, I have read your suggestion carefully and tried in my project. But there was some issues about this solution.
    My device consists of FiPy+pysense, and I connected to TTN via OTAA. My code with lora,nvram_save() and restore() is:

    # pysense sensor part
    from pysense import Pysense
    from LTR329ALS01 import LTR329ALS01
    from LIS2HH12 import LIS2HH12
    
    # FiPy part
    from network import LoRa
    import socket
    import time
    import pycom
    import ubinascii
    import machine
    
    # pysense machine part
    from machine import RTC
    from machine import SD
    import os
    
    from network import WLAN, Bluetooth,LTE
    
    # set parameters for sensor function
    py = Pysense()
    lt = LTR329ALS01(py)  # only use light sensor
    
    
    loraSaved = pycom.nvs_get('loraSaved')  # if join already, it is int 3; or it will be None
    #-------------------------------- if already join -------------------------------------#
    if (loraSaved == 11):
    
        lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
    
        lora.nvram_restore()
        #--------- Remove default channels ----------#
        for index in range(0, 15):
            lora.remove_channel(index)
        lora.add_channel(3, frequency=867100000, dr_min=0, dr_max=5)
        lora.add_channel(4, frequency=867300000, dr_min=0, dr_max=5)
        lora.add_channel(5, frequency=867500000, dr_min=0, dr_max=5)
        lora.add_channel(6, frequency=867700000, dr_min=0, dr_max=5)
        lora.add_channel(7, frequency=867900000, dr_min=0, dr_max=5)
    
        lora.add_channel(8, frequency=868100000, dr_min=0, dr_max=5)
        lora.add_channel(9, frequency=868300000, dr_min=0, dr_max=5)
        lora.add_channel(10, frequency=868500000, dr_min=0, dr_max=5)
        lora.add_channel(11, frequency=868700000, dr_min=0, dr_max=5)
        lora.add_channel(12, frequency=868900000, dr_min=0, dr_max=5)
    
        lora.add_channel(13, frequency=869100000, dr_min=0, dr_max=5)
        lora.add_channel(14, frequency=869300000, dr_min=0, dr_max=5)
        lora.add_channel(15, frequency=869500000, dr_min=0, dr_max=5)
    
        print("Join already")
        #--------------------------------------------------------------------------------#
        #						Set LoRa parameters
        # create a LoRa socket
        s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        # set the LoRaWAN data rate
        s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
    
        #---------- Send uplink & Stroe uplink data ----------------#    
        uplink_payload = ("Light: " + str(lt.light()))
        s.setblocking(True)
        s.send(uplink_payload)
        lora.nvram_save()
        print("send finish")
        
        #--------- Receive downlink & Stroe downlink data ----------#
        s.setblocking(False)
        downlink_message = s.recv(64) # bytes form     and     n is typically < 64 bytes
        time.sleep(1)
        print(downlink_message)
        print(type(downlink_message))
        print("Receive finish")
    
        #----------- Jugde whether there is a downlink -------------#
        if downlink_message == b'':
            print("There is no downlink")
        else:
            downlink_payload = downlink_message.decode('ascii') # string form
            print("Downlink message: " + downlink_payload)
            #-------- Judge downlink message & operate -------------#
            if downlink_message == b'2': # if ==2, it will light green for 5 seconds
                print("Hi, Green!")
                pycom.rgbled(0x007f00) # green
                time.sleep(3)
            if downlink_message == b'4': # if ==4, it will light yellow for 5 seconds
                print("Hi, Yellow!")
                pycom.rgbled(0x7f7f00) # yellow
                time.sleep(3)
        print("####################################")
        print("\n")
    
    #-------------------------------- if never join before -------------------------------------#
    else:
        print("Firstly join")
        #--------------------------------------------------------------------------------#
        # 					Initialise LoRa in LORAWAN mode.
        lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
        #--------------------------------------------------------------------------------#
        #				Set OTAA mode and connect with the gateway
        # create an OTAA authentication parameters
        app_eui = ubinascii.unhexlify('70B3D57ED0013E78')
        app_key = ubinascii.unhexlify('5D87FAB0BC66A45FB0DA07453ED2BC2B')
        # join a network using OTAA (Over the Air Activation)
        lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
        # wait until the module has joined the network
        while not lora.has_joined():
            time.sleep(2.5)
            print('Not yet joined...')
        # join in
        print('Successfully join in!')
        #--------------------------------------------------------------------------------#
        #						Set LoRa parameters
        # create a LoRa socket
        s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        # set the LoRaWAN data rate
        s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
    
        #---------- Send uplink & Stroe uplink data ----------------#
        uplink_payload = ("Light: " + str(lt.light()))
        s.setblocking(True)
        s.send(uplink_payload)
        lora.nvram_save()
    
        #--------- Receive downlink & Stroe downlink data ----------#
        s.setblocking(False)
        downlink_message = s.recv(64) # bytes form     and     n is typically < 64 bytes
        #time.sleep(1)
        print(downlink_message)
        print(type(downlink_message))
    
        #----------- Jugde whether there is a downlink -------------#
        if downlink_message == b'':
            print("There is no downlink")
        else:
            downlink_payload = downlink_message.decode('ascii') # string form
            print("Downlink message: " + downlink_payload)
    
            #-------- Judge downlink message & operate -------------#
            if downlink_message == b'2': # if ==2, it will light green for 5 seconds
                print("Hi, Green!")
                pycom.rgbled(0x007f00) # green
                time.sleep(3)
            if downlink_message == b'4': # if ==4, it will light yellow for 5 seconds
                print("Hi, Yellow!")
                pycom.rgbled(0x7f7f00) # yellow
                time.sleep(3)
        print("####################################")
        print("\n")
        #---------- store in flush to judge next time ----------------#
        pycom.nvs_set('loraSaved', 11)  
    # time sleep
    py.setup_sleep(9)   # setup a 9 seconds sleep time
    py.go_to_sleep()
    
    
    

    And it can work well. However, after one day, when I tried again, there would be an issue when running code at line 65:

        s.send(uplink_payload)
    

    3885de5c-2262-4686-b6bf-bedc703c6446-image.png

    Where I was wrong? Thanks for giving me some advice!



  • @rloro338 I made the following changes to my code and now it works correctly:

    • list item make sure the socket is blocking ( s.setblocking(True) )

    • list item add a time.sleep(2) after sending, before saving and going to deep sleep.



  • I am trying to use lora.nvram_save() and lora.nvram_restore() and not works. I set all parameters (LoRaWAN, adr = True, app_eui, app_key and channel configuration) the first time that I boot the device and send a message Loriot server receive it. Then device go to deepsleep for 5 seconds and restore the join state. If I look the state with lora.has_joined() return True value, but when I trying to send the message it isn't received by the gateway.

    It is curious because when I use the node directly with a command line in Putty the restore and save comands works fine.

    What I am doing wrong??



  • @bmarkus this is the example code I'm testing, based on which share @jalperin, I'm missing something?

    from network import LoRa
    import struct
    import binascii
    import time
    import math
    import pycom
    import socket
    from pysense import Pysense

    py = Pysense()
    loraSaved = pycom.nvs_get('loraSaved')
    print(loraSaved)
    if not loraSaved:
    lora = LoRa(mode=LoRa.LORAWAN)
    freq = 902300000
    for channel in range(0, 72):
    lora.remove_channel(channel)
    for chan in range(0, 8):
    lora.add_channel(chan, frequency=freq, dr_min=0, dr_max=3)

    dev_addr = struct.unpack(">l", binascii.unhexlify('************'.replace(' ','')))[0]
    nwk_swkey = binascii.unhexlify('************ 89 F1 74 79 40'.replace(' ',''))
    app_swkey = binascii.unhexlify('************ 3A AA BD E8 A9'.replace(' ',''))
    lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey))
    while not lora.has_joined():
        machine.idle()
    s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
    s.setsockopt(socket.SOL_LORA, socket.SO_DR, 3)
    s.bind(3) #select the port number
    s.setblocking(False)
    s.send('LoRa Up')
    time.sleep(2)
    lora.nvram_save()
    pycom.nvs_set('loraSaved', 1)
    py.setup_sleep(60)
    py.go_to_sleep()
    

    else:
    lora = LoRa(mode=LoRa.LORAWAN)
    lora.nvram_restore()
    freq = 902300000
    for channel in range(0, 72):
    lora.remove_channel(channel)
    for chan in range(0, 8):
    lora.add_channel(chan, frequency=freq, dr_min=0, dr_max=3)
    s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
    s.setsockopt(socket.SOL_LORA, socket.SO_DR, 3)
    s.bind(3) #select the port number
    s.setblocking(False)
    s.send('LoRa Restored')
    time.sleep(2)
    lora.nvram_save()
    #pycom.nvs_set('loraSaved', 0) # reset for next test
    py.setup_sleep(60)
    py.go_to_sleep()



  • @johncaipa said in Has anyone successfully used lora.nvram_save() and restore?:

    @bmarkus in the documentation says that this value is saved, then I do not know what would be the problem, because in each sending after waking up the packet counters is always in 1 on TTN.
    "lora.nvram_save()
    Save the LoRaWAN state (joined status, network keys, packet counters, etc) in non-volatile memory in order to be able to restore the state when coming out of deepsleep or a power cycle."

    Do you create a new instance when coming out? It resets the counter.



  • @bmarkus in the documentation says that this value is saved, then I do not know what would be the problem, because in each sending after waking up the packet counters is always in 1 on TTN.
    "lora.nvram_save()
    Save the LoRaWAN state (joined status, network keys, packet counters, etc) in non-volatile memory in order to be able to restore the state when coming out of deepsleep or a power cycle."



  • @johncaipa said in Has anyone successfully used lora.nvram_save() and restore?:

    @jalperin @jmarcelino works but the counter is restarted on each send, this value is not stored?

    Unfortunately it is not possible to get or set your own FCnt value, otherwise it would be possible to handle in your code. Just one of the several missing LoRa/LoRaWAN functions.



  • @jalperin @jmarcelino works but the counter is restarted on each send, this value is not stored?



  • @jmarcelino

    Restoring the channel configuration did the trick. Setblocking(True) was not needed here.

    An anomaly that I have seen before showed up. The packets sent after nvram_restore all arrived with "payload not provided". But, if I first send a packet with a payload of a single character, it and all subsequent packets arrive successfully.

    May I suggest that the documentation be amended to detail what is and is not saved by lora.nvram_save().

    Thank you very much for your help.



  • @jalperin

    Try to restore your channel frequency configuration manually again after the nvram_restore, just use your existing code:

    for channel in range(0, 72):
        lora.remove_channel(channel)
    for chan in range(0, 8):
        lora.add_channel(chan, frequency=freq, dr_min=0, dr_max=3)
    

    The current nvram_save() may not save this...



  • @jalperin

    Umm so differences I see is I'm using OTAA and on EU868 region while you use ABP in the US915 region... also I do a few app related things before sending data and send several packets.

    Try s.setblocking(True) for your sends and also try more than one send, maybe a loop sending 10.



  • Thank you, jmarcellino. That is, I think, what I am doing, but without success. Below is my code. I get the first message, but not the second. I have check my gateway. It only sees the first message.

    from network import LoRa
    import struct
    import binascii
    import time
    import math
    import pycom
    import socket
    from pysense import Pysense

    py = Pysense()
    loraSaved = pycom.nvs_get('loraSaved')
    if not loraSaved:
    lora = LoRa(mode=LoRa.LORAWAN)
    freq = 902300000
    for channel in range(0, 72):
    lora.remove_channel(channel)
    for chan in range(0, 8):
    lora.add_channel(chan, frequency=freq, dr_min=0, dr_max=3)
    dev_addr = struct.unpack(">l", binascii.unhexlify('*****21E27'))[0]
    nwk_swkey = binascii.unhexlify('************4BD956A16FF3DADEB05608C1')
    app_swkey = binascii.unhexlify('*************738855C61661D0FF27')
    lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey))
    while not lora.has_joined():
    machine.idle()
    s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
    s.setsockopt(socket.SOL_LORA, socket.SO_DR, 3)
    s.setblocking(False)
    s.send('LoRa Up')
    time.sleep(2)
    lora.nvram_save()
    pycom.nvs_set('loraSaved', 1)
    py.setup_sleep(60)
    py.go_to_sleep()
    else:
    lora = LoRa(mode=LoRa.LORAWAN)
    lora.nvram_restore()
    s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
    s.setsockopt(socket.SOL_LORA, socket.SO_DR, 3)
    s.setblocking(False)
    s.send('LoRa Restored')
    time.sleep(2)
    pycom.nvs_set('loraSaved', 0) # reset for next test



  • Yes it's working and really simple.

    First time you do your normal join (you do need to wait until it has actually joined!) then

    lora.nvram_save()
    

    Afterwards do

    lora = LoRa(mode=LoRa.LORAWAN)
    lora.nvram_restore()
    
    
    s.send(bytes([0x01, 0x02, 0x03]))
    

Log in to reply
 

Pycom on Twitter