LoPy: Confirmed Downlink not supported by design?

  • Hi,
    what I do:

    I am sucessfully sending message to LoPy:

    <code>{“fPort”:1,“data”:“bGVkRW5hYmxlLHRydWU=” , “confirmed”: true}</code>

    This results in server sending the same message in all subsequent session, obviously because LopY does not send ACK for confirmed messages. Effect is similar to one depicted here: https://forum.pycom.io/topic/2135/solved-lopy-otaa-downlink-message-always-repeated

    Observed result is:

    • LoPy receives message correctly but does not send any confirmation by default to LoRa Server.

    Expected result is:

    • Lopy sends ACK to the lora server as to the LoRaWAN 1.1 standard, either always on confirmed type message or by an user: by the code, using methods
    • method available to construct appropriate ACK message, method should expose original message ID and other data required in confirmation

    I am running LoPy release=1.8.0.b1 and custom LoRa Server.

    Can I somehow possibly solve this? am I missing something obvious? was this subject ever on this list?

    Best regards.

    Relevant code:

        s.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, True)
        data = s.recv(242)
        key = (data.decode('utf-8')).split(',')[0]
        logext('SENDRECEIVE: New configuration data: ' , (binascii.unhexlify(binascii.hexlify(data))))```

  • That's correct, the ack will only be sent with the next uplink

    Where is a gotcha (at least it was to me): once the data is received, typically LoPy goes to deepsleep. Once it does, it forgets the previous session and starts the new one without confirmation.

    Indeed this was a problem, but from the upcoming firmware release on it won't - we now save the pending ack status of downlinks as well when using nvram_save(), so if you use nvram_restore after restarting from deepsleep the LoPy will know to send the acknowledgement with the next uplink.

    This is already in our internal code and will be public on the next release.

  • @charly86 ,

    @jmarcelino won't help you more at all IMHO, as he already wrote it all here: "As you know the LoPy will only ack the received downlink on the next uplink".

    And I tracked this down carefuly and it is seems all is fine with your / my code, it is how LoPy which had implemented standard.

    How it works: server sends confirmed downlink. This results in succcessfuly triggered event by LoRa event handler, if you would use it, you can log it easily.

    However, there is no immediate confirmation send back to the server from LoPy, and it is correct as to the standard. LoRaWAN 1.1 and 1.0 says that confirmation can be send immediately or in the next device session, and LoPy indeed sends confirmation in the next session.

    Where is a gotcha (at least it was to me): once the data is received, typically LoPy goes to deepsleep. Once it does, it forgets the previous session and starts the new one without confirmation.

    Now, since device did not confirm the message to the server, server tries to resend it (or in the newest Brocaar versions it removes the payload from the queue and leaves the decistion what to do next to your application).

    So the solution I implemented was to detect confirmed payload (downlink) and send empty information to the server subsequently within the same session.

    The question is: is this behaviour correct? to me - it is OK. Can it be solved differently - maybe.

  • @jmarcelino

    Did you tried confirmed downlink, if so would you mind sharing your code? I have the same issue (latest firmware as today) but I'm sure problem is on my code. May be I need to send another uplink after received downlink?

        action = wait_serial_data()
        if action != None:
          if action >=0 and action <=3:
            payload = struct.pack(">BHB", action, int(value*100),  onoff)
          elif action == 10:
            payload = struct.pack(">BhB", action, int(temp*10), int(hum*2))
          action = None
          print("Sending LORA Packet")
          led.hl(led.MAGENTA, 10)
          # make the socket blocking
          # (waits for the data to be sent and for the 2 receive windows to expire)
          # send some data
          # make the socket non-blocking
          # (because if there's no data received it will block forever...)
          # get any data received (if any...)
          data = s.recv(64)
          lg = len (data)
          if lg > 0:
            cmd, val = unpack('>BB', data)
            if cmd == 1:
      except Exception as e:

    Let me know if you got it ;-)

  • @jmarcelino

    Hi, thanks, indeed. Changed to not deepsleep but wait. Can you point how to check if the receive window has been finished or ack has been received successfully so I do not wait longer than it is needed?

  • @stefanbrudnz
    Thanks for the question, confirmed downlinks were working the last time I tested them - not long ago.
    Just some queries:
    Have you tried a more recent firmware? LoPy release=1.8.0.b1 is now 3 months old.

    Also are you doing anything after receiving the downlink such as going to sleep etc? As you know the LoPy will only ack the received downlink on the next uplink so I'm trying to understand if that information may have been lost.

    In any case I will test this again tomorrow.

    Ps: the LoRaWAN 1.1 standard is not a good reference as both the LoPy and LoRa Server only follow LoRaWAN 1.0.2. As far as I know there are no devices or network servers implementing 1.1 yet.

Pycom on Twitter