Ejemplo n.º 1
0
def restore_lora():
    lora = LoRa(mode=LoRa.LORAWAN,
                region=LoRa.US915,
                tx_power=20,
                bandwidth=LoRa.BW_500KHZ,
                sf=7,
                frequency=903900000)
    lora.nvram_restore()
    #print("setting up lora socket")
    # create a LoRa socket
    s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
    #set to confirmed type of messages
    # set the LoRaWAN data rate
    s.setsockopt(socket.SOL_LORA, socket.SO_DR, 3)
    # make the socket blocking
    # (waits for the data to be sent and for the 2 receive windows to expire)
    s.setblocking(True)
    # send some data
    s.send(make_payload())
    time.sleep(2)
    # make the socket non-blocking
    s.setblocking(False)
    # get any data received (if any...)
    data = s.recvfrom(128)
    print("received message: {0}".format(data))
    #    except OSError as e:
    #        if e.args[0] == 11:
    #            # EAGAIN error occurred, add your retry logic here
    #            time.sleep(2)
    #            s.send(full_packet)
    return
Ejemplo n.º 2
0
def main():

    gps = setup_gps()

    # setup lopy4 pins
    sensor = setup_adc()
    power = setup_power_pin()

    #intialize lora object
    lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.US915)
    lora = setup_single_lora_channel(lora)
    lora.nvram_restore()

    if not lora.has_joined():
        join_via_abp(lora)
        while not lora.has_joined():
            utime.sleep(2.5)
            print('Not yet joined...')
        print('Join successful!')

    sensor_reading = read_sensor(sensor, power)
    send_message(sensor_reading, gps)
    utime.sleep(1)
    lora.nvram_save()
    machine.deepsleep(int(READING_FREQ_IN_MIN * 60 * 1000))
Ejemplo n.º 3
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.º 4
0
def connect(appeui, appkey, force=False, max_retry=20, grace_period=2.5):
    """
    Create and connect Socket for LoRa application using OTAA mechanism
    """

    # Initialise LoRa in LORAWAN mode.
    lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
    #lora.nvram_erase()
    lora.nvram_restore()

    if not lora.has_joined() or force:

        # create an OTAA authentication parameters
        app_eui = ubinascii.unhexlify(appeui)
        app_key = ubinascii.unhexlify(appkey)

        # join a network using OTAA (Over the Air Activation)
        lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
        
    # wait until the module has joined the network
    i = 0
    while not lora.has_joined():
        time.sleep(grace_period)
        i += 1
        print('LORA/OTAA [EUI={}]: Application Join request pending ({}/{})...'.format(appeui, i, max_retry))
        if i >= max_retry:
            break
    else:
        print('LORA/OTAA [EUI={}]: Application Join request accepted'.format(appeui))

    # create a LoRa socket
    sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)

    # set the LoRaWAN data rate
    sock.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)

    # make the socket blocking
    # (waits for the data to be sent and for the 2 receive windows to expire)
    sock.setblocking(True)
    #sock.send(b'')
    
    # make the socket non-blocking
    # (because if there's no data received it will block forever...)
    sock.setblocking(False)
    #sock.recv(64)

    # Save LoRa State:
    # https://forum.pycom.io/topic/1668/has-anyone-successfully-used-lora-nvram_save-and-restore/16
    lora.nvram_save()
    print('LORA/OTAA [EUI={}]: LoRa state saved'.format(appeui))

    return sock, lora
Ejemplo n.º 5
0
class TtnClient:
    def __init__(self, app_eui, app_key, join_timeout, debug=False):
        self.app_eui = unhexlify(app_eui)
        self.app_key = unhexlify(app_key)
        self.join_timeout = join_timeout
        self.debug = debug
        if self.debug:
            print("Turning on LoRa radio...")
        self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868, adr=False)
        if self.debug:
            print("Restoring state from NVRAM")
        self.lora.nvram_restore()

    def _join(self):
        if self.debug:
            print("Joining new session...")
        self.lora.join(activation=LoRa.OTAA,
                       auth=(self.app_eui, self.app_key),
                       timeout=0)
        chrono = Timer.Chrono()
        chrono.start()
        while not self.lora.has_joined() and chrono.read() < self.join_timeout:
            if self.debug:
                print(".", end='')
            sleep(1)
        chrono.stop()
        if not self.lora.has_joined():
            if self.debug:
                print("Could not join a new session")
            raise JoinException
        else:
            if self.debug:
                print("Joined new session")

    def send(self, payload, datarate=5):
        if not self.lora.has_joined():
            self._join()
        s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        s.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, False)
        s.setsockopt(socket.SOL_LORA, socket.SO_DR, datarate)
        s.bind(1)
        s.setblocking(True)
        if self.debug:
            print("Sending payload...")
        s.send(payload)
        if self.debug:
            print("Payload sent")
        s.setblocking(False)
        if self.debug:
            print("Saving state to NVRAM...")
        self.lora.nvram_save()
Ejemplo n.º 6
0
def loraConnection(lora=None):
    """Connection with OTAA to the LoRaWAN network"""
    if lora == None:
        lora = LoRa(mode=LoRa.LORAWAN)
        lora.power_mode(LoRa.TX_ONLY)
    lora.nvram_restore()
    if not lora.has_joined():
        joinRequestTimeout = False
        loRaWANTimeout = Timer.Chrono()
        app_eui = binascii.unhexlify(conf.APP_EUI.replace(' ', ''))
        app_key = binascii.unhexlify(conf.APP_KEY.replace(' ', ''))
        timeout = conf.JOIN_REQUEST_TIMEOUT
        lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
        loRaWANTimeout.start()
        while not lora.has_joined():
            if loRaWANTimeout.read() > timeout:
                loRaWANTimeout.stop()
                joinRequestTimeout = True
                break
Ejemplo n.º 7
0
def loraTask():
    global lora_wdt_lock, lora_stop_flag
    global QueueDelay

    logger = Logger(name='LORA ' + __version__,
                    level=logging.DEBUG,
                    filename=None)
    logger.debug('** LORA Task started **')

    lora = LoRa(mode=LoRa.LORAWAN,
                region=LoRa.EU868,
                adr=True,
                public=True,
                device_class=LoRa.CLASS_C)
    lorawan_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
    lorawan_socket.setblocking(False)

    RadioOffset = getConfigurationVariable(NVS_RADIO_DELAY)
    # defautl is OTAA (old config file may not have this defined)
    JM = 0
    try:
        from deviceid import lora_join_method
        JM = lora_join_method
    except:
        pass

    #add the multicasts
    try:
        from deviceid import multicasts
        for multicast_address in multicasts:
            multicast_devAddr = multicast_address[0]
            multicast_NwkSKey = multicast_address[1]
            multicast_AppSKey = multicast_address[2]
            try:
                lora.join_multicast_group(multicast_devAddr, multicast_NwkSKey,
                                          multicast_AppSKey)
            except:
                pass

    except:
        pass

    # define the reserved Downlink minutes if it exists
    DRM = [8]
    try:
        from deviceid import downlinks_reserved_minutes
        DRM = downlinks_reserved_minutes
    except:
        pass

    if pycom.nvs_get(POWER_FAIL_STATE) == MODE_POWER_FAIL:
        # SPECIAL CASE FOR POWER FAIL AFTER DEEP SLEEP WAKE UP
        lora.nvram_restore()
        processMsgImmediate(
            LoraQueueImmediate, logger, lora,
            lorawan_socket)  # the PF message should already be in the queue
        if lora_queue_immediate_semaphore.locked():
            lora_queue_immediate_semaphore.release(
            )  # tell the main thread we are done

        time.sleep(10)

    if JM == OTAA_JOIN:
        logger.debug("Attempting OTAA Join Kotahi.net...using device EUI " +
                     str(binascii.hexlify(dev_eui)))
        lora.join(activation=LoRa.OTAA,
                  auth=(dev_eui, app_eui, app_key),
                  timeout=0)
        counter = 0
        while not lora.has_joined():
            time.sleep(1)
            counter = counter + 1
            if lora_wdt_lock.locked():
                lora_wdt_lock.release(
                )  # tell the WDT that LoRa task is busy waiting to join
        logger.debug("Join successful after " + str(counter) + "s")
    elif JM == ABP_JOIN:
        from deviceid import dev_addr, nwk_swkey, app_swkey
        logger.debug("Joined Kotahi.net using ABP with EUI " +
                     str(binascii.hexlify(dev_eui)))
        lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey))
        #time.sleep(3)
    # save the state in NVS
    lora.nvram_save()

    #lora.nvram_save()

    # Lora loop starts here, processing the QOS queues

    while not lora_stop_flag.locked():

        # wait 1s while checking for any message to be sent immediately (e.g PF Alarm)
        counter = 10
        while counter > 0:
            if processMsgImmediate(LoraQueueImmediate, logger, lora,
                                   lorawan_socket) == True:
                if lora_queue_immediate_semaphore.locked():
                    lora_queue_immediate_semaphore.release(
                    )  # signal that the immediate msg has been sent
                time.sleep(1)
            counter = counter - 1
            time.sleep_ms(100)

        # Process any downlinks
        lora_rx_data(lora, lorawan_socket, logger)
        if lora_wdt_lock.locked():
            lora_wdt_lock.release(
            )  # tell the WDT that LoRa task is doing just fine

        unixLocalTime = time.time() + time.timezone()

        timetuple = time.localtime()
        maskUplinks = False
        for minute in DRM:
            if (timetuple[4] % 10 == minute):
                maskUplinks = True
                break

        # process the uplinks using basic QOS Queues
        if maskUplinks == False:
            processQOSQueue(LoraQueueP5, 5, unixLocalTime, logger, lora,
                            lorawan_socket, RadioOffset)
            processQOSQueue(LoraQueueP4, 4, unixLocalTime, logger, lora,
                            lorawan_socket, RadioOffset)
            processQOSQueue(LoraQueueP3, 3, unixLocalTime, logger, lora,
                            lorawan_socket, RadioOffset)
            processQOSQueue(LoraQueueP2, 2, unixLocalTime, logger, lora,
                            lorawan_socket, RadioOffset)
            processQOSQueue(LoraQueueP1, 1, unixLocalTime, logger, lora,
                            lorawan_socket, RadioOffset)

    logger.error('** LORA Task ended **')
                               )  #replace 00000000000000000000000000000000
