Getting LoPy4 to consistently work when WiFi or LoRa connectivity is out of range.



  • I'm using LoRa on my LoPy4 to push data to TheThingsNetwork, but currently also need WIFI to push code updates to a bunch of my devices remotely. Things have been great so long as both are available. But now, I'm trying to move devices to places out of my control, which means sometimes either LoRa or WIFI aren't accessible.. My current code seems to get hung when either interface goes down. What do I need to change so that it will use whichever interface is available to push out signals, then shut down the radios for 4 minutes, then wake up and try to reconnect and repeat the process?

    This was my latest attempt (I clipped out the non-essential code)
    It crashes on s.send in the main loop with ERRNO 11: EAGAIN
    but if I revert all the code that shuts off WIFI and handles the LoRa.notjoined, it works.

    from network import LoRa #used to publish data on the LoRa network
    import socket #used for various WiFi and Lora connections
    from network import WLAN
    wl = WLAN()
    known_nets = {
      'aa': {'pwd': 'a1a'},
      'bb': {'pwd':'b2b'}
    }
    def connectToLan():
        #from network import WLAN
        #wl = WLAN()
        wl.mode(WLAN.STA)
        original_ssid = wl.ssid()
        original_auth = wl.auth()
    
        print("Scanning for known wifi nets")
        available_nets = wl.scan()
        netsisee = frozenset([e.ssid for e in available_nets])
    
        known_nets_names = frozenset([key for key in known_nets])
        net_to_use = list(netsisee & known_nets_names)
        try:
            net_to_use = net_to_use[0]
            net_properties = nets.known_nets[net_to_use]
            pwd = net_properties['pwd']
            sec = [e.sec for e in available_nets if e.ssid == net_to_use][0]
            if 'wlan_config' in net_properties:
                wl.ifconfig(config=net_properties['wlan_config'])
            wl.connect(net_to_use, (sec, pwd), timeout=10000)
            while not wl.isconnected():
                machine.idle() # save power while waiting
            print("Connected to "+net_to_use+" with IP address:" + wl.ifconfig()[0])
            pybytes.reconnect()
    
        except Exception as e:
            print("Failed to connect to any known network")
            pass
            #wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT)
            
    if machine.reset_cause() != machine.SOFT_RESET:
      connectToLan()        
      
    lora = LoRa(mode=LoRa.LORAWAN, public=1,  adr=0, tx_retries=0)
    for i in range(0, 71):
        lora.remove_channel(i)
    print('Removed default channels')
    time.sleep(1)
        
        # Set US ISM 915 channel plan for TTN US
    lora.add_channel(0, frequency=903900000, dr_min=0, dr_max=3)
    lora.add_channel(1, frequency=904100000, dr_min=0, dr_max=3)
    lora.add_channel(2, frequency=904300000, dr_min=0, dr_max=3)
    lora.add_channel(3, frequency=904500000, dr_min=0, dr_max=3)
    lora.add_channel(4, frequency=904700000, dr_min=0, dr_max=3)
    lora.add_channel(5, frequency=904900000, dr_min=0, dr_max=3)
    lora.add_channel(6, frequency=905100000, dr_min=0, dr_max=3)
    lora.add_channel(7, frequency=905300000, dr_min=0, dr_max=3)
    
    
    print('US channels set')
    time.sleep(1)
    print('Joining LoRa via OTAA')
    
    # join a network using OTAA (Over the Air Activation)
    lora.join(activation=LoRa.OTAA, auth=(lorakeys._dev_eui,lorakeys._app_eui, lorakeys._app_key), timeout=0, dr=0)
    start=utime.ticks_ms()#set up a start point for sensor timeout
    lorajoin_timeout=120000#2 minutes
    while not lora.has_joined():
        time.sleep(2.4)
        pycom.rgbled(0x7f7f00) #ylw    
        time.sleep(0.1)
        pycom.rgbled(0x000000) #blk    
        print('Not yet joined...')
        if(utime.ticks_diff(start,utime.ticks_ms())> -lorajoin_timeout):
          break
        pass
    # 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, 3)
    while 1:
      if (not lora.has_joined()):
        lora.join(activation=LoRa.OTAA, auth=(lorakeys._dev_eui,lorakeys._app_eui, lorakeys._app_key), timeout=0, dr=0)
        start=utime.ticks_ms()#set up a start point for sensor timeout
        lorajoin_timeout=120000#2 minutes
        while not lora.has_joined():
          time.sleep(2.4)
          pycom.rgbled(0x7f7f00) #ylw    
          time.sleep(0.1)
          pycom.rgbled(0x000000) #blk    
          print('Not yet joined...')
          if(utime.ticks_diff(start,utime.ticks_ms())> -lorajoin_timeout):
            break
          pass
      if lora.has_joined():
        s.setblocking(True)
        print("Sending data!")
        s.send(bytes(0x00,0x00))
      if wl.isconnected():
        pybytes.send_signal(2,0)
      print('saving LoRa NVRAM')
      lora.nvram_save()
        # make the socket non-blocking
        # (because if there's no data received it will block forever...)
      if lora.has_joined():
        s.setblocking(False)
        print("receiving data!")
        # get any data received (if any...)
        data = s.recv(64)
        print(data)
      wl.deinit()
      time.sleep(240)#wait 4 minutes before next reading
      wl.init()
      connectToLan()
      time.sleep(15)
      if wl.isconnected():
        pybytes.send_signal(2,3)
      time.sleep(15)
    
    


  • The EAGAIN error is related to re-using the LoRa socket. If you redefine the socket using s = socket.socket(socket.AF_LORA, socket.SOCK_RAW) before re-using it, the issue should go away I believe.


Log in to reply
 

Pycom on Twitter