Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    lora.nvram_save / restore() | frame counter updates

    Scheduled Pinned Locked Moved LoPy
    4 Posts 4 Posters 394 Views 5 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M Offline
      morrison
      last edited by

      Hey guys,

      I'm running a node which is a pycom lopy4 + pysense and i'm joining a lora session and saving that sessions sending values and restoring the lora session what i want to ask is:

      • does the session expires? if yes when (at what time)?
      • how can i update the frame counter? because i'm always reading the frame 0 despite the information being correct...
      • i have the tag "retry" in the application traffic; what's the consequence of this?

      Thank you guys!

      that's my code there:

      ################################################# General color code #################################################
      # pycom.rgbled(0x007f00) -> green = <action> accepted
      # pycom.rgbled(0x7f7f00) -> yellow = <action> pending
      # pycom.rgbled(0x7f0000) -> red = <action> gone wrong
      ######################################################################################################################
      ##################################################### Libraries ######################################################
      from network import LoRa
      from network import WLAN
      import machine
      import socket
      import ubinascii
      import struct
      import time
      import config
      import pycom
      from pysense import Pysense
      from deepsleep import DeepSleep
      import deepsleep
      from LIS2HH12 import LIS2HH12
      from SI7006A20 import SI7006A20
      from LTR329ALS01 import LTR329ALS01
      from MPL3115A2 import MPL3115A2,ALTITUDE,PRESSURE
      from math import log
      from struct import *
      import base64
      import gc
      
      
      pycom.heartbeat(False)              # turn off the heartbeat to make way for control pulses in rgb
      print("Starting sequence initiated...")
      pycom.rgbled(0x7f0000)              #red = <action> not forwarded
      time.sleep(1)
      pycom.rgbled(0x007f00)              # green = <action> accepted
      print("Off you go!")
      
      #Sensor instances created
      py = Pysense()
      mpp = MPL3115A2(py,mode=PRESSURE)   # Returns height in meters. Mode may also be set to PRESSURE, returning a value in Pascals
      si = SI7006A20(py)                  # temp, humidity
      lt = LTR329ALS01(py)                # light
      li = LIS2HH12(py)                   # accelerometer
      ds=DeepSleep()
      #gc.enable()                         # enable garbage collection
      
      # initialize LoRa in LORAWAN mode.
      # Please pick the region that matches where you are using the device:
      # Asia = LoRa.AS923
      # Australia = LoRa.AU915
      # Europe = LoRa.EU868
      # United States = LoRa.US915
      # lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
      #
      # # create an OTA authentication params
      # dev_eui = ubinascii.unhexlify('70B3D54995F6E9F1') # these settings can be found from TTN
      # app_eui = ubinascii.unhexlify('70B3D57ED0019C87') # these settings can be found from TTN       'o que estava aantes -- 70B3D57ED0019813'
      # app_key = ubinascii.unhexlify('169C2EF739EAAF4051CD16B8CDA3D56A') # these settings can be found from TTN
      #
      # # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
      # lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
      # lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
      # lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
      #
      # # join a network using OTAA
      # lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=config.LORA_NODE_DR)
      #
      # # wait until the module has joined the network
      # while not lora.has_joined():
      #     time.sleep(2.5)
      #     pycom.rgbled(0x7f7f00)                                  # yellow = lora.join pending
      #     print('Not joined yet...')
      # print('LoRa joined!')
      # pycom.rgbled(0x007f00)                                      # green = lora.join complete
      #
      # # remove all the non-default channels
      # for i in range(3, 16):
      #     lora.remove_channel(i)
      #
      # # 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, config.LORA_NODE_DR)
      #
      # # make the socket non-blocking
      # s.setblocking(False)
      #
      # time.sleep(5.0)
      
      ################################################ Funcoes de configuracao #############################################
      
      # Input: void
      # Output: None - LoRaWAN join
      # Join to LoRaWAN session
      def join_LoRaWAN():
          lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
      
          # create an OTA authentication params
          dev_eui = ubinascii.unhexlify('70B3D54995F6E9F1') # these settings can be found from TTN
          app_eui = ubinascii.unhexlify('70B3D57ED0019C87') # these settings can be found from TTN       'o que estava aantes -- 70B3D57ED0019813'
          app_key = ubinascii.unhexlify('169C2EF739EAAF4051CD16B8CDA3D56A') # these settings can be found from TTN
      
          # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
          lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
          lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
          lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
      
          # join a network using OTAA
          lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=config.LORA_NODE_DR)
      
          # wait until the module has joined the network
          while not lora.has_joined():
              time.sleep(2.5)
              pycom.rgbled(0x7f7f00)                                  # yellow = lora.join pending
              print('Not joined yet...')
          print('LoRa joined!')
          pycom.rgbled(0x007f00)                                      # green = lora.join complete
      
          # remove all the non-default channels
          for i in range(3, 16):
              lora.remove_channel(i)
      
          # 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, config.LORA_NODE_DR)
      
          # make the socket non-blocking
          s.setblocking(False)
      
          time.sleep(5.0)
          return s
      
      # Input: void
      # Output: None - WLAN join
      # Join to a WLAN of choice
      def join_WLAN():
          wlan = WLAN(mode=WLAN.STA)
          nets = wlan.scan()
          pycom.rgbled(0x7f7f00)                                    # yellow = scanning networks
          time.sleep(1)
          print("Scanning networks...")
          time.sleep(1)
          for net in nets:
              if net.ssid == WIFI_SSID:
                  print('Network found!')
                  wlan.connect(net.ssid, auth=(net.sec, WIFI_PASS), timeout=5000)
                  # while not wlan.isconnected():
                  #     machine.idle()                              # save power while waiting
                  print('WLAN connection succeeded!')
                  pycom.rgbled(0x007f00)                            # green = wlan.connect accepted
                  break
      
      # Input: void
      # Output: None - RTC synchronized
      # Sincronizacao com RTC
      def sync_RTC():
          rtc=machine.RTC()
          time.sleep(1)
          pycom.rgbled(0x7f7f00)                                    # yellow = rtc.ntp_sync pending
          print("Synchronizing RTC ...")
          time.sleep(1)
          rtc.ntp_sync('pool.ntp.org',3600)
      
          while not rtc.synced():                                   # beware: maybe add counter if unsynced ntp doesn't lead to infinite loop
              rtc.ntp_sync('pool.ntp.org',3600)
              pycom.rgbled(0x7f0000)                                #red = <action> not forwarded
              print("RTC still not synchronized...")
              time.sleep(2.5)
      
          print("RTC synchronized!")
          time.sleep(2.5)
          pycom.rgbled(0x2b14c6)
          time.sleep(2.5)
          pycom.rgbled(0x007f00)                                    # green = rtc.ntp_sync accepted ALTHOUGH rtc.synced() == False
          time.sleep(1)
          print("Prepare for TAKEOFF!")
          time.sleep(1)
          return
      
      ######################################################################################################################
      
      ################################################# Funcoes auxiliares #################################################
      
      # Input: valor n
      # Output: Número de bytes necessários para codificar o valor n
      # Funcao auxiliar de calculo ao nº de bytes necessarios para codificacao de um dado valor
      def bytes_needed(n):
          if n == 0:
              return 1
          return int(log(n, 256)) + 1                             # int(log(n, 2)) + 1  para calcular nº de bits necessarios
      
      ######################################################################################################################
      
      ################################################# Funcoes de sensor ##################################################
      
      # Input: void
      # Output: lista contendo valores lidos em posicoes fixas
      # Leitura de sensores num determinado instante
      def readSensor():
          list=[]
      
          acc_x = li.acceleration()[0]
          acc_y = li.acceleration()[1]
          acc_z = li.acceleration()[2]
          pitch = li.pitch()                                        # [-90, 90]; Unidades: graus
          roll = li.roll()                                          # [-180, 180]; Unidades: graus
          humid = int(round(si.humidity()*10))                      # arredondamento a uma casa decimal; Unidades: %
          temp = int(round((si.temperature()+273.15)*10))           # arredondamento a uma casa decimal; Unidades: K
          light = lt.light()[0]
          light1 = lt.light()[1]
          press=int(mpp.pressure()/100)                             # descodificação a /100; Unidades: kPa com 1 casa decimal
          batt = int(py.read_battery_voltage()*10)                  # Unidades: dV
      
          list.append(acc_x)
          list.append(acc_y)
          list.append(acc_z)
          list.append(pitch)
          list.append(roll)
          list.append(humid)
          list.append(temp)
          list.append(light)
          list.append(light1)
          list.append(press)
          list.append(batt)
          return list
      
      def encoder(v, f):
          bytes=bytearray()
          values=v
          formats=f
      
          for i in range(len(values)):
      	   bytes.extend(struct.pack(formats[i], values[i]))
      
          return bytes
      
      def decoder(bytearray):
          formatSize = {
      	'b': 1,
      	'B': 1,
      	'H': 2,
      	'h': 2,
      	'f': 4,
      	'I': 4,
      	'i': 4,
          }
          headers = ['acc_x','acc_y','acc_z','pitch','roll','humid','temp','light','light1','press','batt']
          NR_VALS = 11
          fin_i=0
          curr_i = 0
          decoded_val=[]
      
          for i in range(NR_VALS):
       	  fin_i = curr_i + formatSize[formats[i]]
       	  subPkt = bytes2send[curr_i:fin_i]
       	  decoded_val.append(struct.unpack(formats[i], subPkt)[0])
       	  curr_i = fin_i
      
          return  decoded_val
      
      ######################################################################################################################
      
      ################################################ Ciclo principal #####################################################
      while (True):
          pycom.rgbled(0x007f00)                                  # green color comencing sequence
          bytes2send = bytearray()                                # bytearray que ira conter os valores em bytes a enviar
          values=[]
          formats = ['f','f','f','f','f','H','H','f','f','H','B']  #Total of 35 bytes + 13 bytes of LoRa header
          decoded_val=[]
      
      # a testar
          lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
          lora.nvram_restore()
      
          if not lora.has_joined():
              print("Firstly join")
      
              dev_eui = ubinascii.unhexlify('70B3D54995F6E9F1') # these settings can be found from TTN
              app_eui = ubinascii.unhexlify('70B3D57ED0019C87') # these settings can be found from TTN       'o que estava aantes -- 70B3D57ED0019813'
              app_key = ubinascii.unhexlify('169C2EF739EAAF4051CD16B8CDA3D56A') # these settings can be found from TTN
      
              # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
              lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
              lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
              lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
      
              # join a network using OTAA
              lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=config.LORA_NODE_DR)
      
              # wait until the module has joined the network
              while not lora.has_joined():
                  time.sleep(2.5)
                  pycom.rgbled(0x7f7f00)                                  # yellow = lora.join pending
                  print('Not joined yet...')
              print('LoRa joined!')
              pycom.rgbled(0x007f00)                                      # green = lora.join complete
      
              # remove all the non-default channels
              for i in range(3, 16):
                  lora.remove_channel(i)
      
              # 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, config.LORA_NODE_DR)
      
              # make the socket non-blocking
              s.setblocking(False)
      
              time.sleep(5.0)
      
              lora.nvram_save()
              print("AHHHHHHHHHHHHh")
          else:
              print("Join already")
              s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
              s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
              s.setsockopt(socket.SOL_LORA, socket.SO_DR, config.LORA_NODE_DR)
              s.setblocking(False)
      
      # a testar
      
          #join_WLAN()
          #sync_RTC()
      
      
          values=readSensor()
          bytes2send=encoder(values, formats)
          print('bytes2send', bytes2send)
          #print('Array size:', len(bytes2send))
          #decoded_val=decoder(bytes2send)
      
          #print("Decoded values: ", decoded_val)
          #print(len(decoded_val))
          print("going to sleep")
          time.sleep(2)
          pycom.rgbled(0x0000ff)
          time.sleep(2)
          #mpp.i2c.writeto_mem(MPL3115A2.MPL3115_I2CADDR, MPL3115A2.MPL3115_CTRL_REG1, bytes([0x0]))
      
          s.send(bytes2send)
          lora.nvram_save()
      
          #time.sleep(10)
          py.setup_sleep(30)   # setup a 10 seconds sleep time
          py.go_to_sleep(False)
          #machine.pin_deepsleep_wakeup(['P13'], machine.WAKEUP_ANY_HIGH, False)
          #time.sleep(2)
          #pycom.rgbled(0xff0000)
          #time.sleep(2)
          #machine.deepsleep(30000)
      
          # time.sleep(4)
          # rx, port = s.recvfrom(256)
          # if rx:
          #     print('Received: {}, on port: {}'.format(rx, port))
          # time.sleep(6)
      
      ##################### Debugging Section #####################
          # a=base64.b64encode(bytes2send)
          # print(a)
      #############################################################
      
      ######################################################################################################################```
      C robert-hhR J 3 Replies Last reply Reply Quote 0
      • C Offline
        CoachAllen @morrison
        last edited by

        @morrison What do you know? Another dead end from Pycom. You have a question and they ignore you. How does it feel to ALPHA a product?

        1 Reply Last reply Reply Quote 1
        • robert-hhR Offline
          robert-hh @morrison
          last edited by

          @morrison Joining (via ABP or OTAA) just establishes the keys for data exchange between the nodes. These keys are established once and do not expire. If you like, you can renew the, but there is nothing enforcing it. And there is not session that expires.

          Frame counter have to be managed at the node side. There is the lora.nvram_save / restore() mechanism, which is a little bit tricky, in that lora.nvram_restore() sets the stored counter to 0. So if you call it more than once in a row, you get 0 as counter value. That is, so to say, sub-optimal. If you request confirmed Lora messages, the message will be re-sent by the LoRa stack until confirmed, at least a few times. But that accumulates to the downlink budget, and some public networks limit that.

          @CoachAllen These questions are partially pycom-specific and have been discussed several times in the forum.

          1 Reply Last reply Reply Quote 0
          • J Offline
            jcaron @morrison
            last edited by

            @morrison my personal guess would be that you are going to sleep a bit too quickly after sending/saving state.

            The Pysense-controlled Deep Sleep is quite brutal, it just cuts the power supply to the ESP32 without any warning.

            Try adding short delays between send and save and between save and sleep to see if that helps.

            Also, is your device rejoining each time, or just sending with the same counter over and over again?

            1 Reply Last reply Reply Quote 1

            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

            With your input, this post could be even better 💗

            Register Login
            • 1 / 1
            • First post
              Last post

            Pycom on Twitter

            Pycom