app_swkey = binascii.unhexlify('00000000000000000000000000000000'
                               )  #replace 00000000000000000000000000000000

print("start join LoRa")
print(utime.localtime())  #utime
print(utime.time())  #utime
# join a network using ABP (Activation By Personalization)
lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, 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, 5)
lora.nvram_restore()  #strange place for the restore but working.

# make the socket blocking
# (waits for the data to be sent and for the 2 receive windows to expire)
s.setblocking(True)

while (True):
    print(".")
    # save the coordinates in a new variable
    coord = l76.coordinates()
    # verify the coordinates received
    if coord == (None, None):
        print("Getting Location...")
        pycom.rgbled(0x7f7f00)  #jaune
        print(utime.time())  #utime
        continue
Ejemplo n.º 9
0
class Startiot:

    def __init__(self):
        self.dev_eui = binascii.unhexlify("YOUR DEV_EUI")
        self.app_eui = binascii.unhexlify("YOUR APP_EUI")
        self.app_key = binascii.unhexlify("YOUR APP_KEY")

        self.lora = LoRa(mode=LoRa.LORAWAN)

    def connect(self, timeout=0, function=None, blocking=False):
        self.lora.nvram_restore()
        if not self.lora.has_joined():
            # No saved connetion state
            pycom.rgbled(0x0f0000)
            self.lora.join(activation=LoRa.OTAA, auth=(
                self.dev_eui, self.app_eui, self.app_key), timeout=0)

            if timeout == 0:
                while not self.lora.has_joined():
                    if function == None:
                        sleep(2.5)
                    else:
                        function()
            else:
                for x in range(timeout):
                    if self.lora.has_joined():
                        break
                    if function == None:
                        sleep(2.5)
                    else:
                        function()

            if not self.lora.has_joined():
                return False

            pycom.rgbled(0x000000)
        else:
            # Connection state restored
            pycom.rgbled(0x0000ff)
            pass

        self.lora.nvram_save()
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)

        # set the LoRaWAN data rate
        self.s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)

        # make the socket non-blocking
        self.s.setblocking(blocking)

        pycom.rgbled(0x000000)

        return True

    def send(self, data):
        self.s.setblocking(True)
        self.s.send(data)

    def recv(self, length=64):
        self.s.setblocking(False)
        return self.s.recv(length)
Ejemplo n.º 10
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.º 11
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
Ejemplo n.º 12
0
class Node:
    def __init__(self,sleep_time,data_rate,pysense):
        self.lora = None                                                        # Instancia de Lora (sin inicializar)
        self.s = None                                                           # Instancia Socket (sin inicializar)
        self.sleep_time = sleep_time                                            # Intervalo de inactividad
        self.dr = data_rate                                                     # Data Rate (defecto 5)
        self.py = pysense                                                       # Instancia de Pysense
        self.lt = LTR329ALS01(self.py)                                          # Instancia Sensor de Luminosidad
        self.mp = MPL3115A2(self.py,mode=PRESSURE)                              # Instancia Sensor de Presión
        self.si = SI7006A20(self.py)                                            # Instancia Sensor de Humedad y tempertura

#------------------------------------------------------------------------------#
    def connect(self,dev_eui,app_eui, app_key):
        """
        Connect device to LoRa.
        Set the socket and lora instances.
        """
        # Initialize LoRa in LORAWAN mode
        self.lora = LoRa(mode = LoRa.LORAWAN,device_class=LoRa.CLASS_A,region=LoRa.EU868)
        # Set the 3 default channels to the same frequency (must be before
        # sending the OTAA join request)
        self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)
        # Join a network using OTAA (Over the Air Activation)
        self.lora.join(activation = LoRa.OTAA, auth = (dev_eui,app_eui, app_key),
                    timeout = 0, dr=self.dr)                                                #login for TheThingsNetwork see here:
                                                                                #https://www.thethingsnetwork.org/forum/t/lopy-otaa-example/4471
        # Wait until the module has joined the network
        while not self.lora.has_joined():
            print("Trying to join LoraWAN with OTAA")
            time.sleep(2.5)
        print ("LoraWAN joined! ")
        # save the LoRaWAN connection state
        self.lora.nvram_save()
#------------------------------------------------------------------------------#
    def send(self,data):
        """
        Send data over the network.
        """
        if py.get_wake_reason() == WAKE_REASON_TIMER:                           #Si despierta tras deepsleep
            # Initialize LoRa in LORAWAN mode
            self.lora = LoRa(mode = LoRa.LORAWAN,adr=True,device_class=LoRa.CLASS_A,region=LoRa.EU868)
            # restore the LoRaWAN connection state
            try:
                self.lora.nvram_restore()
            except OSError:
                print("Error: LoRa Configuration could not be restored")
                self.connect(dev_eui,app_eui,app_key)
                print("LoRa Connection Parameters Recovered")
        # remove all the non-default channels
        for i in range(3, 16):
            self.lora.remove_channel(i)
        # Set the 3 default channels to the same frequency
        # (must be before sending the OTAA join request)
        self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)
        # Create a LoRa socket
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        print("Created LoRaWAN socket")
        # Make the socket blocking
        self.s.setblocking(True)                                                #Necesario para gurdar el contador de mensajes

        try:
            self.s.send(data)                                                   #Envio de datos
            self.s.setblocking(False)                                           # make the socket non-blocking (necesario para no dejar colgado el dispositivo)
            rx = bytes(self.s.recv(128))                                        # (because if there's no data received it will block forever...)
            self.receive(rx=rx)
            self.lora.nvram_save()
            print('Lora Config Saved!')
        except OSError as e:
            if e.errno == 11:
                print("Caught exception while sending")
                print("errno: ", e.errno)
                pass

#------------------------------------------------------------------------------#
#Función de recepción de datos.Es activada tras la ventana de recepción
#posterior al envío.
    def receive(self,rx=None):
        if len(rx) == 0:                                                        #No hay mensaje de recepción
            print('No incoming message')
            pass
        else:
            if rx[0] == 73:                                                     #Orden de Cambio de intervalo (ASCII hex I=0x49 dec 73)
                print("Recibido cambio de intervalo %d"
                           %(int.from_bytes(rx[1:],'big')))
                self.sleep_time = int.from_bytes(rx[1:],'big')                  #Decodifica el valor del nuevo intervalo
                pycom.nvs_set('sleep_time',self.sleep_time)                     #Lo guarda en NVRAM
            elif rx[0] == 82:                                                   #Orden de Cambio Data Rate (ASCII hex R=0x52 dec 87)
                print("Cambiando Data Rate %d" %(int.from_bytes(rx[1:],'big')))
                self.dr = int.from_bytes(rx[1:],'big')                          #Decodifica el valor del nuevo data Rate
                pycom.nvs_set('data_rate',self.data_rate)                       #Lo guarda en NVRAM
            elif rx[0] == 79:                                                   #4Fh
                ota = WiFiOTA('MBP_JuanMa','MBP_JuanMa',"54.154.225.138",8000)      #Amazon Web Services Server
                print("Updating via OTA...")
                print('- ' * 20)
                ota.connect()
                ota.update()
            else:
                pass
