- 实现AT指令通信和4G模组管理 - 支持PDU模式短信接收和发送 - 长短信自动合并功能 - 多通道推送支持(钉钉/飞书/Telegram等) - 管理员短信远程控制 - RESTful API接口 - 完整的日志系统
6.3 KiB
6.3 KiB
4G模块AT指令交互文档
串口配置
- 波特率: 115200
- 数据位: 8
- 停止位: 1
- 校验: None
- 流控: None
初始化流程
1. 基础握手
AT
响应: OK
作用: 测试模组是否响应
2. 查询模组信息
ATI
响应:
厂商名称
型号
固件版本
OK
作用: 获取模组厂商、型号、固件版本
3. 禁用数据连接(防止流量消耗)
AT+CGACT=0,1
响应: OK
作用: 关闭4G数据连接,防止自动联网消耗流量
注意: ML307Y型号此命令有bug,需跳过
4. 配置短信URC上报
AT+CNMI=2,2,0,0,0
响应: OK
作用: 配置短信到达时主动上报(URC模式)
参数说明:
- 第1参数=2: 缓冲URC到TE
- 第2参数=2: 短信直接上报+CMT URC(PDU模式)
- 其余参数=0: 禁用状态报告、广播消息等
5. 设置PDU模式
AT+CMGF=0
响应: OK
作用: 设置短信为PDU模式(支持中文、长短信)
6. 等待网络注册
AT+CEREG?
响应: +CEREG: <n>,<stat>
OK
作用: 查询LTE网络注册状态
<stat>值:
- 0: 未注册,未搜索
- 1: 已注册,本地网络
- 2: 未注册,正在搜索
- 3: 注册被拒绝
- 4: 未知状态
- 5: 已注册,漫游网络
成功条件: <stat>=1 或 5
短信接收(URC自动上报)
当收到短信时,模组会主动发送:
+CMT: ,<length>
<PDU_HEX_STRING>
示例:
+CMT: ,26
0891683108200005F0040D91683158148764F30000222151114270802C4F60597D
PDU解析
PDU是十六进制字符串,需要使用PDU解析库(如 node-pdu)解析:
- 发送者号码
- 时间戳(YYMMDDHHMMSS格式,带时区)
- 短信内容(支持中文UCS2编码)
- 长短信信息(参考号、当前段号、总段数)
长短信处理
长短信PDU包含额外头部(UDH):
- 参考号 (Reference Number): 用于标识同一条长短信的不同分段
- 总段数 (Total Parts): 该长短信分为几段
- 当前段号 (Part Number): 当前是第几段(从1开始)
合并逻辑:
- 检测到长短信(总段数 > 1)时,创建缓存槽位
- 使用
(参考号 + 发送者号码)作为唯一标识 - 收到每一段后,存入对应位置
- 收齐所有分段后,按段号顺序拼接内容
- 30秒超时保护:未收齐也强制转发已收到的部分
短信发送(PDU模式)
1. 编码PDU
使用PDU编码库将目标号码和短信内容编码为PDU十六进制字符串。
2. 发送AT+CMGS命令
AT+CMGS=<length>
响应: > (提示符)
作用: 准备发送短信,<length>为PDU数据长度(字节数,不含SMSC)
3. 发送PDU数据
<PDU_HEX_STRING><Ctrl+Z>
响应: +CMGS: <mr>
OK
作用: 发送PDU数据,以Ctrl+Z(0x1A)结束
<mr>: 消息参考号
完整流程示例:
-> AT+CMGS=23
<- >
-> 0011000D91683158148764F30000AA05E4BDA0E5A5BD1A
<- +CMGS: 123
OK
其他常用命令
查询信号强度
AT+CSQ
响应: +CSQ: <rssi>,<ber>
OK
<rssi>: 信号强度 (0-31, 99=未知)
- 0-9: 弱
- 10-14: 一般
- 15-19: 好
- 20-31: 很好
- 99: 未知或不可检测
查询SIM卡状态
AT+CPIN?
响应: +CPIN: READY (或其他状态)
OK
状态:
- READY: SIM卡已就绪
- SIM PIN: 需要PIN码
- SIM PUK: 需要PUK码
查询ICCID
AT+CCID
响应: +CCID: <iccid>
OK
作用: 获取SIM卡ICCID(集成电路卡识别码)
查询IMEI
AT+GSN
响应: <imei>
OK
作用: 获取模组IMEI号
查询运营商
AT+COPS?
响应: +COPS: <mode>,<format>,<oper>
OK
示例: +COPS: 0,0,"CHINA MOBILE"
临时激活数据连接(用于Ping)
AT+CGACT=1,1
响应: OK
作用: 激活数据连接(用于网络测试后需关闭)
Ping测试
AT+CPING="www.baidu.com",1,4,64,1000,10000,0
响应: +CPING: 1,<ip>,<time>,<ttl>
+CPING: 2,0,0,0,0
OK
参数: 域名,回显次数,数据包大小,超时,间隔,最大等待,保留
注意: 需要先激活数据连接(AT+CGACT=1,1)
删除所有短信(清理存储空间)
AT+CMGD=1,4
响应: OK
作用: 删除所有短信(参数4=删除所有)
URC(主动上报)消息
短信到达
+CMT: ,<length>
<PDU_HEX_STRING>
网络注册状态变化
+CEREG: <stat>
错误处理
常见ERROR原因
- 命令格式错误: 检查AT命令语法
- 参数错误: 检查参数范围和类型
- 模组未就绪: 确保模组已完成初始化
- 网络未注册: 等待CEREG状态变为1或5
- SIM卡未就绪: 检查SIM卡是否插好
超时处理
- AT命令超时: 一般1-2秒,网络相关命令5-10秒
- 发送短信超时: 30秒
- 网络注册超时: 30次重试(约30-60秒)
重试策略
- 初始化命令失败:立即重试
- 网络注册失败:等待后重试
- 发送短信失败:记录日志,不重试
Node.js实现要点
串口读取
- 使用
serialport库 - 设置行解析器 (
@serialport/parser-readline) - 监听数据事件,逐行处理
AT命令发送
async function sendATCommand(cmd, timeout = 2000) {
return new Promise((resolve, reject) => {
let buffer = '';
port.write(cmd + '\r\n');
const timer = setTimeout(() => {
reject(new Error('Timeout'));
}, timeout);
const handler = (data) => {
buffer += data;
if (buffer.includes('OK') || buffer.includes('ERROR')) {
clearTimeout(timer);
port.removeListener('data', handler);
resolve(buffer);
}
};
port.on('data', handler);
});
}
PDU解析
使用 node-pdu 库:
const PDU = require('node-pdu');
const parsed = PDU.parse(pduHexString);
// parsed.sender: 发送者号码
// parsed.text: 短信内容
// parsed.time: 时间戳
URC监听
parser.on('data', (line) => {
if (line.startsWith('+CMT:')) {
// 下一行是PDU数据
isWaitingPDU = true;
} else if (isWaitingPDU && /^[0-9A-Fa-f]+$/.test(line)) {
// 收到PDU数据
handleSMS(line);
isWaitingPDU = false;
}
});
状态机设计
IDLE状态
└─ 收到 +CMT: → WAIT_PDU状态
└─ 收到十六进制行 → 解析PDU → 处理短信 → IDLE状态
└─ 收到非十六进制行 → IDLE状态