OpenStrap/protocol
GitHub: OpenStrap/protocol
WHOOP 4.0 手环的 TypeScript 记录解码器,将设备上传的原始字节 payload 解析为结构化的生理与运动数据。
Stars: 3 | Forks: 2
# OpenStrat 协议
这些是解码器。你将一段从设备手环中解包出来的字节块传递给它们,它们会返回一个带有命名字段的记录。这就是它全部的工作。没有 Bluetooth,没有 CRC,没有重组,只有字节转化为意义。[后端](https://github.com/OpenStrap/backend) 会在服务器端调用这些解码器,以解析你的手机上传的数据帧。
它之所以很小,是因为它只是生产技术栈中实际使用 TypeScript 运行的部分。如果你想要完整的图景、逐字节的映射、数据帧格式、命令集、同步握手,这些内容都位于 [研究仓库](https://github.com/OpenStrap/research) 的 `PROTOCOL.md` 中。这是经过移植和精简的工作子集。
## 最重要的一条记录
`parse_r24` 解码 1 Hz 的历史记录,这是同步时从手环传出的数据主体,佩戴期间每秒会产生一条这样的记录。向其传入内部 payload(89 字节或更多),你就会得到以下返回结果;如果长度太短则返回 `null`:
```
interface R24 {
ts_epoch: number; // [7:11] unix seconds
ts_subsec: number; // [11:13]
counter: number; // [3:7] goes up by one each record
hr: number; // [17] heart rate, 0 means no reading
spo2: number; // [72] blood oxygen %
skin_temp_c: number; // [70]/4 skin temperature in °C
resting_hr: number; // [88] a held baseline, not your live HR
accel_g: [number, number, number]; // [36:48] three little-endian floats, in g
raw_tail: string; // [13:] the whole payload as hex, kept untouched
}
```
```
import { parse_r24 } from 'openstrap-protocol/ts/records'
const sample = parse_r24(inner)
if (sample) console.log(sample.hr, new Date(sample.ts_epoch * 1000))
```
## 我确信的和我不确信的
我想对此保持诚实,因为这是一个你可以信任的解码器和一个悄悄向你撒谎的解码器之间的区别。
Header 和心率?很可靠。我戴着设备时亲眼观察到 `[17]` 字节处的 `hr` 与实时流仅有一两次心跳的误差。那个是真实的。
Header 之后的所有内容都是最佳猜测。手环将这条记录的大部分内容直接转发到 WHOOP 的云端而不进行解码,因此没有干净的参照物可供核对。`[36:48]` 处的加速度计、`[70]` 处的温度、`[72]` 处的 SpO₂、`[88]` 处的静息心率,我都是通过观察这些字节随着我能验证的事物如何变化而推断出来的:当手环静止时加速度在 1g 左右,当你戴上设备时温度字节会升高,休息时 SpO₂ 会停留在 90 出头。很合理。很一致。但未经证实。它们在代码中被标记为 empirical(经验推测),你应该以这种方式来看待它们。
这也是为什么每条记录都保留了其 `raw_tail`:完整的十六进制格式 payload,没有丢弃任何内容。如果有一天有人确切搞清楚了字节 68 到底是什么,我们就可以重新解码我们存储过的每一条记录,旧数据也会变得更有价值。任何东西都不会因为早期的一个错误猜测而丢失。
## 字节在哪里解包
你会注意到这里没有 frame 解析,没有 CRC 校验,没有 `0xAA` 处理。在 `parse_r24` 运行之前,上游的某个程序已经将内部 payload 从 frame 中提取出来并确认其完好无损。这项工作位于客户端中:Flutter 应用([edge](https://github.com/OpenStrap/edge),位于 `lib/protocol/` 中)和 Python 参考客户端([research](https://github.com/OpenStrap/research))都带有各自的重组器。如果你需要构建一个重组器,`PROTOCOL.md` 文档记录了数据包封装结构和 packet 类型。
## 构建它
```
npx tsc # compile ts/ to dist/
npx tsx ts/test_decoder.ts # run it against a fixture capture
```
## 添加或修复解码器
如果你弄清楚了某个字段,或者想在 TS 端添加 `parse_r10` 或任何其他解码器,请编写一个函数,该函数接收内部的 `Uint8Array` 并返回一个类型化对象或 `null`。使用 `DataView` 以小端序读取多字节值。将每个字段标记为 verified(已验证)或 empirical(经验推测),并诚实对待它是哪一种——一个看似自信的错误标签比没有标签更糟糕。保留未修改的尾部。如果你真的用确凿的证据确定了其中一个经验性字段,这正是我希望在 issue 或 PR 中看到的内容。
标签:TypeScript, 可穿戴设备, 后端开发, 安全插件, 数据解析, 物联网协议