Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 112 additions & 8 deletions docs/README.ar.md

Large diffs are not rendered by default.

122 changes: 113 additions & 9 deletions docs/README.es.md

Large diffs are not rendered by default.

216 changes: 156 additions & 60 deletions docs/README.fr.md

Large diffs are not rendered by default.

194 changes: 149 additions & 45 deletions docs/README.ja.md

Large diffs are not rendered by default.

192 changes: 144 additions & 48 deletions docs/README.ru.md

Large diffs are not rendered by default.

55 changes: 47 additions & 8 deletions docs/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

[English](../README.md) | [العربية](README.ar.md) | **简体中文** | [繁體中文](README.zh-TW.md) | [Français](README.fr.md) | [Русский](README.ru.md) | [Español](README.es.md) | [日本語](README.ja.md)

Vocat 是一款面向 Quectel EC20/EC25 系列蜂窝模组的开源 Web 控制面板与工程工具套件。它在一个自包含的服务中整合了模组发现、实时射频状态、AT 与 USSD 终端、短信、WiFi Calling(WiFi 通话)、eSIM 管理、网络选择、代理路由、通知、审计日志以及发布自动化。
Vocat 是一款面向 Quectel EC20/EC25 系列与中移物联 ML307 系列蜂窝模组的开源 Web 控制面板与工程工具套件。它在一个自包含的服务中整合了模组发现、实时射频状态、AT 与 USSD 终端、短信、WiFi Calling(WiFi 通话)、eSIM 管理、网络选择、代理路由、通知、审计日志以及发布自动化。

后端使用 Go 编写,界面采用 React 与 TypeScript 构建,生产环境前端被嵌入进 Go 二进制中。单个可执行文件即包含完整的 Web 应用,并使用 SQLite 进行持久化存储。

Expand All @@ -38,7 +38,7 @@ Vocat 是一款面向 Quectel EC20/EC25 系列蜂窝模组的开源 Web 控制
| 领域 | Vocat 提供的能力 |
| --- | --- |
| 设备管理 | 自动串口/USB 发现、多模组支持、设备友好名称、概览实时刷新、模组重启、飞行模式以及 USB 网卡模式控制。 |
| 射频与网络 | 注册状态、运营商、信号指标、RSRP/RSRQ/SINR、网络模式、频段、信道、运营商扫描以及自动/手动选网。 |
| 射频与网络 | 注册状态、运营商、信号指标、RSRP/RSRQ/SINR、网络模式、频段、信道、运营商扫描、自动/手动选网,以及 LTE 小区查询与单小区锁定/解锁(EARFCN/PCI)。 |
| AT 与 USSD | 交互式 AT 终端、命令历史、原始模组响应、USSD 发起/继续/取消流程以及清晰的模组错误上报。 |
| 短信 | 蜂窝与 IMS 短信直接发送、入站同步、分段短信处理、送达报告、会话历史、未读状态、时间戳以及逐条消息的送达状态。 |
| WiFi Calling | IKEv2/ePDG 隧道建立、EAP-AKA 鉴权、IMS 注册、IMS 短信、重连控制、状态诊断以及按设备路由。 |
Expand All @@ -52,12 +52,13 @@ Vocat 是一款面向 Quectel EC20/EC25 系列蜂窝模组的开源 Web 控制

## 支持的硬件

Vocat 面向基于高通芯片、并暴露兼容 AT、QMI、串口与 USB 网络接口的 Quectel 模组,包括:
Vocat 面向基于高通芯片的 Quectel 模组与中移物联 ML307 系列模组,这些模组需暴露兼容的 AT、QMI、串口与 USB 网络接口,包括:

- Quectel EC20
- Quectel EC25
- Quectel EG25 系列
- 兼容的 EG600 及相关模组
- 中移物联 ML307 系列(例如 ML307A-E5,及各 OEM 变体)

可用功能取决于模组固件、USB 复合设备配置、SIM/eSIM 能力、主机驱动、无线网络以及运营商配置。

Expand Down Expand Up @@ -172,7 +173,7 @@ docker run -d \