#------------------------------------------------------------------------------#
#Función de lectura de medidas. Los sensores ya han sido inicializados al
#crear la instancia de la clase Node
    def readsens(self):
        pressure = (int(self.mp.pressure())-90000).to_bytes(2,'little')                     #Segundo Elemento Lista: Presión (entero)
        humidity = int(round(self.si.humidity(),2)*100).to_bytes(2,'little')                #Tercer Elemento Lista: Humedad (dos decimales)
        temperature = int(round(self.si.temperature(),2)*100).to_bytes(2,'little')          #Cuarto Elemento Lista: Temperatura (dos decimales)
        battery = int(round(self.py.read_battery_voltage(),4)*10000-33000).to_bytes(2,'little') #Quinto Elemento Lista: Voltaje (cuatro decimales)
        light = int(self.lt.light()[0]).to_bytes(2,'little')                                #Primer Elemento Lista: Luminosidad (entero)
        reading = light+pressure+humidity+temperature+battery                   #Union de tipos bytes
        return reading
class PybytesConnection:
    def __init__(self, config, message_callback):
        if config is not None:
            self.__conf = config
            try:
                self.__host = pycom.nvs_get('pybytes_server')
            except:
                self.__host = config.get('server')
            self.__ssl = config.get('ssl', False)
            self.__ssl_params = config.get('ssl_params', {})
            self.__user_name = config.get('username')
            self.__device_id = config.get('device_id')
            self.__mqtt_download_topic = "d" + self.__device_id
            self.__mqtt_upload_topic = "u" + self.__device_id
            self.__pybytes_protocol = PybytesProtocol(
                config, message_callback, pybytes_connection=self
            )
        self.__connection = None
        self.__connection_status = constants.__CONNECTION_STATUS_DISCONNECTED
        self.__lora_socket = None
        self.lora = None
        self.lora_lock = _thread.allocate_lock()
        self.__sigfox_socket = None
        self.lte = None
        self.wlan = None
        self.__network_type = None
        self.__wifi_lte_watchdog = None

    def lte_ping_routine(self, delay):
        while True:
            self.send_ping_message()
            time.sleep(delay)

    def print_pretty_response(self, rsp):
        lines = rsp.split('\r\n')
        for line in lines:
            if line:
                if line not in ['OK']:
                    print(line)

    def __initialise_watchdog(self):
        if self.__conf.get('connection_watchdog', True):
            self.__wifi_lte_watchdog = WDT(
                timeout=constants.__WDT_TIMEOUT_MILLISECONDS
            )
            print('Initialized watchdog for WiFi and LTE connection with timeout {} ms'.format(constants.__WDT_TIMEOUT_MILLISECONDS)) # noqa
        else:
            print('Watchdog for WiFi and LTE was disabled, enable with "connection_watchdog": true in pybytes_config.json') # noqa

    # Establish a connection through WIFI before connecting to mqtt server
    def connect_wifi(self, reconnect=True, check_interval=0.5, timeout=120):
        self.__initialise_watchdog()

        if self.__connection_status != constants.__CONNECTION_STATUS_DISCONNECTED: # noqa
            print("Error connect_wifi: Connection already exists. Disconnect First") # noqa
            return False
        try:
            from network import WLAN
            antenna = self.__conf.get('wlan_antenna', WLAN.INT_ANT)
            known_nets = [((self.__conf['wifi']['ssid'], self.__conf['wifi']['password']))] # noqa
            if antenna == WLAN.EXT_ANT:
                print("WARNING! Using external WiFi antenna.")

            '''to connect it to an existing network,
            the WiFi class must be configured as a station'''

            self.wlan = WLAN(mode=WLAN.STA, antenna=antenna)

            attempt = 0

            print_debug(3, 'WLAN connected? {}'.format(self.wlan.isconnected()))

            while not self.wlan.isconnected() and attempt < 3:
                attempt += 1
                print_debug(3, "Wifi connection attempt: {}".format(attempt))
                print_debug(3, 'WLAN connected? {}'.format(self.wlan.isconnected()))
                available_nets = None
                while available_nets is None:
                    try:
                        available_nets = self.wlan.scan()
                        for x in available_nets:
                            print_debug(5, x)
                        time.sleep(1)
                    except:
                        pass

                nets = frozenset([e.ssid for e in available_nets])
                known_nets_names = frozenset([e[0]for e in known_nets])
                net_to_use = list(nets & known_nets_names)
                try:
                    net_to_use = net_to_use[0]
                    pwd = dict(known_nets)[net_to_use]
                    sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] # noqa
                    print_debug(99, "Connecting with {} and {}".format(net_to_use, pwd))
                    if  sec == 0:
                        self.wlan.connect(net_to_use, timeout=10000)
                    else:
                        self.wlan.connect(net_to_use, (sec, pwd), timeout=10000)
                    start_time = time.time()
                    while not self.wlan.isconnected():
                        if time.time() - start_time > timeout:
                            raise TimeoutError('Timeout trying to connect via WiFi')
                        time.sleep(0.1)
                except Exception as e:
                    if str(e) == "list index out of range" and attempt == 3:
                        print("Please review Wifi SSID and password inside config")
                        self.wlan.deinit()
                        return False
                    elif attempt == 3:
                        print("Error connecting using WIFI: %s" % e)
                        return False

            self.__network_type = constants.__NETWORK_TYPE_WIFI
            print("WiFi connection established")
            try:
                self.__connection = MQTTClient(
                    self.__device_id,
                    self.__host,
                    self.__mqtt_download_topic,
                    self.__pybytes_protocol,
                    user=self.__user_name,
                    password=self.__device_id
                )
                self.__connection.connect()
                self.__connection_status = constants.__CONNECTION_STATUS_CONNECTED_MQTT_WIFI # noqa
                self.__pybytes_protocol.start_MQTT(
                    self,
                    constants.__NETWORK_TYPE_WIFI
                )
                return True
            except Exception as ex:
                if '{}'.format(ex) == '4':
                    print('MQTT ERROR! Bad credentials when connecting to server: "{}"'.format(self.__host)) # noqa
                else:
                    print("MQTT ERROR! {}".format(ex))
                return False
        except Exception as ex:
            print("Exception connect_wifi: {}".format(ex))
            return False

    # Establish a connection through LTE before connecting to mqtt server
    def connect_lte(self, activation_info=False, start_mqtt=True):
        if activation_info:
            lte_cfg = activation_info
        else:
            lte_cfg = self.__conf.get('lte')
            self.__initialise_watchdog()

        if lte_cfg is not None:
            if (os.uname()[0] not in ['FiPy', 'GPy']):
                print("You need a device with FiPy or GPy firmware to connect via LTE") # noqa
                return False
            try:
                from network import LTE
                time.sleep(3)
                if lte_cfg.get('carrier', 'standard') == 'standard':
                    carrier = None
                else:
                    carrier = lte_cfg.get('carrier')
                print_debug(1, 'LTE init(carrier={}, cid={})'.format(carrier, lte_cfg.get('cid', 1))) # noqa
                # instantiate the LTE object
                self.lte = LTE(carrier=carrier, cid=lte_cfg.get('cid', 1))
                try:
                    lte_type = lte_cfg.get('type') if len(lte_cfg.get('type')) > 0 else None
                except:
                    lte_type = None
                try:
                    lte_apn = lte_cfg.get('apn') if len(lte_cfg.get('type')) > 0 else None
                except:
                    lte_apn = None
                try:
                    lte_band = int(lte_cfg.get('band'))
                except:
                    lte_band = None
                print_debug(
                    1,
                    'LTE attach(band={}, apn={}, type={})'.format(
                        lte_band,
                        lte_apn,
                        lte_type
                    )
                )

                self.lte.attach(band=lte_band, apn=lte_apn, type=lte_type)  # noqa   # attach the cellular modem to a base station
                while not self.lte.isattached():
                    time.sleep(0.25)
                time.sleep(1)
                print_debug(1, 'LTE connect()')
                # start a data session and obtain an IP address
                self.lte.connect()
                print_debug(1, 'LTE is_connected()')
                while not self.lte.isconnected():
                    time.sleep(0.25)
                print("LTE connection established")
                self.__network_type = constants.__NETWORK_TYPE_LTE

                if start_mqtt:
                    try:
                        self.__connection = MQTTClient(
                            self.__device_id,
                            self.__host,
                            self.__mqtt_download_topic,
                            self.__pybytes_protocol,
                            user=self.__user_name,
                            password=self.__device_id
                        )
                        self.__connection.connect()
                        self.__connection_status = constants.__CONNECTION_STATUS_CONNECTED_MQTT_LTE # noqa
                        self.__pybytes_protocol.start_MQTT(
                            self,
                            constants.__NETWORK_TYPE_LTE
                        )
                        print("Connected to MQTT {}".format(self.__host))
                        return True
                    except Exception as ex:
                        if '{}'.format(ex) == '4':
                            print('MQTT ERROR! Bad credentials when connecting to server: "{}"'.format(self.__host)) # noqa
                        else:
                            print("MQTT ERROR! {}".format(ex))
                        return False
            except Exception as ex:
                print("Exception connect_lte: {}".format(ex))
                sys.print_exception(ex)
            return False
        else:
            print("Error... missing configuration!")
            return False

    # LORA
    def connect_lora_abp(self, lora_timeout, nanogateway):
        print_debug(1,'Attempting to connect via LoRa')
        if (self.__connection_status != constants.__CONNECTION_STATUS_DISCONNECTED): # noqa
            print("Error connect_lora_abp: Connection already exists. Disconnect First") # noqa
            return False
        try:
            from network import LoRa
        except Exception as ex:
            print("This device does not support LoRa connections: %s" % ex)
            return False

        lora_class = self.__conf.get('lora', {}).get('class', 0)
        if self.__conf.get('lora', {}).get('region') is not None:
            self.lora = LoRa(mode=LoRa.LORAWAN, region=self.__conf.get('lora').get('region'), device_class=lora_class)
        else:
            self.lora = LoRa(mode=LoRa.LORAWAN, device_class=lora_class)
        self.lora.nvram_restore()

        try:
            dev_addr = self.__conf['lora']['abp']['dev_addr']
            nwk_swkey = self.__conf['lora']['abp']['nwk_skey']
            app_swkey = self.__conf['lora']['abp']['app_skey']
        except Exception as ex:
            print("Invalid LoRaWAN ABP configuration!")
            print_debug(1, ex)
            return False
        timeout_ms = self.__conf.get('lora_timeout', lora_timeout) * 1000

        dev_addr = struct.unpack(">l", binascii.unhexlify(dev_addr.replace(' ', '')))[0] # noqa
        nwk_swkey = binascii.unhexlify(nwk_swkey.replace(' ', ''))
        app_swkey = binascii.unhexlify(app_swkey.replace(' ', ''))

        try:
            print("Trying to join LoRa.ABP for %d seconds..." % self.__conf.get('lora_timeout', lora_timeout))
            self.lora.join(
                activation=LoRa.ABP,
                auth=(dev_addr, nwk_swkey, app_swkey),
                timeout=timeout_ms
            )

            # if you want, uncomment this code, but timeout must be 0
            # while not self.lora.has_joined():
            #     print("Joining...")
            #     time.sleep(5)

            self.__open_lora_socket(nanogateway)
