作为一名嵌入式开发工程师,我最近完成了一个基于LuatOS的短信和来电转发项目。这个项目最初源于一个实际需求:我手上有几张需要保号但很少使用的SIM卡(比如绑定银行账户的备用号码),经常因为忘记携带备用手机而错过重要信息。经过几周的开发和测试,终于实现了一个稳定可靠的解决方案。
这个项目的核心是使用合宙Air780EHV等4G模组,通过Lua脚本实现短信和来电的自动转发功能。它不仅解决了个人用户的多卡管理问题,更在工业控制、安防报警等物联网场景展现了强大的应用潜力。最让我兴奋的是,这个方案完全开源,硬件成本可以控制在200元以内。
在选择硬件平台时,我重点考虑了以下几个因素:
经过对比测试,最终选择了合宙的Air780EHV模组。这款模组基于紫光展锐平台,支持LTE Cat.1,功耗表现优异(待机电流仅1mA左右),而且价格实惠(批量采购约80元/片)。更重要的是,它原生支持LuatOS,可以直接用Lua脚本开发,大大降低了开发门槛。
提示:如果项目预算充足,也可以考虑Air780EGH模组,它增加了GPS功能,适合需要定位的场景。
完整的硬件系统除了核心模组外,还需要以下组件:
PCB设计时特别注意了以下几点:
LuatOS是一个专为物联网设备设计的实时操作系统,最大的特点就是支持用Lua语言进行应用开发。相比传统的C开发方式,Lua脚本开发效率更高,特别适合快速原型开发。
开发环境搭建步骤如下:
注意:首次使用时需要安装USB转串口驱动,可以在合宙官网找到对应的驱动程序。
整个项目的代码结构如下:
code复制/sms_call_forward
├── main.lua # 主程序入口
├── sms_forward.lua # 短信转发模块
├── cc_forward.lua # 来电转发模块
├── netdrv_device.lua # 网络驱动管理
├── sntp_app.lua # 时间同步模块
└── config.lua # 配置文件
这种模块化设计使得功能扩展和维护变得非常方便。比如要新增对Slack机器人的支持,只需要修改sms_forward.lua文件即可,不会影响其他功能。
短信转发功能的实现主要分为三个部分:
lua复制-- 配置飞书机器人
local feishu = {
webhook = "https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx",
secret = "xxxxxxxx"
}
-- 配置钉钉机器人
local dingtalk = {
webhook = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxx",
secret = "xxxxxxxx"
}
lua复制function receive_sms()
-- 等待短信到达事件
sys.waitUntil("CC_IND", 5000)
-- 获取短信内容和发送号码
local num, txt = sms.getNewMessage()
-- 调用转发处理函数
sms_handler(num, txt)
end
lua复制function sms_handler(num, txt)
-- 构造消息内容
local msg = string.format("来自%s的短信:%s", num, txt)
-- 根据配置选择转发渠道
if config.feishu.enable then
http.post(feishu.webhook, {
msg_type = "text",
content = {text = msg}
}, {sign = feishu.secret})
end
if config.dingtalk.enable then
local timestamp = os.time()
local sign = crypto.hmac_sha256(timestamp.."\n"..dingtalk.secret, dingtalk.secret)
http.post(dingtalk.webhook.."×tamp="..timestamp.."&sign="..sign, {
msgtype = "text",
text = {content = msg}
})
end
end
来电转发的实现相对复杂一些,需要处理电话状态的变化:
lua复制function cc_setup()
-- 初始化电话功能
cc.init()
-- 设置状态回调函数
cc.setCallback(cc_state)
end
lua复制function cc_state(state, number)
if state == "RING" then
-- 来电状态
log.info("来电号码:", number)
cc_forward(number)
elseif state == "CALL_END" then
-- 通话结束
log.info("通话结束")
end
end
lua复制function cc_forward(number)
local msg = string.format("来自%s的来电", number)
-- 飞书机器人通知
if config.feishu.enable then
http.post(feishu.webhook, {
msg_type = "text",
content = {text = msg}
}, {sign = feishu.secret})
end
-- 如果需要录音功能
if config.record_enable then
cc.startRecord()
sys.timerStart(cc.stopRecord, 30000) -- 30秒后自动停止录音
end
end
考虑到不同场景下的网络需求,项目实现了多种网络接入方式:
lua复制function mobile_net_connect()
net.switchSim(1) -- 使用SIM卡1
net.setup(net.LTE, "cmnet")
while not net.isReady() do
sys.wait(1000)
end
end
lua复制function wifi_connect()
wifi.setup("SSID", "password")
while not wifi.ready() do
sys.wait(1000)
end
end
lua复制function eth_connect()
eth.setup()
while not eth.ready() do
sys.wait(1000)
end
end
为了实现更可靠的网络连接,我设计了一个网络优先级管理系统:
lua复制function net_manage()
-- 尝试以太网连接
eth_connect()
if eth.ready() then return end
-- 尝试Wi-Fi连接
wifi_connect()
if wifi.ready() then return end
-- 最后使用蜂窝网络
mobile_net_connect()
end
这种设计确保了在有线网络可用时优先使用有线连接,降低通信成本;在网络故障时自动切换到备用连接,提高系统可靠性。
在某工厂的PLC监控项目中,我们部署了10台转发设备,实现了以下功能:
实际运行数据显示,报警响应时间从原来的平均15分钟缩短到30秒以内,大大减少了设备停机时间。
在一个别墅区的安防系统中,我们实现了:
这个方案特别适合网络不稳定的地区,即使Wi-Fi中断,蜂窝网络仍能确保报警信息及时送达。
在某葡萄种植基地,我们部署的系统可以:
相比传统的物联网平台方案,这种短信转发方式在偏远地区表现更加可靠,而且农户使用门槛极低。
在长时间运行测试中,我发现Lua脚本容易出现内存泄漏问题。通过以下方法进行了优化:
lua复制-- 不好的写法
function send_msg(msg)
local data = {content = msg} -- 每次调用都创建新表
http.post(url, data)
end
-- 优化后的写法
local msg_template = {content = ""}
function send_msg(msg)
msg_template.content = msg -- 复用表
http.post(url, msg_template)
end
lua复制function process_sms()
local sms_list = sms.getAllMessage()
-- 处理短信...
sms_list = nil -- 显式释放
collectgarbage() -- 手动触发垃圾回收
end
在实际部署中,我遇到了几个典型问题:
对于重要来电,可以扩展录音功能:
lua复制function start_call_record()
local record_file = "/record/"..os.date("%Y%m%d%H%M%S")..".amr"
cc.startRecord(record_file)
log.info("开始录音:", record_file)
end
function stop_call_record()
cc.stopRecord()
log.info("录音结束")
-- 可以将录音文件通过HTTP上传到服务器
upload_file(record_file)
end
对于需要管理多张SIM卡的情况,可以实现自动切换:
lua复制function sim_switch()
local current_sim = config.current_sim or 1
local next_sim = current_sim % #config.sim_cards + 1
net.switchSim(next_sim)
config.current_sim = next_sim
save_config()
log.info("切换到SIM卡", next_sim)
end
-- 定时切换SIM卡
sys.timerLoopStart(sim_switch, 3600000) -- 每小时切换一次
为了便于故障排查,可以添加本地日志存储功能:
lua复制function write_log(level, msg)
local log_file = io.open("/log/system.log", "a")
if log_file then
log_file:write(os.date("[%Y-%m-%d %H:%M:%S]"), " ", level, " ", msg, "\n")
log_file:close()
end
end
-- 重定向系统日志
sys.subscribe("LOG_DEBUG", function(msg) write_log("DEBUG", msg) end)
sys.subscribe("LOG_INFO", function(msg) write_log("INFO", msg) end)
sys.subscribe("LOG_WARN", function(msg) write_log("WARN", msg) end)
sys.subscribe("LOG_ERROR", function(msg) write_log("ERROR", msg) end)
经过多个项目的实际部署,我总结了以下经验:
这个项目从构思到实现花了约两个月时间,期间遇到了不少挑战,但最终的成果非常令人满意。它不仅解决了我个人的多卡管理问题,还在多个物联网项目中得到了成功应用。开源这个项目是希望能帮助到有类似需求的开发者,也欢迎大家一起完善这个方案。