Files
sms_forwarding/README.md
T
2026-06-27 16:57:48 +08:00

8.0 KiB
Raw Blame History

Node.js 4G SMS Gateway

基于Node.js的4G短信网关,通过串口与4G模块通信,接收短信并转发到多种推送渠道。

功能特性

  • ✅ 4G模块AT指令交互
  • ✅ 自动接收短信(PDU模式)
  • ✅ 长短信自动合并
  • ✅ 多通道推送(邮件/钉钉/飞书/Telegram等)
  • ✅ 短信发送功能
  • ✅ RESTful API接口
  • ✅ Web管理界面

环境要求

  • Node.js >= 18.x
  • 4G模块通过USB转串口连接到服务器
  • 支持的4G模块:ML307R-DC、SIM7600等AT指令兼容模块

安装

npm install

配置

复制配置模板:

cp config.example.json config.json

config.json 必须存在,否则程序会直接退出。最小可运行配置如下:

{
  "serial": {
    "path": "/dev/ttyUSB0",
    "baudRate": 115200,
    "autoDetect": true,
    "probeTimeout": 1200
  },
  "api": {
    "port": 3000,
    "webToken": "change-this-token"
  }
}

完整配置可参考 config.example.json。主要配置项如下:

配置项 是否必填 说明
serial.path 是 串口路径;Linux 常用 /dev/ttyUSB0,Windows 使用 COM3 等。autoDetect=true 时作为优先探测项,autoDetect=false 时作为实际串口。
serial.baudRate 是 串口波特率,通常为 115200。
serial.autoDetect 否 是否自动探测可响应 AT 的串口,默认按非 false 处理。
serial.probeTimeout 否 自动探测单个串口的超时时间,单位毫秒,默认 1200。
api.port 是 API 和 Web 管理台监听端口。
api.webToken 是 唯一鉴权凭据;已取消 admin/admin123 Basic Auth。
mobileData.cid 否 移动数据 PDP CID,默认 1;有效范围 1-15,不要使用 8。
simCards 否 SIM 卡显示手机号,slot=0 是 SIM1,slot=1 是 SIM2。
smtp 否 邮件通知配置;填写 smtp.server 后启用。
inbox 否 Web 收件箱持久化和双卡显示策略。
pushChannels 否 推送通道列表;通道开启后才要求目标字段。

api.webToken 可以通过以下方式传入:

  • Authorization: Bearer <token>
  • X-Web-Token: <token>
  • ?token=<token>
  • Web 管理台 token 登录页

完整配置示例

{
  "serial": {
    "path": "/dev/ttyUSB0",
    "baudRate": 115200,
    "autoDetect": true,
    "probeTimeout": 1200
  },
  "mobileData": {
    "cid": 1
  },
  "simCards": [
    { "slot": 0, "phoneNumber": "+8613800138000" },
    { "slot": 1, "phoneNumber": "+447700900000" }
  ],
  "smtp": {
    "server": "smtp.qq.com",
    "port": 465,
    "user": "your@qq.com",
    "pass": "your_auth_code",
    "sendTo": "recipient@example.com"
  },
  "inbox": {
    "maxReceivedMessages": 200,
    "receivedMessagesFile": "data/received-messages.json",
    "partitionBySim": true,
    "allowAllSimMessages": false,
    "dualSimDefaultScope": "all"
  },
  "pushChannels": [
    {
      "enabled": true,
      "type": "dingtalk",
      "name": "钉钉通知",
      "url": "https://oapi.dingtalk.com/robot/send?access_token=xxx",
      "secret": "SECxxx"
    }
  ],
  "api": {
    "port": 3000,
    "webToken": "change-this-token"
  }
}

可选项细节

  • smtp:不需要邮件时可以删除整个对象,或清空 server。启用邮件时需要正确填写 server、port、user、pass、sendTo。
  • inbox.maxReceivedMessages:默认 200,最大按 5000 处理。
  • inbox.receivedMessagesFile:默认 data/received-messages.json,相对路径会基于项目根目录解析。
  • inbox.partitionBySim:默认 true,按当前 SIM 隔离历史短信。
  • inbox.allowAllSimMessages:默认 false,控制是否允许显式查询全部 SIM 历史。
  • inbox.dualSimDefaultScope:可选 all 或 current;current 表示双卡时默认只看当前 SIM。
  • simCards:只影响管理台显示,不影响短信收发。代码也兼容旧字段名 simSlots、sims、sim。

