PRE-M8-T03: finalize WarmteLink hardware validation
This commit is contained in:
@@ -9,8 +9,8 @@
|
||||
- [`m5-iot-energy.md`](./m5-iot-energy.md) — IoT 集成与能耗采集(Modbus/Energy + MQTT/HA Discovery + 前端侧边栏)
|
||||
- [`m6-tibber-dynamic-energy.md`](./m6-tibber-dynamic-energy.md) — 通用电价层 + DSMR 实时电表接入 + 实时买卖电费计算 + HA Energy 反哺
|
||||
- [`m7-meter-epochs-archival.md`](./m7-meter-epochs-archival.md) — 电表生命周期 / 换表归档(Meter epochs)
|
||||
- [`pre-m8-warmtelink-p1-poc.md`](./pre-m8-warmtelink-p1-poc.md) — WarmteLink P1 真机概念验证(bring-up 已完成,正式 probe 待实现)
|
||||
- [`m8-warmtelink-energy.md`](./m8-warmtelink-energy.md) — WarmteLink P1 与多数据源 Meter(Planning 占位)
|
||||
- [`pre-m8-warmtelink-p1-poc.md`](./pre-m8-warmtelink-p1-poc.md) — WarmteLink P1 真机概念验证(已完成;正式 CLI 长测与供暖变化均经物理表复核)
|
||||
- [`m8-warmtelink-energy.md`](./m8-warmtelink-energy.md) — WarmteLink P1 与多数据源 Meter(Planning 已解锁;架构仍开放)
|
||||
|
||||
本文件定义**所有任务共用的格式与协作规则**,各个里程碑文档不再重复这些约定。
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# M8 — WarmteLink P1 与多数据源 Meter(Planning 占位)
|
||||
|
||||
> **状态:Planning 占位;尚未拆解任务卡,尚未锁定架构。** Pre-M8 人工 bring-up 已确认
|
||||
> 两个累计量,但 M8 仍须等待 [Pre-M8 真机概念验证](./pre-m8-warmtelink-p1-poc.md)
|
||||
> 的正式 probe、测试和长时间复验完成后再进入正式设计。
|
||||
> **状态:Planning 已解锁;尚未拆解任务卡,尚未锁定架构。** [Pre-M8 真机概念验证](./pre-m8-warmtelink-p1-poc.md)
|
||||
> 已完成正式 probe、测试和 10 分钟复验;这只满足进入
|
||||
> Planning 的证据门,不授权 schema、API、worker 或前端实现。
|
||||
|
||||
## 1. 候选目标
|
||||
|
||||
@@ -20,11 +20,15 @@
|
||||
- 当前 electricity Meter 与 `dsmr_reading` 之间没有显式 source FK/binding;电费计算通过代码约定直接查询 DSMR 电力寄存器。
|
||||
- `Meter.commodity` 后端已为 `heating` 等品类预留,但“增加 commodity”本身不会自动获得相应数据源或解析能力。
|
||||
- 当前 Devices UI/模型是 Modbus 专用,不能直接假设 WarmteLink 应复用 `modbus_device`。
|
||||
- 真机实测一个 WarmteLink serial source 同时输出两个累计 channel:channel 1 为生活热水
|
||||
`m³`,channel 2 为区域供暖 `GJ`;两者均已与物理表对照一致。
|
||||
- 当前 P1 telegram 约每 10 秒一帧,没有瞬时流量、热功率、供水温度或回水温度字段。
|
||||
- 当前线材/设备组合以 `115200 7N1` 才能稳定解析正文;header/CRC 仍不可验证,正式 ingestion
|
||||
必须显式处理该数据质量状态。
|
||||
- 正式 CLI 复验中,一个 WarmteLink serial source 在 60/60 帧均输出两个累计 channel:channel 1
|
||||
为生活热水 `m³`(device type `006`、`5.900 m³`),channel 2 为区域供暖 `GJ`(device type
|
||||
`012`、基线 `0.017 GJ`);同日与物理表复核一致。最终人工走查开启供暖后,channel 2 又从
|
||||
`0.017 GJ` 增至 `0.018 GJ`,物理热量表同步显示 `0.018 GJ`。
|
||||
- 设备 timestamp 严格每 10 秒递进;frame 平均 256 bytes、范围 237–275,不能假定固定帧长。
|
||||
当前 P1 telegram 没有瞬时流量、热功率、供水温度或回水温度字段。
|
||||
- 当前线材/设备组合以 `115200 7N1` 才能稳定解析正文。60/60 frame 缺少标准 `/`,故均为
|
||||
`unverifiable`;即使部分 footer 恰为四位十六进制也不能验证 CRC。正式 ingestion 必须显式
|
||||
处理该数据质量状态,不能将数值与表盘相符视为 CRC valid。
|
||||
|
||||
## 3. 下一轮 Planning 必须讨论的问题
|
||||
|
||||
@@ -41,11 +45,18 @@
|
||||
|
||||
## 4. Planning 入口条件
|
||||
|
||||
正式编写 M8 目标架构、数据模型和原子任务卡前,至少需要:
|
||||
进入 M8 Planning 的证据门已满足:
|
||||
|
||||
- [x] Pre-M8 通过并留下脱敏字段清单。
|
||||
- [x] 正式 probe 复验两个累计量、单位、channel、device type 与更新时间;equipment identifier
|
||||
保持脱敏。
|
||||
- [x] 记录 parser 适配结论和异常 framing/CRC 状态;10 分钟样本的稳定累计值不构成消费更新、
|
||||
reset/wrap 或长期稳定性的证明。
|
||||
- [x] 最终人工走查确认供暖消费时累计量按 `0.001 GJ` 更新并与物理表一致;精确更新延迟、
|
||||
reset/wrap 和长期接纳策略仍留给 Planning。
|
||||
|
||||
正式编写 M8 目标架构、数据模型和原子任务卡前,仍需:
|
||||
|
||||
- Pre-M8 通过并留下脱敏字段清单。
|
||||
- 用正式 probe 复验两个累计量及其单位、equipment id/channel 和更新时间。
|
||||
- 确认原始 telegram 的长期稳定性、parser 适配方式和异常 CRC 的接纳策略。
|
||||
- 重新走查现有 DSMR ingest、Meter epoch、Modbus device、expose/HA 和 Energy 前端边界。
|
||||
- 与用户讨论并锁定 Meter ↔ source 的配置体验后,再决定 migration/API/UI 方案。
|
||||
|
||||
|
||||
@@ -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