#            print_debug(5, 'Stack size: {}'.format(self.__thread_stack_size))
#            _thread.stack_size(self.__thread_stack_size)
#            _thread.start_new_thread(self.__check_lora_messages, ())
            return True
        except Exception as e:
            message = str(e)
            if message == 'timed out':
                print("LoRa connection timeout: %d seconds" % self.__conf.get('lora_timeout', lora_timeout))
            else:
                print_debug(3, 'Exception in LoRa connect: {}'.format(e))
            return False

    def connect_lora_otaa(self, lora_timeout, nanogateway):
        print_debug(1,'Attempting to connect via LoRa')
        if (self.__connection_status != constants.__CONNECTION_STATUS_DISCONNECTED): # noqa
            print("Error connect_lora_otaa: Connection already exists. Disconnect First") # noqa
            return False
        try:
            from network import LoRa
        except Exception as ex:
            print("This device does not support LoRa connections: %s" % ex)
            return False

        try:
            dev_eui = self.__conf['lora']['otaa']['app_device_eui']
            app_eui = self.__conf['lora']['otaa']['app_eui']
            app_key = self.__conf['lora']['otaa']['app_key']
        except Exception as ex:
            print("Invalid LoRaWAN OTAA configuration!")
            print_debug(1, ex)
            return False

        timeout_ms = self.__conf.get('lora_timeout', lora_timeout) * 1000

        lora_class = self.__conf.get('lora', {}).get('class', 0)
        if self.__conf.get('lora', {}).get('region') is not None:
            self.lora = LoRa(mode=LoRa.LORAWAN, region=self.__conf.get('lora', {}).get('region'), device_class=lora_class)
        else:
            self.lora = LoRa(mode=LoRa.LORAWAN, device_class=lora_class)
        self.lora.nvram_restore()

        dev_eui = binascii.unhexlify(dev_eui.replace(' ', ''))
        app_eui = binascii.unhexlify(app_eui.replace(' ', ''))
        app_key = binascii.unhexlify(app_key.replace(' ', ''))
        try:
            if not self.lora.has_joined():
                print("Trying to join LoRa.OTAA for %d seconds..." % self.__conf.get('lora_timeout', lora_timeout))
                self.lora.join(
                    activation=LoRa.OTAA,
                    auth=(dev_eui, app_eui, app_key),
                    timeout=timeout_ms
                )

            # if you want, uncomment this code, but timeout must be 0
            # while not self.lora.has_joined():
            #     print("Joining...")
            #     time.sleep(5)

            self.__open_lora_socket(nanogateway)
#            print_debug(5, 'Stack size: {}'.format(self.__thread_stack_size))
#            _thread.stack_size(self.__thread_stack_size)
#            _thread.start_new_thread(self.__check_lora_messages, ())
            return True
        except Exception as e:
            message = str(e)
            if message == 'timed out':
                print("LoRa connection timeout: %d seconds" % self.__conf.get('lora_timeout', lora_timeout))
            else:
                print_debug(3, 'Exception in LoRa connect: {}'.format(e))
            return False

    def __open_lora_socket(self, nanogateway):
        if (nanogateway):
            for i in range(3, 16):
                self.lora.remove_channel(i)

            self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
            self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
            self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)

        print("Setting up LoRa socket...")
        self.__lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.__lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)

        self.__connection_status = constants.__CONNECTION_STATUS_CONNECTED_LORA

        self.__pybytes_protocol.start_Lora(self)

        print("Connected using LoRa")

    # SIGFOX
    def connect_sigfox(self):
        if (self.__connection_status != constants.__CONNECTION_STATUS_DISCONNECTED): # noqa
            print("Error: Connection already exists. Disconnect First")
            pass
        try:
            from network import Sigfox
        except Exception:
            print("This device does not support Sigfox connections")
            return
        sigfox_config = self.__conf.get('sigfox', {})
        if sigfox_config is None or sigfox_config.get('RCZ') is None:
            print(constants.__SIGFOX_WARNING)
        try:
            sf_rcz = int(sigfox_config.get('RCZ', 1)) - 1
            if sf_rcz >= 0 and sf_rcz <= 3:
                Sigfox(mode=Sigfox.SIGFOX, rcz=sf_rcz)
                self.__sigfox_socket = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW) # noqa
                self.__sigfox_socket.setblocking(True)
                self.__sigfox_socket.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False) # noqa
                self.__network_type = constants.__NETWORK_TYPE_SIGFOX
                self.__connection_status = constants.__CONNECTION_STATUS_CONNECTED_SIGFOX # noqa
                self.__pybytes_protocol.start_Sigfox(self)
                print(
                    "Connected using Sigfox. Only upload stream is supported"
                )
                return True
            else:
                print('Invalid Sigfox RCZ specified in config!')
                return False
        except Exception as e:
            print('Exception in connect_sigfox: {}'.format(e))
            return False

    # COMMON
    def disconnect(self, keep_wifi=False, force=False):

        if self.__wifi_lte_watchdog is not None:
            self.__wifi_lte_watchdog = WDT(timeout=constants.__WDT_MAX_TIMEOUT_MILLISECONDS)
            print('Watchdog timeout has been increased to {} ms'.format(constants.__WDT_MAX_TIMEOUT_MILLISECONDS)) # noqa

        print_debug(
            1,
            'self.__connection_status={} | self.__network_type={}'.format(
                self.__connection_status, self.__network_type
            )
        )

        if (self.__connection_status == constants.__CONNECTION_STATUS_DISCONNECTED): # noqa
            print_debug(3, "Already disconnected")

        if (constants.__CONNECTION_STATUS_CONNECTED_MQTT_WIFI <= self.__connection_status <= constants.__CONNECTION_STATUS_CONNECTED_MQTT_LTE): # noqa
            print_debug(1, 'MQTT over WIFI||LTE... disconnecting MQTT')
            try:
                self.__connection.disconnect(force=force)
                self.__connection_status = constants.__CONNECTION_STATUS_DISCONNECTED # noqa
            except Exception as e:
                print("Error disconnecting: {}".format(e))

        if (self.__connection_status == constants.__CONNECTION_STATUS_CONNECTED_LORA): # noqa
            print_debug(1, 'Connected over LORA... closing socket and saving nvram') # noqa
            try:
                self.__lora_socket.close()
                self.lora.nvram_save()
            except Exception as e:
                print("Error disconnecting: {}".format(e))

        if (self.__connection_status == constants.__CONNECTION_STATUS_CONNECTED_SIGFOX): # noqa
            print_debug(1, 'Connected over SIGFOX... closing socket')
            try:
                self.__sigfox_socket.close()
            except Exception as e:
                print("Error disconnecting: {}".format(e))

        if (self.__network_type == constants.__NETWORK_TYPE_WIFI and not keep_wifi):
            print_debug(1, 'Connected over WIFI... disconnecting')
            try:
                self.wlan.deinit()
            except Exception as e:
                print("Error disconnecting: {}".format(e))

        if (self.__network_type == constants.__NETWORK_TYPE_LTE):
            print_debug(1, 'Connected over LTE... disconnecting')
            try:
                lte_cfg = self.__conf.get('lte')
                print_debug(1, 'lte.deinit(reset={})'.format(lte_cfg.get('reset', False))) # noqa
                self.lte.deinit(reset=lte_cfg.get('reset', False))
            except Exception as e:
                print("Error disconnecting: {}".format(e))

        self.__network_type = None
        self.__connection_status = constants.__CONNECTION_STATUS_DISCONNECTED

    def is_connected(self):
        return not (self.__connection_status == constants.__CONNECTION_STATUS_DISCONNECTED) # noqa

    # Added for convention with other connectivity classes
    def isconnected(self):
        return not (self.__connection_status == constants.__CONNECTION_STATUS_DISCONNECTED) # noqa
