Downlink Queue Clarification Wanted (first, last, replace) (Regarding Ports)

Hello TTN friends!

I have a question, that might be of interest in general.

How are the downlink flags first, last and replace used?

  1. I am pretty sure each downlink queue is specific per device.
  2. I think there is also a downlink queue for each port, is that correct? (So I might replace downlinks on one port while queuing them on another)
  3. The replace option seems to replace the whole downlink queue for one device on one port, is that correct?

Thank you for your help. I know I could test this - but I would feel better if I had official information on this and the behaviour is well defined (and later maybe added to the documentation :wink: ).

Best regards, Hendrik

Ok, answering myself after testing:
There is only one queue per device. Pushing a downlink message with the “replace” option to the queue clears the whole queue leaving only this message to be downloaded.

Leads me to reformulate my desire:
How about having the option to replace a downlink message of a specific port?!
Is that possible? How? If not, I would really like that.

Imagine you have a node and several configurations and commands you can send to it on different ports. Your device only gives an uplink once per hour. You send a command to port 15 to it (e.g. play buzzer sound after next downlink), 5 minutes later you change some configuration (e.g. set temperature alarm threshold to 30°C) on port 20. But thinking of it, you prefer the threshold to be 33°C 5 more minutes later, change that and QUEUE the downlink. Because if you did choose replace, the first command would be deleted and not sent down to the node. However, now you have the situation that your device will play the buzzer, then (1 hour later) set the threshold to 30°C (which you didn’t like, but you queued it), just to wait 1 more hour to have your favorite setting (33°C) being sent down.

Your application is not fast enough to respond to an uplink and create a downlink to the latest setting, you need the TTN queue.

One solution could be to buffer the downlink queue in your application, modify it there and always push a new queue (first one with the “replace” flag, the other messages appended with the “last” option set) to TTN, which does not seem so elegant.

How about an extra flag:
• replace
• first
• last
replace_for_this_port (replacing all other messages of this port, taking the queue position of the first message of this port)

Is that too specific or do others see value in this, too?

Thank you!

Heads up: V3 only supports push and replace, along with priorities.

(See also the comments in issue #1948. And aside: you’re limited to 10 downlinks per day; you may want to rethink your use case if managing the downlinks proves to be hard.)

1 Like

Hi Arjan,

thank you for the answer. Yes, probably new features shall not be expected in V2, you are right. And if V3 does not support differentiated port handling (yet?) we probably go best with managing updated downlinks ourselves.

And yes, I know the rules. :wink: Replacing downlink messages would even help to reduce downlinks. And as a software-developer I should consider the situation described above, nonetheless - even if it happens once a year.

If one often has multiple configuration commands to send, then combining multiple commands into a single downlink can reduce the total airtime: the additional bytes needed to identify some command type are easily compensated by sharing the 13 bytes LoRaWAN overhead among multiple commands.


That doesn’t really make any sense.

Ports have no real meaning in terms of the opportunity to send a message - you don’t get more opportunities because the data is addressed to different ports.

All a “port” really is is an expansion of the “protocol vs user” identifier bit on traffic to allow distinguishing multiple types of user traffic.

One solution could be to buffer the downlink queue in your application, modify it there and always push a new queue (first one with the “replace” flag, the other messages appended with the “last” option set) to TTN, which does not seem so elegant.

Actually it is far better - it only looks inelegant from the Internet perspective, but that’s of no consequence in comparison to the way it lets you batch the message for efficient transmission over LoRaWAN in a single downlink as Arjan points out - and LoRaWAN is so many orders of magnitude more limited than the Internet that it’s worth the Internet-side inefficiency.

Granted to batch the downlink you’d have to combine them on a single port. But you can certainly invent an efficient coding scheme for the types of things you’ve described, down to bit level. You may even have enough codespace to use (the allowed range of) the port field as a bitmap indicating which message types are present.


Genius - will be dreaming up ways of leveraging this!

1 Like

Thank you for elaborating on this, @cslorabox - very valuable inspiration. :+1:

Let me put this in an example for my own (and others) understanding:
The idea could be to have but always one downlink message in the queue. If I want to send commands, it is the command downlink message on port e.g. 1 (with 2 byte payload), if I only have configurations to send I send the configuration message on port 2 (with 5 byte payload), if I have to change both, I use port 3 and a combined message type (with 7 byte payload).
The node will untangle this, and could reuse decoding schemes (with a 2 byte shift on port 3).

The only thing needed then would be to know if my last downlink was send or not, but this could be retrieved from the TTN API (at least in V3 stack, as far as I can see) or a confirmed downlink. (To know if commands have been sent when I want to change configuration, to distinguish between sending only configurations afterward or prepare the combined message from the previously queued command plus my configuration.)

Thank you, thank you, thank you @cslorabox and @arjanvanb. This will become a nice way of downlink handling.

If you are processing commands on the node, why not add an id in the message that the node sends back on a command ack port - or even the current configuration - so you know not only that it received it OK but it has processed it & implemented it OK


This is actually how we handle the configuration setting. :wink: We compare if the configuration on the mobile App is the same as the last configuration received from the device. If it differs - a configuration message with the desired configuration from the mobile App is created and queued (soon using the process described above).

A simple confirmation acknowledge would not have been enough, because the device dictates the configuration limits and may not accept or modify the desired configuration values. Of course the App should limit the possible user input to these values, too… but: just avoid possible mistakes! Or the mobile device might not know some dynamic config limits (due to the node’s temperature or other sensors’ input etc.).
You then just need to take care that the config uplink resets the desired values in the application, not to trigger an endless config download, because of differing values.

In agreement with what Nick said, it’s probably going to turn out better to do your downlink confirmation with some custom bit(s) in your uplink message rather than use the LoRaWAN “confirmed downlink” capability, as you end up with more ability to tune the exact behavior to your needs.

Note however that you’re likely to end up with a pipeline of steps spread over a substantial amount of time:

uplink packet
see something you want to change, queue it

uplink packet
downlink packet
(have to remember it’s in progress here)

uplink packet
oops, that doesn’t confirm the desired change, maybe dl was missed, queue a new one

uplink packet
downlink packet
(have to remember it’s in progress here…)

uplink packet
yes, the change is confirmed