PRE-M8-T03: finalize WarmteLink hardware validation
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
# Pre-M8 — WarmteLink P1 真机概念验证
|
||||
|
||||
> **状态:进行中。** 2026-08-22 已完成临时脚本真机 bring-up,并确认两个可用累计量;
|
||||
> 仓库内的正式 probe、解析测试和可重复验收流程尚未实现。完成下方 PRE-M8-T01~T03
|
||||
> 后,才把 Pre-M8 标记为完成并解除 M8 Planning 的入口限制。
|
||||
> **状态:已完成。** 2026-08-22 已完成临时脚本真机 bring-up;随后仓库内正式 probe 以
|
||||
> `115200 7N1` 连续运行 10 分钟,形成脱敏的可重复验收证据;最终人工走查开启供暖后又观察到
|
||||
> 区域供暖累计量从 `0.017 GJ` 增至 `0.018 GJ`,并与物理表一致。Pre-M8 现已解除
|
||||
> **M8 Planning** 的入口限制;M8 的架构和实现范围仍未锁定。
|
||||
|
||||
## 1. 目的
|
||||
|
||||
@@ -70,7 +71,8 @@ WarmteLink P1 → USB serial → 原始 telegram → 完整性状态 → 字段
|
||||
|
||||
### 3.3 Framing 与 CRC 异常
|
||||
|
||||
- 连续采集的 telegram 周期约为 10 秒;一次 8 帧盘点中每帧均为 256 字节。
|
||||
- 临时 bring-up 的一次 8 帧盘点中每帧均为 256 字节;正式 10 分钟采样显示长度并不固定,
|
||||
详见 §3.6。
|
||||
- 正文结构稳定,版本、时间戳、两个 M-Bus channel、单位和值均可重复解析。
|
||||
- 实测头部为 `)TU)2NWA-MYRSKY`,偶见 `)TU{2NWA-MYRSKY`;没有标准要求的 `/` 起始符。
|
||||
- 帧尾存在 `!`,但其后的字符并非每帧都稳定为四位十六进制;即使恰好是四位,也无法从
|
||||
@@ -111,6 +113,42 @@ M8 若要持久化这些读数,必须在 Planning 中单独锁定异常帧的
|
||||
- 当前没有瞬时流量、温度或热功率;M8 只承诺累计量采集与展示。
|
||||
- 串口 framing 和 CRC 异常尚未消失,必须作为正式 ingestion 的显式质量状态处理。
|
||||
|
||||
### 3.6 正式 CLI 10 分钟复验(脱敏)
|
||||
|
||||
2026-08-22,仓库内 `python -m scripts.p1_probe` 在真实
|
||||
`/dev/serial/by-id/<redacted>` 上以 `115200 7N1` 运行 `--duration 600 --show-changes`,原始
|
||||
bytes 仅写入 `/tmp`。CLI 正常以 exit code 0 结束;期间没有 I/O error、未处理异常或断连。
|
||||
|
||||
- 读取到 60 个完整 frame、15,362 raw bytes;最后 2 bytes 是下一帧的不完整残片,60 个完整帧
|
||||
合计 15,360 bytes。
|
||||
- 设备 timestamp 从 `18:16:10` 至 `18:26:00`,严格每 10 秒递进。CLI 处理的 59 个相邻间隔中,
|
||||
53 个为 10.0 s、1 个为 9.0 s、3 个为 0.0 s、2 个为 20.0 s,均值 9.81 s;0/20 s 配对来自
|
||||
serial chunk 的批量交付,不代表设备 cadence 改变。
|
||||
- 完整 frame 长度分布为 237 bytes × 2、239 × 1、254 × 12、256 × 31、258 × 11、275 × 3,
|
||||
平均 256 bytes、范围 237–275。不能再把临时样本的「固定 256 bytes」视为帧格式契约;变长与
|
||||
非标准 footer/分块边界一致。
|
||||
- 60/60 的完整性均为 `unverifiable`,因为 60/60 缺少标准 `/` 起始符。footer 长度为 4 × 41、
|
||||
6 × 16、23 × 3;仅 16/60 的 footer 恰为四位十六进制,但仍不能在缺失 `/` 时完成标准 CRC16
|
||||
验证。**没有任何 frame 被报告为 CRC valid。**
|
||||
- 60/60 帧均解析到同一组 9 个 OBIS code:`1-3:0.2.8`、`0-0:1.0.0`、`0-0:96.1.1`、
|
||||
`0-1:24.1.0`、`0-1:96.1.0`、`0-1:24.2.1`、`0-2:24.1.0`、`0-2:96.1.0`、`0-2:24.2.1`。
|
||||
equipment identifier 已脱敏,不进入 Git。
|
||||
- channel 1 的 device type 是 `006`,累计值稳定为 `5.900 m³`;channel 2 的 device type 是
|
||||
`012`,累计值稳定为 `0.017 GJ`。同日人工表盘复核也显示 `5.900 m³` / `0.017 GJ`,正式 CLI
|
||||
因而复现了该基线。
|
||||
- 60 帧中未见瞬时流量、热功率、供水温度或回水温度字段。10 分钟内累计值未变化只能证明这段
|
||||
时间的累计值稳定;它不能证明发生消费时的更新频率,也不能证明 reset 或 wrap 行为。
|
||||
|
||||
### 3.7 最终人工走查:供暖累计量变化
|
||||
|
||||
正式长测交付后,用户又在终端直接运行只读 probe 十几分钟并开启供暖。channel 2 的区域供暖
|
||||
累计量在本次运行中从 `0.017 GJ` 增至 `0.018 GJ`,同一时刻物理热量表也显示 `0.018 GJ`;
|
||||
因此可以确认当前 P1 输出会在实际供暖消费下更新累计量,且 `0.001 GJ` 的变化与物理表一致。
|
||||
|
||||
这次人工走查没有改变完整性结论:telegram 仍缺少标准 `/`,数值与物理表一致不能替代 CRC
|
||||
验证。走查也没有覆盖 reset、wrap 或精确更新延迟;这些仍须由 M8 的接纳、重复确认和告警策略
|
||||
处理,而不能从一次累计量递增外推。
|
||||
|
||||
## 4. 正式 probe 的预期操作方式
|
||||
|
||||
实现后,在 workspace virtual environment 中运行只读 probe:
|
||||
@@ -149,7 +187,7 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
|
||||
### PRE-M8-T01 — 纯函数 telegram framing、CRC 与 OBIS parser
|
||||
|
||||
- **Status**: `todo`
|
||||
- **Status**: `done`
|
||||
- **Depends**: `none`
|
||||
- **Context**: 先把串口 I/O 与解析分开,用脱敏 fixture 固定标准 DSMR 帧和本机异常帧行为。
|
||||
|
||||
@@ -176,11 +214,11 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] 标准 fixture 的 frame boundary 与 CRC 可验证为 `valid`。
|
||||
- [ ] 脱敏本机 fixture 被标为 `unverifiable`,但能按字段而非位置解析 `m³` 和 `GJ` channel。
|
||||
- [ ] 任意 chunk boundary 和字段顺序不影响结果,未知字段原样保留。
|
||||
- [ ] 累计量以 `Decimal` + 原单位返回。
|
||||
- [ ] `pytest tests/test_p1_probe.py`、`pytest`、`ruff check .` 全绿。
|
||||
- [x] 标准 fixture 的 frame boundary 与 CRC 可验证为 `valid`。
|
||||
- [x] 脱敏本机 fixture 被标为 `unverifiable`,但能按字段而非位置解析 `m³` 和 `GJ` channel。
|
||||
- [x] 任意 chunk boundary 和字段顺序不影响结果,未知字段原样保留。
|
||||
- [x] 累计量以 `Decimal` + 原单位返回。
|
||||
- [x] `pytest tests/test_p1_probe.py`、`pytest`、`ruff check .` 全绿。
|
||||
|
||||
**Reviewer checklist**
|
||||
|
||||
@@ -190,7 +228,7 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
|
||||
### PRE-M8-T02 — 只读 serial probe CLI
|
||||
|
||||
- **Status**: `todo`
|
||||
- **Status**: `done`
|
||||
- **Depends**: `PRE-M8-T01`
|
||||
- **Context**: 在纯 parser 通过后增加最小 serial I/O,使真机验证可以从仓库稳定复现。
|
||||
|
||||
@@ -217,12 +255,12 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] CLI 可用 `/dev/serial/by-id/...` 读取,且所有 framing 参数都可显式覆盖。
|
||||
- [ ] 默认参数准确反映本机 `115200 7N1`,帮助文本说明它是实测值而非 DSMR 标准默认。
|
||||
- [ ] raw output 保留原始 bytes;终端清楚区分 `valid`、`invalid`、`unverifiable`。
|
||||
- [ ] permission/busy/disconnect 错误非零退出并给出可执行诊断,绝不建议常驻 root。
|
||||
- [ ] 依赖输入与两个生成 requirements 文件同步。
|
||||
- [ ] `pytest tests/test_p1_probe.py`、`pytest`、`ruff check .` 全绿。
|
||||
- [x] CLI 可用 `/dev/serial/by-id/...` 读取,且所有 framing 参数都可显式覆盖。
|
||||
- [x] 默认参数准确反映本机 `115200 7N1`,帮助文本说明它是实测值而非 DSMR 标准默认。
|
||||
- [x] raw output 保留原始 bytes;终端清楚区分 `valid`、`invalid`、`unverifiable`。
|
||||
- [x] permission/busy/disconnect 错误非零退出并给出可执行诊断,绝不建议常驻 root。
|
||||
- [x] 依赖输入与两个生成 requirements 文件同步。
|
||||
- [x] `pytest tests/test_p1_probe.py`、`pytest`、`ruff check .` 全绿。
|
||||
|
||||
**Reviewer checklist**
|
||||
|
||||
@@ -232,7 +270,7 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
|
||||
### PRE-M8-T03 — 正式真机验收与 M8 交接
|
||||
|
||||
- **Status**: `todo`
|
||||
- **Status**: `done`
|
||||
- **Depends**: `PRE-M8-T02`
|
||||
- **Context**: 用仓库内 probe 替代本轮临时脚本,形成可重复、脱敏且能支撑 M8 Planning 的证据。
|
||||
|
||||
@@ -257,11 +295,11 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] 仓库内 probe 在真机连续运行至少 10 分钟,无未处理异常退出。
|
||||
- [ ] 脱敏摘要列出两个累计 channel、单位、精度、cadence 和完整性异常。
|
||||
- [ ] `0.017 GJ`、`5.900 m³` 的基线或运行时新值与物理表再次对照。
|
||||
- [ ] 明确没有从当前 P1 输出读取到瞬时流量、功率或温度。
|
||||
- [ ] Pre-M8 状态与 roadmap/M8 入口同步;代码闸门保持全绿。
|
||||
- [x] 仓库内 probe 在真机连续运行至少 10 分钟,无未处理异常退出。
|
||||
- [x] 脱敏摘要列出两个累计 channel、单位、精度、cadence 和完整性异常。
|
||||
- [x] `0.017 GJ`、`5.900 m³` 的基线或运行时新值与物理表再次对照。
|
||||
- [x] 明确没有从当前 P1 输出读取到瞬时流量、功率或温度。
|
||||
- [x] Pre-M8 状态与 roadmap/M8 入口同步;代码闸门保持全绿。
|
||||
|
||||
**Reviewer checklist**
|
||||
|
||||
@@ -277,10 +315,11 @@ parser 契约。是否引入 [`dsmr_parser`](https://github.com/ndokter/dsmr_par
|
||||
- [x] GJ 和生活热水 m³ 均与物理表面板完全一致。
|
||||
- [x] 已记录精度、约 10 秒 telegram cadence 和当前字段集合。
|
||||
- [x] framing/CRC 失败已保留为显式异常,没有误报为校验通过。
|
||||
- [ ] 仓库内 parser、fixtures、probe CLI 和自动化测试完成。
|
||||
- [ ] 正式 probe 完成至少 10 分钟真机复验并产出脱敏摘要。
|
||||
- [x] 仓库内 parser、fixtures、probe CLI 和自动化测试完成。
|
||||
- [x] 正式 probe 完成至少 10 分钟真机复验并产出脱敏摘要。
|
||||
- [x] 最终人工走查在供暖开启后观察到 `0.017 → 0.018 GJ`,并再次与物理表核对一致。
|
||||
|
||||
当前人工 bring-up 已足以锁定 M8 的两个累计量目标,但 Pre-M8 milestone 仍需完成 T01~T03。
|
||||
Pre-M8 已完成并向 M8 解锁 Planning;它只交付下列真机事实,不锁定正式架构或实现任务。
|
||||
|
||||
## 7. 向 M8 的交付物
|
||||
|
||||
|
||||
Reference in New Issue
Block a user