ZeppBridge 0.10.0
新增身体状态与训练状态两个页面,心率区间支持三种算法,并接入跑步功率与跑姿。
新增:身体状态页(/body)
- 八张趋势卡:恢复、压力、血氧、夜间血氧 ODI、HRV (SDNN)、HRV (RMSSD)、呼吸率、静息心率。
- 每张卡支持 7 天 / 1 个月 / 6 个月切换。数据早已在本机库里,这一版只是把它们呈现出来,不需要重新联网。
- 压力、血氧、HRV、呼吸率在折线后面画出当日实测区间的阴影;当天没测出区间的,不画零宽阴影。
- 每张卡都写明覆盖度,例如「30 天里有 12 天记录」。没有记录的那几天曲线直接断开,不插值也不补 0。
- 某个范围内只有 1 天数据时不画图,直接说「画不出趋势」——一个读数是数值,不是趋势。
新增:训练状态页(/training)
- VO₂max、训练负荷、PAI 三张趋势卡。
- 乳酸阈值卡:心率与配速双轴,配速轴反向,让「更快」朝上。
- 运动负荷平衡卡:7 天负荷、28 天周均、急慢比三条线。急慢比 = 7 天负荷之和 ÷(28 天负荷之和 ÷ 4);28 天窗口覆盖不足 21 天时不给比值,曲线在那里断开——是没算,不是等于零。
- 急慢比与导出里的
training_load_balance现在共用同一个函数,界面和文件不可能给出不同的数字。 - 6 个月这一档不是装饰:VO₂max 与乳酸阈值一年只测几次,30 天窗口会把库里已有的数据显示成空。
新增:心率区间,三种算法,不预设默认
- 支持最大心率区间、储备心率区间、乳酸阈值区间三种算法。
- 五个基准全部取自本机实测,各自标注出处与测量日期:
max(workouts.max_hr)、daily_metrics.device_max_hr、daily_metrics.device_resting_hr、近 30 天avg(daily_metrics.resting_hr)、daily_metrics.lactate_threshold_hr。 - 不预设默认,也不替你挑基准。 选择器初始为空;导出里
selected_model为null时列出全部可算的组合,每一项selected都是false。 - 不使用 220−年龄 之类的公式估算。
- 区间百分比与向下取整不是照抄来的:运动摘要里带着手表自己的边界(
heart_range)与heartrate_setting_type。本账号heartrate_setting_type = 3、边界 113/141/154/162/173/190,而lactateThresholdHr = 175——正好是 floor(175 × 65/81/88/93/99/109%)。这组数字现在由测试守着。 - 五个区间之外的时间单独统计为「低于 Z1」与「高于 Z5」,五个带标签的区间因此严格就是标签所说的范围。
新增:跑步功率与跑姿
workout_samples 增加五列,全部由本地已存的原始报文回填,不需要重新联网。每一项都对着同一次运动的摘要字段验证过,不是看着像就接:
| 字段 | 语义 | 验证方式 |
|---|---|---|
power_meter |
跑步功率(W) | 序列均值 249.3 / 231.5 对上摘要 average_power 249.0 / 231.0;最大值 326 / 303 对上 max_power |
runPosture 第 1 项 |
触地时间(ms) | 均值 263.5 对上 averageGct 263,最小值 232 对上 minGct |
runPosture 第 2 项 |
垂直振幅(mm) | 均值 88.3 对上 averageVo 88,最大值 95 对上 maxVo |
runPosture 第 3 项 |
垂直步幅比(%) | 均值 87.1 对上 avgVertStrideRatio 87;且 88 mm ÷ 1010 mm 步幅 = 8.7%,两个字段互证单位 |
equivPace |
等效配速(秒/公里) | 最小值 264 对上 bestEquivPace;按距离加权均值 355.8 对上 avgEquivPace 355 |
- 运动详情页新增六项:平均功率、最大功率、平均触地时间、平均垂直振幅、垂直步幅比、最佳等效配速。
runPosture的哨兵65535与255一律转null,不落库为 0。equivPace不是1/speed:两者逐秒比对有三分之一的样本对不上,最佳偏移下仍有 32%–36% 偏差。它是坡度校正配速,不能拿现有pace顶替,也不能拿它反推速度。- 站着不动时设备照发等效配速读数,本账号库里出现过 51604 秒/公里(十四小时每公里)。读取路径只接受 60–3600 秒/公里,与
pace转分钟每公里用的是同一个窗口。
改动:概览页
- 新增「身体状态」「训练状态」两张入口卡,各带当日数值与 7 天走势。
- 这两张卡取代了原来的训练负荷、VO₂ Max 两张小卡——同一屏不重复展示同一个数字。
- 走势图少于两个点时不画:一个读数是数值不是趋势,画成一条平线等于宣称了没测过的稳定性。
改动:交给 AI
- 「已选数据流」从只读列表改成真正的选择器:按活动 / 睡眠 / 身体状态 / 训练四组呈现,组标题可整组全选或全不选,单项是复选框。
- 提示词模板只负责预填选择,不再锁定它。勾了什么,导出就是什么,摘要里的条数与体积始终描述你马上会拿到的那个文件。
修复:重放与同步抢锁
- 解析器修订号变化后,启动时的原始报文重放会批量写库;此前落在这期间的自动同步会输掉 SQLite 写锁之争,弹出红色的「workouts 失败:本地数据库暂时不可用」。数据其实一条没丢。
- 现在同步会主动让路,返回中性的
deferred状态并在一分钟后自动重试,横幅是灰色而不是红色。 busy_timeout从 5 秒提高到 30 秒。SyncReport.outcome因此新增deferred。
数据层与接口
- SQLite schema 升到
user_version = 10(新增跑步功率与跑姿列)。 NORMALIZER_REVISION升到zepp-normalizer-2026-08-v14。- 新增四个 command:
get_metric_series、get_training_balance、get_heart_rate_zones、set_heart_rate_zone_preference。 get_metric_series只应答白名单内的指标名,别的直接跳过,调用方写错名字不会得到一个凭空编出单位的图表。- 心率区间选择的四个槽位都可为
null——「还没决定」必须能存回去。 - 设置页「你的设备能提供什么」卡片对齐设计 token,与上方「连接设备」卡片统一间距、圆角与字号。
- Rust 测试从 98 个增加到 102 个。
文档
- README 重写:界面一览、当前能力、下载与安装、第一次连接、隐私、许可证全部对齐现状。
- 架构摘要补上运动 detail 字段的验证结论、心率区间三种算法的来源,以及事件接口的第四种形态(
/users/me/fileInfo/events)。 - 发版说明改为取附注标签的正文,而不是自动生成的 commit 列表。
已知未接入
以下四项都留在「未验证清单」里,没有猜测性接入:
Charge/insight_data— 曾被怀疑是综合能量分,已排除:同一天可以出现三条样本(insight分别为 6 / 79 / 6)。一个日度分数不会一天出现三个值。字段语义没有对照组可验证,因此只保留原始报文。Charge/stress_data— 已确认是 protobuf,解析后是四组 float32,没有一组对得上 App 显示的日均与区间。日汇总走已验证的all_day_stress。- 逐秒心率 — 接口确认有数据,但返回的是文件索引而不是样本,取到样本还需要下载额外域名上的文件;接入等于放宽 host 白名单,未做。
- 2026-08-16 之后的逐条血氧 — 点测在该日停止,之后只有夜间汇总。已逐一排除文件索引接口、
band_data8 字节块、auto/real_data子类型;剩下的方向只有抓取 App 的真实请求,而本项目禁止恢复 MITM / 用户 CA / 代理路线,因此到此为止。
升级注意
首次启动这一版时,应用会在后台重放本地已存的原始报文来回填跑步功率与跑姿。大库(1 GB 以上)约需 15 分钟,跑在后台线程,不阻塞窗口;期间的自动同步会显示灰色的「稍后自动重试」而不再报错。整个过程不需要联网。