容器启动后打开 `http://<server-address>:7575`。必须使用主机网络,才能让 QMI 网络接口保持对 Vocat 可见;串口、QMI 控制节点、TUN 接口、网络配置以及容器启动后新增的设备则需要特权设备访问。`/dev` 绑定挂载使新的 `ttyUSB*`、`ttyACM*`、`cdc-wdm*` 和 MHI `wwan*` 节点无需重建容器即可见。

该模式有意赋予 Vocat 对主机设备和网络栈的广泛访问权限,请仅在受信任的 Linux 主机上使用。自动发现会识别受支持的 Quectel USB 模组(USB 厂商 ID `2c7c`),以及通过 Linux WWAN 子系统暴露的 PCIe/MHI 模组;它不能识别任意模组布局。仅用 `--device` 映射单个节点,例如 `/dev/ttyUSB2`、`/dev/cdc-wdm0` 或 `/dev/wwan0qmi0`,会将容器限定在这些固定节点上,无法提供完整的多设备或热插拔发现。
该模式有意赋予 Vocat 对主机设备和网络栈的广泛访问权限,请仅在受信任的 Linux 主机上使用。自动发现会识别受支持的 Quectel USB 模组(USB 厂商 ID `2c7c`)、中移物联 ML307 系列模组(按产品字符串识别),以及通过 Linux WWAN 子系统暴露的 PCIe/MHI 模组;它不能识别任意模组布局。仅用 `--device` 映射单个节点,例如 `/dev/ttyUSB2`、`/dev/cdc-wdm0` 或 `/dev/wwan0qmi0`,会将容器限定在这些固定节点上,无法提供完整的多设备或热插拔发现。

在 OpenWrt 主机上,fw4 的 input 链会丢弃来自其未管理接口的新连接,其中包括 Vocat 为每个 VoWiFi 会话创建的 TUN 接口。因此 Vocat 会用镜像自带的 `nft` 插入范围很窄的 `vocat-ims-*` 放行规则(仅 P-CSCF 到协商得到的内层地址)。缺少这些规则时 IMS 注册和发短信仍然正常,但收短信和来电会被拒绝。如果镜像自带的 `nft` 无法读取主机规则集,Vocat 会记录 `nft could not inspect the OpenWrt fw4 input chain`,此时可让 `VOCAT_NFT` 指向主机自己的 nft:

Expand Down Expand Up @@ -205,6 +206,11 @@ VoCat 使用 `qmicli` 验证 QMI 控制通道是否就绪,并使用 `qmi-proxy

`vocat doctor --repair-dji-qmi` 会在更改任何 USB 驱动绑定或置位 DTR 之前检查 `qmicli`。如果该工具不可用,命令会停止并给出安装提示,保持设备当前状态不变。

### AT 蜂窝主机数据

基于 AT 的 ECM/RNDIS 数据需要 Linux、iproute2 以及带有 `udhcpc` 的 BusyBox。
VoCat 必须独占管理模组网络接口;请禁用该接口上竞争的 DHCP 客户端或网络管理配置。VoCat 会维护 IPv4 租约和打标策略路由,而不会更改系统默认路由或解析器配置。该路径目前需要支持 IPv4 的蜂窝服务。

## 配置

Vocat 先从 `VOCAT_CONFIG` 读取可选的 JSON 配置文件,再应用 `VOCAT_*` 环境变量。环境变量优先级更高。
Expand All @@ -217,6 +223,8 @@ Vocat 先从 `VOCAT_CONFIG` 读取可选的 JSON 配置文件,再应用 `VOCAT
| `VOCAT_SECURE_COOKIES` | `false` | 可选:强制所有入口使用安全 Cookie;默认按 HTTP/HTTPS 入口自动适配。 |
| `VOCAT_SHUTDOWN_TIMEOUT` | `10s` | 优雅关闭超时时间。 |
| `VOCAT_MAX_REQUEST_BODY_BYTES` | `1048576` | API 请求体最大字节数。 |
| `VOCAT_MCP_ENABLED` | `true` | 在 `/mcp` 提供面向 AI Agent 的 MCP 端点。设为 `false` 可禁用。 |
| `VOCAT_PROBE_UNKNOWN_USB` | `false` | 允许使用 AT 命令探测未识别的 USB 串口设备。探测会更改串口设置并清空输入缓存;仅当这些端口专用于模组时再启用。已验证的模组身份会自动被发现。JSON 键名:`probe_unknown_usb`。 |
| `VOCAT_REPO` | `MengMengCode/VoCat` | 自更新器使用的受信任 GitHub 仓库,格式为 `owner/name`。 |
| `GITHUB_TOKEN` | 空 | 可选的 GitHub token,用于私有仓库或更高的 API 限额。 |