Ejemplo n.º 14
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.º 15
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.º 16
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.º 17
0
class LoRaWAN:

    DEBUG = False

    def __init__(self,
                 app_eui,
                 app_key,
                 region=LoRa.EU868,
                 sf=7,
                 adr=True,
                 dr=5,
                 timeout=15):
        """Setup LoRaWAN"""
        self._timeout = timeout
        self._app_eui = ubinascii.unhexlify(app_eui)
        self._app_key = ubinascii.unhexlify(app_key)
        self._socket = None
        self._dr = dr
        self.lora = LoRa(mode=LoRa.LORAWAN, region=region, sf=sf, adr=adr)
        self.setup()

    def setup(self):
        """Try to restore from nvram or join the network with OTAA"""
        self.lora.nvram_restore()

        if not self.lora.has_joined():
            self.join()
        else:
            self.open_socket()

    def join(self):
        try:
            self.dprint("Send join request")
            timeout = self._timeout * 1000
            self.lora.join(
                activation=LoRa.OTAA,
                auth=(self._app_eui, self._app_key),
                timeout=timeout,
                dr=self._dr,
            )

            if self.lora.has_joined():
                self.lora.nvram_save()
                self.open_socket()
                self.dprint("Joined network")
        except LoRa.timeout:
            self.dprint("Timeout error")
            raise

    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):
        """Reset socket, clear on device stored LoRaWAN session and re-join the network"""
        self._socket.close()
        self.lora.lora_erase()
        self.join()

    def send(self, payload, port=1):
        """Send out uplink data as bytes"""
        self._socket.bind(port)
        if self.lora.has_joined():
            if isinstance(payload, (float, str, int)):
                payload = bytes([payload])
            self.dprint("Send payload: {}".format(payload))
            self._socket.setblocking(True)
            self._socket.send(payload)
            self._socket.setblocking(False)
            self.lora.nvram_save()

    def recv(self, rbytes=1):
        """Receive bytes from downlink"""
        retval = self._socket.recvfrom(rbytes)
        self.dprint("Recv payload: {}, port: {}".format(retval[0], retval[1]))
        return retval

    def shutdown(self):
        """Shutdown LoRa modem"""
        self._socket.close()
        self.lora.power_mode(LoRa.SLEEP)

    def dprint(self, message):
        if self.DEBUG:
            print("LoRaWAN: {}".format(message))
Ejemplo n.º 18
0
class LoraController:
    def __init__(self, options, logger, eventLog, ledController):
        self.options = options
        self.logger = logger
        self.eventLog = eventLog
        self.led = ledController

        self.lora = LoRa(mode=LoRa.LORA, power_mode=LoRa.SLEEP)
        self.tx_runner = None  # thread which sends events over lora
        self.lastJoin = 0  # when did we join the lora network
        self.isJoinLogged = False  # did we log the initial LORA join
        self.lastEventId = 0  # last sent event id
        self.sendLock = _thread.allocate_lock()
        self.socketLock = _thread.allocate_lock()
        self.isAckingCounter = 0
        self.noDownlinkCounter = 0
        self.lastUplinkTime = 0
        self.isAcking = False

    # logging
    def log(self, *text):
        self.logger.log("LORA", *text)

    # start lora connectivity
    def start(self):
        # setup lorawan
        self.lora = LoRa(mode=LoRa.LORAWAN,
                         region=LoRa.EU868,
                         device_class=LoRa.CLASS_A,
                         tx_retries=3,
                         adr=True,
                         sf=12)
        self.lora.nvram_restore()

        self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT
                                    | LoRa.TX_FAILED_EVENT),
                           handler=self.lora_callback)
        self.log('Lora DevEUI is', self.getDeviceEUI())
        self.log('Lora AppEUI is', self.options['lora_app_eui'])

        if len(self.options['lora_app_eui']) != 16:
            self.log("ERROR", "Setting 'lora_app_eui' is invalid:",
                     self.options['lora_app_eui'])
            return

        # issue join
        if self.options['lora_mode'] == "abp":
            self.join()
        elif self.lora.has_joined():
            self.log("Lora network is already joined, re-joining anyway")
        else:
            self.join()

    def lora_callback(self, lora):
        events = lora.events()
        if events & LoRa.TX_FAILED_EVENT:
            self.log('Lora TX FAILED')

    # determines the LORA MAC address (string)
    def getDeviceEUI(self):
        return ubinascii.hexlify(self.lora.mac()).decode('ascii').upper()

    # joins the lora network via OTAA
    def joinOTAA(self):
        app_eui = ubinascii.unhexlify(self.options['lora_app_eui'])
        app_key = ubinascii.unhexlify(self.options['lora_app_key'])

        self.lora.join(activation=LoRa.OTAA,
                       auth=(app_eui, app_key),
                       timeout=0)
        self.log("Joining via OTAA")
        self.lastJoin = time.time()

    # joins the lora network via ABP
    def joinABP(self):
        net_key = ubinascii.unhexlify(self.options['lora_net_key'])
        app_key = ubinascii.unhexlify(self.options['lora_app_key'])
        # note: TTN seems to want the reverse bytes of this address
        device_address = ubinascii.unhexlify(self.options['lora_dev_adr'])

        self.lora.join(activation=LoRa.ABP,
                       auth=(device_address, net_key, app_key))
        self.log("Joining via ABP with device address", device_address)
        self.lastJoin = time.time()

    # joins the lora network via ABP or OTAA
    def join(self):
        if self.options['lora_mode'] == "abp":
            self.joinABP()
        else:
            self.joinOTAA()

    def hasJoined(self):
        return self.lora.has_joined()

    def stats(self):
        return self.lora.stats()

    def makePayload(self, event):
        payload = None
        command = event['Command']
        idbytes = event['ID'].to_bytes(2, 'little')
        event_ts = event['Time']
        try:
            if command == eventlog.CMD_TAG_DETECTED:
                # Tag with 4-Byte UID detected
                # <0x01> <Event ID 0..1> <Timestamp 0..3> <UID 0..3/6/9>
                timeBytes = event_ts.to_bytes(4, 'little')
                uid = event['Data'][0:10]

                # remove trailing 0x00
                uid_size = 10
                for i in range(uid_size - 1, 3, -1):
                    if uid[i] != 0x00:
                        break
                    uid_size = uid_size - 1
                uid = uid[:uid_size]

                payload = bytes([0x01]) + idbytes + timeBytes + uid
                uidText = ubinascii.hexlify(uid).decode()
                self.log("CMD 0x01 [NFC_DETECTED] SEQ#", event['ID'],
                         ". uid =", uidText, ", ts =", event_ts)

            if command == eventlog.CMD_TIME_REQUEST2:
                # ask backend for current time (new)
                # <0x04> <ID 0..1> <Our Time 0..3>
                mytime = time.time().to_bytes(4, 'little')
                payload = bytes([command]) + idbytes + mytime
                self.log("CMD 0x04 [TIME_REQUEST] ID#",
                         event['ID'], ". our_time =", time.time(),
                         utime.gmtime(time.time()))

            if command == eventlog.CMD_TIME_CHANGED:
                # <0x05> <Event ID 0..1> <Our Time 0..3> <Old Time 0..3>
                mytime = event_ts.to_bytes(4, 'little')
                oldTime = event['Data'][0:4]
                payload = bytes([eventlog.CMD_TIME_CHANGED
                                 ]) + idbytes + mytime + oldTime
                self.log("CMD 0x05 [TIME_CHANGED] SEQ#",
                         event['ID'], ". our_time =", event_ts,
                         utime.gmtime(event_ts), ", old_time =", oldTime)

        except Exception as e:
            self.log("ERROR: Unable to prepare LORA payload:", e.args[0], e)
        return payload

    # attempts to send the given event
    def sendEvent(self, event):
        with self.sendLock:
            eventId = event['ID']
            command = event['Command']
            self.log("Preparing to send CMD =", command, ", SEQ_NO =", eventId)
            if self.lastEventId > 0 and eventId > self.lastEventId + 1:
                self.log("ERROR", "Event IDs are not in sequence - last:",
                         self.lastEventId, ", current:", eventId)
            self.lastEventId = eventId
            # prepare lora payload for supported event log entries
            payload = self.makePayload(event)
            if payload == None:
                self.log(
                    "WARN: Event payload is None and therefore ignored for lora transmission"
                )
                return True
            # send payload
            return self.sendAndHandleResponse(payload)

    # sends the payload and handles the optional response
    def sendAndHandleResponse(self, payload):
        if not self.hasJoined():
            self.log("ERROR", "Unable to send LORA payload because not joined")
            return False

        # send
        responseData = self.sendPayload(payload)
        if responseData == False:
            self.noDownlinkCounter = self.noDownlinkCounter + 1
            return False

        # handle response
        if responseData != None and len(responseData) > 0:
            try:
                return True
            except Exception as e:
                self.log("ERROR: Unable to handle LORA payload: ", e.args[0],
                         e)
                self.noDownlinkCounter = self.noDownlinkCounter + 1
        else:
            self.noDownlinkCounter = self.noDownlinkCounter + 1
        # the message has been sent
        return True

    def sendTimeRequest(self, clockSyncEvent, clockSyncRequests):
        clockSyncEvent['Command'] = eventlog.CMD_TIME_REQUEST2
        payload = self.makePayload(clockSyncEvent)
        try:
            with self.sendLock:
                # send lora uplink
                responseData = self.sendPayload(payload, False)
                if responseData == False:
                    return None

        except Exception as e:
            self.log("ERROR", "Unable to sync clock via LORA:", e.args[0], e)
        return None

    # send the specified payload
    def sendPayload(self, data, updateTime=True):
        try:
            with self.socketLock:
                self.log("> sending", len(data), "bytes:",
                         binascii.hexlify(data))
                responseData = None
                # create a LoRa socket
                s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
                s.setblocking(False)
                try:
                    """free_memory = gc.mem_free()
                    allocated_memory = gc.mem_alloc()
                    print("Free Memory: " + str(free_memory) + " -- Allocated Memory : " + str(allocated_memory))"""
                    s.send(data)
                    time.sleep(5)
                    responseData = s.recv(64)
                except Exception as e:
                    self.log("ERROR", "LORA Socket Exception", e)
                s.close()
                if responseData != None:
                    responseLen = len(responseData)
                    if responseLen > 0:
                        self.log("< received", responseLen, "bytes:",
                                 binascii.hexlify(responseData))
                    else:
                        self.log("< no downlink")
                # log
                if updateTime == True:
                    self.lastUplinkTime = time.time()
                self.log(self.stats())
                time.sleep_ms(10)
                # save frame counters
                self.lora.nvram_save()
                time.sleep_ms(5)
                return responseData
        except Exception as e:
            self.log("ERROR", "Unable to send payload", e.args[0], e)
        return False
