init: Air780EPM 官方 LuatOS 项目代码基线

- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码
- 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等)
- 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
This commit is contained in:
wangfq
2026-08-31 08:53:49 +08:00
commit 173dd6874f
813 changed files with 125484 additions and 0 deletions
@@ -0,0 +1,237 @@
--[[
@module prj_vl53l1x
@summary Air8780P VL53L1X激光测距传感器低功耗数据采集与上报项目编排模块
@version 2.0
@date 2026.07.23
@author 江访
@usage
本文件为项目主业务编排模块,负责协调各功能模块完成完整业务流程。
三层架构说明:
drv/ 硬件驱动层 — 通过 sys.subscribe 注册,事件驱动
drv_led → LED_SET_HIGH / LED_SET_LOW
drv_psm → DRV_SET_PSM
app/ 应用功能层 — return table,直接调用
sensor_vl53l1x — 传感器驱动封装
aircloud — 云平台数据上报
fota_mgr — FOTA远程升级管理
prj/ 项目编排层 — 本文件,协调业务流程
完整业务流程:
① 发布LED_SET_HIGH → drv_led点亮LED
② 检查FOTA首次启动(fota_mgr.check_first_boot
③ 初始化传感器(sensor_vl53l1x.init
④ 采集传感器数据(sensor_vl53l1x.collect_data
⑤ 关闭传感器(sensor_vl53l1x.close
⑥ 等待4G网络就绪
⑦ 初始化excloud连接(aircloud.init
⑧ 双通道上报(aircloud.report_excloud + report_mqtt
⑨ FOTA升级检查(fota_mgr.check_and_upgrade
⑩ 关闭传感器 + 发布LED_SET_LOW → drv_led熄灭LED
⑪ 发布DRV_SET_PSM → drv_psm进入PSM+
消息协议(发布/订阅):
发布: LED_SET_HIGH(gpio) → drv_led: 拉高LED
发布: LED_SET_LOW(gpio) → drv_led: 拉低LED
发布: DRV_SET_PSM(sleep_min) → drv_psm: 进入PSM+模式
本文件没有对外接口,require "prj_vl53l1x"即可加载运行
]]
-- ==================== 加载应用功能模块(app层,return table直接调用) ====================
-- sensor_vl53l1x: VL53L1X传感器驱动封装,提供init/collect_data/close接口
local sensor_vl53l1x = require "sensor_vl53l1x"
-- aircloud: 云平台数据上报,封装excloud和MQTT双通道上报
local aircloud = require "aircloud"
-- fota_mgr: FOTA远程升级管理,含版本文件管理和首次启动检测
local fota_mgr = require "fota_mgr"
-- ==================== 加载硬件驱动模块(drv层,事件订阅,不返回接口表) ====================
-- drv_led: LED指示灯控制,订阅LED_SET_HIGH/LED_SET_LOW消息
-- 通过sys.publish("LED_SET_HIGH", gpio)控制LED点亮
-- 通过sys.publish("LED_SET_LOW", gpio)控制LED熄灭
require "drv_led"
-- drv_psm: PSM+低功耗模式驱动,订阅DRV_SET_PSM消息
-- 通过sys.publish("DRV_SET_PSM", sleep_min)进入PSM+模式
-- 进入前需要先关闭外设和熄灭LED
require "drv_psm"
-- ==================== 可配置参数 ====================
-- 用户可根据项目需求修改以下参数
-- 这些参数决定了设备的工作行为和功耗表现
local CFG = {
-- PSM+休眠时间(分钟)
-- 唤醒后重新开始完整的数据采集和上报循环
-- 合宙IoT平台建议最多10分钟请求一次,建议≤10
psm_sleep_min_s = 15,
-- 开机到进入PSM+的超时上限(秒)
-- 到时间后不管任务2是否完成,都强制进入PSM+
psm_entry_max_s = 90,
-- FOTA等待最长时间(秒)
-- 超时说明网络不好,进入PSM+下次再试
fota_wait_max_s = 600,
-- 每次唤醒后采集传感器的次数
-- 多次采集取平均值可以降低单次测量误差
sensor_samples = 3,
-- 测距模式
-- "short" — 短距离(~1.36m),抗环境光能力强
-- "standard" — 标准距离(~2.9m),通用场景
-- "long" — 长距离(~4.6m),需较好的环境光条件
sensor_range_mode = "standard",
-- I2C引脚定义(软件I2C模式)
gpio_i2c_scl = 1, -- I2C SCLGPIO1
gpio_i2c_sda = 2, -- I2C SDAGPIO2
gpio_led_ctrl = 27, -- LED指示灯,高电平点亮,PSM+前熄灭
-- MQTT配置(使用合宙测试服务器)
mqtt_broker = "lbsmqtt.airm2m.com",
mqtt_port = 1884,
}
-- ==================== 网络等待工具函数 ====================
--[[
等待4G网络就绪
通过socket.adapter判断默认网卡是否已获得IP地址。
每秒检查一次,同时等待IP_READY消息,兼顾即时性和兜底。
@param number timeout_s 等待超时时间(秒),默认120秒
@return boolean true=网络就绪,false=超时未就绪
]]
local function wait_network_ready(timeout_s)
timeout_s = timeout_s or 120
log.info("prj_vl53l1x", "等待4G网络就绪,最长" .. timeout_s .. "秒...")
for i = 1, timeout_s do
if socket.adapter(socket.dft()) then
log.info("prj_vl53l1x", "4G网络已就绪,IP:", socket.localIP(socket.LWIP_GP))
return true
end
log.warn("prj_vl53l1x", "等待IP_READY", socket.dft())
sys.waitUntil("IP_READY", 1000)
end
log.warn("prj_vl53l1x", "4G网络等待超时(未插卡或无信号),跳过联网操作")
return false
end
-- ==================== 项目主任务 ====================
local function vl53l1x_task()
log.info("prj_vl53l1x", "========== Air8780P VL53L1X 主任务启动 ==========")
-- ==================== 第一步:LED点亮 ====================
-- 通过事件驱动drv_led模块控制GPIO
-- drv_led接收到LED_SET_HIGH消息后,将指定GPIO拉高
sys.publish("LED_SET_HIGH", CFG.gpio_led_ctrl)
-- ==================== 第二步:检查FOTA首次启动 ====================
-- 比对版本标记文件中的版本号与当前运行版本号
-- 如果版本不一致,说明经历了FOTA升级并重启
-- 返回的字符串包含升级前后版本信息,需在上报时附带
local fota_first_boot_info = fota_mgr.check_first_boot()
if fota_first_boot_info then
log.info("prj_vl53l1x", "FOTA升级后首次启动:", fota_first_boot_info)
end
-- ==================== 第三步:初始化传感器 ====================
-- 配置I2C引脚并初始化VL53L1X传感器
-- 如果初始化失败,跳过数据采集步骤
local sensor_ok = sensor_vl53l1x.init(CFG.gpio_i2c_scl, CFG.gpio_i2c_sda, CFG.sensor_range_mode)
-- ==================== 第四步:采集传感器数据 ====================
-- 采集多次后取平均值,降低单次测量误差
local sensor_data = nil
if sensor_ok then
sensor_data = sensor_vl53l1x.collect_data(CFG.sensor_samples)
if sensor_data then
log.info("prj_vl53l1x", string.format("测距结果 = %d mm (有效%d帧)",
sensor_data.avg_distance, sensor_data.valid_count))
else
log.warn("prj_vl53l1x", "测距结果 = 无效(所有帧均未测到目标)")
end
-- 采集完成后立即关闭传感器,降低功耗
sensor_vl53l1x.close()
end
-- ==================== 第五步:等待4G网络就绪 ====================
-- 如果超时,跳过所有需要联网的操作
local net_ok = wait_network_ready()
if net_ok then
-- ==================== 第六步:初始化excloud连接 ====================
-- 连接到合宙IoT平台,等待认证完成
aircloud.init({transport = "tcp", auto_reconnect = true, reconnect_interval = 10, max_reconnect = 3})
-- ==================== 第七步:双通道数据上报 ====================
-- 通过excloud(合宙IoT平台)和MQTT双通道同时上报
local mqtt_topic = mobile.imei() .. "/vl53l1x/up"
local mqtt_payload
if fota_first_boot_info then
-- FOTA升级后首次启动:上报升级信息+传感器数据
local fota_msg = "FOTA升级成功: " .. fota_first_boot_info
aircloud.report_excloud(sensor_data, fota_msg)
mqtt_payload = aircloud.build_mqtt_payload(sensor_data, fota_msg)
-- 上报完成后删除版本文件,避免下次重启再次上报
fota_mgr.clear_version_file()
else
-- 正常启动:仅上报传感器数据
aircloud.report_excloud(sensor_data, nil)
mqtt_payload = aircloud.build_mqtt_payload(sensor_data, nil)
end
aircloud.report_mqtt(mqtt_topic, mqtt_payload, CFG.mqtt_broker, CFG.mqtt_port)
-- ==================== 第八步:FOTA升级检查 ====================
-- 非FOTA后首次启动才检查FOTA升级
if not fota_first_boot_info then
aircloud.report_fota_status("FOTA: 正在检查/升级中", sensor_data)
local need_reboot = fota_mgr.check_and_upgrade(CFG.fota_wait_max_s)
if need_reboot then
aircloud.report_excloud(nil, "FOTA升级包下载成功, 升级前版本: " .. VERSION)
sys.wait(1000)
rtos.reboot()
end
end
else
-- 无网络:跳过所有联网操作,直接进入PSM+
if fota_first_boot_info then
fota_mgr.clear_version_file()
end
log.info("prj_vl53l1x", "无网络,跳过上报和FOTA检查")
end
-- ==================== 第九步:关闭外设并进入PSM+ ====================
-- 关闭传感器
sensor_vl53l1x.close()
-- 熄灭LED(通过事件驱动drv_led)
-- drv_led接收到LED_SET_LOW消息后,将指定GPIO拉低
sys.publish("LED_SET_LOW", CFG.gpio_led_ctrl)
log.info("prj_vl53l1x", "所有业务完成,准备进入PSM+模式,休眠" .. CFG.psm_sleep_min_s .. "分钟")
-- 发布PSM+进入消息,通知drv_psm模块
-- drv_psm接收到DRV_SET_PSM消息后,在独立协程中执行:
-- 1. 设置深度休眠定时器(dtimer)
-- 2. 调用pm.power(pm.WORK_MODE, 3)
-- 3. 等待80秒后如果未进入PSM+则强制重启
-- drv_psm模块内部已有中断唤醒引脚和功能引脚的配置说明
sys.publish("DRV_SET_PSM", CFG.psm_sleep_min_s)
end
-- ==================== 启动项目主任务 ====================
sys.taskInit(vl53l1x_task)