运行

开发模式

npm run dev

生产模式

npm start

使用PM2(推荐)

pm2 start ecosystem.config.js
pm2 save
pm2 startup

API接口

查询状态

GET /api/status

发送短信

POST /api/sms/send
Content-Type: application/json

{
  "phone": "13800138000",
  "message": "测试短信"
}

查询收到的短信

GET /api/sms/received?limit=50

双卡双待模式下,默认返回全部 SIM 历史;显式传 scope=current 时才按当前卡槽过滤。短信记录会保留 simSlot、simLabel 与 simSource,用于判断收件卡槽。 也可以显式按卡槽查询:

GET /api/sms/received?limit=50&simSlot=0  # SIM1
GET /api/sms/received?limit=50&simSlot=1  # SIM2

直出模式下,新短信主要通过模组 +CMT URC 进入收件箱;如果 URC 未携带卡槽信息,会显示为未知 SIM。

查询信号强度

GET /api/modem/signal

查询模组信息

GET /api/modem/info

查询与切换SIM

GET /api/modem/sim
POST /api/modem/sim/switch
Content-Type: application/json

{
  "slot": 1
}

当模组返回 AT+DUALSIM?、AT+SWITCHSIM? 与 AT+BINDSIM? 能力时,管理台会显示 SIM1/SIM2。短信接收使用 CNMI 直出模式,不为了接收短信切换 SWITCHSIM。如果模组上报的 URC 未携带卡槽信息,新短信会记录为未知 SIM。

管理台切卡会同时设置 AT+SWITCHSIM 与 AT+BINDSIM,随后恢复短信直出配置。发送短信前会提示当前使用的 SIM。

如果希望管理台显示手机号,可在 config.json 中配置:

{
  "simCards": [
    { "slot": 0, "phoneNumber": "+8613800138000" },
    { "slot": 1, "phoneNumber": "+447700900000" }
  ]
}

发送AT命令

POST /api/modem/at
Content-Type: application/json

{
  "command": "AT+CSQ"
}

获取日志

GET /api/logs

所有API均需要有效 token。可以通过 Authorization: Bearer <token>、X-Web-Token 请求头或 token 查询参数传入。

项目结构

.
├── src/
│   ├── index.js           # 入口文件
│   ├── modem.js           # 4G模块通信
│   ├── sms.js             # 短信处理
│   ├── push.js            # 推送通道
│   ├── concat.js          # 长短信合并
│   ├── api.js             # REST API
│   └── logger.js          # 日志系统
├── config.json            # 配置文件
├── package.json
└── README.md

推送通道类型

类型 type值 配置项
钉钉机器人 dingtalk url, secret(可选)
飞书机器人 feishu url, secret(可选)
Telegram Bot telegram url(bot token), key1(chat_id)
PushPlus pushplus key1(token)
Server酱 serverchan key1(sendkey)
Bark bark url(bark服务器)
POST JSON post_json url
GET请求 get url
自定义模板 custom url, customBody

pushChannels 中 enabled: false 的通道可以保留空字段;enabled: true 时必须配置对应目标:

  • post_json、bark、get、dingtalk、custom、feishu:必须有 url。
  • telegram:url 填 Bot Token,key1 填 Chat ID。
  • pushplus:key1 填 PushPlus Token。
  • serverchan:key1 填 Server酱 SendKey。
  • custom:customBody 如果填写,必须是合法 JSON 字符串,支持 {sender}、{message}、{timestamp} 占位符。

长短信处理

  • 自动检测长短信(分段数 > 1)
  • 使用参考号和发送者号码标识同一条长短信
  • 收齐所有分段后自动合并
  • 30秒超时保护(未收齐也转发)

故障排查

串口打不开

# Linux检查串口设备
ls -l /dev/ttyUSB*
# 添加用户到dialout组
sudo usermod -a -G dialout $USER

模块不响应

  • 检查串口路径和波特率
  • 检查USB连接
  • 检查SIM卡是否插好

收不到短信

  • 检查AT+CEREG?网络注册状态
  • 检查AT+CNMI配置是否正确
  • 检查SIM卡余额和服务状态

许可证

MIT