Ejemplo n.º 19
0
class LoRa(OutputModule):
    """
    Example of an output module that prints the output to the log.
    """
    def __init__(self):
        super(LoRa, self).__init__()

        # check if safety variable is true
        if not self.config().get("antenna_connected"):
            raise Exception("configuration variable 'antenna_connected' is not true")

        # get the reset cause
        import machine
        reset_cause = machine.reset_cause()

        # initialize lora network
        from network import LoRa as LoRa_drv
        self.lora = LoRa_drv(mode=LoRa_drv.LORAWAN, region=LoRa_drv.EU868, adr=self.config().get("adr"))
        # try to load previous lora connection if waking up from deep sleep
        if reset_cause == machine.DEEPSLEEP_RESET:
            self.lora.nvram_restore()

        if reset_cause == machine.DEEPSLEEP_RESET and self.lora.has_joined():
            log_info("Restored previous LoRaWAN join.")

        else:
            # get authentication parameters
            import ubinascii
            app_eui = ubinascii.unhexlify(self.config().get("app_eui"))
            app_key = ubinascii.unhexlify(self.config().get("app_key"))
            
            # join a network using OTAA (Over the Air Activation)
            self.lora.join(activation=LoRa_drv.OTAA, auth=(app_eui, app_key), timeout=0, dr=self.config().get("data_rate"))

            # wait until the module has joined the network
            log_debug("Waiting until LoRa has joined.")
            while not self.lora.has_joined():
                time.sleep(2.5)
                log_debug("Not joined yet.")
            log_info("Joined LoRa network.")

        # create a lora socket to send data
        import socket
        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.config().get("data_rate"))

        # timer variable for measuring time between send commands
        self.chrono = None



    def send(self, binary, base64, json, json_base64):
        # check minimum time between messages
        min = self.config().get("minimum_time")
        if min != 0:
            # first send call
            if self.chrono == None:
                log_debug("Starting LoRa sending timer.")

                # Import timer
                from machine import Timer
                import time

                self.chrono = Timer.Chrono()

                #Start timer
                self.chrono.start()

            else:
                if self.chrono.read() > min:
                    self.chrono.reset()
                else:
                    log_debug("Minimal time between LoRa sending not reached, skipping.")
                    return

        try:
            # make the socket blocking
            # (waits for the data to be sent and for the 2 receive windows to expire)
            if self.config().get("blocking"):
                self.socket.setblocking(True)

            # send some data
            #s.send(bytes([0x01, 0x02, 0x03]))
            self.socket.send(binary)

            # make the socket non-blocking
            # (because if there's no data received it will block forever...)
            if self.config().get("blocking"):
                self.socket.setblocking(False)

            # get any data received (if any...)
            data = self.socket.recv(64)

            # TODO activate ota mode

            # save lora connection
            self.lora.nvram_save()

        except:
            log_error("LoRa send failed!")

    def test(self):
        pass

    def get_config_definition():
        return (
            "output_lora_otaa",
            "LoRaWAN output module using OTAA.",
            (
                ("antenna_connected", "false", "This variable is for safety reasons to ensure a antenna is connected before LoRa is initialzed.\nWARNING: Setting this to true without an actual antenna connected can destroy your device!", ConfigFile.VariableType.bool),
                #("region", "EU868", "Pick the region that matches where you are using the device:\n\tAsia = 'AS923'\n\tAustralia = 'AU915'\n\tEurope = 'EU868'\n\tUnited States = 'US915'", ConfigFile.VariableType.string),
                ("app_eui", "UNSET", "app eui", ConfigFile.VariableType.string),
                ("app_key", "UNSET", "app key", ConfigFile.VariableType.string),
                ("data_rate", "5", "LoRa data rate. Use a value between 0 and 5.", ConfigFile.VariableType.uint),
                ("adr", "False", "Enables LoRa adaptive data rate. True / False", ConfigFile.VariableType.bool),
                ("blocking", "true", "Wait for data to be sent before continuing.", ConfigFile.VariableType.bool),
                ("minimum_time", "0", "Set minimum time between LoRa messages in seconds", ConfigFile.VariableType.uint)
            )
        )
