Update Protocol

Drogue Ajour uses a custom application level protocol sent on a special 'dfu' channel in Drogue Cloud to communicate with a device or gateway. The protocol is stateless, meaning that Drogue Ajour will track only send out firmware updates to devices that are reporting their status.

The protocol is designed so that devices do not have to be online continuously during the update, but can receive firmware at their own pace.

The protocol uses Consise Binary Object Representation (CBOR), to ensure a small message size that works well with embedded devices.

Update protocol

The above sequence diagram corresponds to the example messages below. For descriptive purposes, the examples here are provided in JSON.

A typical firmware update cycle runs as follows:

  1. At any given time, a device publishes message to the 'dfu' channel with the following payload

    {
       "version": "0.1.0",
       "correlation_id": 1 // Optional: Opaque request identifier, for devices that aggregate multiple updates
       "mtu": 512, // Optional: The desired block size to use for firmware blobs
    }

    This allows the Drogue Ajour to check if an update is necessary at all.

  2. Drogue Ajour checks the desired firmware for that particular device and will attempt to locate it in the firmware registry.

    1. If the device is already updated, a 'dfu' command is sent to the device with the following payload:

      {
        "sync": {
          "version": "0.1.0", // Desired firmware version
          "correlation_id": 1 // Optional: Should be set to the id from the device status
          "poll": 300, // The amount of time to wait before checking in again
        }
      }
    2. If a device needs to be updated, a 'dfu' command is sent to the device with the following payload

      {
        "write": {
          "version": "0.1.1", // Version of blob
          "offset": 0, // Offset this blob should be written to
          "data": aGVsbG8= // Base64-encoded firmware block (Binary in CBOR)
        }
      }
    3. If there is no new information about firmware, and server needs the client to wait before asking again, a 'wait' command is sent.

      {
        "write": {
          "poll": 300, // The amount of time to wait before checking in again
        }
      }
  3. Device receives command

    1. When a device is seeing the "sync" operation, it should make sure it’s current firmware version is marked as 'good' if it have not already done so. The 'poll' field can be used as a heuristic of how long the device should wait before checking in again.

    2. When a device is seeing the "write" operation, it should write the provided data to it’s storage. Once persisted, it should report back the next expected offset and last received version:

      {
         "version": "0.1.0",
         "mtu": 512, // The desired block size to use for the next firmware block
         "status": {
            "version": "0.1.1", // Version of the last block the device received from the server. To safeguard against new versions arriving
            "offset": 512, // Current write offset after applying the last firmware block.
         }
      }
  4. Server receives status event

    1. If device is in sync, optionally reply with a sync command indicating the delay before polling again.

    2. When the server receives the next event from the device, it repeats the previous write step until the complete firmware have been sent. When the final block is confirmed written, and it is desired to deploy the new firmware, the fleet-manager will send the following command:

      {
        "swap": {
          "version": "0.1.1",
          "checksum": "097d501382f5817eb2c5f741d37845158c76dd6a8af899001b36b5a75188aeeb"
        }
      }
  5. Device receives command

    1. When the device receives the 'swap' command, it should initiate the firmware update and report back with the updated version as soon as it’s back online.