a90f35fbd8800ab73c03303c236e21238bd74ec7
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
Languages
JavaScript
76.7%
CSS
14%
HTML
9%
Dockerfile
0.3%