Ejemplo n.º 20
0
class Comunication:
    def __init__(self):
        self.key = b'encriptaincendis'
        pass

    # Initialize LoRa in LORAWAN mode.
    def JoinLoraWan(self):
        self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)

        # create an OTA authentication params
        app_eui = ubinascii.unhexlify('70B3D57ED001C55E')
        dev_eui = ubinascii.unhexlify(
            '006D2D7767E7BAFE')  # these settings can be found from TTN
        #app_eui = ubinascii.unhexlify('70B3D57ED0019255') # these settings can be found from TTN
        app_key = ubinascii.unhexlify('0A05862CEA15FC56C047FC03FBDF34DB'
                                      )  # these settings can be found from TTN

        # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
        self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)

        # join a network using OTAA
        self.lora.join(activation=LoRa.OTAA,
                       auth=(dev_eui, app_eui, app_key),
                       timeout=0)

        # wait until the module has joined the network
        while not self.lora.has_joined():
            time.sleep(5)
            print('Not joined yet...')

        # remove all the non-default channels
        for i in range(3, 16):
            self.lora.remove_channel(i)

        # 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, 5)

        # make the socket non-blocking
        self.s.setblocking(False)

        time.sleep(5)

    """ Your own code can be written below! """

    def start_LoraRaw(self):
        self.lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.s.setblocking(False)  #Aquesta instrucció igual sobra
        #time.sleep(5)
        lora = self.lora
        #return(lora)
    def savestate(self):
        self.lora.nvram_save()

        # def restorestate(self):
        #     self.lora.nvram_restore()

    def Switch_to_LoraRaw(self):
        self.lora.nvram_save()
        self.lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.s.setblocking(False)  #Aquesta instrucció igual sobra
        time.sleep(5)

    def Switch_to_LoraWan(self):
        self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
        self.lora.nvram_restore()
        time.sleep(5)
        #Si no es reinicia el socket el missatge 3 no s'envia
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)

    def EnviarGateway(self, data):
        self.s.send(data)
        time.sleep(5)

    def RebreGateway(self):
        data, port = self.s.recvfrom(256)
        print(data)

    def sendData(self, misg):
        self.s.setblocking(True)
        iv = crypto.getrandbits(
            128)  # hardware generated random IV (never reuse it)
        cipher = AES(self.key, AES.MODE_CFB, iv)
        msg = iv + cipher.encrypt(misg)
        self.s.send(msg)
        self.s.setblocking(False)
        #print(msg)
        #print(len(msg))
        time.sleep(5)

    def reciveData(self):
        self.s.setblocking(False)
        msg = self.s.recv(128)  #Get any data recieved
        #If there's any data, decrypt
        if len(msg) > 0:
            print("encriptat: ", msg)
            cipher = AES(self.key, AES.MODE_CFB,
                         msg[:16])  # on the decryption side
            original = cipher.decrypt(msg[16:])
            print("original ", original)
            return (original)
        else:
            return
Ejemplo n.º 21
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.º 22
0
fw_version = py.read_fw_version()
print("Pytrack firmware version: " + str(fw_version))
# Get wakeup reason
wakeup = py.get_wake_reason()
print("Wakeup reason: " + str(wakeup) + "; Aproximate sleep remaining: " +
      str(py.get_sleep_remaining()) + " sec")
# Init GPS
gps = L76GNSS(py, timeout=10)
# Init accelerometer
acc = LIS2HH12()
# Init CayenneLPP buffer
lpp = CayenneLPP()
# Init LoRaWAN
lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868, adr=config.ADR)
# Restore LoRaWAN states after deepsleep
lora.nvram_restore()


def blink_led(color, delay=0.2):
    """ blink led for a short time """
    pycom.rgbled(color)
    time.sleep(delay)
    pycom.rgbled(config.COLOR_BLACK)


def check_join():
    """ Join OTAA if not already """
    if not lora.has_joined():
        # print DevEUI
        print("DevEUI: %s" % (binascii.hexlify(lora.mac())))
        app_eui = binascii.unhexlify(config.APP_EUI)
Ejemplo n.º 23
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.º 24
0
class Comunication:
    def __init__(self):
        self.key = b'encriptaincendis'
        self.node_list = ""
        pass

    # Initialize LoRa in LORAWAN mode.
    def JoinLoraWan(self):
        self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)

        # create an OTA authentication params
        app_eui = ubinascii.unhexlify('70B3D57ED001C55E')
        dev_eui = ubinascii.unhexlify(
            '006D2D7767E7BAFE')  # these settings can be found from TTN
        #app_eui = ubinascii.unhexlify('70B3D57ED0019255') # these settings can be found from TTN
        app_key = ubinascii.unhexlify('0A05862CEA15FC56C047FC03FBDF34DB'
                                      )  # these settings can be found from TTN

        # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
        self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)

        # join a network using OTAA
        self.lora.join(activation=LoRa.OTAA,
                       auth=(dev_eui, app_eui, app_key),
                       timeout=0)

        # wait until the module has joined the network
        while not self.lora.has_joined():
            time.sleep(2.5)
            print('Not joined yet...')

        # remove all the non-default channels
        for i in range(3, 16):
            self.lora.remove_channel(i)

        # create a LoRa socket
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)

        # set the LoRaWAN data rate. DR5 means 5470 bits/s ans max payload=230
        self.s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)

        # make the socket non-blocking
        self.s.setblocking(False)

        time.sleep(5)

    def start_LoraRaw(self):
        self.lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.s.setblocking(False)  #Aquesta instrucció igual sobra
        time.sleep(5)
        lora = self.lora
        #return(lora)

    def change_txpower(self, power):
        self.lora.tx_power(power)

    def savestate(self):
        self.lora.nvram_save()

    def Switch_to_LoraRaw(self):
        self.lora.nvram_save()
        self.lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.s.setblocking(False)  #Aquesta instrucció igual sobra
        time.sleep(5)

    def Switch_to_LoraWan(self):
        self.lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
        self.lora.nvram_restore()
        time.sleep(2.5)
        #Si no es reinicia el socket
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        self.s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
        self.s.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, False)

    def EnviarGateway(self, data):
        self.s.bind(2)
        self.s.send(data)
        time.sleep(10)

    def sendData(self, msg, rtc, f):
        if "Hay" not in msg:
            f = open('msg_sent_final.txt', 'a')
            f.write("{}/{}/{} {}:{}:{} msg {} stats {}\n".format(
                rtc.now()[2],
                rtc.now()[1],
                rtc.now()[0],
                rtc.now()[3],
                rtc.now()[4],
                rtc.now()[5], msg, self.lora.stats()))
            f.close()
        self.s.setblocking(True)
        iv = crypto.getrandbits(
            128)  # hardware generated random IV (never reuse it)
        cipher = AES(self.key, AES.MODE_CFB, iv)
        misg_crc = msg + " " + str(self.calculate_crc(msg))
        msg = iv + cipher.encrypt(misg_crc)
        self.s.send(msg)
        #print("missatge amb crc", msg)
        self.s.setblocking(False)
        #print(msg)
        #print(len(msg))
        #time.sleep(5)

    def reciveData(self, rtc, f):
        self.s.setblocking(False)
        msg = self.s.recv(128)  #Get any data recieved
        #If there's any data, decrypt
        if (len(msg) > 0):
            try:
                #print("encriptat: ",msg)
                cipher = AES(self.key, AES.MODE_CFB,
                             msg[:16])  # on the decryption side
                original = cipher.decrypt(msg[16:])
                print("original ", original)
                if "Config" in original or "stop" in original or "Discover" in original or "Hello" in original or "Info" in original or "Token" in original or "Alarm" in original or "Hay" in original:
                    crc_OK, msg = self.check_crc(original)
                    if crc_OK:
                        if "Hay" not in msg:
                            f = open('msg_received_final.txt', 'a')
                            f.write(
                                "{}/{}/{} {}:{}:{} msg {} stats {}\n".format(
                                    rtc.now()[2],
                                    rtc.now()[1],
                                    rtc.now()[0],
                                    rtc.now()[3],
                                    rtc.now()[4],
                                    rtc.now()[5], msg, self.lora.stats()))
                            f.close()
                        return (msg)
                    else:
                        print("CRC not OK")
                        return ("error")
                else:
                    return ("error")
                    print("Keyword not in msg")
            except:
                return ("error")
                print("Exception")
        else:
            return ("error")
            print("Empty msg")

    def update_neighbours(self, pow, id_n, neighbours):
        if id_n in neighbours[0]:
            if pow < neighbours[1][neighbours[0].index(id_n)]:
                neighbours[1][neighbours[0].index(id_n)] = pow
        else:
            neighbours[0].append(id_n)
            neighbours[1].append(pow)
            #print("I have a friend ")
        print(neighbours)
        return neighbours

    def neighbours_min(self, neighbours, neighbours_aux, id):
        for id in neighbours[0]:
            if id in neighbours_aux[0]:
                neighbours[1][neighbours[0].index(id)] = min(
                    neighbours[1][neighbours[0].index(id)],
                    neighbours_aux[1][neighbours_aux[0].index(id)])
        print(neighbours)
        return (neighbours)

    def ApplyFormat(self, splitmsg):
        packet_dust = ustruct.pack('H',
                                   int(splitmsg[3]))  #Unsigned short 2 bytes
        packet_tempC = ustruct.pack('H', int(splitmsg[4]))
        packet_Tht = ustruct.pack('H', int(splitmsg[5]))
        packet_Hht = ustruct.pack(
            'B', round(int(splitmsg[6]) *
                       100))  #Form 0 to 1 -> 0% to 100% #Unsigned char 1 byte
        packet_tbmp = ustruct.pack('H', int(splitmsg[7]))
        packet_val = ustruct.pack('H', int(splitmsg[8]))
        packet_dhi = ustruct.pack('B', int(splitmsg[9]))
        #+packet_TCam=ustruct.pack('f',int(splitmsg[10]))
        #id=splitmsg[1].encode('utf-8')
        id_aux = ustruct.pack('>Q', int(splitmsg[1], 16))  #long long: 8 bytes
        return (packet_dust + packet_tempC + packet_Tht + packet_Hht +
                packet_tbmp + packet_val + packet_dhi + id_aux)  #+packet_TCam)

    def calculate_crc(self, msg):
        """
        Compute CRC
        """
        if type(msg) == bytes:
            msg = bytes.decode(msg)
        crc = 0
        data = bin(int(binascii.hexlify(msg), 16))
        data = str.encode(data)
        for i in range(len(data)):
            byte = data[i]
            for b in range(8):
                fb_bit = (crc ^ byte) & 0x01
                if fb_bit == 0x01:
                    crc = crc ^ 0x18
                crc = (crc >> 1) & 0x7f
                if fb_bit == 0x01:
                    crc = crc | 0x80
                byte = byte >> 1
        return crc

    def check_crc(self, msg):
        """
            Check if CRC received is correct
            """
        if type(msg) == bytes:
            msg = bytes.decode(msg)
        splitmsg = msg.split()
        crc_rcv = int(splitmsg[-1])
        aux = " ".join(splitmsg[:-1])  #Not including the CRC received
        crc_new = self.calculate_crc(aux)
        return (crc_new == crc_rcv, aux)

    def get_node_list(self, list):
        self.node_list = list
