Reliable Downlinks
Many LoRaWAN devices support bi-directional communication using downlinks: changing device configuration, turning on a light, or adjusting a valve. The device typically confirms the change with an uplink. Because downlinks may be lost due to radio interference, the Reliable Downlink service provides an easy interface to send a downlink and ensure the device responds with the expected payload, retrying at a configurable interval. This guide explains how the service works and how to configure it.
Before You Begin
You need:
- The downlink payload and FPort you want to send, plus the expected uplink payload and FPort the device responds with. These are device- and application-specific: consult the device manual.
- A list of DevEUIs or a
device_group_ididentifying the target devices. See Quick Start Guide. $MQ_TOKENexported from the authentication step. See Quick Start Guide.
How It Works
Initiate the reliable downlink job with the create job API. The response contains a job_id you use later to get the status of the job.
| Field | Required | Description |
|---|---|---|
downlink_hex, downlink_fport |
Yes | The downlink message for the device. |
expected_uplink_hex, expected_uplink_fport |
Yes | The expected payload response from the device. |
name |
Yes | The name of the job. |
devices or device_group_id |
Yes | One (or both) must be provided to know which devices to include. |
max_retries |
No | How many times to retry sending downlink_hex if the expected uplink is not received. Default: 10. |
retry_interval |
No | The delay between retries, in seconds. Should be equal to or slightly lower than the average transmit period of the devices. Default: 30 seconds. |
Note: After you create the job, retrieve its status with the get job API. The response contains
device_count,failed_count, andsuccessful_count, plusfailed_devicesandsuccessful_deviceslists. Any device not in either list is still in progress.
State Transition
Note: The FUOTA server listens for uplinks asynchronously. The uplink can arrive right after the downlink (for example, with Class C devices). If the FPort and payload match, the server cancels the pending retry/wait.
Recommendations
- Batch end devices when the downlink and uplink contents are identical. Avoid creating a reliable downlink job for each individual DevEUI. For example, an automated system might capture all devices of a type with the wrong configuration; create arbitrary batching criteria such as every 24 hours or every 100 devices, and create a job when the batch meets the requirement.
- Avoid short
retry_intervalvalues. Combined with a lowmax_retries, the job might fail faster than most devices send their uplinks.- For Class A devices, values substantially lower than the average transmission period have little effect, because the network server only sends downlinks after the device sends an uplink.
- For Class C devices, a short
retry_intervalcould cause radio interference and occupy the radio, because the network server sends downlinks immediately. This can reduce the gateways' chances of receiving uplinks, especially on half-duplex gateways.
Example
Suppose you discovered five MQflexes running a non-standard configuration and want to apply the standard configuration by sending a downlink on FPort 221 (set config) with the payload 0101C20200E103C8050100. Per the MQflex manual, each device responds with the same payload in the very next uplink, also on FPort 221.
Because some flexes transmit every 6 hours and others every 15 minutes, configure max_retries at 23 and retry_interval at 3600 (1 hour) to ensure each device applies the config within a 23-hour period.
curl -sS -X POST "https://fuota.machineq.net/api/v3.2/reliable_downlink" \
-H "Authorization: Bearer $MQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"devices": ["2CC407FFFE500C3F", "2CC407FFFE500BDC", "2CC407FFFE500C02", "2CC407FFFE500C04", "2CC407FFFE500C05"],
"downlink_fport": 221,
"downlink_hex": "0101C20200E103C8050100",
"expected_uplink_fport": 221,
"expected_uplink_hex": "0101C20200E103C8050100",
"max_retries": 23,
"retry_interval": 3600,
"name": "Reliable Downlink Demo"
}' | jq
The API response echoes the job and includes the job_id:
{
"name": "Reliable Downlink Demo",
"downlink_hex": "0101C20200E103C8050100",
"downlink_fport": 221,
"expected_uplink_hex": "0101C20200E103C8050100",
"expected_uplink_fport": 221,
"devices": [
"2CC407FFFE500C04",
"2CC407FFFE500BDC",
"2CC407FFFE500C02",
"2CC407FFFE500C05",
"2CC407FFFE500C3F"
],
"device_group_id": null,
"max_retries": 23,
"retry_interval": 3600,
"job_id": "SuTJ5h",
"created_at": "2024-03-07T21:33:32.661293Z"
}
Use the job_id to check the status of the command:
curl -sS "https://fuota.machineq.net/api/v3.2/reliable_downlink/SuTJ5h" \
-H "Authorization: Bearer $MQ_TOKEN" | jq
{
"name": "Reliable Downlink Demo",
"job_id": "SuTJ5h",
"successful_devices": [
"2CC407FFFE500C05",
"2CC407FFFE500C02",
"2CC407FFFE500BDC",
"2CC407FFFE500C04",
"2CC407FFFE500C3F"
],
"failed_devices": [],
"device_count": 5,
"successful_count": 5,
"failed_count": 0
}
What's Next?
- Quick Start Guide: Authenticate and learn basic API usage.
- Managed Campaigns: Automate firmware upgrades across many devices.
- Troubleshooting: Diagnose why a device did not respond as expected.