I lose many packages in Lora



  • Hello! I'm having some troubles with LoRa uplinks and I'm not sure if it's my fault (probably) or what's happening.

    Basically the problem is that I send some data, and always the lora.event() says "Lora packet sent", but sometimes (to much times) the packet never arrive to my server (I'm not using TTN).

    It's weird because if the packets never arrived, I would understand that it is my code or maybe the antenna. But in this case sometimes yes, sometimes no ...

    Some idea?

    My code is made based on the own examples offered by Pycom.

    class myLoRa:
    
        def __init__(self):
            # LoRa device parameters
            self.dev_eui = config.dev_eui
            self.app_eui = config.app_eui
            self.app_key = config.app_key
    
            #
            self.frequency = config.LORA_FREQUENCY
            self.dr = config.LORA_NODE_DR
            self.region =  config.lora_region
            self.lora_class = config.lora_class
            self.lora_sf = config.lora_sf
    
            # Initialize LoRa in LORAWAN mode.
            self.lora = LoRa(
                mode=LoRa.LORAWAN, region=self.region,
                device_class=self.lora_class,
                tx_retries = 3,
                adr=False, sf=self.lora_sf)
    
            # Understand the events during LoRa comunication
            self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT | LoRa.TX_FAILED_EVENT), handler=self.lora_events)
    
        def LoRa_join(self):        
            # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
            self.lora.add_channel(0, frequency=self.frequency, dr_min=0, dr_max=5)
            self.lora.add_channel(1, frequency=self.frequency, dr_min=0, dr_max=5)
            self.lora.add_channel(2, frequency=self.frequency, dr_min=0, dr_max=5)
    
            # join a network using OTAA
            self.lora.join(
                activation=LoRa.OTAA,
                auth=(self.dev_eui, self.app_eui,self.app_key),
                timeout=0,
                dr=self.dr)
            
            # wait until the module has joined the network
            cnt = 0
            while not self.lora.has_joined():
                time.sleep(2.5)
                if config.debug:
                    print('\t\t· Trying to join...', str(cnt))
                if (cnt < 30):
                    cnt += 1
                else:
                    machine.reset()
    
            # remove all the non-default channels
            for i in range(3, 16):
                self.lora.remove_channel(i)
    
        def LoRa_socket(self):
            # create a LoRa socket
            self.lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
            # set the LoRaWAN data rate
            self.lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, self.dr)
            # make the socket non-blocking
            self.lora_socket.setblocking(False)
    
        def LoRa_send(self, payload):
            self.lora_socket.send(payload)
    
        def lora_events(self, lora):
            events = self.lora.events()
            if events & LoRa.RX_PACKET_EVENT:
                if config.debug:
                    print('\t\t· Lora packet RECEIVED')
                self.lora_socket.setblocking(False)
                value = self.lora_socket.recv(64)
                self.lora_socket.setblocking(True)
                self.LoRa_downlink_handler(value)
    
            if events & LoRa.TX_PACKET_EVENT:
                if config.debug:
                    print('\t\t· Lora packet sent')
    
            if events & LoRa.TX_FAILED_EVENT:
                if config.debug:
                    print('\t\t· Lora packet sent FAIL')
    

    I will appreciate any comments, because losing data is not an option and the server api does not allow knowing if the data has arrived or not, thank you very much!



  • @M-m unless you tell us what region you are in and the settings of your network+gateway (and the packet loss you observed, ideally with logs showing channels used), I think it’s going to be very difficult to know what your configuration should be and why those changes help (or if another configuration would help even more).



  • I'm not sure to understand the solution but I have modified the lora configuration and now seems works better.

    The changes are:

    • Remove the channels config.
    • Modify the socket.
    class myLoRa:
    
        def __init__(self):
            # LoRa device parameters
            self.dev_eui = config.dev_eui
            self.app_eui = config.app_eui
            self.app_key = config.app_key
    
            #
            self.frequency = config.LORA_FREQUENCY
            self.dr = config.LORA_NODE_DR
            self.region =  config.lora_region
            self.lora_class = config.lora_class
            self.lora_sf = config.lora_sf
    
            # Initialize LoRa in LORAWAN mode.
            self.lora = LoRa(
                mode=LoRa.LORAWAN, region=self.region,
                device_class=self.lora_class,
                tx_retries = 3,
                adr=False, sf=self.lora_sf)
    
            # Understand the events during LoRa comunication
            self.lora.callback(trigger=(LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT | LoRa.TX_FAILED_EVENT), handler=self.lora_events)
    
        def LoRa_join(self):        
            # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
            """self.lora.add_channel(0, frequency=self.frequency, dr_min=0, dr_max=5)
            self.lora.add_channel(1, frequency=self.frequency, dr_min=0, dr_max=5)
            self.lora.add_channel(2, frequency=self.frequency, dr_min=0, dr_max=5)"""
    
            # join a network using OTAA
            self.lora.join(
                activation=LoRa.OTAA,
                auth=(self.dev_eui, self.app_eui,self.app_key),
                timeout=0,
                dr=self.dr)
            
            # wait until the module has joined the network
            cnt = 0
            while not self.lora.has_joined():
                time.sleep(2.5)
                if config.debug:
                    print('\t\t· Trying to join...', str(cnt))
                if (cnt < 30):
                    cnt += 1
                else:
                    machine.reset()
    
            # remove all the non-default channels
            """for i in range(3, 16):
                self.lora.remove_channel(i)"""
    
        def LoRa_socket(self):
            """self.lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
            self.lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, self.dr)
            self.lora_socket.setblocking(False)"""
            self.lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
            self.lora_socket.setsockopt(socket.SOL_LORA,socket.SO_CONFIRMED,True)
            self.lora_socket.setblocking(True)
    
        def LoRa_send(self, payload):
            self.lora_socket.send(payload)
    
        def lora_events(self, lora):
            events = self.lora.events()
            if events & LoRa.RX_PACKET_EVENT:
                if config.debug:
                    print('\t\t· Lora packet RECEIVED')
                self.lora_socket.setblocking(False)
                value = self.lora_socket.recv(64)
                self.lora_socket.setblocking(True)
                self.LoRa_downlink_handler(value)
    
            if events & LoRa.TX_PACKET_EVENT:
                if config.debug:
                    print('\t\t· Lora packet sent')
    
            if events & LoRa.TX_FAILED_EVENT:
                if config.debug:
                    print('\t\t· Lora packet sent FAIL')
    

    As I said I really don't know why this works better, but I'll leave it here in case someone has similar problems and needs it in the future.

    And if somebody can explain me the difference between my first code and this one, I'll be glad. Because I hate doing things without understanding.

    Thanks for the answers!!!



  • @M-m what region are you in and what gateway and network server are you using?

    If your use a another LoPy as a nano-gateway then you have to send all traffic on a single channel. That means removing all existing channels then adding the 3 default channels with the same frequency (the one the gateway is listening on). The network must also send correct channel information (or you need to set the channels again before each send).

    If you are using a “real” gateway but are in a region where there are more than 9 channels (e.g. US915, AU915...) then you need to do find out the channels the gateway/network are listening on (usually a set of 8 or 9 channels), and remove all channels not in the set. The network must likewise send the correct info to the device, or you may need to set the channels again.

    You’ll need to tell us the region, the gateway, the gateway settings (if you are operating it yourself), the network server and its settings (ditto) or the network you use and its frequency plan otherwise.

    Note that if losing packets is not an option then LoRa is probably not the best solution. It is really a best-effort network. You can set packets to be “confirmed” but there are in many regions strict limits on their use which make them often unusable.

    Also, how often are you sending, how much data, and at what data rate? Also, what’s your observed packet loss rate?


  • Global Moderator

    Of course, we can assume LoRa is not 100% reliable, but Im not sure about the packet loss you are describing.
    It could be the case that other devices are also using the ISM band simultaneously, causing interference. There can be many causes for a packet to be sent out, but never received. Also, make sure to attached the correct antenna to the correct port.

    I assume you are using a local gateway to receiver the packets. Do you have any view on the RSSI / SNR of the packets that do get received, and compare that to the distance to the gateway so we can make a logical assumption there.


Log in to reply
 

Pycom on Twitter