Ejemplo n.º 25
0
class Node:
    def __init__(self, data_rate, py):
        self.lora = None  # Instancia de Lora (sin inicializar)
        self.s = None  # Instancia Socket (sin inicializar)
        self.dr = data_rate  # Data Rate (defecto 5)
        self.py = py  # Instancia de Pysense
        self.acc = LIS2HH12(self.py)  # Instancia del Acelerometro
        self.last = [0, 0, 0]  # Último valor leído de aceleracion
        self.raw = [0, 0, 0]  # Valor leído actual de aceleracion
        self.busy = 0  # Value has passed limit
        self.interval = 10  # Intervalo de toma de datos
        self.battery = None  # Valor de la tensión de batería
        self.s_lock = _thread.allocate_lock()  # Semaforo para envío
#------------------------------------------------------------------------------#

    def connect(self, dev_eui, app_eui, app_key):
        """
        Connect device to LoRa.
        Set the socket and lora instances.
        """
        # Initialize LoRa in LORAWAN mode
        self.lora = LoRa(mode=LoRa.LORAWAN, device_class=LoRa.CLASS_A)
        # Set the 3 default channels to the same frequency (must be before
        # sending the OTAA join request)
        self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)
        # Join a network using OTAA (Over the Air Activation)
        self.lora.join(activation=LoRa.OTAA,
                       auth=(dev_eui, app_eui, app_key),
                       timeout=0,
                       dr=5)  #login for TheThingsNetwork see here:
        #https://www.thethingsnetwork.org/forum/t/lopy-otaa-example/4471
        # Wait until the module has joined the network
        while not self.lora.has_joined():
            print("Trying to join LoraWAN with OTAA")
            time.sleep(2.5)
        print("LoraWAN joined! ")
        #Handler de Recepción
        #self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT),handler=self.lora_cb)
        # save the LoRaWAN connection state
        self.lora.nvram_save()
#------------------------------------------------------------------------------#

    def send(self, data):
        """
        Send data over the network.
        """

        self.s_lock.acquire(
        )  # Espera a que el semáforo esté disponible (tiempo indefinido)

        if py.get_wake_reason(
        ) == WAKE_REASON_ACCELEROMETER:  #Si despierta tras deepsleep
            # Initialize LoRa in LORAWAN mode
            self.lora = LoRa(mode=LoRa.LORAWAN,
                             adr=True,
                             device_class=LoRa.CLASS_A)
            # restore the LoRaWAN connection state
            try:
                self.lora.nvram_restore()
            except OSError:
                print("Error: LoRa Configuration could not be restored")
                self.connect(
                    binascii.unhexlify('006A76B0778AEDA7'),
                    binascii.unhexlify('70B3D57ED0009ABB'),
                    binascii.unhexlify('08D62712D816F1C28B7E6EA39E711209'))
                print("LoRa Connection Parameters Recovered")
        for i in range(3, 16):
            self.lora.remove_channel(i)
        # Set the 3 default channels to the same frequency
        # (must be before sending the OTAA join request)
        self.lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
        self.lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)
        # Create a LoRa socket
        self.s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
        print("Created LoRaWAN socket")
        # Make the socket non-blocking
        self.s.setblocking(True)

        try:
            self.s.send(data)
            self.s.setblocking(False)  #Espera para posible recepción
            rx = bytes(self.s.recv(128))  #Recepción de datos
            self.receive(rx=rx)
            self.lora.nvram_save()
        except OSError as e:
            if e.errno == 11:
                print("Caught exception while sending")
                print("errno: ", e.errno)

        self.s_lock.release()  #Libera el semáforo
        _thread.exit()  #Cierra el hilo

#------------------------------------------------------------------------------#
#Función de recpeción de datos.Es activada tras la ventana de recepción
#posterior al envío.

    def receive(self, rx=None):
        if len(rx) == 0:  #No hay mensaje de recepción
            pass
        else:
            if rx[0] == 82:  #Orden de Cambio Data Rate (ASCII hex R=0x52 dec 87)
                print("Cambiando Data Rate %d" %
                      (int.from_bytes(rx[1:], 'big')))
                self.dr = int.from_bytes(
                    rx[1:], 'big')  #Decodifica el valor del nuevo data Rate
                pycom.nvs_set('data_rate', self.data_rate)  #Lo guarda en NVRAM
            else:
                pass
#------------------------------------------------------------------------------#
#Función de lectura de medidas. Los sensores ya han sido inicializados al
#crear la instancia de la clase Node

    def readsens(self):
        self.raw = self.acc.acceleration(
        )  # Devuelve tuple con aceleracion en tres ejes (G)
        print("Aceleracion-> X:%fG Y:%fG Z:%fG" %
              (self.raw[0], self.raw[1], self.raw[2]))
        #Cálculos
        #if (self.raw[0] > 2.1) or (self.raw[1] > 2.1) or (self.raw[2] > 2.1):
        #        print("Enviando datos")
        #        XR=int(self.raw[0]*10000).to_bytes(2,'little')
        #        YR=int(self.raw[1]*10000).to_bytes(2,'little')
        #        ZR=int(self.raw[2]*10000).to_bytes(2,'little')
        #        XL=int(self.last[0]*10000).to_bytes(2,'little')
        #        YL=int(self.last[1]*10000).to_bytes(2,'little')
        #        ZL=int(self.last[2]*10000).to_bytes(2,'little')
        #        data = XR+YR+ZR+XL+YL+ZL
        #        _thread.start_new_thread(self.send,data)                        # Se crea un hilo para el envío de valores
        self._compare_update()
        alarmaPub = Timer.Alarm(self.readsens(), 10, periodic=False)
        #if (self.raw[0] < 1.5) and (self.raw[1] < 1.5) and (self.raw[2] < 1.5):
        #    alarmaPub.cancel();
        #    n.py.setup_int_wake_up(rising=True,falling=False)                   #Activa la interrupcion para el boton DEBUG
        #    print('Activada Interrupccion de Actividad')
        #    n.acc.enable_activity_interrupt(1500,100)                           #Threshold= 1,5G, Min Time = 100ms
        #    print("Going to Sleep")
        #    n.py.setup_sleep(300)
        #    n.py.go_to_sleep()

        #self.battery = round(self.py.read_battery_voltage(),2)
        #print("Battery: %f",%(self.battery))
        #if (self.battery < 3.4):
        #    print("Batería Crítica")
        #    _thread.start_new_thread(self.send,("Batería"," Crítica"))          # Se crea un hilo para el envío de alarma de batería

#------------------------------------------------------------------------------#

    def _compare_update(self):
        if self.raw is not self.last:
            self.last = self.raw
        else:
            pass