All Products
Search
Document Center

IoT Platform:OTA updates for devices

Last Updated:Sep 03, 2023

IoT Platform allows you to download and update device firmware using Over-the-Air Technology (OTA).

Background information

The following figure describes the process of updating the firmware based on the Message Queuing Telemetry Transport (MQTT) protocol.

OTA update process

  • OTA APIs can be used to implement automatic downloads for firmware updates on devices. However, the storage and installation of the update package must be managed by the user.

  • You must specify the storage location of the downloaded package. You can specify a medium such as the flash memory of the device to store the downloaded package.

  • To install or use the downloaded package, user interaction is required. For example, you must click a button to perform the update.

You can implement OTA updates by using basic APIs or advanced APIs. The following procedures provide examples on the two methods.

Using basic APIs

The following procedure uses src/ota/examples/ota_example_mqtt.c to describe how to implement an OTA update by using basic APIs.

  1. Prepare for connecting the device to the OTA service. Import the device trituple, and configure required parameters for the connection.

    int main(int argc, char *argv[]) {
        ...
        /**< get device info*/
        HAL_SetProductKey(PRODUCT_KEY);
        HAL_SetDeviceName(DEVICE_NAME);
        HAL_SetDeviceSecret(DEVICE_SECRET);
        /**< end*/
        _ota_mqtt_client()
    }
  2. Call the _ota_mqtt_client function to configure the OTA logic and establish the connection.

        /* Device AUTH */
        if (0 != IOT_SetupConnInfo(g_product_key, g_device_name, g_device_secret, (void **)&pconn_info)) {
            EXAMPLE_TRACE("AUTH request failed!");
            rc = -1;
            goto do_exit;
        }
    
        /* Initialize MQTT parameter */
        memset(&mqtt_params, 0x0, sizeof(mqtt_params));
        mqtt_params.port = pconn_info->port;
        mqtt_params.host = pconn_info->host_name;
        mqtt_params.client_id = pconn_info->client_id;
        mqtt_params.username = pconn_info->username;
        mqtt_params.password = pconn_info->password;
        mqtt_params.pub_key = pconn_info->pub_key;
    
        mqtt_params.request_timeout_ms = 2000;
        mqtt_params.clean_session = 0;
        mqtt_params.keepalive_interval_ms = 60000;
        mqtt_params.read_buf_size = OTA_MQTT_MSGLEN;
        mqtt_params.write_buf_size = OTA_MQTT_MSGLEN;
    
        mqtt_params.handle_event.h_fp = event_handle;
        mqtt_params.handle_event.pcontext = NULL;
    
        /* Construct a MQTT client with specify parameter */
        pclient = IOT_MQTT_Construct(&mqtt_params);
        if (NULL == pclient) {
            EXAMPLE_TRACE("MQTT construct failed");
            rc = -1;
            goto do_exit;
        }
  3. Call the _ota_mqtt_client function to initialize the OTA service. In this step, the device subscribes to its firmware update information.

        h_ota = IOT_OTA_Init(PRODUCT_KEY, DEVICE_NAME, pclient);
        if (NULL == h_ota) {
            rc = -1;
            EXAMPLE_TRACE("initialize OTA failed");
            goto do_exit;
        }
  4. Create a loop to keep receiving messages about OTA updates.

        int ota_over = 0;
        do {
            uint32_t firmware_valid;
            EXAMPLE_TRACE("wait ota upgrade command....");
    
            /* Receive an MQTT message. */
            IOT_MQTT_Yield(pclient, 200);
    
            /* Check whether the received message contains information about a firmware upgrade. */
            if (IOT_OTA_IsFetching(h_ota)) {
             /* Download the latest firmware from the OTA service and report the download progress. For more information, see "Step 5. Download the latest firmware from the OTA service and report the download progress." */
             /* Check the MD5 hash value of the firmware. For more information, see "Step 6 Check the MD5 hash value." */
            }
    
            } while (!ota_over);

    You must push a firmware update event to the server so that the server responds to IOT_OTA_IsFetching with 1. The firmware update logic then takes effect. To push a firmware update event, perform the following steps:

    1. Go to the OTA Service page in the IoT Platform console and click Add New Firmware.

    2. Click Create Firmware and Verify Firmware.

    3. Click Batch Upgrade for the firmware that you added, and select the product that corresponds to the trituple of examples/ota/ota_mqtt-example.c.

    4. Select the current version number from the version drop-down list, and set Upgrade Scope to Directional Upgrade. Select the device whose trituple is the same as that of examples/ota/ota_mqtt-example.c from the Equipment Scope drop-down list, and then click OK.

  5. Download the latest firmware from the OTA service and report the download progress.

        do {
    
            /* Download the latest firmware from the OTA service. */
            len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
            if (len > 0) {
                if (1 != fwrite(buf_ota, len, 1, fp)) {
                    EXAMPLE_TRACE("write data to file failed");
                    rc = -1;
                    break;
                }
            } else {
    
                /* Report the download progress. */
                IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_FAILED, NULL);
                EXAMPLE_TRACE("ota fetch fail");
            }
    
            /* get OTA information */
            /* Obtain the firmware information, such as the volume of data that has been downloaded, total file size, MD5 hash value, and the version number. */
            IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
            IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
            IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
            IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
    
            last_percent = percent;
            percent = (size_downloaded * 100) / size_file;
            if (percent - last_percent > 0) {
    
                /* Report the download progress. */
                IOT_OTA_ReportProgress(h_ota, percent, NULL);
                IOT_OTA_ReportProgress(h_ota, percent, "hello");
            }        IOT_MQTT_Yield(pclient, 100);
    
            /* Check whether the download is complete. */
        } while (!IOT_OTA_IsFetchFinish(h_ota));
  6. Check the MD5 hash value.

        IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
        if (0 == firmware_valid) {
            EXAMPLE_TRACE("The firmware is invalid");
        } else {
            EXAMPLE_TRACE("The firmware is valid");
        }
    
        ota_over = 1;
  7. Call IOT_OTA_Deinit to release all resources.

        if (NULL != h_ota) {
            IOT_OTA_Deinit(h_ota);
        }
    
        if (NULL != pclient) {
            IOT_MQTT_Destroy(&pclient);
        }
    
        if (NULL != msg_buf) {
            HAL_Free(msg_buf);
        }
    
        if (NULL != msg_readbuf) {
            HAL_Free(msg_readbuf);
        }
    
        if (NULL != fp) {
            fclose(fp);
        }
    
        return rc;
  8. Store the firmware.

    Call the _ota_mqtt_client function to open or close a file, or write data into the file.

    fp = fopen("ota.bin", "wb+")
    ...
    if (1 != fwrite(buf_ota, len, 1, fp)) {
        EXAMPLE_TRACE("write data to file failed");
        rc = -1;
        break;
    }
    ...
    if (NULL != fp) {
        fclose(fp);
    }

