跳转至

libfota3-远程升级

一、概述

FOTA远程升级功能是物联网设备的核心功能之一,它允许设备通过无线网络更新固件,而无需物理接触。在LuatOS开发模式下,固件分为两部分:core(底层核心固件)和script(用户脚本)。远程升级时,core采用差分升级方式,而 script 则采用全量覆盖升级方式。您可以选择仅升级script、仅升级core或同时升级core+script。

LuatOS主要提供了三代FOTA接口,按演进顺序依次为libfota、libfota2和libfota3:

  1. libfota:初代FOTA接口,通过一长串顺序参数传递配置,必须按顺序填写,可选参数处理不够灵活。

  2. libfota2:第二代FOTA接口,改用opts表传递参数,结构清晰、可选参数管理方便,并对合宙IoT平台的错误码做了更细致的提示。

  3. libfota3:第三代FOTA接口,面向支持LuatOS开发的所有产品,仅对接合宙IoT平台。扩展库内部完成「检测新版本 → 下载升级包 → 校验 → 写入升级分区 → 重启生效 → 结果上报」的完整升级闭环,并内置自动定时检测、运行期动态配置、全过程状态回调与带屏确认能力。使用前需在合宙IoT平台创建项目并获取project_key(具体操作演示请参考 libfota3 文档)。

其中libfota和libfota2既支持通过合宙官方IoT平台升级,也支持自建第三方HTTP服务器升级。

需要注意的是第三方http服务器需要满足如下两点(仅适用于libfota和libfota2;libfota3仅对接合宙IoT平台,不适用此约定):
-- 若需要升级, 响应http 200, body为升级文件的内容
-- 若不需要升级, 响应300或以上的代码,务必注意

为了更清晰地了解这三个库的特点,下表对比了它们的主要特性。

区别项 libfota libfota2 libfota3
参数传递方式 一长串顺序参数传递,必须按顺序填写,可选参数处理不够灵活 使用opts表传递参数,结构清晰,可选参数管理方便 使用opts表传递参数,配置项覆盖检测、下载、回调等完整流程
使用便捷性 相对较低。需要关注较多参数,配置稍显繁琐。 较高。接口设计更现代,只需关注关键配置,简化了使用流程。 较高。一次request()完成配置,内部自动处理等待网络、时间同步、定时检测、下载、刷写与重启
服务器支持 支持合宙IoT平台和自建服务器 支持合宙IoT平台和自建服务器 仅支持合宙IoT平台,不支持自建升级服务器
升级包校验 无 无 下载完成后进行SHA256校验,校验通过才写入升级分区
过程状态回调 回调函数提供状态码 回调函数提供详细状态码 on_status覆盖检测、下载(含百分比)、刷写、重启等环节;on_confirm可为带屏设备提供下载前、重启前确认
升级结果上报 无 无 升级结果在重启后自动比对并上报服务器
定时升级 需应用层定时调用 需应用层定时调用 内置auto+interval定时检测,重启后按时间戳续算不漏检
适用产品 支持LuatOS开发的所有产品 支持LuatOS开发的所有产品 支持LuatOS开发的所有产品
推荐使用场景 存量老项目维护,或代码已依赖初代接口、不打算调整的项目。 新项目需对接自建第三方HTTP升级服务器时;或对接合宙IoT平台、但已有成熟libfota2代码,或团队/客户更熟悉libfota2、希望沿用现有实现时。 对接合宙IoT平台的项目,除上一栏所述情况外优先选择;尤其是希望省去设备归属处理、定时检测、升级包校验、升级结果上报等自研工作量的场景。

如何选择 libfota / libfota2 / libfota3

(一)按项目情况选择

  • libfota:仅建议存量老项目维护使用,或代码已依赖初代接口、不打算调整的项目。新项目不建议使用。
  • libfota2:以下两种情况建议使用 libfota2 ——
    1. 新项目需要对接自建的第三方HTTP升级服务器(libfota 和 libfota2 都支持自建服务器,但新项目建议用 libfota2;libfota3 只对接合宙IoT平台,不支持自建服务器);
    2. 项目对接合宙IoT平台,但已有成熟的 libfota2 代码,或团队/客户对 libfota2 更熟悉,希望沿用现有实现。
  • libfota3:对接合宙IoT平台的项目,除上述第 2 种情况外优先选择 libfota3。

libfota 和 libfota2 目前仍在持续维护,已使用这两个库的项目继续使用不受影响。

(二)libfota3 解决了 libfota2 的哪些问题

  1. 设备归属:使用 libfota2 通过合宙IoT平台升级时,需要自行判断设备(IMEI/MAC)是否已归属到目标账号及对应项目下,未归属时还要做自动化的归属处理,处理不当就会升级失败;使用 libfota3 时不需要判断设备IMEI/MAC与IoT账号的归属关系,也不需要对设备IMEI/MAC做任何自动化归属处理。
  2. 定时检测:libfota2 需要应用层自己起定时器周期调用检测;libfota3 内置自动定时检测,且重启后会按已保存的时间戳续算,不会因为设备中途重启而漏检。
  3. 升级包校验:libfota2 下载完成后直接写入;libfota3 下载后先做 SHA256 校验,校验通过才写入升级分区,降低坏包/半包把设备刷坏的风险。
  4. 升级结果上报:libfota2 不提供升级结果上报;libfota3 在重启后自动比对实际版本并上报服务器,平台侧可直接掌握升级成功与否。
  5. 过程可观测、可交互:libfota2 只有一个升级结果回调;libfota3 的 on_status 覆盖检测、下载(含百分比)、刷写、重启等过程,on_confirm 还能为带屏设备提供下载前、重启前的确认交互。
  6. 联网与时间同步、运行期配置:libfota2 需要应用层自行保证已联网、时间已同步;libfota3 的 request() 内部自动等待网络就绪并完成时间同步,还支持 config() 在运行期动态开闭自动检测、调整检测间隔。

(三)一句话总结

存量老项目维护、或代码已依赖初代接口的项目,继续用 libfota,新项目不建议使用;需要对接自建服务器,选 libfota2(libfota 虽同样支持自建服务器,但新项目不建议使用);对接合宙IoT平台且团队已熟悉 libfota2,可继续用 libfota2;其余对接合宙IoT平台的项目,优先选 libfota3。

本文档介绍第三代接口 libfota3 的用法。libfota3 把检测、下载、校验、刷写、重启、结果上报整合为完整闭环,并内置定时升级与带屏确认能力,无需应用层自行实现,点击此处了解libfota,点击此处了解libfota2。

二、核心示例

local libfota3 = require("libfota3")

-- 一站式启动(自动检测 + 下载 + 重启)
libfota3.request({
    project_key = "your_project_key",    -- 项目密钥,用于FOTA服务认证
    script_name = "fota3_temp",          -- 脚本名称
    script_version = "001.999.000",      -- 脚本版本
    auto = true,                         -- 启用自动定时检测
    interval = 86400,                    -- 自动检测间隔(秒),默认24小时
    on_status = function(status, msg, percent)
        log.info("fota_temp", status, msg, percent)
    end,
    on_confirm = function(action, info, callback)
        if action == "download" then
            -- true 表示用户确认下载
            callback(true)
        elseif action == "reboot" then
            -- true 表示用户确认重启升级
            callback(true)
        end
    end,
})

-- 手动触发检测更新
libfota3.check_update()

-- 动态修改配置
libfota3.config({auto = false})
libfota3.config({auto = true, interval = 3600})

三、常量详解

libfota3 库没有常量。

四、函数详解

4.1 libfota3.request(new_opts)

功能

启动 FOTA 升级流程,是“自动检测 + 下载 + 重启”的一站式入口。

调用 request() 后,库会保存本次配置,并等待网络就绪、完成时间同步;随后按 auto / interval 配置自动定时检测更新,发现新版本时依次完成“下载升级包 → 校验 → 刷写 → 重启”的升级闭环。

request() 可多次调用,用于在开机后重新下发整套配置;运行过程中也可通过 check_update() 手动触发检测、通过 config() 动态修改配置。

