class LoRaWANNode: def __init__(self, app_eui, app_key): """setup LoRaWAN for the European 868 MHz region with OTAA""" self.app_eui = ubinascii.unhexlify(app_eui) self.app_key = ubinascii.unhexlify(app_key) self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868) self.socket = None self.setup() @property def has_joined(self): return self.lora.has_joined() def setup(self): """Try to restore from nvram or join the network with OTAA""" self.lora.nvram_restore() if not self.has_joined: self.join() else: self.open_socket() def join(self, timeout=30): try: timeout = timeout * 1000 self.lora.join( activation=LoRa.OTAA, auth=(self.app_eui, self.app_key), timeout=timeout, dr=DR, ) if self.has_joined: self.lora.nvram_save() self.open_socket() except TimeoutError: pass def open_socket(self, timeout=6): self.socket = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW) self.socket.setsockopt(usocket.SOL_LORA, usocket.SO_DR, DR) self.socket.settimeout(timeout) def reset(self): self.socket.close() self.lora.nvram_erase() self.join() def send(self, data): """Send out data as bytes""" if self.has_joined: if isinstance(data, (float, str, int)): data = bytes([data]) self.socket.send(data) utime.sleep(2) self.lora.nvram_save()
region=LoRa.US915, tx_power=20, bandwidth=LoRa.BW_500KHZ, sf=7, frequency=903900000) def lora_cb(lora): events = lora.events() if events & LoRa.RX_PACKET_EVENT: print('Lora packet received') if events & LoRa.TX_PACKET_EVENT: print('Lora packet sent') lora.nvram_erase() #lora.nvram_restore() # remove all the channels the gateway doesn't use for channel in range(16, 72): lora.remove_channel(channel) for channel in range(0, 7): lora.remove_channel(channel) #create an OTAA authentication parameters for test lopy dev_eui = ubinascii.unhexlify( '70B3D54997802DF8') # these settings can be found from TTN app_eui = ubinascii.unhexlify('70B3D57ED0028A4F') app_key = ubinascii.unhexlify('CE46C01958A612D102F0D106AB415862') # create an OTAA authentication parameters for lopy with ring/ckt #dev address = 26012DBE #dev_eui = ubinascii.unhexlify('70B3D549952757BF') # these settings can be found from TTN
class LoRaDriverPycom: """ LoRa driver for Pycom MicroPython """ def __init__(self, network_manager, settings): self.network_manager = network_manager self.settings = settings def start(self): """ Start driver """ from network import LoRa if self.settings.get('networking.lora.region') == 'AS923': lora_region = LoRa.AS923 elif self.settings.get('networking.lora.region') == 'AU915': lora_region = LoRa.AU915 elif self.settings.get('networking.lora.region') == 'EU868': lora_region = LoRa.EU868 elif self.settings.get('networking.lora.region') == 'US915': lora_region = LoRa.US915 lora_adr = self.settings.get('networking.lora.adr') or False self.lora_socket = None self.lora = LoRa(mode=LoRa.LORAWAN, region=lora_region, adr=lora_adr) # Restore LoRa state from NVRAM after waking up from DEEPSLEEP. # Otherwise, reset LoRa NVRAM and rejoin. if platform_info.vendor in [ platform_info.MICROPYTHON.Vanilla, platform_info.MICROPYTHON.Pycom ]: import machine # Restore LoRaWAN status after wake up from deep sleep if machine.reset_cause() == machine.DEEPSLEEP_RESET: self.lora.nvram_restore() log.info( '[LoRa] LoRaWAN state restored from NVRAM after deep sleep' ) # Otherwise reset LoRaWAN status and deep sleep interval from NVRAM else: self.lora.nvram_erase() log.info( '[LoRa] LoRaWAN state erased from NVRAM. Rejoin forced') if platform_info.vendor == platform_info.MICROPYTHON.Pycom: import pycom nvram_get = pycom.nvs_get nvram_erase = pycom.nvs_erase elif platform_info.vendor == platform_info.MICROPYTHON.Vanilla: import esp32 nvram_get = esp32.nvs_get nvram_erase = esp32.nvs_erase try: if nvram_get('deepsleep') is not None: nvram_erase('deepsleep') log.info( '[LoRa] Deep sleep interval erased from NVRAM. Return to settings value' ) except: pass if not self.lora.has_joined(): import binascii datarate_join = self.settings.get('networking.lora.datarate_join') # Over-the-Air Activation (OTAA) if self.settings.get('networking.lora.activation') == 'otaa': app_eui = binascii.unhexlify( self.settings.get('networking.lora.otaa.application_eui')) app_key = binascii.unhexlify( self.settings.get('networking.lora.otaa.application_key')) log.info('[LoRa] Attaching to the LoRaWAN network using OTAA') if self.settings.get( 'networking.lora.otaa.device_eui') is None: self.lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0, dr=datarate_join) else: dev_eui = binascii.unhexlify( self.settings.get('networking.lora.otaa.device_eui')) self.lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=datarate_join) # Activation by Personalization (ABP) elif self.settings.get('networking.lora.activation') == 'abp': import struct dev_addr = struct.unpack( ">l", binascii.unhexlify( self.settings.get( 'networking.lora.abp.device_address')))[0] nwk_swkey = binascii.unhexlify( self.settings.get( 'networking.lora.abp.network_session_key')) app_swkey = binascii.unhexlify( self.settings.get('networking.lora.abp.app_session_key')) log.info('[LoRa] Attaching to the LoRaWAN network using ABP') self.lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey), timeout=0, dr=datarate_join) def ensure_connectivity(self): self.wait_for_join() if self.lora_joined: if self.lora_socket is None: try: self.create_socket() except: log.exception("[LoRa] Could not create LoRa socket") else: log.error("[LoRa] Could not join network") def wait_for_join(self): """ wait for device activation to complete """ self.lora_joined = None while not self.lora.has_joined(): log.info('[LoRa] Not joined yet...') time.sleep( self.settings.get('networking.lora.otaa.join_check_interval', 2.5)) self.lora_joined = self.lora.has_joined() if self.lora_joined: log.info('[LoRa] Joined successfully') else: log.info('[LoRa] Failed to join network') return self.lora_joined def create_socket(self): """ Create socket for LoRa communication """ # create a lora socket self.socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW) self.socket.settimeout(6.0) self.lora_socket = True log.info('[LoRa] Socket created') return self.lora_socket def send(self, payload): """ Send a LoRa packet. :param payload: """ self.socket.setblocking(True) success = self.socket.send(payload) self.socket.setblocking(False) self.lora.nvram_save() return success def receive(self): """ Receive a LoRa packet. """ try: rx, port = self.socket.recvfrom(256) except socket.timeout: log.info('[LoRa] No packet received within receive window') if rx: log.info('[LoRa] Received: {} on port: {}'.format(rx, port)) return rx, port
class LORA(object): 'Wrapper class for LoRa' def __init__(self, dr=2): # LoRa and socket instances # Initialize LoRa in LORAWAN mode self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868) self.callback = None self.sockets = [] self.dr = dr # socket dr self.LED = None self.debug = False def connect(self, method, ports=1, callback=None, myLED=None, dr=None, debug=False): """ Connect device to LoRa. Set the socket and lora instances. myLED is led object, on resume use lora nvram """ self.callback = callback # call back routine on LoRa reply callback(port,response) self.debug = debug self.LED = myLED if myLED: myLED.heartbeat(False) self.restore sleep_ms(100) if self.lora.has_joined() or self.status: # resume LoRa OTAA or ABP self.getPorts(ports) return True if self.debug: print("No previous LoRa join. Try to join.") if (not type(method) is dict): raise ValueError("No activation method defined.") fnd = False try: if not method['OTAA'][0]: raise ValueError() fnd = True except: try: # OTAA from Config import dev_eui except: from machine import unique_id from ubinascii import hexlify dev_eui = 'AAAA' + hexlify(unique_id()) # use dflt try: from Config import app_eui, app_key method['OTAA'] = (dev_eui, app_eui, app_key) fnd = True except: pass if not fnd: try: if not method['ABP'][0]: raise ValueError() fnd = True except: # ABP try: from Config import dev_addr, nwk_swkey, app_swkey method['ABP'] = (dev_addr, nwk_swkey, app_swkey) fnd = True except: pass if not fnd: raise ValueError("No LoRa keys defined") if self.debug: print("LoRa keys load from Config") count = 0 if self.debug: print("Try to join LoRa/%s" % str(method.keys())) if 'OTAA' in method.keys(): # first OTAA from ubinascii import unhexlify # Join a network using OTAA (Over the Air Activation) next code looks strange dev_eui = method['OTAA'][0] dev_eui = unhexlify(dev_eui) app_eui = method['OTAA'][1] app_eui = unhexlify(app_eui) app_key = method['OTAA'][2] app_key = unhexlify(app_key) self.lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=dr) # Wait until the module has joined the network if myLED: myLED.blink(4, 2.5, 0x04acf6) else: sleep_ms(10000) while not self.lora.has_joined(): if count > 15: break # machine.reset()? print("Wait for OTAA join: ", count) count += 1 if myLED: myLED.blink(2, 2.5, 0xff0000) else: sleep_ms(5000) if self.lora.has_joined(): count = 1 print("LoRa OTAA join.") else: count = 0 if not count: # if not ABP if not 'ABP' in method.keys(): print("No ABP TTN keys defined.") return False import struct from ubinascii import unhexlify # next code is strange. ABP method is not yet operational dev_addr = method['ABP'][0] dev_addr = unhexlify(dev_addr) dev_addr = struct.unpack('>l', dev_addr)[0] nwk_swkey = method['ABP'][1] nwk_swkey = unhexlify(nwk_swkey) app_swkey = method['ABP'][2] app_swkey = unhexlify(app_swkey) print("LoRa ABP join.") self.lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey)) self.getPorts(ports) if myLED: myLED.blink(2, 0.1, 0x009900) self.dump return True def getPorts(self, ports): # Create a LoRa sockets self.sockets = [] self.sockets.append(socket.socket(socket.AF_LORA, socket.SOCK_RAW)) # Set the LoRaWAN data rate self.sockets[0].setsockopt(socket.SOL_LORA, socket.SO_DR, self.dr) # Make the socket non-blocking self.sockets[0].setblocking(False) # Create a raw LoRa socket # default port 2 self.sockets.append(None) for nr in range(ports): self.sockets.append(socket.socket(socket.AF_LORA, socket.SOCK_RAW)) self.sockets[nr + 2].setblocking(False) if nr: self.sockets[nr + 2].bind(nr + 2) if self.debug: print("Installed LoRa port %d" % (nr + 2)) return True def send(self, data, port=2): """ Send data over the network. """ if (port < 2) or (port > len(self.sockets)): raise ValueError('Unknown LoRa port %d' % port) if not self.sockets[port]: raise OSError('No socket') rts = True try: self.sockets[port].send(data) if self.LED: self.LED.blink(2, 0.1, 0x0000ff) if self.debug: print("Sending data") # print(data) except OSError as e: if e.errno == 11: print("Caught exception while sending") print("errno: ", e.errno) else: print("Lora ERROR: %s" % e) rts = False if self.LED: self.LED.off data = self.sockets[port].recv(64) if self.debug: print("Received data:", data) if self.callback and data: self.callback(port, data) sleep_ms(1000) self.dump # save status return rts @property def dump(self): from time import sleep_ms sleep_ms(2000) if self.debug: print("Save LoRa keys") return self.lora.nvram_save() @property def restore(self): self.lora.nvram_restore() if self.debug: print("Restore LoRa keys") return self.lora.stats().tx_counter @property def status(self): return self.lora.stats().tx_counter @property def clear(self): if self.debug: print("Clear LoRa keys") self.lora.nvram_erase()
class LoRaManager: """ """ def __init__(self, manager, settings): self.manager = manager self.settings = settings # LoRa settings. self.otaa_settings = self.settings.get('networking.lora.otaa') #self.generated_device_eui = binascii.hexlify(LoRa().mac()) def start(self): """ """ self.start_lora_join() def start_lora_join(self): """ """ from network import LoRa if self.otaa_settings['region'] == 'AS923': lora_region = LoRa.AS923 elif self.otaa_settings['region'] == 'AU915': lora_region = LoRa.AU915 elif self.otaa_settings['region'] == 'EU868': lora_region = LoRa.EU868 elif self.otaa_settings['region'] == 'US915': lora_region = LoRa.US915 lora_adr = self.otaa_settings['adr'] or False self.lora_socket = None self.lora = LoRa(mode=LoRa.LORAWAN, region=lora_region, adr=lora_adr) # restore LoRa state from NVRAM after waking up from DEEPSLEEP. Reset LoRa NVRAM and rejoin otherwise if machine.reset_cause() == machine.DEEPSLEEP_RESET: self.lora.nvram_restore() log.info( '[LoRa] LoRaWAN state restored from NVRAM after deep sleep') else: self.lora.nvram_erase() log.info('[LoRa] LoRaWAN state erased from NVRAM. Rejoin forced') # Create LoRaWAN OTAA connection to TTN. app_eui = binascii.unhexlify(self.otaa_settings['application_eui']) app_key = binascii.unhexlify(self.otaa_settings['application_key']) if not self.lora.has_joined(): log.info('[LoRa] joining the network...') if self.otaa_settings.get('device_eui') is None: self.lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0) else: dev_eui = binascii.unhexlify(self.otaa_settings['device_eui']) self.lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0) def wait_for_lora_join(self, attempts): """ :param attempts: """ self.lora_joined = None for i in range(0, attempts): while not self.lora.has_joined(): log.info('[LoRa] Not joined yet...') time.sleep(2.5) self.lora_joined = self.lora.has_joined() if self.lora_joined: log.info('[LoRa] joined...') else: log.info('[LoRa] did not join in %s attempts', attempts) return self.lora_joined def create_lora_socket(self): """ """ # create a lora socket self.socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW) self.socket.settimeout(6.0) self.lora_socket = True log.info('[LoRa] socket created') return self.lora_socket def lora_send(self, payload): """ :param payload: """ self.socket.setblocking(True) success = self.socket.send(payload) self.socket.setblocking(False) self.lora.nvram_save() return success def lora_receive(self): """ """ import binascii try: rx, port = self.socket.recvfrom(256) except socket.timeout: log.info('[LoRa] no packet received within receive window ') if rx: log.info('[LoRa] Received: {}, on port: {}'.format(rx, port)) return rx, port
class LoRaManager: """ """ def __init__(self, manager, settings): self.manager = manager self.settings = settings # LoRa settings. self.otaa_settings = self.settings.get('networking.lora.otaa') #self.generated_device_eui = binascii.hexlify(LoRa().mac()) def start(self): """ """ self.start_lora_join() self.wait_for_lora_join(42) time.sleep(2.5) if self.lora_joined: self.create_lora_socket() else: log.error("[LoRa] Could not join network") def start_lora_join(self): """ """ from network import LoRa #pycom.rgbled(0x0f0000) # red #self.lora = LoRa(mode=LoRa.LORAWAN, region=self.otaa_settings['region']) self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868) # restore LoRa state from NVRAM after waking up from DEEPSLEEP. Rejoin otherwise if machine.reset_cause() == machine.DEEPSLEEP_RESET: self.lora.nvram_restore() log.info( '[LoRA] LoRaWAN state restored from NVRAM after deep sleep') else: self.lora.nvram_erase() log.info( '[LoRA] LoRaWAN state erased from NVRAM to let the device join the network' ) # Create LoRaWAN OTAA connection to TTN. app_eui = binascii.unhexlify(self.otaa_settings['application_eui']) app_key = binascii.unhexlify(self.otaa_settings['application_key']) # Remark: For Pycom Nanogateway. # Set the 3 default channels to the same frequency (must be before sending the otaa join request) #self.lora.add_channel(0, frequency=self.otaa_settings['frequency'], dr_min=0, dr_max=5) #self.lora.add_channel(1, frequency=self.otaa_settings['frequency'], dr_min=0, dr_max=5) #self.lora.add_channel(2, frequency=self.otaa_settings['frequency'], dr_min=0, dr_max=5) if not self.lora.has_joined(): if self.otaa_settings.get('device_eui') is None: self.lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0) else: dev_eui = binascii.unhexlify(self.otaa_settings['device_eui']) self.lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0) def wait_for_lora_join(self, attempts): """ :param attempts: """ self.lora_joined = None for i in range(0, attempts): while not self.lora.has_joined(): time.sleep(2.5) #pycom.rgbled(0x0f0f00) # yellow time.sleep(0.1) log.info('[LoRA] Not joined yet...') #pycom.rgbled(0x000000) # off self.lora_joined = self.lora.has_joined() if self.lora_joined: log.info('[LoRA] joined...') # TODO: move nvram_save() to after payload send call self.lora.nvram_save() else: log.info('[LoRa] did not join in %s attempts', attempts) #for i in range(3, 16): # self.lora.remove_channel(i) return self.lora_joined def create_lora_socket(self): """ """ # create a lora socket self.lora_socket = None self.socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW) # set the LoRaWAN data rate #self.socket.setsockopt(socket.SOL_LORA, socket.SO_DR, self.otaa_settings['datarate']) self.socket.setsockopt(socket.SOL_LORA, socket.SO_DR, self.otaa_settings['datarate']) # make the socket non-blocking self.socket.setblocking(False) self.lora_socket = True log.info('[LoRa] socket created') for i in range(0, 2): #pycom.rgbled(0x000f00) # green time.sleep(0.1) #pycom.rgbled(0x000000) # off time.sleep(4.0) return self.lora_socket def lora_send(self, payload): """ :param payload: """ success = self.socket.send(payload) for i in range(0, 2): #pycom.rgbled(0x00000f) # green time.sleep(0.1) #pycom.rgbled(0x000000) # off return success def lora_receive(self): """ """ rx, port = self.socket.recvfrom(256) if rx: #pycom.rgbled(0x000f00) # green log.info('[LoRa] Received: {}, on port: {}'.format(rx, port)) #pycom.rgbled(0x000f00) # green time.sleep(6) return rx, port
class LoRaWANNode: def __init__(self, app_eui, app_key, frequency=868100000, dr=5): '''setup LoRaWAN for the European 868 MHz region with OTAA''' self.dr = dr self.frequency = frequency self.app_eui = ubinascii.unhexlify(app_eui) self.app_key = ubinascii.unhexlify(app_key) self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868) self.socket = None self.setup() @property def has_joined(self): return self.lora.has_joined() def default_channels(self): ''' Remove all non-default channels and set the 3 default channels to the same frequency (must be before ending the OTAA join request) ''' for i in range(3, 16): self.lora.remove_channel(i) self.lora.add_channel(0, frequency=self.frequency, dr_min=0, dr_max=self.dr) self.lora.add_channel(1, frequency=self.frequency, dr_min=0, dr_max=self.dr) self.lora.add_channel(2, frequency=self.frequency, dr_min=0, dr_max=self.dr) def setup(self): '''Try to restore from nvram or join the network with otaa''' self.default_channels() self.lora.nvram_restore() if not self.has_joined: self.join() else: self.open_socket() def join(self, timeout=10): try: timeout = timeout * 1000 self.lora.join(activation=LoRa.OTAA, auth=(self.app_eui, self.app_key), timeout=timeout, dr=self.dr) if self.has_joined: self.lora.nvram_save() self.open_socket() except TimeoutError: pass def open_socket(self, timeout=6): self.socket = usocket.socket(usocket.AF_LORA, usocket.SOCK_RAW) self.socket.setsockopt(usocket.SOL_LORA, usocket.SO_DR, self.dr) self.socket.settimeout(timeout) def reset(self): self.socket.close() self.lora.nvram_erase() self.join() def send(self, data): '''Send out data as bytes''' if self.has_joined: if isinstance(data, (float, str, int)): data = bytes([data]) self.socket.send(data) utime.sleep(2) self.lora.nvram_save()
def nvram_erase(): lora = LoRa(mode=LoRa.LORAWAN) lora.nvram_erase()
class Transceiver: def __init__(self, app_eui=0, app_key=0, dev_addr=0, nwk_swkey=0, app_swkey=0, dataRate=0, adr=False, useSavedState=True): self.app_eui = app_eui self.app_key = app_key self.dev_addr = dev_addr self.nwk_swkey = nwk_swkey self.app_swkey = app_swkey self.dataRate = dataRate self.adr = adr self.useSavedState = useSavedState # Initialize LoRa in LORAWAN mode self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868, power_mode=LoRa.TX_ONLY, adr=self.adr) # Restore LoRa state from memory (join state, frame counter) if self.useSavedState: self.lora.nvram_restore() else: self.lora.nvram_erase() # Only (re)join if not joined before if not self.lora.has_joined(): if self.app_eui != 0 and self.app_key != 0: # join a network using OTAA (Over the Air Activation). Start with sf12 self.lora.join(activation=LoRa.OTAA, auth=(self.app_eui, self.app_key), dr=0, timeout=0) elif self.dev_addr != 0 and self.nwk_swkey != 0 and self.app_swkey != 0: # join a network using ABP (Authentication By Personalization) self.lora.join(activation=LoRa.ABP, auth=(self.dev_addr, self.nwk_swkey, self.app_swkey)) else: print("Invalid ABP or OTAA keys") return # wait until the module has joined the network (ToDo: timeout to prevent indefinite loop) while not self.lora.has_joined(): time.sleep(2.5) print('.', end='') return def transmit(self, payload): self.lora.set_battery_level(self.__getLoraBattLevel()) # create a LoRa socket self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW) # set the LoRaWAN data rate self.s.setsockopt(socket.SOL_LORA, socket.SO_DR, self.dataRate) # selecting non-confirmed type of messages self.s.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, False) # make the socket blocking # (waits for the data to be sent and for the 2 receive windows to expire) self.s.setblocking(True) # select port self.s.bind(1) # Send the LoRa message self.s.send(payload) # make the socket non-blocking # (because if there's no data received it will block forever...) self.s.setblocking(False) # get any data received (if any...) self.receivePayload = self.s.recv(64) #print("Store LoRa state in memory") self.lora.nvram_save() return def receive(self): return self.receivePayload def getMac(self): return binascii.hexlify(self.lora.mac()).upper().decode('utf-8') def stats(self): return self.lora.stats() def __getLoraBattLevel(self): adc = machine.ADC() battReg = adc.channel(pin='P16', attn=1) #print('Battery voltage:', battReg() * 3 * 1.334 / 4095) loraBattLevel = int(battReg() / 14.9) if loraBattLevel > 254: loraBattLevel = 0 battVoltage = battReg() * 3 * 1.334 / 4095 #print("Battery level: %d (%f V)" % (loraBattLevel, battVoltage)) return loraBattLevel
class LORAWAN(object): """ Class to sent messages via LORAWAN network. """ def __init__(self, mode=LoRa.LORAWAN, activation=LoRa.OTAA, region=LoRa.EU868, data_rate=5, join_timeout=0, tx_retries=3, adr=True, public=True, device_class=LoRa.CLASS_A, app_eui=None, app_key=None, dev_addr=None, nwk_swkey=None, app_swkey=None): # OTAA authentication parameters if activation == LoRa.OTAA: if app_eui: self.__app_eui = binascii.unhexlify(app_eui.replace(' ', '')) if app_key: self.__app_key = binascii.unhexlify(app_key.replace(' ', '')) # ABP authentication parameters if activation == LoRa.ABP: if dev_addr: self.__dev_addr = binascii.unhexlify(dev_addr.replace(' ', '')) if nwk_swkey: self.__nwk_swkey = binascii.unhexlify( nwk_swkey.replace(' ', '')) if app_swkey: self.__nwk_appkey = binascii.unhexlify( app_swkey.replace(' ', '')) self.__join_timeout = join_timeout * 1000 self.__data_rate = data_rate self.__activation = activation self.__lora = None self.__socket = None self.__mode = mode self.__lora = LoRa(mode=mode, region=region, adr=adr, public=public, tx_retries=tx_retries, device_class=device_class) # Restore self.__lora.nvram_restore() time.sleep(1) log.debug('Device EUI: {}', binascii.hexlify(self.__lora.mac()).upper().decode('utf-8')) log.debug('Frequency: {}', self.__lora.frequency()) def start(self): """ Start the LORAWAN connection """ try: # When device isn't joined if not self.__lora.has_joined(): # Join network using OTAA if self.__activation == LoRa.OTAA: log.debug('Join network using OTAA') self.__lora.join(activation=LoRa.OTAA, auth=(self.__app_eui, self.__app_key), timeout=self.__join_timeout) while not self.__lora.has_joined(): log.debug('Wait for joining LoRa network...') time.sleep(2.5) # Join network using ABP if self.__activation == LoRa.ABP: log.debug('Join network using ABP') self.__lora.join(activation=LoRa.ABP, auth=(self.__dev_addr, self.__nwk_swkey, self.__nwk_appkey), timeout=self.__join_timeout) except Exception as e: log.error('Exception {} accesssing or joining LoRa network', e) def send_str(self, message=None): 'Send the message' self.__socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW) self.__socket.setsockopt(socket.SOL_LORA, socket.SO_DR, self.__data_rate) if self.__lora and self.__socket: # make the socket blocking # (waits for the data to be sent and for the 2 receive windows to expire) self.__socket.setblocking(True) try: if message: log.debug('Send: ', message) self.__socket.send(message) self.__lora.nvram_save() time.sleep(1) except OSError as e: log.error('OSError {}', e) self.__lora.nvram_erase() time.sleep(1) # make the socket non-blocking # (because if there's no data received it will block forever...) self.__socket.setblocking(False) def receive(self): 'Receive a message' if self.__socket: # get any data received (if any...) data = self.__socket.recv(64) return data def stop(self): ' Stop the LORAWAN connection' log.debug('Stop the LORAWAN connection') if self.__socket: self.__socket.close() self.__socket = None