Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
            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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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()
Ejemplo n.º 8
0
def nvram_erase():
    lora = LoRa(mode=LoRa.LORAWAN)
    lora.nvram_erase()
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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