Expand Down Expand Up @@ -340,6 +348,35 @@ Docker 通过拉取镜像并重建容器升级。

生产发布前,应在实际部署完成 Pocket ID Passkey/访问策略联调和升级、回滚演练。

## API Token 与 MCP

非浏览器客户端可以使用 Bearer Token 向相同的 `/api/...` 端点进行身份验证,无需使用浏览器的会话 Cookie 和 CSRF 流程:

```bash
vocat token create --read-only --ttl 720h ci-runner # 仅打印一次 Token
curl -H "Authorization: Bearer vcat_..." http://127.0.0.1:7575/api/devices
```

`vocat token list` 和 `vocat token revoke <name>` 用于管理 Token 清单。Token 拥有管理员权限;`--read-only` Token 只能发起 `GET` 请求(一个经文档记录的特例:读取短信会话会将其在本地标记为已读——规则是“不产生硬件或网络变更”)。轮换管理员密码会撤销所有 Token。请在首次执行 `bootstrap-admin` 后创建 Token。远程 Bearer 客户端还需要其来源地址在网络访问策略许可范围内;默认的 `internal` 模式仅允许私有网络。

默认情况下(设置 `VOCAT_MCP_ENABLED=false` 可禁用),同一服务会在 `http://<host>:7575/mcp` 为 AI Agent 暴露一个基于 Streamable HTTP 传输和 Bearer Token 认证的 MCP(Model Context Protocol)端点。提供的工具涵盖设备状态、短信会话及受保护的发送、eSIM 配置文件列表与切换,以及 WiFi Calling 状态/重连;敏感操作(原始 AT、eSIM 下载/删除、SIM PIN、网络选择、系统更新)未暴露,且工具输出中绝不包含 IMSI、SIM PIN 或激活码。只读 Token 获取的工具列表中不包含写操作工具。短信发送遵循与 Web 界面相同的受阻目的地策略和全局每小时限额,并走蜂窝 AT 路径发送(Web 界面在启用 WiFi Calling 时的 IMS 优先路由仍保留在 Web 端,且通过 MCP 发送的短信暂未写入 Web 会话历史)。

客户端配置示例(以 Claude Code 为例):

```json
{
"mcpServers": {
"vocat": {
"type": "http",
"url": "http://192.168.1.10:7575/mcp",
"headers": { "Authorization": "Bearer vcat_..." }
}
}
}
```

设计记录请参阅 [docs/API_MCP_DEVELOPMENT_PLAN.md](API_MCP_DEVELOPMENT_PLAN.md)。

## Telegram 机器人

启用 Telegram 通知并配置好 Chat ID 与 Admin ID 后,机器人支持:
Expand Down Expand Up @@ -483,10 +520,12 @@ cd web && npm run build

参见 [LICENSE](../LICENSE)。

<a href="https://star-history.dera.page/#MengMengCode/VoCat">
## Star History

<a href="https://www.star-history.com/?repos=mengmengcode%2Fvocat&type=date&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://star-history.dera.page/svg?repos=MengMengCode/VoCat&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://star-history.dera.page/svg?repos=MengMengCode/VoCat" />
<img alt="Star History Chart" src="https://star-history.dera.page/svg?repos=MengMengCode/VoCat" />
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=mengmengcode/vocat&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=mengmengcode/vocat&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=mengmengcode/vocat&type=date&legend=top-left" />
</picture>
</a>
Loading
Loading