feat: 初始化Node.js 4G短信网关项目

- 实现AT指令通信和4G模组管理
- 支持PDU模式短信接收和发送
- 长短信自动合并功能
- 多通道推送支持(钉钉/飞书/Telegram等)
- 管理员短信远程控制
- RESTful API接口
- 完整的日志系统
This commit is contained in:
wuxu
2026-06-23 17:46:56 +08:00
commit 3ab7a19874
13 changed files with 2171 additions and 0 deletions
+310
View File
@@ -0,0 +1,310 @@
# 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命令发送
```javascript
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` 库:
```javascript
const PDU = require('node-pdu');
const parsed = PDU.parse(pduHexString);
// parsed.sender: 发送者号码
// parsed.text: 短信内容
// parsed.time: 时间戳
```
### URC监听
```javascript
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状态
```