注意事项

  1. 配置整体替换,非合并:每次调用 request() 都会用本次传入的 new_opts 整体覆盖上一次保存的全部配置(含 project_key、on_status 等)。只修改单个或部分参数时,请使用 config()。

  2. 运行互斥:FOTA 流程(等待网络、时间同步、检测、下载等任意阶段)执行期间,重复调用 request() 或 check_update() 会被忽略,请等待上一轮流程结束(如收到 download_done / rebooting 等状态)后再发起。

  3. 自动检测依赖时间同步:时间同步成功后才会按 auto / interval 启动自动定时检测;若同步失败(网络差、NTP 超时),本次不会自动检测,可通过 check_update() 手动检测或稍后重试 request()。

  4. 网络未就绪提示:网络等待上限 60 秒,未就绪期间会每秒回调一次 "network_fail",业务侧如需提示请自行节流。

  5. 开机自动上报上次升级结果:若上次检测到新版本且确认下载过,设备重启后开机时库会先回调 "boot_report",再根据版本比对结果回调 "upgrade_success" 或 "upgrade_fail"。

  6. on_confirm 确认回调:不传时默认允许所有操作(自动下载、自动重启);传入后,每次收到回调都必须调用一次 callback(true) / callback(false) 表示确认或取消,否则流程会一直等待。

  7. interval 取值:单位秒,默认 86400(24 小时);interval \<= 0 视为未启用自动检测;请勿设置过短(如小于 60 秒),避免频繁请求服务器。

参数

new_opts

参数含义:fota升级参数配置;参数为 table 类型,table 内容格式说明如下:
         {
             参数含义:项目密钥,此处为合宙 iot 平台上 Turnkey 标题栏中的项目密钥,详细说明请看下方的操作说明;
             数据类型:string;
             取值范围:无;
             是否必选:必须传入此参数;
             注意事项:无;
             参数示例:"your_project_key";
             project_key = ,

             参数含义:脚本名称,此处指的是 main.lua 中的 PROJECT;
             数据类型:string;
             取值范围:无;
             是否必选:可选传入此参数,不填时默认为 _G.PROJECT(需要代码中的 PROJECT 为全局变量);
             注意事项:无;
             参数示例:"fota3_temp";
             script_name = ,

             参数含义:脚本版本号,此处指的是 main.lua 中的 VERSION;
             数据类型:string;
             取值范围:无;
             是否必选:可选传入此参数,不填时默认为 _G.VERSION(需要代码中的 VERSION 为全局变量);
             注意事项:无;
             参数示例:"001.999.000";
             script_version = ,

             参数含义:是否启动定时检测,默认为开启;
             数据类型:boolean;
             取值范围:true/false;
             是否必选:可选传入此参数,不填时默认为 true,表示开启;
             注意事项:设备第一次开机(不包含重启)时会自动进行一次检测;
             参数示例:true;
             auto = ,

             参数含义:自动检测间隔,单位秒;
             数据类型:number;
             取值范围:无,以定时器支持的最大时间为主;
             是否必选:可选传入此参数,不填时默认为 86400(24 小时);
             注意事项:不要设置过短,避免频繁触发;
             参数示例:86400;
             interval = ,

             参数含义:状态回调函数,内含三个参数,格式如下:
                      status
                      参数含义:状态码,用于表示整个 FOTA 过程中的状态;
                      数据类型:string;
                      取值范围:"network_fail" -- 网络连接失败
                               "boot_report"  -- 正在检测上次升级结果
                               "checking"     -- 正在检测更新
                               "check_fail" -- 检测失败
                               "no_new_version" -- 当前已是最新版本
                               "new_version" -- 发现新版本
                               "download_start" -- 开始下载升级包
                               "downloading" -- 正在下载(包含进度)
                               "download_fail" -- 下载失败
                               "download_done" -- 升级包已就绪
                               "rebooting" -- 正在重启
                               "upgrade_success" -- 升级成功
                               "upgrade_fail" -- 升级失败/无变化
                      是否必选:可选传入此参数;
                      注意事项:无;
                      参数示例:-- 如下方所示,定义了一个函数 fota_cb 就可以做为此参数传入
                               local function fota_cb(status, msg, percent)
                                   if status == "network_fail" then
                                       -- 网络连接失败,可记录日志或提示用户检查网络
                                       log.warn("fota", "网络连接失败:", msg)
                                   elseif status == "boot_report" then
                                       -- 正在检测上次升级结果,启动时自动触发
                                       log.info("fota", "检测升级结果:", msg)
                                   elseif status == "checking" then
                                       -- 正在检测更新
                                       log.info("fota", "检测更新:", msg)
                                   elseif status == "check_fail" then
                                       -- 检测失败,可能是网络问题或服务器异常
                                       log.warn("fota", "检测失败:", msg)
                                   elseif status == "no_new_version" then
                                       -- 当前已是最新版本,无需升级
                                       log.info("fota", "已是最新版本:", msg)
                                   elseif status == "new_version" then
                                       -- 发现新版本,准备下载
                                       log.info("fota", "发现新版本:", msg)
                                   elseif status == "download_start" then
                                       -- 开始下载升级包
                                       log.info("fota", "开始下载:", msg)
                                   elseif status == "downloading" then
                                       -- 正在下载,显示进度(percent 为 0-100 的整数)
                                       log.info("fota", "下载进度:", msg, percent .. "%")
                                   elseif status == "download_fail" then
                                       -- 下载失败,可能是网络中断或存储空间不足
                                       log.warn("fota", "下载失败:", msg)
                                   elseif status == "download_done" then
                                       -- 升级包已就绪,等待用户确认重启
                                       log.info("fota", "下载完成:", msg)
                                   elseif status == "rebooting" then
                                       -- 正在重启,准备应用升级
                                       log.info("fota", "重启升级:", msg)
                                   elseif status == "upgrade_success" then
                                       -- 升级成功,版本已更新
                                       log.info("fota", "升级成功:", msg)
                                   elseif status == "upgrade_fail" then
                                       -- 升级失败或无变化
                                       log.warn("fota", "升级失败:", msg)
                                   end
                               end

                      msg
                      参数含义:状态描述信息,参考状态码说明;
                      数据类型:string;
                      取值范围:参考 status 状态码说明;
                      是否必选:可选传入此参数;
                      注意事项:无;
                      参数示例:参考上方 status 参数示例;

                      percent
                      参数含义:下载进度百分比(0~100),仅在 status == "downloading" 时有效,其他状态为 nil;
                      数据类型:number;
                      取值范围:0-100;
                      注意事项:无;
                      参数示例:参考上方 status 参数示例;

             数据类型:function;
             取值范围:无;
             是否必选:可选传入此参数;
             注意事项:无;
             参数示例:参考上方 status 参数示例;
             on_status = ,

             参数含义:确认回调函数,内含三个参数,格式如下:
                      action
                      参数含义:确认操作类型;
                      数据类型:string;
                      取值范围:"download" -- 确认下载
                               "reboot"   -- 确认重启
                      是否必选:是;
                      注意事项:无;
                      参数示例:参考下方 on_confirm 参数示例;

                      info
                      参数含义:确认操作的详细信息,当 action == "download" 时:包含以下字段:
                               info.version
                               参数含义:升级包的脚本版本号;
                               数据类型:string;
                               取值范围:由FOTA服务端返回;
                               是否必选:是;
                               注意事项:仅 action == "download" 时存在;
                               参数示例:"001.999.000"

                               info.size
                               参数含义:升级包大小(字节);
                               数据类型:number;
                               取值范围:大于0的整数;
                               是否必选:是;
                               注意事项:仅 action == "download" 时存在;
                               参数示例:102400

                               info.fota_sn
                               参数含义:FOTA序列号,用于标识本次升级任务;
                               数据类型:string;
                               取值范围:由FOTA服务端返回;
                               是否必选:是;
                               注意事项:仅 action == "download" 时存在;
                               参数示例:"202606201234567890"
                      数据类型:table 或 nil;
                      取值范围:当 action == "download" 时:包含以上字段;
                               当 action == "reboot" 时:为 nil;
                      是否必选:可选传入此参数;
                      注意事项:无;
                      参数示例:参考下方 on_confirm 参数示例;

                      callback
                      参数含义:确认结果回调函数,用于通知库用户的选择;
                      数据类型:function;
                      取值范围:无;
                      是否必选:可选传入此参数;
                      注意事项:调用 callback(true) 表示确认,callback(false) 表示取消;
                      参数示例:参考下方 on_confirm 参数示例;

             数据类型:function;
             取值范围:无;
             是否必选:可选传入此参数;
             注意事项:不传入时默认允许所有操作;
             参数示例:-- 如下方所示,定义了一个函数 fota_confirm 就可以做为此参数传入
                      local function fota_confirm(action, info, callback)
                          if action == "download" then
                              -- 确认下载,info 包含版本、大小、序列号
                              log.info("fota", "收到下载请求:")
                              log.info("fota", "  版本:", info.version)
                              log.info("fota", "  大小:", info.size, "字节")
                              log.info("fota", "  序列号:", info.fota_sn)
                              -- true 表示用户确认下载
                              callback(true)
                          elseif action == "reboot" then
                              -- 确认重启,info 为 nil
                              log.info("fota", "收到重启请求")
                              -- true 表示用户确认重启升级
                              callback(true)
                          end
                      end
        }

