1. 项目概述
作为一名嵌入式开发工程师,我最近完成了一个基于LuatOS的短信和来电转发系统项目。这个项目最初源于一个实际需求:我手上有几张需要保号但很少使用的SIM卡(比如绑定银行账户、各种平台的备用号码),每次换卡查看短信非常麻烦,而且经常错过重要来电。
这个系统使用低功耗Cat.1模组作为硬件基础,通过Lua脚本实现了短信和来电的自动转发功能。它不仅解决了我的个人需求,更在工业控制、安防报警等物联网场景中展现了强大的应用潜力。最让我兴奋的是,这个方案成本低廉,一个完整的转发器硬件成本可以控制在200元以内。
2. 核心功能解析
2.1 短信转发机制
短信转发是这个系统的核心功能之一。它的工作流程是这样的:
- SIM卡插入转发器后,系统会持续监听短信通道
- 当有新短信到达时,模组会触发中断通知
- Lua脚本解析短信内容,提取发送方号码和短信正文
- 通过预先配置的Webhook,将信息转发到指定的协同平台
在实际开发中,我发现几个关键点需要注意:
- 短信编码问题:不同运营商可能使用不同的编码方式(7-bit、UCS2等),需要做好兼容处理
- 长短信处理:超过70个汉字的长短信会被拆分,需要实现重组逻辑
- 重试机制:网络不稳定时需要有自动重试功能
2.2 来电转发实现
来电转发功能比短信转发更复杂一些,因为它涉及到实时性要求更高的语音处理:
- 当有来电时,模组会发送来电通知事件
- 系统立即获取来电号码
- 根据预设规则决定是否接听
- 可选择录音或直接转发来电信息
这里有个实用技巧:我发现在来电转发的实现中,设置一个短暂延迟(比如3秒)再发送通知,可以有效过滤掉骚扰电话和响一声就挂的电话。
3. 硬件选型与配置
3.1 核心模组选择
经过对比测试,我最终选择了Air780EHV作为核心模组,主要基于以下考虑:
- 支持Cat.1网络,覆盖广、功耗低
- 内置语音编解码器,来电处理更方便
- 提供丰富的GPIO接口,便于扩展
- 价格适中,批量采购单价约80元
其他备选方案包括:
- Air780EG:更适合需要GPS的场景
- Air8000系列:性能更强但价格更高
3.2 外围电路设计
为了确保系统稳定运行,我在硬件设计上做了这些优化:
-
电源部分:
- 使用TPS63020升降压芯片,支持3.7-5V宽电压输入
- 增加1000μF储能电容,应对瞬时大电流
- 加入TVS二极管保护,防止电源浪涌
-
SIM卡电路:
- 采用双SIM卡槽设计,支持热插拔
- 每个SIM卡槽都配有ESD保护器件
- 信号线走线严格控制在50mm以内
-
天线设计:
- 使用外接天线接口,方便更换高增益天线
- 预留π型匹配电路,便于天线调谐
4. 软件开发详解
4.1 开发环境搭建
LuatOS的开发环境配置相对简单:
- 下载LuatIDE(版本建议2.1.8以上)
- 安装USB驱动(CH340/CP2102等)
- 配置项目模板,选择对应的模组型号
- 连接调试器,设置下载参数
这里有个小技巧:在开发初期,建议开启详细的日志输出,可以帮助快速定位问题。正式发布时可以关闭非关键日志以减少资源占用。
4.2 核心代码解析
让我们深入看看几个关键模块的实现:
4.2.1 短信转发模块
lua复制-- 短信处理回调函数
local function sms_handler(num, txt)
-- 过滤空短信和系统短信
if not num or not txt or txt == "" then return end
-- 短信内容预处理
local clean_txt = txt:gsub("[%c%z]", " ") -- 去除控制字符
-- 构造飞书机器人消息体
local msg = {
msg_type = "text",
content = {
text = string.format("来自%s的短信:%s", num, clean_txt)
}
}
-- 发送到飞书
local ok, ret = http.post(webhook_url, json.encode(msg), {["Content-Type"]="application/json"})
-- 失败重试逻辑
if not ok then
sys.timerStart(function()
sms_handler(num, txt) -- 5秒后重试
end, 5000)
end
end
4.2.2 来电处理模块
lua复制-- 电话状态回调
function cc_state(state, num)
if state == "RING" then -- 来电
-- 来电号码过滤
if is_blacklist(num) then return end
-- 记录来电时间
last_call_time = os.time()
-- 构造通知消息
local msg = {
msg_type = "text",
content = {
text = string.format("来电:%s 时间:%s", num, os.date("%H:%M:%S"))
}
}
-- 发送通知
notify_robot(msg)
-- 可选:自动接听并录音
if auto_record then
sys.timerStart(function()
cc.command("ATA") -- 接听电话
start_recording() -- 开始录音
end, 2000) -- 2秒后接听
end
elseif state == "HANGUP" then -- 挂断
if is_recording then
stop_recording()
upload_recording() -- 上传录音文件
end
end
end
4.3 网络连接管理
考虑到不同场景下的网络需求,我实现了多网络支持:
- 4G蜂窝网络:默认连接方式
- WiFi备用连接:当有可用WiFi时自动切换
- 以太网支持:通过SPI接口扩展
网络切换的关键逻辑:
lua复制function network_monitor()
-- 检查当前网络状态
local net_stat = net.getState()
-- 4G网络异常时尝试切换
if net_stat ~= "REGISTERED" then
if wifi_available then
switch_to_wifi()
elseif eth_available then
switch_to_ethernet()
else
-- 启动重连定时器
sys.timerStart(network_monitor, 30000) -- 30秒后重试
end
end
end
5. 物联网场景应用实例
5.1 工业设备监控
在某工厂的PLC监控项目中,我们部署了10台转发器:
- 每台转发器连接一个振动传感器
- 当振动值超过阈值时,自动发送报警短信
- 维护人员可以直接回拨查询设备状态
实际运行数据显示,故障响应时间从平均4小时缩短到15分钟。
5.2 智能家居安防
我自己的家庭安防系统也接入了这个方案:
- 门窗传感器触发报警后,立即发送短信和来电通知
- 通过回拨可以启动现场录音
- 夜间模式会自动屏蔽非紧急通知
特别实用的是,当家里WiFi出现故障时,系统会自动切换到4G网络,确保报警不丢失。
5.3 农业环境监测
在一个温室大棚项目中,我们实现了:
- 每30分钟采集温湿度数据
- 超过阈值时自动报警
- 管理员可以发送特定格式短信查询当前状态
- 系统回复最新监测数据
这个方案在没有宽带覆盖的农村地区特别实用,部署成本只有传统方案的1/3。
6. 性能优化与问题排查
6.1 内存管理技巧
在长期运行中,我发现内存泄漏是常见问题。通过以下方法优化:
- 使用sys.timerStopAll()定期清理未触发定时器
- 避免在循环中创建大表
- 使用collectgarbage()主动触发垃圾回收
- 限制最大短信缓存数量(建议50条以内)
6.2 常见问题排查
-
短信接收延迟
- 检查SIM卡信号强度(AT+CSQ)
- 确认短信中心号码设置正确(AT+CSCA)
- 测试短信存储位置(AT+CPMS)
-
来电无法识别
- 验证CLIP功能是否开启(AT+CLIP=1)
- 检查音频通道配置(AT+CHFA)
- 测试振铃检测电路
-
网络连接不稳定
- 更新运营商APN设置
- 调整天线位置或更换高增益天线
- 检查电源纹波(建议<100mV)
7. 进阶功能扩展
7.1 规则引擎实现
为了让转发逻辑更灵活,我开发了一个简单的规则引擎:
lua复制local rules = {
{
pattern = "验证码",
actions = {
{"forward", "wechat"},
{"save", "db"}
}
},
{
pattern = "银行",
actions = {
{"forward", "sms"},
{"alert", "call"}
}
}
}
function apply_rules(text)
for _, rule in ipairs(rules) do
if text:find(rule.pattern) then
for _, action in ipairs(rule.actions) do
execute_action(action)
end
break
end
end
end
7.2 本地存储方案
对于无网络时的数据暂存,我添加了TF卡支持:
- 使用SPI模式连接TF卡
- 实现FAT32文件系统操作
- 设计环形缓冲区存储机制
- 网络恢复后自动同步
关键代码片段:
lua复制function save_to_card(data)
local file = io.open("/mnt/sd/log.txt", "a")
if file then
file:write(os.date().." "..data.."\n")
file:close()
end
end
function sync_from_card()
local file = io.open("/mnt/sd/log.txt", "r")
if file then
for line in file:lines() do
if network_available() then
send_data(line)
end
end
file:close()
os.remove("/mnt/sd/log.txt")
end
end
8. 实际部署建议
经过多个项目的实践,我总结出以下部署经验:
-
天线安装
- 尽量远离金属物体
- 竖直安装效果最佳
- 室内部署建议使用外接天线
-
SIM卡选择
- 优先选择支持Cat.1的物联网卡
- 确认开通了短信和语音功能
- 注意APN设置要求
-
电源管理
- 持续供电建议5V/2A
- 电池供电需考虑休眠模式
- 加入电源指示灯便于排查
-
环境适应性
- 工业环境需做好防尘防潮
- 高温场合要加装散热片
- 车载应用注意防震动设计
这个项目从构思到稳定运行花了约3个月时间,期间遇到了无数挑战,但最终的成果非常值得。它不仅解决了我最初的多卡管理问题,还衍生出了多个商业应用场景。开源这个项目是希望能帮助到有类似需求的开发者,也欢迎大家一起完善这个方案。