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.