跳转至

30 libfota-远程升级

作者:孟伟 | 最后修改:2026-09-22

一、概述

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。

本文档介绍初代接口 libfota 的用法。libfota 需要传递较多参数,使用起来相对复杂,点击此处了解libfota2,点击此处了解libfota3。

二、核心示例

1、核心示例是指:使用本库文件提供的核心API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

3、如果是新项目不建议使用此接口,建议使用libfota2仓库接口。

--注意:因使用了sys.wait(),所以api需要在协程中使用
--用法实例
local libfota = require("libfota")

-- 功能:升级包下载结果回调函数,用于返回升级包下载结果
-- 参数:
-- result:number类型
--        0表示成功
--        1表示连接失败
--        2表示url错误
--        3表示服务器断开
--        4表示接收报文错误
--        5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
function libfota_cb(result)
    log.info("fota", "result", result)
    -- fota成功
    if result == 0 then
        rtos.reboot()   --如果还有其他事情要做,就不要立刻reboot
    end
end

--注意!!!:使用合宙iot平台,必须用luatools量产生成的.bin文件!!! 自建服务器可使用.ota文件!!!
--注意!!!:使用合宙iot平台,必须用luatools量产生成的.bin文件!!! 自建服务器可使用.ota文件!!!
--注意!!!:使用合宙iot平台,必须用luatools量产生成的.bin文件!!! 自建服务器可使用.ota文件!!!

--下方示例为合宙iot平台,地址:http://iot.openluat.com
libfota.request(libfota_cb)
-- 4个小时检查一次升级
sys.timerLoopStart(libfota.request, 4*3600*1000, libfota_cb)

三、常量详解

libfota核心库没有常量。

四、函数详解

libfota.request(cbFnc,ota_url,storge_location, len, param1,ota_port,libfota_timeout,server_cert, client_cert, client_key, client_password,show_otaurl)

功能

fota升级

参数

cbFnc

参数含义:升级包下载结果回调函数,用于返回升级包下载结果。回调函数的调用形式为:cbFnc(result),
         result:number类型:
                0表示成功;
                1表示连接失败;
                2表示url错误;
                3表示服务器断开;
                4表示接收报文错误;
                5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
数据类型:function类型;
取值范围:任意有效的函数名都行;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:如下方所示,定义了一个函数fota_cb就可以做为此参数传入;
         local function fota_cb(result)
             log.info("fota", result)
             if result == 0 then
                 log.info("升级包下载成功,重启模块")
                 rtos.reboot()
             elseif result == 1 then
                 log.info("连接失败", "请检查url拼写或服务器配置(是否为内网)")
             elseif result == 2 then
                 log.info("url错误", "检查url拼写")
             elseif result == 3 then
                 log.info("服务器断开", "检查服务器白名单配置")
             elseif result == 4 then
                 log.error("FOTA 失败",
                    "原因可能有:\n" ..
                    "1) 服务器返回 200/206 但报文体为空(0 字节)—— 通常是升级包文件缺失或 URL 指向空文  件;\n" ..
                    "2) 服务器返回 4xx/5xx 等异常状态码 —— 请确认升级包已上传、URL 正确、鉴权信息有 效;\n"..
                    "3) 已经是最新版本,无需升级" )
             elseif result == 5 then
                 log.info("版本号书写错误", "iot平台版本号需要使用xxx.yyy.zzz形式")
             else
                 log.info("不是上面几种情况 result为", result)
             end
         end
ota_url

参数含义:升级URL,用于指定FOTA升级的服务器地址。
数据类型:string类型
取值范围:任意有效的URL字符串
是否必选:否,不填的话默认是合宙iot平台
注意事项:暂无
参数示例:"http://xxxxxx.com/xxx/upgrade?version=" .. _G.VERSION

storge_location