返回值

无;

示例

libfota3.request({
    project_key = "your_project_key",    -- 项目密钥,用于FOTA服务认证
    script_name = "fota3_temp",          -- 脚本名称
    script_version = "001.999.000",      -- 脚本版本
    auto = true,                         -- 启用自动定时检测
    interval = 86400,                    -- 自动检测间隔(秒),默认24小时
    on_status = function(status, msg, percent)
        log.info("fota_temp", status, msg, percent)
    end,
    on_confirm = function(action, info, callback)
        if action == "download" then
            log.info("fota_temp", "download", info.version, info.size, info.fota_sn)
            -- true 表示用户确认下载
            callback(true)
        elseif action == "reboot" then
            -- true 表示用户确认重启升级
            callback(true)
        end
    end,
})

4.2 libfota3.check_update()

功能

手动触发一次更新检测,与自动定时检测走同一套完整升级闭环:

等待网络就绪 → 向 FOTA 服务器查询是否有新版本 →(发现新版本)on_confirm 确认下载 → 下载升级包并做校验 → 写入 FOTA 分区 → on_confirm 确认重启 → 重启设备。

一般用于设备运行过程中由用户主动触发的场景(如按键、云平台指令、业务定时器等)。

注意事项

  1. 使用前必须先调用 request() 完成初始化配置(至少包含 project_key),否则检测会因缺少 project_key 而失败。

  2. 与 request() 共用运行互斥:任意 FOTA 流程执行期间调用 check_update() 会被忽略。

  3. 无返回值,检测结果通过 on_status 回调获知(依次可能收到 checking / check_fail / no_new_version / new_version;确认下载后还会收到下载与重启相关状态)。

参数

无。

返回值

无;

示例

-- 启动 FOTA 升级功能
libfota3.request({
    project_key = "your_project_key",    -- 项目密钥,用于FOTA服务认证
    script_name = "fota3_temp",          -- 脚本名称
    script_version = "001.999.000",      -- 脚本版本
    auto = true,                         -- 启用自动定时检测
    interval = 86400,                    -- 自动检测间隔(秒),默认24小时
    on_status = function(status, msg, percent)
        log.info("fota_temp", status, msg, percent)
    end,
    on_confirm = function(action, info, callback)
        if action == "download" then
            log.info("fota_temp", "download", info.version, info.size, info.fota_sn)
            -- true 表示用户确认下载
            callback(true)
        elseif action == "reboot" then
            -- true 表示用户确认重启升级
            callback(true)
        end
    end,
})

-- 间隔一段时间后。。。。。。。

-- 手动执行检测更新
libfota3.check_update()

4.3 libfota3.config(new_opts)

功能

动态修改 FOTA 配置,并自动处理自动检测定时器的启停。支持只传需要修改的部分字段,未传字段保持原值(与 request() 的整体替换不同),例如:

  • 关闭自动定时检测:libfota3.config({auto = false});

  • 调整检测间隔:libfota3.config({auto = true, interval = 3600});

  • 修改 project_key / script_name / script_version / on_status / on_confirm 等字段,将在后续检测流程中生效。

注意事项

  1. 使用之前必须先调用 request() 完成初始化后再使用 config();单独使用 config() 不会启动时间同步与任何 FOTA 流程。

  2. 修改 auto / interval 会按新配置重新安排自动检测定时器;config() 不会打断正在执行的检测/下载流程,新配置从下一轮检测开始生效。

  3. 修改 project_key / on_status / on_confirm 等非定时器字段时立即生效,不影响自动检测节奏。

参数

new_opts

