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

    OTAA Node to Nano Gateway AU915

    Scheduled Pinned Locked Moved LoPy
    3 Posts 2 Posters 388 Views 2 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.
    • Y Offline
      Yendor
      last edited by

      Hi,
      I just recently got a couple of Lopy 4's to act as nodes, but while I wait for my gateway, I was trying to set the pair up in a LoraWan nano gateway and OTAA node test.

      I’m using the GitHub code for a base https://github.com/pycom/pycom-libraries/tree/master/examples/lorawan-nano-gateway and trying to modify it for use in Australia AU915.

      I think I got the gateway working but it never shows connected in the TNN console.

      config.py

      #!/usr/bin/env python
      #
      # Copyright (c) 2019, Pycom Limited.
      #
      # This software is licensed under the GNU GPL version 3 or any
      # later version, with permitted additional terms. For more information
      # see the Pycom Licence v1.0 document supplied with this file, or
      # available at https://www.pycom.io/opensource/licensing
      #
      
      """ LoPy LoRaWAN Nano Gateway configuration options """
      
      import machine
      import ubinascii
      
      WIFI_MAC = ubinascii.hexlify(machine.unique_id()).upper()
      # Set  the Gateway ID to be the first 3 bytes of MAC address + 'FFFE' + last 3 bytes of MAC address
      GATEWAY_ID = WIFI_MAC[:6] + "FFFE" + WIFI_MAC[6:12]
      
      SERVER = 'router.thethings.meshed.com.au'
      PORT = 1700
      
      NTP = "pool.ntp.org"
      NTP_PERIOD_S = 3600
      
      WIFI_SSID = 'ssid'
      WIFI_PASS = 'password'
      WIFI_ADDRESS = '192.168.1.50'
      WIFI_MASK = '255.255.255.0'
      WIFI_GATEWAY = '192.168.1.1'
      
      # for EU868
      # LORA_FREQUENCY = 868100000
      # LORA_GW_DR = "SF7BW125" # DR_5
      # LORA_NODE_DR = 5
      
      # for US915
      # LORA_FREQUENCY = 903900000
      # LORA_GW_DR = "SF7BW125" # DR_3
      # LORA_NODE_DR = 3
      
      # for AU915
      LORA_FREQUENCY = 916800000
      LORA_GW_DR = "SF7BW125"
      LORA_NODE_DR = 4
      

      nanogateway.py

      #!/usr/bin/env python
      #
      # Copyright (c) 2019, Pycom Limited.
      #
      # This software is licensed under the GNU GPL version 3 or any
      # later version, with permitted additional terms. For more information
      # see the Pycom Licence v1.0 document supplied with this file, or
      # available at https://www.pycom.io/opensource/licensing
      #
      
      """ LoPy LoRaWAN Nano Gateway. Can be used for both EU868 and US915. """
      
      import errno
      import machine
      import ubinascii
      import ujson
      import uos
      import usocket
      import utime
      import _thread
      from micropython import const
      from network import LoRa
      from network import WLAN
      from machine import Timer
      
      
      PROTOCOL_VERSION = const(2)
      
      PUSH_DATA = const(0)
      PUSH_ACK = const(1)
      PULL_DATA = const(2)
      PULL_ACK = const(4)
      PULL_RESP = const(3)
      
      TX_ERR_NONE = 'NONE'
      TX_ERR_TOO_LATE = 'TOO_LATE'
      TX_ERR_TOO_EARLY = 'TOO_EARLY'
      TX_ERR_COLLISION_PACKET = 'COLLISION_PACKET'
      TX_ERR_COLLISION_BEACON = 'COLLISION_BEACON'
      TX_ERR_TX_FREQ = 'TX_FREQ'
      TX_ERR_TX_POWER = 'TX_POWER'
      TX_ERR_GPS_UNLOCKED = 'GPS_UNLOCKED'
      
      UDP_THREAD_CYCLE_MS = const(20)
      
      STAT_PK = {
          'stat': {
              'time': '',
              'lati': 0,
              'long': 0,
              'alti': 0,
              'rxnb': 0,
              'rxok': 0,
              'rxfw': 0,
              'ackr': 100.0,
              'dwnb': 0,
              'txnb': 0
          }
      }
      
      RX_PK = {
          'rxpk': [{
              'time': '',
              'tmst': 0,
              'chan': 0,
              'rfch': 0,
              'freq': 0,
              'stat': 1,
              'modu': 'LORA',
              'datr': '',
              'codr': '4/5',
              'rssi': 0,
              'lsnr': 0,
              'size': 0,
              'data': ''
          }]
      }
      
      TX_ACK_PK = {
          'txpk_ack': {
              'error': ''
          }
      }
      
      
      class NanoGateway:
          """
          Nano gateway class, set up by default for use with TTN, but can be configured
          for any other network supporting the Semtech Packet Forwarder.
          Only required configuration is wifi_ssid and wifi_password which are used for
          connecting to the Internet.
          """
      
          def __init__(self, id, frequency, datarate, ssid, password, address, mask, gateway, server, port, ntp_server='pool.ntp.org', ntp_period=3600):
              self.id = id
              self.server = server
              self.port = port
      
              self.frequency = frequency
              self.datarate = datarate
      
              self.ssid = ssid
              self.password = password
              self.address = address
              self.mask = mask
              self.gateway = gateway
      
              self.ntp_server = ntp_server
              self.ntp_period = ntp_period
      
              self.server_ip = None
      
              self.rxnb = 0
              self.rxok = 0
              self.rxfw = 0
              self.dwnb = 0
              self.txnb = 0
      
              self.sf = self._dr_to_sf(self.datarate)
              self.bw = self._dr_to_bw(self.datarate)
      
              self.stat_alarm = None
              self.pull_alarm = None
              self.uplink_alarm = None
      
              self.wlan = None
              self.sock = None
              self.udp_stop = False
              self.udp_lock = _thread.allocate_lock()
      
              self.lora = None
              self.lora_sock = None
      
              self.rtc = machine.RTC()
      
          def start(self):
              """
              Starts the LoRaWAN nano gateway.
              """
      
              self._log('Starting LoRaWAN nano gateway with id: {}', self.id)
      
              # setup WiFi as a station and connect
              self.wlan = WLAN(mode=WLAN.STA)
              self.wlan.ifconfig(config=(self.address, self.mask, self.gateway, self.gateway))
              self._connect_to_wifi()
      
              # get a time sync
              self._log('Syncing time with {} ...', self.ntp_server)
              self.rtc.ntp_sync(self.ntp_server, update_period=self.ntp_period)
              while not self.rtc.synced():
                  utime.sleep_ms(50)
              self._log("RTC NTP sync complete")
      
              # get the server IP and create an UDP socket
              self.server_ip = usocket.getaddrinfo(self.server, self.port)[0][-1]
              self._log('Opening UDP socket to {} ({}) port {}...', self.server, self.server_ip[0], self.server_ip[1])
              self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM, usocket.IPPROTO_UDP)
              self.sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
              self.sock.setblocking(False)
      
              # push the first time immediatelly
              self._push_data(self._make_stat_packet())
      
              # create the alarms
              self.stat_alarm = Timer.Alarm(handler=lambda t: self._push_data(self._make_stat_packet()), s=60, periodic=True)
              self.pull_alarm = Timer.Alarm(handler=lambda u: self._pull_data(), s=25, periodic=True)
      
              # start the UDP receive thread
              self.udp_stop = False
              _thread.start_new_thread(self._udp_thread, ())
      
              # initialize the LoRa radio in LORA mode
              self._log('Setting up the LoRa radio at {} Mhz using {}', self._freq_to_float(self.frequency), self.datarate)
              self.lora = LoRa(
                  mode=LoRa.LORAWAN,
                  frequency=self.frequency,
                  bandwidth=self.bw,
                  sf=self.sf,
                  preamble=8,
                  coding_rate=LoRa.CODING_4_5,
                  tx_iq=True
              )
      
              # create a raw LoRa socket
              self.lora_sock = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW)
              self.lora_sock.setblocking(False)
              self.lora_tx_done = False
      
              self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT), handler=self._lora_cb)
              self._log('LoRaWAN nano gateway online')
      
          def stop(self):
              """
              Stops the LoRaWAN nano gateway.
              """
      
              self._log('Stopping...')
      
              # send the LoRa radio to sleep
              self.lora.callback(trigger=None, handler=None)
              self.lora.power_mode(LoRa.SLEEP)
      
              # stop the NTP sync
              self.rtc.ntp_sync(None)
      
              # cancel all the alarms
              self.stat_alarm.cancel()
              self.pull_alarm.cancel()
      
              # signal the UDP thread to stop
              self.udp_stop = True
              while self.udp_stop:
                  utime.sleep_ms(50)
      
              # disable WLAN
              self.wlan.disconnect()
              self.wlan.deinit()
      
          def _connect_to_wifi(self):
              self.wlan.connect(self.ssid, auth=(None, self.password))
              while not self.wlan.isconnected():
                  utime.sleep_ms(50)
              self._log('WiFi connected to: {}', self.ssid)
      
          def _dr_to_sf(self, dr):
              sf = dr[2:4]
              if sf[1] not in '0123456789':
                  sf = sf[:1]
              return int(sf)
      
          def _dr_to_bw(self, dr):
              bw = dr[-5:]
              if bw == 'BW125':
                  return LoRa.BW_125KHZ
              elif bw == 'BW250':
                  return LoRa.BW_250KHZ
              else:
                  return LoRa.BW_500KHZ
      
          def _sf_bw_to_dr(self, sf, bw):
              dr = 'SF' + str(sf)
              if bw == LoRa.BW_125KHZ:
                  return dr + 'BW125'
              elif bw == LoRa.BW_250KHZ:
                  return dr + 'BW250'
              else:
                  return dr + 'BW500'
      
          def _lora_cb(self, lora):
              """
              LoRa radio events callback handler.
              """
      
              events = lora.events()
              if events & LoRa.RX_PACKET_EVENT:
                  self.rxnb += 1
                  self.rxok += 1
                  rx_data = self.lora_sock.recv(256)
                  stats = lora.stats()
                  packet = self._make_node_packet(rx_data, self.rtc.now(), stats.rx_timestamp, stats.sfrx, self.bw, stats.rssi, stats.snr)
                  packet = self.frequency_rounding_fix(packet, self.frequency)
                  self._push_data(packet)
                  self._log('Received packet: {}', packet)
                  self.rxfw += 1
              if events & LoRa.TX_PACKET_EVENT:
                  self.txnb += 1
                  lora.init(
                      mode=LoRa.LORA,
                      frequency=self.frequency,
                      bandwidth=self.bw,
                      sf=self.sf,
                      preamble=8,
                      coding_rate=LoRa.CODING_4_5,
                      tx_iq=True
                      )
      
          def _freq_to_float(self, frequency):
              """
              MicroPython has some inprecision when doing large float division.
              To counter this, this method first does integer division until we
              reach the decimal breaking point. This doesn't completely elimate
              the issue in all cases, but it does help for a number of commonly
              used frequencies.
              """
      
              divider = 6
              while divider > 0 and frequency % 10 == 0:
                  frequency = frequency // 10
                  divider -= 1
              if divider > 0:
                  frequency = frequency / (10 ** divider)
              return frequency
      
          def frequency_rounding_fix(self, packet, frequency):
              freq = str(frequency)[0:3] + '.' + str(frequency)[3]
      
              start = packet.find("freq\":")
              end = packet.find(",", start)
      
              packet = packet[:start + 7] + freq + packet[end:]
      
              return packet
      
          def _make_stat_packet(self):
              now = self.rtc.now()
              STAT_PK["stat"]["time"] = "%d-%02d-%02d %02d:%02d:%02d GMT" % (now[0], now[1], now[2], now[3], now[4], now[5])
              STAT_PK["stat"]["rxnb"] = self.rxnb
              STAT_PK["stat"]["rxok"] = self.rxok
              STAT_PK["stat"]["rxfw"] = self.rxfw
              STAT_PK["stat"]["dwnb"] = self.dwnb
              STAT_PK["stat"]["txnb"] = self.txnb
              return ujson.dumps(STAT_PK)
      
          def _make_node_packet(self, rx_data, rx_time, tmst, sf, bw, rssi, snr):
              RX_PK["rxpk"][0]["time"] = "%d-%02d-%02dT%02d:%02d:%02d.%dZ" % (rx_time[0], rx_time[1], rx_time[2], rx_time[3], rx_time[4], rx_time[5], rx_time[6])
              RX_PK["rxpk"][0]["tmst"] = tmst
              RX_PK["rxpk"][0]["freq"] = self._freq_to_float(self.frequency)
              RX_PK["rxpk"][0]["datr"] = self._sf_bw_to_dr(sf, bw)
              RX_PK["rxpk"][0]["rssi"] = rssi
              RX_PK["rxpk"][0]["lsnr"] = snr
              RX_PK["rxpk"][0]["data"] = ubinascii.b2a_base64(rx_data)[:-1]
              RX_PK["rxpk"][0]["size"] = len(rx_data)
              return ujson.dumps(RX_PK)
      
          def _push_data(self, data):
              token = uos.urandom(2)
              packet = bytes([PROTOCOL_VERSION]) + token + bytes([PUSH_DATA]) + ubinascii.unhexlify(self.id) + data
              with self.udp_lock:
                  try:
                      self.sock.sendto(packet, self.server_ip)
                  except Exception as ex:
                      self._log('Failed to push uplink packet to server: {}', ex)
      
          def _pull_data(self):
              token = uos.urandom(2)
              packet = bytes([PROTOCOL_VERSION]) + token + bytes([PULL_DATA]) + ubinascii.unhexlify(self.id)
              with self.udp_lock:
                  try:
                      self.sock.sendto(packet, self.server_ip)
                  except Exception as ex:
                      self._log('Failed to pull downlink packets from server: {}', ex)
      
          def _ack_pull_rsp(self, token, error):
              TX_ACK_PK["txpk_ack"]["error"] = error
              resp = ujson.dumps(TX_ACK_PK)
              packet = bytes([PROTOCOL_VERSION]) + token + bytes([PULL_ACK]) + ubinascii.unhexlify(self.id) + resp
              with self.udp_lock:
                  try:
                      self.sock.sendto(packet, self.server_ip)
                  except Exception as ex:
                      self._log('PULL RSP ACK exception: {}', ex)
      
          def _send_down_link(self, data, tmst, datarate, frequency):
              """
              Transmits a downlink message over LoRa.
              """
      
              self.lora.init(
                  mode=LoRa.LORA,
                  frequency=frequency,
                  bandwidth=self._dr_to_bw(datarate),
                  sf=self._dr_to_sf(datarate),
                  preamble=8,
                  coding_rate=LoRa.CODING_4_5,
                  tx_iq=True
                  )
              #while utime.ticks_cpu() < tmst:
              #    pass
              self.lora_sock.send(data)
              self._log(
                  'Sent downlink packet scheduled on {:.3f}, at {:.3f} Mhz using {}: {}',
                  tmst / 1000000,
                  self._freq_to_float(frequency),
                  datarate,
                  data
              )
      
          def _send_down_link_class_c(self, data, datarate, frequency):
              self.lora.init(
                  mode=LoRa.LORA,
                  frequency=frequency,
                  bandwidth=self._dr_to_bw(datarate),
                  sf=self._dr_to_sf(datarate),
                  preamble=8,
                  coding_rate=LoRa.CODING_4_5,
                  tx_iq=True,
                  device_class=LoRa.CLASS_C
                  )
      
              self.lora_sock.send(data)
              self._log(
                  'Sent downlink packet scheduled on {:.3f}, at {:.3f} Mhz using {}: {}',
                  utime.time(),
                  self._freq_to_float(frequency),
                  datarate,
                  data
              )
      
          def _udp_thread(self):
              """
              UDP thread, reads data from the server and handles it.
              """
      
              while not self.udp_stop:
                  try:
                      data, src = self.sock.recvfrom(1024)
                      _token = data[1:3]
                      _type = data[3]
                      if _type == PUSH_ACK:
                          self._log("Push ack")
                      elif _type == PULL_ACK:
                          self._log("Pull ack")
                      elif _type == PULL_RESP:
                          self.dwnb += 1
                          ack_error = TX_ERR_NONE
                          tx_pk = ujson.loads(data[4:])
                          if "tmst" in data:
                              tmst = tx_pk["txpk"]["tmst"]
                              t_us = tmst - utime.ticks_cpu() - 15000
                              if t_us < 0:
                                  t_us += 0xFFFFFFFF
                              if t_us < 20000000:
                                  self.uplink_alarm = Timer.Alarm(
                                      handler=lambda x: self._send_down_link(
                                          ubinascii.a2b_base64(tx_pk["txpk"]["data"]),
                                          tx_pk["txpk"]["tmst"] - 50, tx_pk["txpk"]["datr"],
                                          int(tx_pk["txpk"]["freq"] * 1000) * 1000
                                      ),
                                      us=t_us
                                  )
                              else:
                                  ack_error = TX_ERR_TOO_LATE
                                  self._log('Downlink timestamp error!, t_us: {}', t_us)
                          else:
                              self.uplink_alarm = Timer.Alarm(
                                  handler=lambda x: self._send_down_link_class_c(
                                      ubinascii.a2b_base64(tx_pk["txpk"]["data"]),
                                      tx_pk["txpk"]["datr"],
                                      int(tx_pk["txpk"]["freq"] * 1000) * 1000
                                  ),
                                  us=50
                              )
                          self._ack_pull_rsp(_token, ack_error)
                          self._log("Pull rsp")
                  except usocket.timeout:
                      pass
                  except OSError as ex:
                      if ex.errno != errno.EAGAIN:
                          self._log('UDP recv OSError Exception: {}', ex)
                  except Exception as ex:
                      self._log('UDP recv Exception: {}', ex)
      
                  # wait before trying to receive again
                  utime.sleep_ms(UDP_THREAD_CYCLE_MS)
      
              # we are to close the socket
              self.sock.close()
              self.udp_stop = False
              self._log('UDP thread stopped')
      
          def _log(self, message, *args):
              """
              Outputs a log message to stdout.
              """
      
              print('[{:>10.3f}] {}'.format(
                  utime.ticks_ms() / 1000,
                  str(message).format(*args)
                  ))
      

      main.py

      #!/usr/bin/env python
      #
      # Copyright (c) 2019, Pycom Limited.
      #
      # This software is licensed under the GNU GPL version 3 or any
      # later version, with permitted additional terms. For more information
      # see the Pycom Licence v1.0 document supplied with this file, or
      # available at https://www.pycom.io/opensource/licensing
      #
      
      """ LoPy LoRaWAN Nano Gateway example usage """
      
      import config
      from nanogateway import NanoGateway
      
      if __name__ == '__main__':
          nanogw = NanoGateway(
              id=config.GATEWAY_ID,
              frequency=config.LORA_FREQUENCY,
              datarate=config.LORA_GW_DR,
              ssid=config.WIFI_SSID,
              password=config.WIFI_PASS,
              address=config.WIFI_ADDRESS,
              mask=config.WIFI_MASK,
              gateway=config.WIFI_GATEWAY,
              server=config.SERVER,
              port=config.PORT,
              ntp_server=config.NTP,
              ntp_period=config.NTP_PERIOD_S
              )
      
          nanogw.start()
          nanogw._log('You may now press ENTER to enter the REPL')
          input()
      

      Start up log

      rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
      configsip: 0, SPIWP:0xee
      clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
      mode:DIO, clock div:1
      load:0x3fff8028,len:8
      load:0x3fff8030,len:1688
      load:0x4009fa00,len:0
      load:0x4009fa00,len:14592
      entry 0x400a059c
      WMAC: 3C71BF8750F0
      Firmware: 1.18.2.r6
      Pybytes: 0.9.12
      Pybytes configuration read from /flash/pybytes_config.json
      Initialized watchdog for WiFi and LTE connection with timeout 660000 ms
      WiFi connection established
      WARNING: consider enabling certificate validation
      Using MQTT over TLS
      Connected to MQTT mqtt.pybytes.pycom.io
      Pybytes connected successfully (using the built-in pybytes library)
      Now starting user code in main.py
      [    31.212] Starting LoRaWAN nano gateway with id: b'3C71BFFFFE8750F0'
      [    31.238] WiFi connected to: ssid
      [    31.245] Syncing time with pool.ntp.org ...
      [    35.502] RTC NTP sync complete
      [    42.098] Opening UDP socket to router.thethings.meshed.com.au (224.94.149.63) port 1700...
      [    42.116] Setting up the LoRa radio at 916.7999 Mhz using SF7BW125
      [    42.160] LoRaWAN nano gateway online
      [    42.167] You may now press ENTER to enter the REPL
      

      As for the OTAA client I can not get it to connect
      config.py

      #!/usr/bin/env python
      #
      # Copyright (c) 2019, Pycom Limited.
      #
      # This software is licensed under the GNU GPL version 3 or any
      # later version, with permitted additional terms. For more information
      # see the Pycom Licence v1.0 document supplied with this file, or
      # available at https://www.pycom.io/opensource/licensing
      #
      
      """ LoPy Node configuration options """
      
      import machine
      import ubinascii
      
      WIFI_MAC = ubinascii.hexlify(machine.unique_id()).upper()
      # Set  the Node ID to be the first 3 bytes of MAC address + 'FFFE' + last 3 bytes of MAC address
      NODE_ID = WIFI_MAC[:6] + "FFFE" + WIFI_MAC[6:12]
      
      # for EU868
      # LORA_FREQUENCY = 868100000
      # LORA_GW_DR = "SF7BW125" # DR_5
      # LORA_NODE_DR = 5
      
      # for US915
      # LORA_FREQUENCY = 903900000
      # LORA_GW_DR = "SF7BW125" # DR_3
      # LORA_NODE_DR = 3
      
      # for AU915
      LORA_FREQUENCY = 916800000
      LORA_GW_DR = "SF7BW125"
      LORA_NODE_DR = 4
      

      main.py

      #!/usr/bin/env python
      #
      # Copyright (c) 2019, Pycom Limited.
      #
      # This software is licensed under the GNU GPL version 3 or any
      # later version, with permitted additional terms. For more information
      # see the Pycom Licence v1.0 document supplied with this file, or
      # available at https://www.pycom.io/opensource/licensing
      #
      
      """ OTAA Node example compatible with the LoPy Nano Gateway """
      
      from network import LoRa
      import socket
      import binascii
      import struct
      import time
      import config
      
      # 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.AU915)
      
      # create an OTA authentication params
      dev_eui = config.NODE_ID
      app_eui = binascii.unhexlify('3C71BFFFFE8750F0')
      app_key = binascii.unhexlify('36AB7625FE770B6881683B495300FFD6')
      
      for channel in range(0, 16):
          lora.remove_channel(channel)
      # 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=config.LORA_NODE_DR)
      lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=config.LORA_NODE_DR)
      lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=config.LORA_NODE_DR)
      
      # 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)
          print('Not joined yet...')
      
      # 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)
      
      for i in range (200):
          pkt = b'PKT #' + bytes([i])
          print('Sending:', pkt)
          s.send(pkt)
          time.sleep(4)
          rx, port = s.recvfrom(256)
          if rx:
              print('Received: {}, on port: {}'.format(rx, port))
          time.sleep(6)
      
      

      Startup Log

      rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
      configsip: 0, SPIWP:0xee
      clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
      mode:DIO, clock div:1
      load:0x3fff8028,len:8
      load:0x3fff8030,len:1688
      load:0x4009fa00,len:0
      load:0x4009fa00,len:14592
      entry 0x400a059c
      WMAC: 807D3A934E9C
      Firmware: 1.18.2.r6
      Pybytes: 0.9.12
      Pybytes configuration read from /flash/pybytes_config.json
      Initialized watchdog for WiFi and LTE connection with timeout 660000 ms
      WiFi connection established
      WARNING: consider enabling certificate validation
      Using MQTT over TLS
      Connected to MQTT mqtt.pybytes.pycom.io
      Pybytes connected successfully (using the built-in pybytes library)
      Now starting user code in main.py
      Not joined yet...
      Not joined yet...
      Not joined yet...
      Not joined yet...
      Not joined yet...
      Not joined yet...
      Not joined yet...
      Not joined yet...
      

      Most likely I’ve don’t something wrong been new to Lora and the Lopy’s

      Any help would be appreciated, thanks.

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

        @Yendor I think you have the Pybytes firmware loaded, you probably want the version without Pybytes in this case.

        1 Reply Last reply Reply Quote 0
        • Y Offline
          Yendor
          last edited by

          Thanks @jcaron ,
          Got it working using ABP and a few change to the TNN config, but would still like to get it working with OTAA this was all done with the Pybytes firmware, I have now removed it on your suggestion and I'll see how it goes.

          Current configuration
          Gateway config.py

          #!/usr/bin/env python
          #
          # Copyright (c) 2019, Pycom Limited.
          #
          # This software is licensed under the GNU GPL version 3 or any
          # later version, with permitted additional terms. For more information
          # see the Pycom Licence v1.0 document supplied with this file, or
          # available at https://www.pycom.io/opensource/licensing
          #
          
          """ LoPy LoRaWAN Nano Gateway configuration options """
          
          import machine
          import ubinascii
          
          WIFI_MAC = ubinascii.hexlify(machine.unique_id()).upper()
          # Set  the Gateway ID to be the first 3 bytes of MAC address + 'FFFE' + last 3 bytes of MAC address
          GATEWAY_ID = WIFI_MAC[:6] + "FFFE" + WIFI_MAC[6:12]
          
          SERVER = 'router.au.thethings.network'
          PORT = 1700
          
          NTP = "au.pool.ntp.org"
          NTP_PERIOD_S = 3600
          
          WIFI_SSID = 'ssid'
          WIFI_PASS = 'password'
          WIFI_ADDRESS = '192.168.1.50'
          WIFI_MASK = '255.255.255.0'
          WIFI_GATEWAY = '192.168.1.1'
          
          # for EU868
          # LORA_FREQUENCY = 868100000
          # LORA_GW_DR = "SF7BW125" # DR_5
          # LORA_NODE_DR = 5
          
          # for US915
          # LORA_FREQUENCY = 903900000
          # LORA_GW_DR = "SF7BW125" # DR_3
          # LORA_NODE_DR = 3
          
          # for AU915
          LORA_FREQUENCY = 916800000
          LORA_GW_DR = "SF7BW125"
          LORA_NODE_DR = 5
          

          nanogateway.py

          #!/usr/bin/env python
          #
          # Copyright (c) 2019, Pycom Limited.
          #
          # This software is licensed under the GNU GPL version 3 or any
          # later version, with permitted additional terms. For more information
          # see the Pycom Licence v1.0 document supplied with this file, or
          # available at https://www.pycom.io/opensource/licensing
          #
          
          """ LoPy LoRaWAN Nano Gateway. Can be used for both EU868 and US915. """
          
          import errno
          import machine
          import ubinascii
          import ujson
          import uos
          import usocket
          import utime
          import _thread
          from micropython import const
          from network import LoRa
          from network import WLAN
          from machine import Timer
          
          
          PROTOCOL_VERSION = const(2)
          
          PUSH_DATA = const(0)
          PUSH_ACK = const(1)
          PULL_DATA = const(2)
          PULL_ACK = const(4)
          PULL_RESP = const(3)
          
          TX_ERR_NONE = 'NONE'
          TX_ERR_TOO_LATE = 'TOO_LATE'
          TX_ERR_TOO_EARLY = 'TOO_EARLY'
          TX_ERR_COLLISION_PACKET = 'COLLISION_PACKET'
          TX_ERR_COLLISION_BEACON = 'COLLISION_BEACON'
          TX_ERR_TX_FREQ = 'TX_FREQ'
          TX_ERR_TX_POWER = 'TX_POWER'
          TX_ERR_GPS_UNLOCKED = 'GPS_UNLOCKED'
          
          UDP_THREAD_CYCLE_MS = const(20)
          
          STAT_PK = {
              'stat': {
                  'time': '',
                  'lati': 0,
                  'long': 0,
                  'alti': 0,
                  'rxnb': 0,
                  'rxok': 0,
                  'rxfw': 0,
                  'ackr': 100.0,
                  'dwnb': 0,
                  'txnb': 0
              }
          }
          
          RX_PK = {
              'rxpk': [{
                  'time': '',
                  'tmst': 0,
                  'chan': 0,
                  'rfch': 0,
                  'freq': 0,
                  'stat': 1,
                  'modu': 'LORA',
                  'datr': '',
                  'codr': '4/5',
                  'rssi': 0,
                  'lsnr': 0,
                  'size': 0,
                  'data': ''
              }]
          }
          
          TX_ACK_PK = {
              'txpk_ack': {
                  'error': ''
              }
          }
          
          
          class NanoGateway:
              """
              Nano gateway class, set up by default for use with TTN, but can be configured
              for any other network supporting the Semtech Packet Forwarder.
              Only required configuration is wifi_ssid and wifi_password which are used for
              connecting to the Internet.
              """
          
              def __init__(self, id, frequency, datarate, ssid, password, address, mask, gateway, server, port, ntp_server='au.pool.ntp.org', ntp_period=3600):
                  self.id = id
                  self.server = server
                  self.port = port
          
                  self.frequency = frequency
                  self.datarate = datarate
          
                  self.ssid = ssid
                  self.password = password
                  self.address = address
                  self.mask = mask
                  self.gateway = gateway
          
                  self.ntp_server = ntp_server
                  self.ntp_period = ntp_period
          
                  self.server_ip = None
          
                  self.rxnb = 0
                  self.rxok = 0
                  self.rxfw = 0
                  self.dwnb = 0
                  self.txnb = 0
          
                  self.sf = self._dr_to_sf(self.datarate)
                  self.bw = self._dr_to_bw(self.datarate)
          
                  self.stat_alarm = None
                  self.pull_alarm = None
                  self.uplink_alarm = None
          
                  self.wlan = None
                  self.sock = None
                  self.udp_stop = False
                  self.udp_lock = _thread.allocate_lock()
          
                  self.lora = None
                  self.lora_sock = None
          
                  self.rtc = machine.RTC()
          
              def start(self):
                  """
                  Starts the LoRaWAN nano gateway.
                  """
          
                  self._log('Starting LoRaWAN nano gateway with id: {}', self.id)
          
                  # setup WiFi as a station and connect
                  self.wlan = WLAN(mode=WLAN.STA)
                  self.wlan.ifconfig(config=(self.address, self.mask, self.gateway, self.gateway))
                  self._connect_to_wifi()
          
                  # get a time sync
                  self._log('Syncing time with {} ...', self.ntp_server)
                  self.rtc.ntp_sync(self.ntp_server, update_period=self.ntp_period)
                  while not self.rtc.synced():
                      utime.sleep_ms(50)
                  self._log("RTC NTP sync complete")
          
                  # get the server IP and create an UDP socket
                  self.server_ip = usocket.getaddrinfo(self.server, self.port)[0][-1]
                  self._log('Opening UDP socket to {} ({}) port {}...', self.server, self.server_ip[0], self.server_ip[1])
                  self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM, usocket.IPPROTO_UDP)
                  self.sock.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
                  self.sock.setblocking(False)
          
                  # push the first time immediatelly
                  self._push_data(self._make_stat_packet())
          
                  # create the alarms
                  self.stat_alarm = Timer.Alarm(handler=lambda t: self._push_data(self._make_stat_packet()), s=60, periodic=True)
                  self.pull_alarm = Timer.Alarm(handler=lambda u: self._pull_data(), s=25, periodic=True)
          
                  # start the UDP receive thread
                  self.udp_stop = False
                  _thread.start_new_thread(self._udp_thread, ())
          
                  # initialize the LoRa radio in LORA mode
                  self._log('Setting up the LoRa radio at {} Mhz using {}', self._freq_to_float(self.frequency), self.datarate)
                  self.lora = LoRa(
                      mode=LoRa.LORA,
                      frequency=self.frequency,
                      bandwidth=self.bw,
                      sf=self.sf,
                      preamble=8,
                      coding_rate=LoRa.CODING_4_5,
                      tx_iq=True
                  )
          
                  # create a raw LoRa socket
                  self.lora_sock = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW)
                  self.lora_sock.setblocking(False)
                  self.lora_tx_done = False
          
                  self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT), handler=self._lora_cb)
                  self._log('LoRaWAN nano gateway online')
          
              def stop(self):
                  """
                  Stops the LoRaWAN nano gateway.
                  """
          
                  self._log('Stopping...')
          
                  # send the LoRa radio to sleep
                  self.lora.callback(trigger=None, handler=None)
                  self.lora.power_mode(LoRa.SLEEP)
          
                  # stop the NTP sync
                  self.rtc.ntp_sync(None)
          
                  # cancel all the alarms
                  self.stat_alarm.cancel()
                  self.pull_alarm.cancel()
          
                  # signal the UDP thread to stop
                  self.udp_stop = True
                  while self.udp_stop:
                      utime.sleep_ms(50)
          
                  # disable WLAN
                  self.wlan.disconnect()
                  self.wlan.deinit()
          
              def _connect_to_wifi(self):
                  self.wlan.connect(self.ssid, auth=(None, self.password))
                  while not self.wlan.isconnected():
                      utime.sleep_ms(50)
                  self._log('WiFi connected to: {}', self.ssid)
          
              def _dr_to_sf(self, dr):
                  sf = dr[2:4]
                  if sf[1] not in '0123456789':
                      sf = sf[:1]
                  return int(sf)
          
              def _dr_to_bw(self, dr):
                  bw = dr[-5:]
                  if bw == 'BW125':
                      return LoRa.BW_125KHZ
                  elif bw == 'BW250':
                      return LoRa.BW_250KHZ
                  else:
                      return LoRa.BW_500KHZ
          
              def _sf_bw_to_dr(self, sf, bw):
                  dr = 'SF' + str(sf)
                  if bw == LoRa.BW_125KHZ:
                      return dr + 'BW125'
                  elif bw == LoRa.BW_250KHZ:
                      return dr + 'BW250'
                  else:
                      return dr + 'BW500'
          
              def _lora_cb(self, lora):
                  """
                  LoRa radio events callback handler.
                  """
          
                  events = lora.events()
                  if events & LoRa.RX_PACKET_EVENT:
                      self.rxnb += 1
                      self.rxok += 1
                      rx_data = self.lora_sock.recv(256)
                      stats = lora.stats()
                      packet = self._make_node_packet(rx_data, self.rtc.now(), stats.rx_timestamp, stats.sfrx, self.bw, stats.rssi, stats.snr)
                      packet = self.frequency_rounding_fix(packet, self.frequency)
                      self._push_data(packet)
                      self._log('Received packet: {}', packet)
                      self.rxfw += 1
                  if events & LoRa.TX_PACKET_EVENT:
                      self.txnb += 1
                      lora.init(
                          mode=LoRa.LORA,
                          frequency=self.frequency,
                          bandwidth=self.bw,
                          sf=self.sf,
                          preamble=8,
                          coding_rate=LoRa.CODING_4_5,
                          tx_iq=True
                          )
          
              def _freq_to_float(self, frequency):
                  """
                  MicroPython has some inprecision when doing large float division.
                  To counter this, this method first does integer division until we
                  reach the decimal breaking point. This doesn't completely elimate
                  the issue in all cases, but it does help for a number of commonly
                  used frequencies.
                  """
          
                  divider = 6
                  while divider > 0 and frequency % 10 == 0:
                      frequency = frequency // 10
                      divider -= 1
                  if divider > 0:
                      frequency = frequency / (10 ** divider)
                  return frequency
          
              def frequency_rounding_fix(self, packet, frequency):
                  freq = str(frequency)[0:3] + '.' + str(frequency)[3]
          
                  start = packet.find("freq\":")
                  end = packet.find(",", start)
          
                  packet = packet[:start + 7] + freq + packet[end:]
          
                  return packet
          
              def _make_stat_packet(self):
                  now = self.rtc.now()
                  STAT_PK["stat"]["time"] = "%d-%02d-%02d %02d:%02d:%02d GMT" % (now[0], now[1], now[2], now[3], now[4], now[5])
                  STAT_PK["stat"]["rxnb"] = self.rxnb
                  STAT_PK["stat"]["rxok"] = self.rxok
                  STAT_PK["stat"]["rxfw"] = self.rxfw
                  STAT_PK["stat"]["dwnb"] = self.dwnb
                  STAT_PK["stat"]["txnb"] = self.txnb
                  return ujson.dumps(STAT_PK)
          
              def _make_node_packet(self, rx_data, rx_time, tmst, sf, bw, rssi, snr):
                  RX_PK["rxpk"][0]["time"] = "%d-%02d-%02dT%02d:%02d:%02d.%dZ" % (rx_time[0], rx_time[1], rx_time[2], rx_time[3], rx_time[4], rx_time[5], rx_time[6])
                  RX_PK["rxpk"][0]["tmst"] = tmst
                  RX_PK["rxpk"][0]["freq"] = self._freq_to_float(self.frequency)
                  RX_PK["rxpk"][0]["datr"] = self._sf_bw_to_dr(sf, bw)
                  RX_PK["rxpk"][0]["rssi"] = rssi
                  RX_PK["rxpk"][0]["lsnr"] = snr
                  RX_PK["rxpk"][0]["data"] = ubinascii.b2a_base64(rx_data)[:-1]
                  RX_PK["rxpk"][0]["size"] = len(rx_data)
                  return ujson.dumps(RX_PK)
          
              def _push_data(self, data):
                  token = uos.urandom(2)
                  packet = bytes([PROTOCOL_VERSION]) + token + bytes([PUSH_DATA]) + ubinascii.unhexlify(self.id) + data
                  with self.udp_lock:
                      try:
                          self.sock.sendto(packet, self.server_ip)
                      except Exception as ex:
                          self._log('Failed to push uplink packet to server: {}', ex)
          
              def _pull_data(self):
                  token = uos.urandom(2)
                  packet = bytes([PROTOCOL_VERSION]) + token + bytes([PULL_DATA]) + ubinascii.unhexlify(self.id)
                  with self.udp_lock:
                      try:
                          self.sock.sendto(packet, self.server_ip)
                      except Exception as ex:
                          self._log('Failed to pull downlink packets from server: {}', ex)
          
              def _ack_pull_rsp(self, token, error):
                  TX_ACK_PK["txpk_ack"]["error"] = error
                  resp = ujson.dumps(TX_ACK_PK)
                  packet = bytes([PROTOCOL_VERSION]) + token + bytes([PULL_ACK]) + ubinascii.unhexlify(self.id) + resp
                  with self.udp_lock:
                      try:
                          self.sock.sendto(packet, self.server_ip)
                      except Exception as ex:
                          self._log('PULL RSP ACK exception: {}', ex)
          
              def _send_down_link(self, data, tmst, datarate, frequency):
                  """
                  Transmits a downlink message over LoRa.
                  """
          
                  self.lora.init(
                      mode=LoRa.LORA,
                      frequency=frequency,
                      bandwidth=self._dr_to_bw(datarate),
                      sf=self._dr_to_sf(datarate),
                      preamble=8,
                      coding_rate=LoRa.CODING_4_5,
                      tx_iq=True
                      )
                  #while utime.ticks_cpu() < tmst:
                  #    pass
                  self.lora_sock.send(data)
                  self._log(
                      'Sent downlink packet scheduled on {:.3f}, at {:.3f} Mhz using {}: {}',
                      tmst / 1000000,
                      self._freq_to_float(frequency),
                      datarate,
                      data
                  )
          
              def _send_down_link_class_c(self, data, datarate, frequency):
                  self.lora.init(
                      mode=LoRa.LORA,
                      frequency=frequency,
                      bandwidth=self._dr_to_bw(datarate),
                      sf=self._dr_to_sf(datarate),
                      preamble=8,
                      coding_rate=LoRa.CODING_4_5,
                      tx_iq=True,
                      device_class=LoRa.CLASS_C
                      )
          
                  self.lora_sock.send(data)
                  self._log(
                      'Sent downlink packet scheduled on {:.3f}, at {:.3f} Mhz using {}: {}',
                      utime.time(),
                      self._freq_to_float(frequency),
                      datarate,
                      data
                  )
          
              def _udp_thread(self):
                  """
                  UDP thread, reads data from the server and handles it.
                  """
          
                  while not self.udp_stop:
                      try:
                          data, src = self.sock.recvfrom(1024)
                          _token = data[1:3]
                          _type = data[3]
                          if _type == PUSH_ACK:
                              self._log("Push ack")
                          elif _type == PULL_ACK:
                              self._log("Pull ack")
                          elif _type == PULL_RESP:
                              self.dwnb += 1
                              ack_error = TX_ERR_NONE
                              tx_pk = ujson.loads(data[4:])
                              if "tmst" in data:
                                  tmst = tx_pk["txpk"]["tmst"]
                                  t_us = tmst - utime.ticks_cpu() - 15000
                                  if t_us < 0:
                                      t_us += 0xFFFFFFFF
                                  if t_us < 20000000:
                                      self.uplink_alarm = Timer.Alarm(
                                          handler=lambda x: self._send_down_link(
                                              ubinascii.a2b_base64(tx_pk["txpk"]["data"]),
                                              tx_pk["txpk"]["tmst"] - 50, tx_pk["txpk"]["datr"],
                                              int(tx_pk["txpk"]["freq"] * 1000) * 1000
                                          ),
                                          us=t_us
                                      )
                                  else:
                                      ack_error = TX_ERR_TOO_LATE
                                      self._log('Downlink timestamp error!, t_us: {}', t_us)
                              else:
                                  self.uplink_alarm = Timer.Alarm(
                                      handler=lambda x: self._send_down_link_class_c(
                                          ubinascii.a2b_base64(tx_pk["txpk"]["data"]),
                                          tx_pk["txpk"]["datr"],
                                          int(tx_pk["txpk"]["freq"] * 1000) * 1000
                                      ),
                                      us=50
                                  )
                              self._ack_pull_rsp(_token, ack_error)
                              self._log("Pull rsp")
                      except usocket.timeout:
                          pass
                      except OSError as ex:
                          if ex.errno != errno.EAGAIN:
                              self._log('UDP recv OSError Exception: {}', ex)
                      except Exception as ex:
                          self._log('UDP recv Exception: {}', ex)
          
                      # wait before trying to receive again
                      utime.sleep_ms(UDP_THREAD_CYCLE_MS)
          
                  # we are to close the socket
                  self.sock.close()
                  self.udp_stop = False
                  self._log('UDP thread stopped')
          
              def _log(self, message, *args):
                  """
                  Outputs a log message to stdout.
                  """
          
                  print('[{:>10.3f}] {}'.format(
                      utime.ticks_ms() / 1000,
                      str(message).format(*args)
                      ))
          

          main.py

          #!/usr/bin/env python
          #
          # Copyright (c) 2019, Pycom Limited.
          #
          # This software is licensed under the GNU GPL version 3 or any
          # later version, with permitted additional terms. For more information
          # see the Pycom Licence v1.0 document supplied with this file, or
          # available at https://www.pycom.io/opensource/licensing
          #
          
          """ LoPy LoRaWAN Nano Gateway example usage """
          
          import config
          from nanogateway import NanoGateway
          
          if __name__ == '__main__':
              nanogw = NanoGateway(
                  id=config.GATEWAY_ID,
                  frequency=config.LORA_FREQUENCY,
                  datarate=config.LORA_GW_DR,
                  ssid=config.WIFI_SSID,
                  password=config.WIFI_PASS,
                  address=config.WIFI_ADDRESS,
                  mask=config.WIFI_MASK,
                  gateway=config.WIFI_GATEWAY,
                  server=config.SERVER,
                  port=config.PORT,
                  ntp_server=config.NTP,
                  ntp_period=config.NTP_PERIOD_S
                  )
          
              nanogw.start()
              nanogw._log('You may now press ENTER to enter the REPL')
              input()
          
          Connecting to COM11...
          [     2.595] Starting LoRaWAN nano gateway with id: b'3C71BFFFFE8750F0'
          [     6.118] WiFi connected to: ssid
          [     6.123] Syncing time with au.pool.ntp.org ...
          [     6.179] RTC NTP sync complete
          [     6.189] Opening UDP socket to router.au.thethings.network (52.62.83.250) port 1700...
          [     6.204] Setting up the LoRa radio at 916.7999 Mhz using SF7BW125
          [     6.213] LoRaWAN nano gateway online
          [     6.218] You may now press ENTER to enter the REPL
          
          Pycom MicroPython 1.18.2.r7 [v1.8.6-849-df9f237] on 2019-05-14; LoPy4 with ESP32
          Type "help()" for more information.
          >>> [     6.249] Push ack
          [    21.068] Received packet: {"rxpk": [{"data": "QLIXAiYAAAACQ9+WpQPqPkmVOg==", "time": "2019-05-31T19:49:52.173381Z", "chan": 0, "tmst": 21050429, "stat": 1, "modu": "LORA", "lsnr": 6.0, "rssi": 0, "rfch": 0, "codr": "4/5", "freq": 916.8, "datr": "SF7BW125", "size": 19}]}
          [    21.129] Push ack
          [    31.066] Received packet: {"rxpk": [{"data": "QLIXAiYAAQAC1T4VWxMKlrC8Aw==", "time": "2019-05-31T19:50:02.172292Z", "chan": 0, "tmst": 31049439, "stat": 1, "modu": "LORA", "lsnr": 6.0, "rssi": -1, "rfch": 0, "codr": "4/5", "freq": 916.8, "datr": "SF7BW125", "size": 19}]}
          [    31.208] Push ack
          [    31.252] Pull ack
          

          ABP Node config.py

          #!/usr/bin/env python
          #
          # Copyright (c) 2019, Pycom Limited.
          #
          # This software is licensed under the GNU GPL version 3 or any
          # later version, with permitted additional terms. For more information
          # see the Pycom Licence v1.0 document supplied with this file, or
          # available at https://www.pycom.io/opensource/licensing
          #
          
          """ LoPy Node configuration options """
          
          import machine
          import binascii
          import struct
          
          WIFI_MAC = binascii.hexlify(machine.unique_id()).upper()
          # Set  the Node ID to be the first 3 bytes of MAC address + 'FFFE' + last 3 bytes of MAC address
          NODE_ID = WIFI_MAC[:6] + "FFFE" + WIFI_MAC[6:12]
          
          # create an OTA authentication params
          DEV_EUI = binascii.unhexlify('0x')
          APP_EUI = binascii.unhexlify('0x')
          APP_KEY = binascii.unhexlify('0x')
          DEV_ADDR = struct.unpack(">l", binascii.unhexlify('0x'))[0]
          NWK_SWKEY = binascii.unhexlify('0x')
          APP_SWKEY = binascii.unhexlify('0x')
          
          # for EU868
          # LORA_FREQUENCY = 868100000
          # LORA_GW_DR = "SF7BW125" # DR_5
          # LORA_NODE_DR = 5
          
          # for US915
          # LORA_FREQUENCY = 903900000
          # LORA_GW_DR = "SF7BW125" # DR_3
          # LORA_NODE_DR = 3
          
          # for AU915
          LORA_FREQUENCY = 916800000
          LORA_GATEWAY_DR = "SF7BW125"
          LORA_NODE_DR = 5
          

          main.py

          #!/usr/bin/env python
          #
          # Copyright (c) 2019, Pycom Limited.
          #
          # This software is licensed under the GNU GPL version 3 or any
          # later version, with permitted additional terms. For more information
          # see the Pycom Licence v1.0 document supplied with this file, or
          # available at https://www.pycom.io/opensource/licensing
          #
          
          """ ABP Node example compatible with the LoPy Nano Gateway """
          
          from network import LoRa
          import socket
          import binascii
          import struct
          import time
          import config
          
          # 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.AU915)
          
          # remove all the channels
          for channel in range(0, 72):
              lora.remove_channel(channel)
          
          # # set all channels to the same frequency (must be before sending the OTAA join request)
          # for channel in range(0, 72):
          #     lora.add_channel(channel, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=config.LORA_NODE_DR)
          
          # set the 3 default channels to the same frequency
          lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=config.LORA_NODE_DR)
          lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=config.LORA_NODE_DR)
          lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=config.LORA_NODE_DR)
          
          # join a network using ABP
          lora.join(activation=LoRa.ABP, auth=(config.DEV_ADDR, config.NWK_SWKEY, config.APP_SWKEY))
          
          # 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)
          
          for i in range (200):
              pkt = b'PKT #' + bytes([i])
              print('Sending:', pkt)
              s.send(pkt)
              time.sleep(4)
              rx, port = s.recvfrom(256)
              if rx:
                  print('Received: {}, on port: {}'.format(rx, port))
              time.sleep(6)
          
          Connecting to COM11...
          Sending: b'PKT #\x00'
          Sending: b'PKT #\x01'
          Sending: b'PKT #\x02'
          
          1 Reply Last reply Reply Quote 0

          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