参数含义:ota数据存储的起始位置
数据类型:nil,由底层决定存储位置
取值范围:无特别限制
是否必选:可选传入此参数
注意事项:暂无
参数示例:nil
len
参数含义:数据存储的最大空间
数据类型:不需要特别控制,由底层决定
取值范围:无特别限制
是否必选:可选传入此参数
注意事项:暂无
参数示例:nil
param1
参数含义:如果数据存储在spiflash时,为spi_device
数据类型:userdata类型,不需要特别控制,由底层决定
取值范围:无特别限制
是否必选:可选传入此参数
注意事项:暂无
参数示例:nil
ota_port
参数含义:请求端口,默认80
数据类型:number类型
取值范围:无特别限制
是否必选:可选传入此参数
注意事项:暂无
参数示例:80
libfota_timeout
参数含义:请求超时时间,单位毫秒,默认30000毫秒
数据类型:number类型
取值范围:无特别限制
是否必选:可选传入此参数
注意事项:暂无
参数示例:30000,表示超时时间30s
server_cert
参数含义:服务器ca证书数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当客户端需要验证服务器证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给server_ca_cert;
参数示例:例如通过Luatools烧录了server_ca.crt文件,就可以通过io.readFile("/luadb/server_ca.crt")读出文件内容赋值给赋值给server_ca_cert;
client_cert
参数含义:客户端证书数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当服务器需要验证客户端证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给client_cert;
参数示例:例如通过Luatools烧录了clinet.crt文件,就可以通过io.readFile("/luadb/clinet.crt")读出文件内容赋值给赋值给client_cert;
client_key
参数含义:加密后的客户端私钥数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_key;
参数示例:例如通过Luatools烧录了clinet.key文件,就可以通过io.readFile("/luadb/clinet.key")读出文件内容赋值给client.key;
client_password
参数含义:客户端私钥口令数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_password;
参数示例:例如通过Luatools烧录了clinet.password文件,就可以通过io.readFile("/luadb/clinet.password")读出文件内容赋值给client_password;
show_otaurl
参数含义:是否从日志中输出打印OTA升级包的URL路径,默认会打印
数据类型:boolean类型
取值范围:true或false
是否必选:可选传入此参数
注意事项:暂无
参数示例:false

返回值

无

示例

使用合宙iot服务器升级示例

--注意:因使用了sys.wait(),所以api需要在协程中使用
--用法实例
local libfota = require("libfota")

-- 功能:升级包下载结果回调函数,用于返回升级包下载结果
-- 参数:
-- result:number类型
--   0表示成功
--   1表示连接失败
--   2表示url错误
--   3表示服务器断开
--   4表示接收报文错误
--   5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
function libfota_cb(result)
    log.info("fota", "result", result)
    -- fota成功
    if result == 0 then
        rtos.reboot()   --如果还有其他事情要做,就不要立刻reboot
    end
end

--注意!!!:使用合宙iot平台,必须用luatools量产生成的.bin文件!!! 自建服务器可使用.ota文件!!!
--注意!!!:使用合宙iot平台,必须用luatools量产生成的.bin文件!!! 自建服务器可使用.ota文件!!!
--注意!!!:使用合宙iot平台,必须用luatools量产生成的.bin文件!!! 自建服务器可使用.ota文件!!!

--下方示例为合宙iot平台,地址:http://iot.openluat.com
libfota.request(libfota_cb)
-- 4个小时检查一次升级
sys.timerLoopStart(libfota.request, 4*3600*1000, libfota_cb)
使用自建服务器升级示例

--注意:因使用了sys.wait(),所以api需要在协程中使用
--用法实例
local libfota = require("libfota")

-- 功能:升级包下载结果回调函数,用于返回升级包下载结果
-- 参数:
-- result:number类型
--   0表示成功
--   1表示连接失败
--   2表示url错误
--   3表示服务器断开
--   4表示接收报文错误
--   5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
function libfota_cb(result)
    log.info("fota", "result", result)
    -- fota成功
    if result == 0 then
        rtos.reboot()   --如果还有其他事情要做,就不要立刻reboot
    end
end

-- 如使用自建服务器,自行更换url
-- 对自定义服务器的要求是:
-- 若需要升级, 响应http 200, body为升级文件的内容
-- 若不需要升级, 响应300或以上的代码,务必注意
libfota.request(libfota_cb,"http://xxxxxx.com/xxx/upgrade?version=" .. _G.VERSION)

-- 自建平台
sys.timerLoopStart(libfota.request, 4*3600*1000, libfota_cb, "http://xxxxxx.com/xxx/upgrade?version=" .. _G.VERSION)

libfota.version()

功能 获取库文件版本信息

参数

无参数

返回值

local version= libfota.version()

log.info("libfota", "version -> " .. version)

version

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

示例

--返回string类型的年月日时分,例如:"202607021200"
libfota.version()

五、版本更新说明

版本号:202607021200

1、更新时间:2026-07-02 12:00

2、更新内容

  • 新增libfota.version()接口
  • 支持libfota库文件版本号管理功能,版本号的格式为:yyyymmddhhmm,表示yyyy年mm月dd日hh时mm分发布的版本

六、产品支持说明

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

搜索