参数含义:fota升级参数配置;参数为 table 类型,table 内容格式说明如下:
         {
             参数含义:项目密钥,此处为合宙 iot 平台上 Turnkey 标题栏中的项目密钥,详细说明请看下方的操作说明;
             数据类型:string;
             取值范围:无;
             是否必选:必须传入此参数;
             注意事项:无;
             参数示例:"your_project_key";
             project_key = ,

             参数含义:脚本名称,此处指的是 main.lua 中的 PROJECT;
             数据类型:string;
             取值范围:无;
             是否必选:可选传入此参数,不填时默认为 _G.PROJECT(需要代码中的 PROJECT 为全局变量);
             注意事项:无;
             参数示例:"fota3_temp";
             script_name = ,

             参数含义:脚本版本号,此处指的是 main.lua 中的 VERSION;
             数据类型:string;
             取值范围:无;
             是否必选:可选传入此参数,不填时默认为 _G.VERSION(需要代码中的 VERSION 为全局变量);
             注意事项:无;
             参数示例:"001.999.000";
             script_version = ,

             参数含义:是否启动定时检测,默认为开启;
             数据类型:boolean;
             取值范围:true/false;
             是否必选:可选传入此参数,不填时默认为 true,表示开启;
             注意事项:设备第一次开机(不包含重启)时会自动进行一次检测;
             参数示例:true;
             auto = ,

             参数含义:自动检测间隔,单位秒;
             数据类型:number;
             取值范围:无,以定时器支持的最大时间为主;
             是否必选:可选传入此参数,不填时默认为 86400(24 小时);
             注意事项:不要设置过短,避免频繁触发;
             参数示例:86400;
             interval = ,

             参数含义:状态回调函数,内含三个参数,格式如下:
                      status
                      参数含义:状态码,用于表示整个 FOTA 过程中的状态;
                      数据类型:string;
                      取值范围:"network_fail" -- 网络连接失败
                               "boot_report"  -- 正在检测上次升级结果
                               "checking"     -- 正在检测更新
                               "check_fail" -- 检测失败
                               "no_new_version" -- 当前已是最新版本
                               "new_version" -- 发现新版本
                               "download_start" -- 开始下载升级包
                               "downloading" -- 正在下载(包含进度)
                               "download_fail" -- 下载失败
                               "download_done" -- 升级包已就绪
                               "rebooting" -- 正在重启
                               "upgrade_success" -- 升级成功
                               "upgrade_fail" -- 升级失败/无变化
                      是否必选:可选传入此参数;
                      注意事项:无;
                      参数示例:-- 如下方所示,定义了一个函数 fota_cb 就可以做为此参数传入
                               local function fota_cb(status, msg, percent)
                                   if status == "network_fail" then
                                       -- 网络连接失败,可记录日志或提示用户检查网络
                                       log.warn("fota", "网络连接失败:", msg)
                                   elseif status == "boot_report" then
                                       -- 正在检测上次升级结果,启动时自动触发
                                       log.info("fota", "检测升级结果:", msg)
                                   elseif status == "checking" then
                                       -- 正在检测更新
                                       log.info("fota", "检测更新:", msg)
                                   elseif status == "check_fail" then
                                       -- 检测失败,可能是网络问题或服务器异常
                                       log.warn("fota", "检测失败:", msg)
                                   elseif status == "no_new_version" then
                                       -- 当前已是最新版本,无需升级
                                       log.info("fota", "已是最新版本:", msg)
                                   elseif status == "new_version" then
                                       -- 发现新版本,准备下载
                                       log.info("fota", "发现新版本:", msg)
                                   elseif status == "download_start" then
                                       -- 开始下载升级包
                                       log.info("fota", "开始下载:", msg)
                                   elseif status == "downloading" then
                                       -- 正在下载,显示进度(percent 为 0-100 的整数)
                                       log.info("fota", "下载进度:", msg, percent .. "%")
                                   elseif status == "download_fail" then
                                       -- 下载失败,可能是网络中断或存储空间不足
                                       log.warn("fota", "下载失败:", msg)
                                   elseif status == "download_done" then
                                       -- 升级包已就绪,等待用户确认重启
                                       log.info("fota", "下载完成:", msg)
                                   elseif status == "rebooting" then
                                       -- 正在重启,准备应用升级
                                       log.info("fota", "重启升级:", msg)
                                   elseif status == "upgrade_success" then
                                       -- 升级成功,版本已更新
                                       log.info("fota", "升级成功:", msg)
                                   elseif status == "upgrade_fail" then
                                       -- 升级失败或无变化
                                       log.warn("fota", "升级失败:", msg)
                                   end
                               end

                      msg
                      参数含义:状态描述信息,参考状态码说明;
                      数据类型:string;
                      取值范围:参考 status 状态码说明;
                      是否必选:可选传入此参数;
                      注意事项:无;
                      参数示例:参考上方 status 参数示例;

                      percent
                      参数含义:下载进度百分比(0~100),仅在 status == "downloading" 时有效,其他状态为 nil;
                      数据类型:number;
                      取值范围:0-100;
                      注意事项:无;
                      参数示例:参考上方 status 参数示例;

             数据类型:function;
             取值范围:无;
             是否必选:可选传入此参数;
             注意事项:无;
             参数示例:参考上方 status 参数示例;
             on_status = ,

             参数含义:确认回调函数,内含三个参数,格式如下:
                      action
                      参数含义:确认操作类型;
                      数据类型:string;
                      取值范围:"download" -- 确认下载
                               "reboot"   -- 确认重启
                      是否必选:是;
                      注意事项:无;
                      参数示例:参考下方 on_confirm 参数示例;

                      info
                      参数含义:确认操作的详细信息,当 action == "download" 时:包含以下字段:
                               info.version
                               参数含义:升级包的脚本版本号;
                               数据类型:string;
                               取值范围:由FOTA服务端返回;
                               是否必选:是;
                               注意事项:仅 action == "download" 时存在;
                               参数示例:"001.999.000"

                               info.size
                               参数含义:升级包大小(字节);
                               数据类型:number;
                               取值范围:大于0的整数;
                               是否必选:是;
                               注意事项:仅 action == "download" 时存在;
                               参数示例:102400

                               info.fota_sn
                               参数含义:FOTA序列号,用于标识本次升级任务;
                               数据类型:string;
                               取值范围:由FOTA服务端返回;
                               是否必选:是;
                               注意事项:仅 action == "download" 时存在;
                               参数示例:"202606201234567890"
                      数据类型:table 或 nil;
                      取值范围:当 action == "download" 时:包含以上字段;
                               当 action == "reboot" 时:为 nil;
                      是否必选:可选传入此参数;
                      注意事项:无;
                      参数示例:参考下方 on_confirm 参数示例;

                      callback
                      参数含义:确认结果回调函数,用于通知库用户的选择;
                      数据类型:function;
                      取值范围:无;
                      是否必选:可选传入此参数;
                      注意事项:调用 callback(true) 表示确认,callback(false) 表示取消;
                      参数示例:参考下方 on_confirm 参数示例;

             数据类型:function;
             取值范围:无;
             是否必选:可选传入此参数;
             注意事项:不传入时默认允许所有操作;
             参数示例:-- 如下方所示,定义了一个函数 fota_confirm 就可以做为此参数传入
                      local function fota_confirm(action, info, callback)
                          if action == "download" then
                              -- 确认下载,info 包含版本、大小、序列号
                              log.info("fota", "收到下载请求:")
                              log.info("fota", "  版本:", info.version)
                              log.info("fota", "  大小:", info.size, "字节")
                              log.info("fota", "  序列号:", info.fota_sn)
                              -- true 表示用户确认下载
                              callback(true)
                          elseif action == "reboot" then
                              -- 确认重启,info 为 nil
                              log.info("fota", "收到重启请求")
                              -- true 表示用户确认重启升级
                              callback(true)
                          end
                      end
        }

返回值

无;

示例

-- 启动 FOTA 升级功能
libfota3.request({
    project_key = "your_project_key",    -- 项目密钥,用于FOTA服务认证
    script_name = "fota3_temp",          -- 脚本名称
    script_version = "001.999.000",      -- 脚本版本
    auto = true,                         -- 启用自动定时检测
    interval = 86400,                    -- 自动检测间隔(秒),默认24小时
    on_status = function(status, msg, percent)
        log.info("fota_temp", status, msg, percent)
    end,
    on_confirm = function(action, info, callback)
        if action == "download" then
            log.info("fota_temp", "download", info.version, info.size, info.fota_sn)
            -- true 表示用户确认下载
            callback(true)
        elseif action == "reboot" then
            -- true 表示用户确认重启升级
            callback(true)
        end
    end,
})

-- 间隔一段时间后。。。。。。。

-- 手动执行检测更新
libfota3.check_update()

-- 间隔一段时间后。。。。。。。

-- 动态修改自动检测参数
libfota3.config({auto = true, interval = 86400})

4.4 libfota3.version()

功能

获取当前 libfota3 扩展库自身的版本号,返回值为字符串形式的“年月日时分”(格式:YYYYMMDDHHmm),可用于确认设备上实际运行的扩展库版本。

注意事项

  1. 该接口为纯查询接口,不依赖 request() 初始化,可在脚本任意位置随时调用。

  2. 返回的是扩展库自身的版本号,与脚本版本(script_version)、核心固件版本无关,扩展库更新后返回值才会随之变化。

  3. 扩展库加载时会自动通过 log.debug 打印一次版本号(格式为 “libfota3 version -> 版本号”),便于排查设备上运行的库版本。

参数

无。

返回值

local version = libfota3.version()

version

含义说明:库文件版本信息,string 类型的年月日时分;
数据类型:string;
取值范围:12 位数字;
返回示例:"202609151040"

示例

local libfota3 = require("libfota3")

-- 获取扩展库版本号并打印
log.info("fota", "libfota3版本:", libfota3.version())    -- 输出:libfota3版本: 202609151040

五、版本更新说明

版本号:202609151040

1、更新时间:2026-09-15 10:40

2、更新内容(首版发布)

  • 新增 request() 接口,等待时间同步后启动自动检测定时器,支持基于时间戳的跨重启延续检测

  • 新增 check_update() 接口,手动触发检测更新,复用 running 互斥标志

  • 新增 config() 接口,动态修改配置参数并自动同步定时器启停

  • 新增 version() 接口,返回库版本号

  • 支持 HTTP 检测更新,自动向 FOTA 服务器查询新版本

  • 支持 HTTP 下载升级包,自动选择 PSRAM 或内部 Flash 存储临时文件

  • 支持 SHA256 校验,确保升级包完整性

  • 支持下载进度回调,实时反馈下载百分比

  • 支持用户确认回调,有屏设备可交互确认下载和重启操作

  • 支持升级结果上报,自动将升级成功/失败结果发送给 FOTA 服务器

  • 支持开机版本比对,重启后自动检测升级是否成功并上报

  • 支持多平台设备标识获取(IMEI/MAC/unique_id),覆盖 Air780E/Air8000/Air8101/Air1601/Air1602/Air1780 等系列

六、产品支持说明

支持 LuatOS 开发的所有产品都支持 libfota3 扩展库。

七、操作演示说明

7.1 概述

根据前面 4.1 libfota3.request(new_opts) 接口说明,我们可以通过手动去控制自动下载和自动重启,因此本扩展库支持 UI 和非 UI 场景。示例代码参考 support_ui 和 no_support_ui 两种示例代码。

本操作演示文档使用 Air780EPM 核心板搭配 no_support_ui 示例代码进行演示 libfota3.request(new_opts) 这一个接口的功能。其余接口请自行研究。

本次演示从 Air780EPM V2050 1 号固件 001.999.000 版本升级到 V2052 1 号固件 001.999.001。

