wylandplex/zappctl

GitHub: wylandplex/zappctl

SuuntoPlus 手表应用的 Linux 开发客户端,通过 Bluetooth LE 实现应用的构建、安装和管理,无需数据线或厂商桌面软件。

Stars: 0 | Forks: 0

# zappctl **一款用于 SuuntoPlus 手表应用的 Linux 开发客户端 —— 通过 Bluetooth LE 进行构建、安装、列出和拉取,无需数据线,也无需厂商的桌面软件。** Suunto 官方的 SuuntoPlus 工具链通过一个打包的二进制文件从 VS Code 刷入应用 (`SDSApplicationServer`),该文件**仅限 Windows 和 macOS**。在 Linux 上,你可以*构建* `.fea` 应用,但无法*安装*它。`zappctl` 弥补了这一空白:它直接与手表原生的 Bluetooth “whiteboard” 协议进行通信,因此“编辑 → 构建 → 安装 → 验证”的闭环可以完全 在 Linux 上运行。 ``` $ ./bledeploy.sh my-app [bledeploy] app=my-app appID=myapp01 variant=q [bledeploy] building… Build successful [bledeploy] built myapp01-q.fea (53200 bytes) [bledeploy] deploying over Bluetooth… [scan] found via service UUID: Suunto Vertical 2 ABCD @ 7F:2C:19:A4:0B:63 (RSSI -54) [connect] connected, MTU=127 (BLE chunks 124B) [plan] 53,200 bytes -> 266 frames (139 init + 1 name + 118 stream + 8 finish) [send] 260/266 crc=ok [done] 266 frames sent, install CONFIRMED (status 200). App 'myapp01' is on the watch. ``` ## 状态 功能正常,且每天用于真实的应用开发 —— 但它是一款逆向工程工具,测试覆盖面较窄,并非正式商业产品。 | 功能 | 状态 | |---|---| | 安装 `.fea` 应用 | ✅ 正常工作,通过状态码确认安装 | | 列出目录 | ✅ 正常工作 | | 下载文件(包括固件 syslog) | ✅ 正常工作 | | 删除应用 | ❌ 未实现 —— 需在手表上移除 | | 锻炼记录、设置、路线、固件更新 | ❌ 超出范围(属于主机端,不走此通道) | **测试环境:** Suunto Vertical 2 (NG3) 和 Suunto 9 Peak Pro (NG1),运行在 Fedora 和 BlueZ 5.87 环境下。 其他 SuuntoPlus 手表(Race、Race S、Race 2、Ocean、Vertical)使用相同的协议系列,且 极大概率可以正常工作,但尚未经过测试 —— 欢迎反馈。请参阅 [docs/VARIANTS.md](docs/VARIANTS.md) 以确定要构建的显示变体。 ## 依赖要求 - **装有 BlueZ 的 Linux**(在 5.87 版本上开发)以及可正常工作的 Bluetooth LE 适配器 - **Python 3.11+**(需要 `tomllib`)和 [`bleak`](https://github.com/hbldh/bleak) - **仅 `bledeploy.sh` 需要:** Node.js 和 Suunto 的 SuuntoPlus Editor 扩展,它提供了 `build-app.js` 编译器。如果你已有构建好的 `.fea`,则不需要此项。 ## 安装 ``` git clone https://github.com/wylandplex/zappctl cd zappctl python3 -m venv .venv && ./.venv/bin/pip install -r requirements.txt ``` 可选择创建 `watches.toml`(参见 `watches.example.toml`)—— 只有在同时 有多块兼容手表在通信范围内时才有用。**单块手表无需任何配置。** ## 首次运行 **1. 对手表进行一次配对。** BlueZ 需要与其配对一次;之后配对记录会一直保留。 ``` ./pair-watch.sh scan # find the watch and its address ./pair-watch.sh init # open a pairing session ./pair-watch.sh go # start pairing — a 6-digit code pops up on the watch ./pair-watch.sh 123456 # feed the code back ./pair-watch.sh done # ALWAYS finish with this, or the adapter scans forever ``` 没有需要寻找的“配对界面”:只需打开手表的 **Connectivity(连接)** 菜单并保持 屏幕常亮。完整的操作步骤和失败模式详见 [docs/PAIRING.md](docs/PAIRING.md)。 **2. 释放 Bluetooth 连接。** 手表同一时间只接受**一个**中心设备。在整个 操作过程中关闭手机的 Bluetooth(或强制停止 Suunto app)—— 否则 这里的每项操作都会连接失败。 **3. 在进行任何写入操作前先验证通道。** ``` ./.venv/bin/python watchfs.py list b:/zapp ``` 出现已安装应用列表意味着协议、配对和连接均已正常。 **4. 安装应用。** ``` ./bledeploy.sh path/to/my-app # build + install ./.venv/bin/python deploy.py my-app-q.fea # install a prebuilt .fea ``` ## 命令 ``` # 一步完成 build + install(需要 vendor build-app.js) ./bledeploy.sh [--variant q] [--appid ] [--watch ] [--dry-run] # 安装预编译的 .fea python deploy.py [--watch ] [--dry-run] # filesystem python watchfs.py list b:/zapp # installed apps python watchfs.py list b:syslogs # firmware logs python watchfs.py pull b:syslogs/systemevent_1297017.log --out fresh.log # diagnostics(安全的 read-only) python probe.py --selftest-only # offline codec check, no watch needed python probe.py --no-write # GATT/handshake sanity check python probe_paths.py # which path spellings this watch accepts python probe_dump.py # dump every reply frame python probe_ngfs.py # read the device-assigned filesystem handle # protocol RE(请先阅读 docs/SAFETY.md — 部分 resources 会使 watch 重启) python wbexplore.py register "/Device/SystemEvent" python wbinvoke.py --selftest ``` 每个工具都采用相同的手表选择 flag:`--watch `(来自 `watches.toml`)、 `--needle `、`--mac
`。这些参数都是可选的。 ## 验证安装是否真正生效 **安装提交时返回 200 状态码并不能证明应用已在手表上。** 这让我们吃过 大亏:路径拼写错误会导致上传被丢弃在手表忽略的位置,而安装 步骤依然会返回 200。务必通过以下方式进行确认: ``` ./.venv/bin/python watchfs.py list b:/zapp # look for .fea ``` ## 工作原理 手表暴露了一个 GATT 服务,承载着带有帧结构的请求/响应协议(Suunto 的 “whiteboard”)。`zappctl` 会建立会话,将 `.fea` 流式传输到 手表文件系统上的 `/zapp/.zip`,然后通过 `/Plugin/Install` 提交。 有两个细节曾耗费了我们数天的调试时间,在你扩展此功能之前值得了解: - **安装引用由设备分配。** 注册 `/Plugin/Install` 会返回一个 handle, 后续的帧必须寻址到该 handle。重放录制的值只能在其被录制的 那块手表上生效,在其他任何地方都会返回 400 报错。 - **驱动器前缀因代际而异。** NG3 需要 `b:/zapp`;NG1 需要 `/zapp`,并且对于 另一种写法,它会返回格式正确但*内容为空*的 `{}`。 完整的帧语法、能力映射以及开放的 RE 目标详见:[docs/PROTOCOL.md](docs/PROTOCOL.md)。 ## 故障排除 连接问题几乎总是由以下四种情况之一引起:手机仍占用连接、 打开的桌面 Bluetooth 面板正在扫描、手表已休眠, 或者是代码在寻找一个地址而不是服务 UUID。错误码特征及修复方案详见:[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)。 ## 致谢 该协议源自 *~eppuh* 开发的 **[SyncFix](https://git.sr.ht/~eppuh/SyncFix)**,基于 0BSD 许可发布。该项目完成了艰苦的逆向工程工作;`zappctl` 将其 Android 实现移植到了 Python,并扩展了文件系统访问、多代际支持、状态 解码以及设备分配的 handle 解析功能。我们在 [`vendor/SyncFix`](vendor/) 中保留了一份带有来源说明的固定副本 —— 表示感谢。 ## 许可证 [0BSD](LICENSE),与上游协议工作保持一致:可用于任何目的,无需署名。 Suunto、SuuntoPlus 和 Amer Sports 是其各自所有者的商标,此处使用仅用于 说明本工具的兼容对象。
标签:MITM代理, SOC Prime, 云资产清单, 可穿戴设备, 开发工具, 物联网开发, 移动端开发, 蓝牙低功耗, 逆向工具, 逆向工程