设备 OTA

更新时间:2023-09-06 10:40:14下载pdf

OTA(Over-the-Air)即空中下载技术,通过网络远程为设备更新和升级软件程序。TuyaOS 网关开发框架提供了简易的 OTA 接口,让您的产品快速集成 OTA 功能。

本文介绍了如何使用 TuyaOS 网关开发框架实现网关固件 OTA 功能。

背景信息

TuyaOS 不仅支持网关自身的固件 OTA,还支持网关附属固件 OTA。

网关附属固件是指,网关产品外接了 MCU、Zigbee、蓝牙等模组,可以通过附属固件来升级这类外接模组的固件。

网关固件 OTA 和网关附属固件 OTA 的流程是一样的,根据 升级通道号 来区分不同类型的固件升级。

网关固件的升级通道号固定是 0。升级通道号小于 10 是涂鸦内部定义,不可修改,因此,如果外接的模组是非涂鸦模组,则网关附属固件的升级通道号要在 [10, 19] 中自定义。如果外接的模组是涂鸦模组,TuyaOS 内置了模组 OTA 功能,您无需开发。

前提条件

固件上传和升级需要在 涂鸦 IoT 开发平台 上完成,因此,您需要先熟悉涂鸦 IoT 开发平台的 固件管理固件升级 操作步骤,以便更好地完成设备固件 OTA 功能开发。

使用方法

  • 通过 tuya_iot_reg_gw_app_cb 接口注册 TY_GW_APP_CBS_S gw_upgrade_cb 升级通知回调,在回调中调用 tuya_iot_upgrade_gw 接口下载固件。
  • tuya_iot_upgrade_gw 接口有两个回调需要实现,分别是 GET_FILE_DATA_CBUPGRADE_NOTIFY_CB
    • GET_FILE_DATA_CB 回调接口中实现把数据块写入到文件。
    • UPGRADE_NOTIFY_CB 回调接口中执行升级操作。先判断固件下载的结果,若固件下载并校验成功,则根据 FW_UG_S->tp 的固件类型执行对应的升级操作,FW_UG_S->tp 对应涂鸦 IoT 开发平台 固件升级通道号
  • 升级成功后重启设备,启动后上报新的版本号。

固件 OTA 的流程:

CloudSDKApplicationOTA NotificationTY_GW_APP_CBS_S.gw_upgrade_cbtuya_iot_upgrade_gwStart a Thread to Download OTA FileOTA File Data Block RequestOTA File Data Block ResponseGET_FILE_DATA_CBloop[Break when the download is finished]OTA File Data ValidationUPGRADE_NOTIFY_CBUpgrading and RebootInitialization with New VersionVersions ReportCloudSDKApplication

使用示例

/**
 * @brief OTA 文件数据块回调
 * @note 您需要在回调中把数据保存到 OTA 文件,该回调会被多次调用直到文件下载完成
 */
STATIC OPERATE_RET __dev_ota_data(IN CONST FW_UG_S *fw, IN CONST UINT_T total_len, IN CONST UINT_T offset,
                                  IN CONST BYTE_T *data, IN CONST UINT_T len, OUT UINT_T *remain_len, IN PVOID_T pri_data)
{
    INT_T fd = 0;
    ssize_t w_len = 0;

    PR_DEBUG("OTA File Data, total len: %d, len: %d, offset: %d", total_len, len, offset);

    if (pri_data == NULL) {
        PR_ERR("pri_data is null");
        return OPRT_INVALID_PARM;
    }

    fd = *(INT_T *)pri_data;

    // 写文件
    w_len = write(fd, data, len);
    if (w_len <= 0) {
        close(fd);
        *remain_len = 0;
        return OPRT_COM_ERROR;
    }

    return OPRT_OK;
}

/**
 * @brief OTA 文件下载结果通知回调
 * @note 您需要在回调中判断下载的结果是否成功,成功则根据具体的固件类型执行对应的升级操作
    */
STATIC OPERATE_RET __dev_ota_notify(IN CONST FW_UG_S *fw, IN CONST INT_T download_result, IN PVOID_T pri_data)
{
    INT_T fd = 0;

    if (pri_data == NULL) {
        PR_ERR("pri_data is null");
        return OPRT_INVALID_PARM;
    }

    fd = *(INT_T *)pri_data;
    close(fd);

    // 判断固件下载结果
    if (download_result == OPRT_OK) {
        PR_DEBUG("OTA File Download Successfully");
        if (fw->tp == DEV_NM_ATH_SNGL) {
            // 主固件,执行主固件升级操作
        } else {
            // 附属固件,根据具体的固件类型执行对应的升级操作
        }
    } else {
        PR_WARN("OTA File Download Failure");
    }

    return OPRT_OK;
}

/**
 * @brief 固件升级通知回调
 * @note 您需要在回调中调用接口下载固件
 */
STATIC VOID __gw_upgrade_cb(CONST FW_UG_S *fw)
{
    STATIC INT_T fd = 0;
    OPERATE_RET op_ret = OPRT_OK;

    PR_DEBUG("upgrade callback");
    PR_DEBUG("        tp: %d", fw->tp);
    PR_DEBUG("    fw_url: %s", fw->fw_url);
    PR_DEBUG("    sw_ver: %s", fw->sw_ver);
    PR_DEBUG("   fw_hmac: %s", fw->fw_hmac);
    PR_DEBUG(" file_size: %u", fw->file_size);

    // 移除 OTA 文件
    remove(MY_FW_FILE);

    // 创建 OTA 文件
    fd = open(MY_FW_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0755);
    if (fd < 0) {
        PR_ERR("open error");
        return OPRT_COM_ERROR;
    }

    op_ret = tuya_iot_upgrade_gw(fw, __dev_ota_data, __dev_ota_notify, (VOID *)&fd);
    if (op_ret != OPRT_OK) {
        PR_ERR("tuya_iot_upgrade_dev err: %d", op_ret);
    }

    return;
}

STATIC VOID ota_demo(VOID)
{
    TY_GW_APP_CBS_S gw_app_cbs = {
        .gw_upgrade_cb     = __gw_upgrade_cb,
    };

    // 注册升级通知回调
    tuya_iot_reg_gw_app_cb(&gw_app_cbs);

    // 主固件升级,升级后初始化要传递新的版本号
    // tuya_iot_wr_wf_sdk_init

    // 附属固件升级,升级后需要上报新的版本号
    // tuya_user_ncp_ver_upload_reg
}