7.2 准备硬件环境

1、本操作演示文档使用 4G 网络环境,其他环境还需自己实测;

2、libfota3 扩展库支持所有二次开发的模组。

本次演示使用 Air780EPM 核心板、SIM 卡、数据线。下图为 Air780EPM 核心板示意图。

采购链接:Air780EPM 核心板

image.png

7.3 准备软件环境

1、Luatools 下载调试工具;

2、Air780EPM fota3 示例代码;

3、Air780EPM 演示固件;

1、需要准备两个生成的量产固件(一个旧版本量产固件,一个新版本量产固件);

2、如何生成量产固件,请看 Luatools 下载调试工具使用文档,或者直接看下方实际的操作说明即可;

3、此处存放本次演示使用的两个量产固件,方便验证问题,实际测试时要自己重新生成,待升级不成功时可以拿这两个量产固件验证。

旧版本量产固件:

FOTA3_NO_UI_001.999.000_LuatOS-SoC_V2050_Air780EPM_1.soc

新版本量产固件:

FOTA3_NO_UI_001.999.001_LuatOS-SoC_V2052_Air780EPM_1.soc

7.4 操作步骤演示

打开 合宙云平台,进入合宙 IoT 平台页面。

image.png

在“合宙IoT-我的项目”页面点击“新建项目”按钮,按照下图要求填写信息,最后点击“提交”按钮,在“合宙IoT-我的项目”页面可以看到新建的项目。

项目名称:可根据自己项目需求自定义名称。我填写的名称为“libfota3升级测试”;

项目描述:非必填。

image.png

在“合宙IoT-我的项目”页面,找到对应项目的“项目key”列,点击复制这个对应项目的项目key。

image.png

使用 vscode/trae 等工具打开本文要用的示例代码文件(参考 7.3 准备软件环境),打开 fota3_auto.lua 文件,参考下图所示,将刚才复制到的项目 key 粘贴到代码中对应位置。

image.png

参考 LuaTools工具教程 熟悉资源下载、新建项目、添加脚本、底层固件操作。

1、打开 Luatools 工具,点击左上侧的“4 合宙各种资源入口”;

2、点击“4.3 软件资源下载”,此时会弹出“LuaTools资源管理”窗口;

3、勾选对应的底层固件标签,本次要下载的是“Air780EPM V2050 1 号固件”和“Air780EPM V2052 1 号固件”;

4、点击“LuaTools资源管理”窗口上方的“开始下载(非刷机)”,此时两个底层固件就被下载到本地了;可通过点击“打开本地资源目录”查看下载的资源文件;

image.png

5、点击右侧的“项目管理”按钮,此时会弹出“项目管理”窗口;

6、点击“项目管理”窗口左下角的“创建”按钮,此时会弹出“创建”窗口,输入项目名称;

7、点击“创建”窗口中的“确定”按钮,新建完成;

8、新建好的项目会在“项目管理”窗口左侧显示;

image.png

9、点击新建好的项目;

10、点击“项目管理”窗口右上角的“选择文件”,添加对应的底层固件,此时添加的是 Air780EPM V2050 1 号固件;

11、点击“项目管理”窗口右侧的“增加脚本或资源文件”或者“增加目录(递归)”,添加对应脚本文件,也就是前面说的示例代码文件;(此时 main.lua 文件中 VERSION 版本号为 001.999.000)

image.png

image.png

12、点击“项目管理”窗口中间的“选择目录”按钮,选择一个合适的保存路径,用于保存生成后的量产文件;

13、点击“项目管理”窗口中间的“生成量产文件”按钮,生成量产文件;

image.png

14、点击“项目管理”窗口右上角的“选择文件”,更换其他底层固件,此时添加的是 Air780EPM V2052 1 号固件;

15、同时需要将 main.lua 文件中的 VERSION 版本号修改为 001.999.001,不需要重新添加;

image.png

image.png

16、点击“项目管理”窗口中间的“生成量产文件”按钮,生成另一个量产文件;

image.png

17、每一次生成,会生成三个文件,后缀分别为 .soc 、.binpkg 、.bin,我们要用到的是 .soc 文件;

image.png

点击进入“合宙IoT-固件升级-libfota3-固件列表”界面。选择对应的项目。

libfota/libfota2、libfota3的固件列表位置说明:

在合宙IoT平台页面顶部的导航菜单栏区域,找到名为固件升级的下拉按钮,将鼠标指针悬停在【固件升级】按钮上,会展开一级下拉菜单;在展开的菜单内:

1、将鼠标悬停在libfota/libfota2选项中,会弹出二级子菜单,libfota/libfota2的固件列表就位于这个二级子菜单中;

2、将鼠标悬停在libfota3选项中,也会弹出二级子菜单,libfota3的固件列表就位于这个二级子菜单中;

image.png

在“合宙IoT-固件升级-libfota3-固件列表”界面,点击右侧的“创建固件”按钮,此时会有一个“创建固件”窗口,接着点击“创建固件”窗口中的“点击选择文件”,添加刚才生成好的量产文件(.soc 后缀),本次先添加第一个量产文件(FOTA3_NO_UI_001.999.000_LuatOS-SoC_V2050_Air780EPM_1.soc),然后点击“创建固件”窗口中的“提交”按钮。

image.png

接着按照刚才的步骤重新点击“创建固件”按钮,然后添加第二个量产文件(FOTA3_NO_UI_001.999.001_LuatOS-SoC_V2052_Air780EPM_1.soc),最后点击“提交”。

添加好的两个文件在“合宙IoT-固件升级-libfota3-固件列表”界面均有显示。

image.png

点击进入“合宙IoT-固件升级-libfota3-升级配置”界面。选择对应的项目。

image.png

在“合宙IoT-固件升级-libfota3-升级配置”界面,点击右侧的“创建配置”按钮,此时会弹出一个“新建升级配置”的窗口。

根据下图中的描述,按照项目需求进行填写和选择,最后点击“提交”按钮;

名称:根据项目需求自定义;

备注:非必填

状态:激活状态时,这个升级配置会生效;非激活状态时,这个升级配置不会生效;

指定设备:选择“所有设备”时,则对应项目下的所有设备在使用 libfota3 时,都会按照这个配置触发升级;如果不打算升级所有设备,请不要勾选“所有设备”,请自己填写对应设备的IMEI/MAC。

目标固件:可以理解为要升级到哪个固件,也就是新固件;

基础固件:勾选“所有固件”时,那么设备只要符合下方基础固件列表中的任一版本基础固件,都会触发升级到目标固件;

勾选基础固件:不勾选“所有固件”时,只要自己选择基础固件,支持手动多选。

image.png

点击“合宙IoT-固件升级-libfota3-升级配置”界面“新建升级配置”窗口的“提交”按钮之后,这个升级配置就会在“合宙IoT-固件升级-libfota3-升级配置”界面显示,需要观察这个升级配置的“升级包状态”,如果配置没有问题,一段时间之后会从“生成中”变成“已完成”。(注意:UI显示不会自动更新,需要手动刷新页面)

image.png

在 Luatools 工具界面,点击右侧的“使用量产文件刷机”按钮,此时会弹出一个“下载固件”窗口,接着点击“选择文件”按钮,添加旧版本量产文件(FOTA3_NO_UI_001.999.000_LuatOS-SoC_V2050_Air780EPM_1.soc),最后点击下载。

注意:

1、先让设备正常开机,可以输出日志,然后点击下载,此时会自动进入下载模式进行烧录操作。

2、设备只有在第一次烧录后,才会触发一次升级请求,后续都会按照设定的触发周期才会触发升级,哪怕重启模组也会生效,因此烧录时记得勾选“清除kv分区”、“清除文件系统分区”。

image.png

下方为设备从最开始烧录成功到最后升级成功的完整日志信息。