Using advanced APIs

The following procedure uses src/dev_model/examples/linkkit_example_solo.c to describe how to implement an OTA update by using advanced APIs.

  1. Initialize the gateway, register the firmware-over-the-air (FOTA) callback, and connect the gateway to IoT Platform.

    int res = 0;
    int domain_type = 0, dynamic_register = 0, post_reply_need = 0;
    iotx_linkkit_dev_meta_info_t master_meta_info;
    
    memset(&g_user_example_ctx, 0, sizeof(user_example_ctx_t));
    
    memset(&master_meta_info, 0, sizeof(iotx_linkkit_dev_meta_info_t));
    memcpy(master_meta_info.product_key, PRODUCT_KEY, strlen(PRODUCT_KEY));
    memcpy(master_meta_info.product_secret, PRODUCT_SECRET, strlen(PRODUCT_SECRET));
    memcpy(master_meta_info.device_name, DEVICE_NAME, strlen(DEVICE_NAME));
    memcpy(master_meta_info.device_secret, DEVICE_SECRET, strlen(DEVICE_SECRET));
    
    /* Register Callback */
    ...
    ...
    IOT_RegisterCallback(ITE_FOTA, user_fota_event_handler);
    
    domain_type = IOTX_CLOUD_REGION_SHANGHAI;
    IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN, (void *)&domain_type);
    
    /* Choose Login Method */
    dynamic_register = 0;
    IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register);
    
    /* post reply doesn't need */
    post_reply_need = 1;IOT_Ioctl(IOTX_IOCTL_RECV_EVENT_REPLY, (void *)&post_reply_need);
    
    /* Create Master Device Resources */
    g_user_example_ctx.master_devid = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER, &master_meta_info);
    if (g_user_example_ctx.master_devid < 0) {
        EXAMPLE_TRACE("IOT_Linkkit_Open Failed\n");
        return -1;}
    
    /* Start Connect Aliyun Server */
    res = IOT_Linkkit_Connect(g_user_example_ctx.master_devid);
    if (res < 0) {
        EXAMPLE_TRACE("IOT_Linkkit_Connect Failed\n");
        return -1;
    }
  2. Call the user_fota_event_handler callback that is registered in the preceding step.

    The callback is called in the following scenarios:

    • The device receives a notification from IoT Platform. The notification indicates that new firmware is available.

    • The device initiates a firmware update query, and IoT Platform responds with a notification that new firmware is available.

    After the device receives the notification, call IOT_Linkkit_Query to download the firmware.

    int user_fota_event_handler(int type, const char *version){
        char buffer[128] = {0};
        int buffer_length = 128;
    
        /* 0 - new firmware exist, query the new firmware */
        if (type == 0) {
            EXAMPLE_TRACE("New Firmware Version: %s", version);
    
            IOT_Linkkit_Query(EXAMPLE_MASTER_DEVID, ITM_MSG_QUERY_FOTA_DATA, (unsigned char *)buffer, buffer_length);
        }
    
        return 0;
    }
  3. Store the firmware.

    Call the following Hardware Abstraction Layer (HAL) operations to store the firmware.

    /* Use the SDK to call this operation before the firmware download starts. */
    void HAL_Firmware_Persistence_Start(void);
    
    /* Use the SDK to call this operation when the firmware data is received. */
    int HAL_Firmware_Persistence_Write(char *buffer, uint32_t length);
    
    /* Use the SDK to call this operation when the firmware download is complete. */
    int HAL_Firmware_Persistence_Stop(void);
  4. Query whether the new firmware is available.

    IOT_Linkkit_Query(user_example_ctx->master_devid, ITM_MSG_REQUEST_FOTA_IMAGE,
                          (unsigned char *)("app-1.0.0-20180101.1001"), 30);

