Files
sms_forwarding/AT_COMMANDS.md
T
wuxu 3ab7a19874 feat: 初始化Node.js 4G短信网关项目
- 实现AT指令通信和4G模组管理
- 支持PDU模式短信接收和发送
- 长短信自动合并功能
- 多通道推送支持(钉钉/飞书/Telegram等)
- 管理员短信远程控制
- RESTful API接口
- 完整的日志系统
2026-06-23 17:46:56 +08:00

6.3 KiB
Raw Blame History

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. 检测到长短信(总段数 > 1)时,创建缓存槽位
  2. 使用 (参考号 + 发送者号码) 作为唯一标识
  3. 收到每一段后,存入对应位置
  4. 收齐所有分段后,按段号顺序拼接内容
  5. 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状态