[2026-09-18 14:02:45.177] 工具提示: soc log port COM4打开成功
[2026-09-18 14:02:45.377] 工具提示: ap log port COM6打开成功
[2026-09-18 14:02:45.385] 工具提示: 用户虚拟串口 COM5
[2026-09-18 14:02:45.406][000000000.000] main_entry 708:SDK base line V017_p001.026
[2026-09-18 14:02:45.407][000000000.007] am_service_init 1388:Air780EPM_A11
[2026-09-18 14:02:45.408][000000000.007] am_get_chip_type 874:6bef6,8,4,6d,8,EC718PM
[2026-09-18 14:02:45.409][000000000.007] am_service_init 1396:APB MP 102400000
[2026-09-18 14:02:45.409][000000000.061] bsp_user_init_io 390:io volt 3.3v 21
[2026-09-18 14:02:45.410][000000000.062] BSP_CustomInit 558:hardfault mode init 4
[2026-09-18 14:02:45.411][000000000.062] Uart_ChangeBR 1461:uart0, 6000000 6028985 26000000 69
[2026-09-18 14:02:45.412][000000000.083] I/pm poweron: Power/Reset
[2026-09-18 14:02:45.413][000000000.083] luat_pm_get_poweron_reason 332:ap 2, cp 2
[2026-09-18 14:02:45.414][000000000.083] I/pm poweron reason: 0 0 5
[2026-09-18 14:02:45.415][000000000.334] self_info 125:model Air780EPM_A11 imei 866597079394597 dbversion 0x07c3672f
[2026-09-18 14:02:45.416][000000000.334] self_info 127:firmware[1] BASIC fs 168kbyte script 256kbyte
[2026-09-18 14:02:45.417][000000000.336] D/vfs fopen /apns.bin rb not found
[2026-09-18 14:02:45.418][000000000.336] D/vfs fopen /luadb/apns.bin rb not found
[2026-09-18 14:02:45.419][000000000.336] I/main LuatOS@Air780EPM base 26.04 bsp V2050 32bit
[2026-09-18 14:02:45.419][000000000.336] I/main ROM Build: Aug 21 2026 19:53:21
[2026-09-18 14:02:45.420][000000000.339] W/pins /luadb/pins_air780epm.json not exist!!
[2026-09-18 14:02:45.422][000000000.341] D/main loadlibs luavm 1048568 14784 14784
[2026-09-18 14:02:45.423][000000000.341] D/main loadlibs sys   2365512 82956 87232
[2026-09-18 14:02:45.424][000000000.341] D/main loadlibs psram 2365512 82956 87232
[2026-09-18 14:02:45.425][000000000.359] I/user.main FOTA3_NO_UI 001.999.000
[2026-09-18 14:02:45.426][000000000.392] D/vfs fopen /fota_state.json r not found
[2026-09-18 14:02:45.427][000000000.393] I/user.libfota3 no state file, skip boot report
[2026-09-18 14:02:45.428][000000000.396] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:45.986][000000001.397] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:46.990][000000002.398] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:47.991][000000003.395] I/user.fota3 脚本版本号 001.999.000 core版本号 V2050
[2026-09-18 14:02:47.992][000000003.399] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:48.993][000000004.400] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:49.992][000000005.401] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:50.987][000000006.395] I/user.fota3 脚本版本号 001.999.000 core版本号 V2050
[2026-09-18 14:02:50.988][000000006.402] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:02:51.475][000000006.775] I/mobile sim0 sms ready
[2026-09-18 14:02:51.476][000000006.775] D/mobile cid1, state0
[2026-09-18 14:02:51.476][000000006.776] D/mobile bearer act 0, result 0
[2026-09-18 14:02:51.477][000000006.776] D/mobile NETIF_LINK_ON -> IP_READY
[2026-09-18 14:02:51.477][000000006.777] I/user.netdrv_4g.ip_ready_func IP_READY 10.116.204.85 255.255.255.255 0.0.0.0 nil
[2026-09-18 14:02:51.478][000000006.778] I/user.fota3_auto recv IP_READY 1 1
[2026-09-18 14:02:51.478][000000006.779] I/user.libfota3 wait network, timeout 60s
[2026-09-18 14:02:51.479][000000006.779] I/user.libfota3 network ready
[2026-09-18 14:02:51.479][000000006.780] D/sntp query ntp.aliyun.com
[2026-09-18 14:02:51.480][000000006.780] dns_run 845:ntp.aliyun.com state 0 id 48297 ipv6 0 use dns server0, try 0
[2026-09-18 14:02:51.480][000000006.813] D/mobile TIME_SYNC 0 tm 1789711371
[2026-09-18 14:02:51.481][000000006.815] I/user.libfota3 时间同步完成 2026-09-18 14:02:51
[2026-09-18 14:02:51.481][000000006.817] D/vfs fopen /fota_timer_state.json r not found
[2026-09-18 14:02:51.482][000000006.818] I/user.libfota3 检测已过期或首次运行,立即触发
[2026-09-18 14:02:51.483][000000006.818] I/user.libfota3 wait network, timeout 60s
[2026-09-18 14:02:51.483][000000006.819] I/user.libfota3 network ready
[2026-09-18 14:02:51.484][000000006.819] I/user.fota3 [checking] 正在检测更新...
[2026-09-18 14:02:51.485][000000006.823] I/user.libfota3 check id imei 866597079394597 model Air780EPM core_id 1 core_version 2050 script 001.999.000
[2026-09-18 14:02:51.485][000000006.824] dns_run 845:iot.openluat.com state 0 id 48298 ipv6 0 use dns server0, try 0
[2026-09-18 14:02:51.486][000000006.863] dns_run 862:dns all done ,now stop
[2026-09-18 14:02:51.486][000000006.888] D/sntp Unix timestamp: 1789711371
[2026-09-18 14:02:51.639][000000007.040] I/http http close c1d5920
[2026-09-18 14:02:51.639][000000007.042] I/user.libfota3 new version found script 001.999.001 size 83609
[2026-09-18 14:02:51.640][000000007.043] I/user.fota3 [new_version] 发现新版本 001.999.001 (81KB)
[2026-09-18 14:02:51.640][000000007.047] I/user.libfota3 state file saved has_update
[2026-09-18 14:02:51.641][000000007.047] I/user.libfota3 wait network, timeout 60s
[2026-09-18 14:02:51.641][000000007.048] I/user.libfota3 network ready
[2026-09-18 14:02:51.642][000000007.048] I/user.fota3 [download_start] 开始下载升级包...
[2026-09-18 14:02:51.642][000000007.049] D/vfs fopen /ram/fota_update.bin r not found
[2026-09-18 14:02:51.643][000000007.049] I/user.libfota3 download http://cdn.openluat-backend.openluat.com/upgrade_firmware/turnkey_diff_c220_b582_t583_2d96618826594cc1ac6a41c370de94ec.bin -> /ram/fota_update.bin
[2026-09-18 14:02:51.643][000000007.051] dns_run 845:cdn.openluat-backend.openluat.com state 0 id 48299 ipv6 0 use dns server0, try 0
[2026-09-18 14:02:51.777][000000007.188] dns_run 862:dns all done ,now stop
[2026-09-18 14:02:52.243][000000007.647] I/user.fota3 [downloading] 正在下载: 0% (0/81 KB) 0%
[2026-09-18 14:02:52.244][000000007.650] I/user.fota3 [downloading] 正在下载: 2% (1/81 KB) 2%
[2026-09-18 14:02:52.245][000000007.651] I/user.fota3 [downloading] 正在下载: 3% (3/81 KB) 3%
[2026-09-18 14:02:52.246][000000007.651] I/user.fota3 [downloading] 正在下载: 5% (4/81 KB) 5%
[2026-09-18 14:02:52.246][000000007.652] I/user.fota3 [downloading] 正在下载: 6% (5/81 KB) 6%
[2026-09-18 14:02:52.247][000000007.655] I/user.fota3 [downloading] 正在下载: 8% (7/81 KB) 8%
[2026-09-18 14:02:52.331][000000007.691] I/user.fota3 [downloading] 正在下载: 10% (8/81 KB) 10%
[2026-09-18 14:02:52.332][000000007.692] I/user.fota3 [downloading] 正在下载: 11% (9/81 KB) 11%
[2026-09-18 14:02:52.333][000000007.706] I/user.fota3 [downloading] 正在下载: 13% (10/81 KB) 13%
[2026-09-18 14:02:52.334][000000007.707] I/user.fota3 [downloading] 正在下载: 14% (12/81 KB) 14%
[2026-09-18 14:02:52.334][000000007.709] I/user.fota3 [downloading] 正在下载: 16% (13/81 KB) 16%
[2026-09-18 14:02:52.335][000000007.724] I/user.fota3 [downloading] 正在下载: 18% (14/81 KB) 18%
[2026-09-18 14:02:52.336][000000007.731] I/user.fota3 [downloading] 正在下载: 19% (16/81 KB) 19%
[2026-09-18 14:02:52.336][000000007.732] I/user.fota3 [downloading] 正在下载: 21% (17/81 KB) 21%
[2026-09-18 14:02:52.337][000000007.745] I/user.fota3 [downloading] 正在下载: 22% (18/81 KB) 22%
[2026-09-18 14:02:52.348][000000007.761] I/user.fota3 [downloading] 正在下载: 24% (20/81 KB) 24%
[2026-09-18 14:02:52.365][000000007.766] I/user.fota3 [downloading] 正在下载: 26% (21/81 KB) 26%
[2026-09-18 14:02:52.366][000000007.767] I/user.fota3 [downloading] 正在下载: 27% (22/81 KB) 27%
[2026-09-18 14:02:52.367][000000007.771] I/user.fota3 [downloading] 正在下载: 29% (24/81 KB) 29%
[2026-09-18 14:02:52.367][000000007.772] I/user.fota3 [downloading] 正在下载: 31% (25/81 KB) 31%
[2026-09-18 14:02:52.379][000000007.785] I/user.fota3 [downloading] 正在下载: 32% (26/81 KB) 32%
[2026-09-18 14:02:52.444][000000007.801] I/user.fota3 [downloading] 正在下载: 34% (27/81 KB) 34%
[2026-09-18 14:02:52.444][000000007.806] I/user.fota3 [downloading] 正在下载: 35% (29/81 KB) 35%
[2026-09-18 14:02:52.445][000000007.806] I/user.fota3 [downloading] 正在下载: 37% (30/81 KB) 37%
[2026-09-18 14:02:52.445][000000007.809] I/user.fota3 [downloading] 正在下载: 39% (31/81 KB) 39%
[2026-09-18 14:02:52.446][000000007.810] I/user.fota3 [downloading] 正在下载: 40% (33/81 KB) 40%
[2026-09-18 14:02:52.446][000000007.825] I/user.fota3 [downloading] 正在下载: 42% (34/81 KB) 42%
[2026-09-18 14:02:52.447][000000007.841] I/user.fota3 [downloading] 正在下载: 43% (35/81 KB) 43%
[2026-09-18 14:02:52.447][000000007.846] I/user.fota3 [downloading] 正在下载: 45% (37/81 KB) 45%
[2026-09-18 14:02:52.448][000000007.847] I/user.fota3 [downloading] 正在下载: 47% (38/81 KB) 47%
[2026-09-18 14:02:52.448][000000007.848] I/user.fota3 [downloading] 正在下载: 48% (39/81 KB) 48%
[2026-09-18 14:02:52.456][000000007.866] I/user.fota3 [downloading] 正在下载: 50% (41/81 KB) 50%
[2026-09-18 14:02:52.457][000000007.867] I/user.fota3 [downloading] 正在下载: 51% (42/81 KB) 51%
[2026-09-18 14:02:52.470][000000007.881] I/user.fota3 [downloading] 正在下载: 53% (43/81 KB) 53%
[2026-09-18 14:02:52.471][000000007.885] I/user.fota3 [downloading] 正在下载: 55% (44/81 KB) 55%
[2026-09-18 14:02:52.472][000000007.886] I/user.fota3 [downloading] 正在下载: 56% (46/81 KB) 56%
[2026-09-18 14:02:52.490][000000007.891] I/user.fota3 [downloading] 正在下载: 58% (47/81 KB) 58%
[2026-09-18 14:02:52.490][000000007.892] I/user.fota3 [downloading] 正在下载: 59% (48/81 KB) 59%
[2026-09-18 14:02:52.550][000000007.926] I/user.fota3 [downloading] 正在下载: 61% (50/81 KB) 61%
[2026-09-18 14:02:52.551][000000007.927] I/user.fota3 [downloading] 正在下载: 63% (51/81 KB) 63%
[2026-09-18 14:02:52.552][000000007.929] I/user.fota3 [downloading] 正在下载: 64% (52/81 KB) 64%
[2026-09-18 14:02:52.552][000000007.929] I/user.fota3 [downloading] 正在下载: 66% (54/81 KB) 66%
[2026-09-18 14:02:52.562][000000007.966] I/user.fota3 [downloading] 正在下载: 67% (55/81 KB) 67%
[2026-09-18 14:02:52.563][000000007.967] I/user.fota3 [downloading] 正在下载: 69% (56/81 KB) 69%
[2026-09-18 14:02:52.563][000000007.968] I/user.fota3 [downloading] 正在下载: 71% (58/81 KB) 71%
[2026-09-18 14:02:52.599][000000008.001] I/user.fota3 [downloading] 正在下载: 72% (59/81 KB) 72%
[2026-09-18 14:02:52.600][000000008.006] I/user.fota3 [downloading] 正在下载: 74% (60/81 KB) 74%
[2026-09-18 14:02:52.600][000000008.007] I/user.fota3 [downloading] 正在下载: 75% (61/81 KB) 75%
[2026-09-18 14:02:52.600][000000008.009] I/user.fota3 [downloading] 正在下载: 77% (63/81 KB) 77%
[2026-09-18 14:02:52.601][000000008.010] I/user.fota3 [downloading] 正在下载: 79% (64/81 KB) 79%
[2026-09-18 14:02:52.654][000000008.041] I/user.fota3 [downloading] 正在下载: 80% (65/81 KB) 80%
[2026-09-18 14:02:52.655][000000008.046] I/user.fota3 [downloading] 正在下载: 82% (67/81 KB) 82%
[2026-09-18 14:02:52.656][000000008.047] I/user.fota3 [downloading] 正在下载: 83% (68/81 KB) 83%
[2026-09-18 14:02:52.657][000000008.049] I/user.fota3 [downloading] 正在下载: 85% (69/81 KB) 85%
[2026-09-18 14:02:52.661][000000008.066] I/user.fota3 [downloading] 正在下载: 87% (71/81 KB) 87%
[2026-09-18 14:02:52.661][000000008.067] I/user.fota3 [downloading] 正在下载: 88% (72/81 KB) 88%
[2026-09-18 14:02:52.672][000000008.081] I/user.fota3 [downloading] 正在下载: 90% (73/81 KB) 90%
[2026-09-18 14:02:52.689][000000008.091] I/user.fota3 [downloading] 正在下载: 91% (75/81 KB) 91%
[2026-09-18 14:02:52.690][000000008.093] I/user.fota3 [downloading] 正在下载: 93% (76/81 KB) 93%
[2026-09-18 14:02:52.690][000000008.094] I/user.fota3 [downloading] 正在下载: 95% (77/81 KB) 95%
[2026-09-18 14:02:52.710][000000008.106] I/user.fota3 [downloading] 正在下载: 96% (78/81 KB) 96%
[2026-09-18 14:02:52.711][000000008.107] I/user.fota3 [downloading] 正在下载: 98% (80/81 KB) 98%
[2026-09-18 14:02:52.774][000000008.125] I/user.fota3 [downloading] 正在下载: 99% (81/81 KB) 99%
[2026-09-18 14:02:52.775][000000008.126] I/user.fota3 [downloading] 正在下载: 100% (81/81 KB) 100%
[2026-09-18 14:02:52.776][000000008.127] I/http http close c1d5920
[2026-09-18 14:02:52.776][000000008.129] I/user.libfota3 download complete 83609 bytes
[2026-09-18 14:02:52.777][000000008.180] I/user.libfota3 sha256 verified
[2026-09-18 14:02:52.799][000000008.202] I/fota write common data
[2026-09-18 14:02:52.925][000000008.334] I/fota common data done, now checking 0
[2026-09-18 14:02:52.926][000000008.336] I/fota common data md5 ok
[2026-09-18 14:02:52.926][000000008.337] I/fota write core data
[2026-09-18 14:02:53.199][000000008.610] I/fota validate delta ok!
[2026-09-18 14:02:53.479][000000008.891] I/fota sdk data ok!
[2026-09-18 14:02:53.525][000000008.930] I/fota fota type 1 ok!, wait reboot
[2026-09-18 14:02:53.526][000000008.930] I/fota fota file write done, call fota.done()
[2026-09-18 14:02:53.526][000000008.931] I/fota fota done success, call fota.end()
[2026-09-18 14:02:53.527][000000008.931] I/user.libfota3 download and flash complete
[2026-09-18 14:02:53.527][000000008.940] I/user.libfota3 state file saved download_done
[2026-09-18 14:02:53.528][000000008.941] I/user.fota3 [download_done] 升级包已就绪,重启即可升级
[2026-09-18 14:02:53.528][000000008.941] I/user.fota3 [rebooting] 正在重启...
[2026-09-18 14:02:53.541][000000008.945] I/user.libfota3 timer state saved, ts 1789711373
[2026-09-18 14:02:53.542][000000008.946] I/user.libfota3 下次检测间隔 86400 秒
[2026-09-18 14:02:53.992][000000009.395] I/user.fota3 脚本版本号 001.999.000 core版本号 V2050
[2026-09-18 14:02:54.183] 工具提示: print com USB 断开连接 COM4 CommError,[WinError 22] 设备不识别此命令。
[2026-09-18 14:03:25.230] 工具提示: soc log port COM4打开成功
[2026-09-18 14:03:25.345] 工具提示: ap log port COM6打开成功
[2026-09-18 14:03:25.359] 工具提示: 用户虚拟串口 COM5
[2026-09-18 14:03:26.303][000000000.000] main_entry 708:SDK base line V017_p001.026
[2026-09-18 14:03:26.304][000000000.007] am_service_init 1388:Air780EPM_A11
[2026-09-18 14:03:26.305][000000000.007] am_get_chip_type 874:6bef6,8,4,6d,8,EC718PM
[2026-09-18 14:03:26.306][000000000.007] am_service_init 1396:APB MP 102400000
[2026-09-18 14:03:26.307][000000000.050] bsp_user_init_io 390:io volt 3.3v 21
[2026-09-18 14:03:26.308][000000000.051] BSP_CustomInit 558:hardfault mode init 4
[2026-09-18 14:03:26.308][000000000.051] Uart_ChangeBR 1461:uart0, 6000000 6028985 26000000 69
[2026-09-18 14:03:26.309][000000000.072] I/pm poweron: Power/Reset
[2026-09-18 14:03:26.311][000000000.072] luat_pm_get_poweron_reason 332:ap 3, cp 2
[2026-09-18 14:03:26.312][000000000.073] I/pm poweron reason: 0 0 3
[2026-09-18 14:03:26.313][000000000.196] self_info 125:model Air780EPM_A11 imei 866597079394597 dbversion 0x07c3672f
[2026-09-18 14:03:26.314][000000000.196] self_info 127:firmware[1] BASIC fs 168kbyte script 256kbyte
[2026-09-18 14:03:26.315][000000000.199] D/vfs fopen /apns.bin rb not found
[2026-09-18 14:03:26.316][000000000.199] D/vfs fopen /luadb/apns.bin rb not found
[2026-09-18 14:03:26.317][000000000.199] I/main LuatOS@Air780EPM base 26.04 bsp V2052 32bit
[2026-09-18 14:03:26.318][000000000.199] I/main ROM Build: Sep 16 2026 18:11:46
[2026-09-18 14:03:26.319][000000000.201] W/pins /luadb/pins_air780epm.json not exist!!
[2026-09-18 14:03:26.320][000000000.203] D/main loadlibs luavm 1048568 14784 14784
[2026-09-18 14:03:26.321][000000000.204] D/main loadlibs sys   2365224 82876 89396
[2026-09-18 14:03:26.322][000000000.204] D/main loadlibs psram 2365224 82876 89396
[2026-09-18 14:03:26.322][000000000.225] I/user.main FOTA3_NO_UI 001.999.001
[2026-09-18 14:03:26.323][000000000.268] I/user.libfota3 === 升级版本比对 ===
[2026-09-18 14:03:26.324][000000000.269] I/user.libfota3 core_id:     old=1  new=1  cur=1
[2026-09-18 14:03:26.325][000000000.269] I/user.libfota3 core_version:old=2050  new=2052  cur=2052
[2026-09-18 14:03:26.326][000000000.269] I/user.libfota3 script_ver:  old=001.999.000  new=001.999.001  cur=001.999.001
[2026-09-18 14:03:26.327][000000000.269] I/user.libfota3 upgrade success core_changed true script_changed true
[2026-09-18 14:03:26.328][000000000.270] I/user.libfota3 上报上次升级结果 fota_sn tk480544_20260918140251_9620619 code 1
[2026-09-18 14:03:26.329][000000000.270] I/user.libfota3 wait network, timeout 60s
[2026-09-18 14:03:26.330][000000000.273] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:26.331][000000001.273] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:27.504][000000002.273] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:27.930][000000003.272] I/user.fota3 脚本版本号 001.999.001 core版本号 V2052
[2026-09-18 14:03:27.931][000000003.274] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:28.924][000000004.274] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:29.922][000000005.274] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:30.933][000000006.272] I/user.fota3 脚本版本号 001.999.001 core版本号 V2052
[2026-09-18 14:03:30.934][000000006.275] W/user.fota3_auto wait IP_READY 1 1
[2026-09-18 14:03:31.033][000000006.299] I/mobile sim0 sms ready
[2026-09-18 14:03:31.034][000000006.299] D/mobile cid1, state0
[2026-09-18 14:03:31.034][000000006.300] D/mobile bearer act 0, result 0
[2026-09-18 14:03:31.035][000000006.300] D/mobile NETIF_LINK_ON -> IP_READY
[2026-09-18 14:03:31.035][000000006.301] I/user.netdrv_4g.ip_ready_func IP_READY 10.198.42.182 255.255.255.255 0.0.0.0 nil
[2026-09-18 14:03:31.036][000000006.302] I/user.fota3_auto recv IP_READY 1 1
[2026-09-18 14:03:31.036][000000006.302] I/user.libfota3 wait network, timeout 60s
[2026-09-18 14:03:31.037][000000006.303] I/user.libfota3 network ready
[2026-09-18 14:03:31.037][000000006.303] D/sntp query ntp.aliyun.com
[2026-09-18 14:03:31.038][000000006.303] dns_run 845:ntp.aliyun.com state 0 id 54910 ipv6 0 use dns server0, try 0
[2026-09-18 14:03:31.038][000000006.355] dns_run 862:dns all done ,now stop
[2026-09-18 14:03:31.038][000000006.356] D/mobile TIME_SYNC 0 tm 1789711411
[2026-09-18 14:03:31.039][000000006.358] I/user.libfota3 时间同步完成 2026-09-18 14:03:31
[2026-09-18 14:03:31.039][000000006.366] I/user.libfota3 定时器已启动,等待 86362 秒后检测 预计时间 2026-09-19 14:02:53
[2026-09-18 14:03:31.091][000000006.404] D/sntp Unix timestamp: 1789711411
[2026-09-18 14:03:31.927][000000007.270] I/user.libfota3 network ready
[2026-09-18 14:03:31.928][000000007.271] I/user.libfota3 report result fota_sn tk480544_20260918140251_9620619 code 1
[2026-09-18 14:03:31.929][000000007.273] dns_run 845:iot.openluat.com state 0 id 54911 ipv6 0 use dns server0, try 0
[2026-09-18 14:03:31.930][000000007.280] I/user.libfota3 state file removed
[2026-09-18 14:03:32.021][000000007.329] dns_run 862:dns all done ,now stop
[2026-09-18 14:03:32.157][000000007.508] I/http http close c1d680c
[2026-09-18 14:03:32.158][000000007.510] I/user.libfota3 report success
[2026-09-18 14:03:33.932][000000009.272] I/user.fota3 脚本版本号 001.999.001 core版本号 V2052
[2026-09-18 14:03:36.921][000000012.272] I/user.fota3 脚本版本号 001.999.001 core版本号 V2052

设备升级日志也可通过“合宙 IoT 平台-固件升级-升级日志”界面查看。

image.png

搜索