MachineQ Developer Documentation logo DOCS

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_id identifying the target devices. See Quick Start Guide.
  • $MQ_TOKEN exported 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, and successful_count, plus failed_devices and successful_devices lists. 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.

FUOTA ServerDeviceFUOTA ServerDeviceReliable Downlink Job is Createdif retry > max_retriesDevice Failloop[until sent max_retries downlinks]if expected_uplink_hex == received_uplink_hexDevice SuccessotherwiseDevice Failloop[Every Device]send downlink_hex on downlink_fport1Wait retry_interval2uplink on expected_uplink_fport3

Recommendations

  1. 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.
  2. Avoid short retry_interval values. Combined with a low max_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_interval could 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.

Create the reliable downlink job
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:

Inspect the create job response
{
  "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:

Check the reliable downlink job status
curl -sS "https://fuota.machineq.net/api/v3.2/reliable_downlink/SuTJ5h" \
  -H "Authorization: Bearer $MQ_TOKEN" | jq
Inspect the job status response
{
  "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?