OTA updates for software modules

OTA allows you to download and update software modules of a device. You must create modules in the IoT Platform console before you perform OTA updates for the modules.

In device-side development, you must set the module name to the module name that you specified in the IoT Platform console.

char* module = "mcu";
IOT_Ioctl(IOTX_IOCTL_SET_MODULE, (void *)module);

Other steps of the OTA update are the same as those in an OTA test procedure. After you start an OTA update for a device module in the IoT Platform console, the following logs are displayed on the device. You can check the module field to see whether the OTA update is performed on the correct module.

[dbg] otamqtt_UpgrageCb(111): topic=/ota/device/upgrade/a1******PjW/foDzDj*******3PDJ9d
[dbg] otamqtt_UpgrageCb(112): len=431, topic_msg={"code":"1000","data":{"size":143360,"module":"mcu","sign":"867f1536fb********a2205436252","version":"111","url":"https://iotx-******ily.oss-cn-shanghai.aliyuncs.com/ota/338ac9db05545dcab9*********52/ck75mi***********5xbgz61vl.tar?Expires=1582951757&OSSAccessKeyId=aS4***********j6Gy&Signature=urw%2F9WAlizQui*************0A%3D","signMethod":"Md5","md5":"867f1536fb*********436252"},"id":1582865357795,"message":"success"}
[dbg] otamqtt_UpgrageCb(129): receive device upgrade
[inf] ofc_Init(47): protocol: https
received state: -0x092C(msg queue size: 0, max size: 50)
received state: -0x092C(msg enqueue w/ message type: 43)
received state: -0x092C(msg dequeue)
received state: -0x0938(alink event type: 43)
received state: -0x0938(new fota information received, 111)
user_fota_module_event_handler.219: New Firmware Version: 111, module: mcu