From d3d914b1172dc584079f1dcbd8812c85d52eff4c Mon Sep 17 00:00:00 2001 From: Tianyu Liu Date: Tue, 18 Aug 2026 17:20:31 +0200 Subject: [PATCH] PRE-M8: add WarmteLink P1 planning placeholders --- docs/design/README.md | 2 + docs/design/m8-warmtelink-energy.md | 50 +++++++++++++ docs/design/pre-m8-warmtelink-p1-poc.md | 96 +++++++++++++++++++++++++ docs/roadmap.md | 28 +++++++- 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 docs/design/m8-warmtelink-energy.md create mode 100644 docs/design/pre-m8-warmtelink-p1-poc.md diff --git a/docs/design/README.md b/docs/design/README.md index eb72672..0541e84 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -9,6 +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 真机概念验证(等待线到货) +- [`m8-warmtelink-energy.md`](./m8-warmtelink-energy.md) — WarmteLink P1 与多数据源 Meter(Planning 占位) 本文件定义**所有任务共用的格式与协作规则**,各个里程碑文档不再重复这些约定。 diff --git a/docs/design/m8-warmtelink-energy.md b/docs/design/m8-warmtelink-energy.md new file mode 100644 index 0000000..e6305c9 --- /dev/null +++ b/docs/design/m8-warmtelink-energy.md @@ -0,0 +1,50 @@ +# M8 — WarmteLink P1 与多数据源 Meter(Planning 占位) + +> **状态:Planning 占位;尚未拆解任务卡,尚未锁定架构。** M8 必须等待 [Pre-M8 真机概念验证](./pre-m8-warmtelink-p1-poc.md)完成后再进入正式设计。 + +## 1. 候选目标 + +把 Vattenfall WarmteLink 的 P1 数据接入现有 Energy 模块,至少支持: + +- 区域供暖累计热量(GJ)。 +- 真机 telegram 确认存在时的生活热水累计量(预计为 m³,最终以实测为准)。 +- 历史读数、当前状态以及按需暴露给 Home Assistant。 +- 与现有 Meter epoch/换表归档语义兼容。 + +## 2. 当前已知边界 + +- 现有 DSMR 模块独立订阅 `dsmr/json`,把 DSMR Reader 已解析的 JSON 降采样写入 `dsmr_reading`。 +- 现有 `Meter` 表示物理计量表的安装 epoch,本身不订阅 MQTT,也不负责解析 telegram。 +- 当前 electricity Meter 与 `dsmr_reading` 之间没有显式 source FK/binding;电费计算通过代码约定直接查询 DSMR 电力寄存器。 +- `Meter.commodity` 后端已为 `heating` 等品类预留,但“增加 commodity”本身不会自动获得相应数据源或解析能力。 +- 当前 Devices UI/模型是 Modbus 专用,不能直接假设 WarmteLink 应复用 `modbus_device`。 + +## 3. 下一轮 Planning 必须讨论的问题 + +以下问题当前全部保持开放,不在本占位文档中拍板: + +1. Meter 是否显式绑定可配置的数据源,以及绑定的生命周期和基数。 +2. 如何表示现有 DSMR MQTT source 与新的 WarmteLink P1 serial source。 +3. “Device”与“Data Source”是否为同一概念;前端 Devices 是否需要改名或分组。 +4. 一个 P1 source 暴露多个 measurement channel 时,如何映射到一个或多个 Meter。 +5. 直接 P1 读数是否使用独立存储,还是将现有 `dsmr_reading` 泛化;如何保证多 source 去重和隔离。 +6. heating GJ 与可选 hot-water m³ 的 commodity、单位、累计/换表语义。 +7. M8 是否只做采集与展示;区域供暖合同、价格和成本计算是否留到后续里程碑。 +8. 串口 worker 的重连、停止、配置热更新、Docker device mapping 与权限边界。 + +## 4. Planning 入口条件 + +正式编写 M8 目标架构、数据模型和原子任务卡前,至少需要: + +- Pre-M8 通过并留下脱敏字段清单。 +- 确认实际存在几个累计量及其单位、equipment id/channel 和更新时间。 +- 确认原始 telegram 的稳定性与 parser 适配方式。 +- 重新走查现有 DSMR ingest、Meter epoch、Modbus device、expose/HA 和 Energy 前端边界。 +- 与用户讨论并锁定 Meter ↔ source 的配置体验后,再决定 migration/API/UI 方案。 + +## 5. 当前明确不做 + +- 本占位不创建 implementation task,不授权 schema/API/frontend 变更。 +- 不假设生活热水 m³ 一定可读,也不承诺可拆分“空间供暖 GJ”和“生活热水 GJ”。 +- 不提前把 WarmteLink 塞进 `modbus_device` 或现有 `dsmr_reading`。 +- 不在缺少真机证据时设计通用 telemetry framework。 diff --git a/docs/design/pre-m8-warmtelink-p1-poc.md b/docs/design/pre-m8-warmtelink-p1-poc.md new file mode 100644 index 0000000..114719f --- /dev/null +++ b/docs/design/pre-m8-warmtelink-p1-poc.md @@ -0,0 +1,96 @@ +# Pre-M8 — WarmteLink P1 真机概念验证 + +> **状态:等待 USB→P1 线到货后执行。** 本文只定义验证边界与证据要求;当前仓库尚未实现下文所示的 probe 命令。 + +## 1. 目的 + +在进入 M8 正式设计和实现前,先用新家的 Vattenfall WarmteLink 做一次只读真机验证,回答以下问题: + +1. 当前 USB→P1 线、主机串口权限和 WarmteLink P1 端口能否稳定输出完整 telegram。 +2. telegram 的 framing、CRC、时间戳、OBIS/M-Bus channel 和单位能否被 parser 正确识别。 +3. 实际能够读取哪些累计量:区域供暖热量(GJ)、生活热水体积(m³)或其它字段。 +4. 读数的精度、更新频率和累计语义,是否与热力表/水表面板上的数字一致。 + +Pre-M8 是 M8 的证据门:在真机字段和语义确认前,不决定数据库结构、Meter 数据源绑定、后台采集服务或前端布局。 + +## 2. 执行边界 + +本阶段只建立下面这条最短链路: + +```text +WarmteLink P1 → USB serial → 完整 telegram → CRC 校验 → 字段解析 → 终端输出 +``` + +明确不做: + +- 不写入 `app.db`,不新增 Alembic migration。 +- 不新增 FastAPI API、后台常驻 worker、配置页面或 Energy 前端。 +- 不发布 MQTT / Home Assistant Discovery。 +- 不修改现有 DSMR Reader MQTT、电费计算或 Meter 逻辑。 +- 不在本阶段决定 WarmteLink 应落在哪个正式 Device/Source 模型中。 + +## 3. 预期操作方式 + +线到货后,在 workspace 的 virtual environment 中实现并运行一个只读 probe。命令形态暂定为: + +```bash +source .venv/bin/activate +python -m scripts.p1_probe \ + --device /dev/serial/by-id/ \ + --duration 600 \ + --show-changes \ + --raw-output /tmp/warmtelink-p1-telegram.txt +``` + +最终参数名可在实现 probe 时调整,但应保留这些能力: + +- 使用稳定的 `/dev/serial/by-id/...` 路径,而不是依赖可能变化的 `/dev/ttyUSB0`。 +- 连续读取多帧,而不是只看一帧偶然样本。 +- 同时显示完整帧/CRC 结果、原始 OBIS 字段和解析后的值/单位。 +- 枚举 telegram 中出现的所有 M-Bus channel、device type、equipment id、capture timestamp、value 和 unit,不依赖固定字段顺序。 +- 可只显示发生变化的字段,便于观察更新频率。 +- 原始 telegram 默认只写到 `/tmp`;未经脱敏不提交到 Git。 + +## 4. 人工对照 + +probe 运行期间,人工从热力表和相关水表面板记录同一时间附近的显示值,并与终端结果对照: + +| 检查项 | 需要记录 | +| --- | --- | +| 区域供暖 | 面板累计值、P1 值、单位、两者时间差 | +| 生活热水 | 面板累计值、P1 是否存在对应字段、单位、两者时间差 | +| 更新时间 | 连续 telegram 中数值变化的间隔 | +| 累计语义 | 数值是否单调累计,是否出现每日归零或其它重置 | + +允许 P1 capture time 与按表时间之间存在合理延迟;不能只凭数值接近就认定字段含义,必须同时核对单位、channel/device type 和时间戳。 + +## 5. 通过条件 + +Pre-M8 完成需留下以下证据: + +- [ ] 连续收到可识别为 WarmteLink 的完整 telegram。 +- [ ] CRC 校验通过;若失败,已区分串口/线材问题与 parser 问题。 +- [ ] parser 不依赖字段固定顺序,并列出全部实际 channel/OBIS 字段。 +- [ ] 找到 GJ 累计值并与热力表面板对照,误差可由显示精度或 capture 延迟解释。 +- [ ] 明确实际 telegram 是否包含独立的生活热水 m³ 累计量;若包含,已与水表面板对照。 +- [ ] 记录数值精度、telegram 频率、字段更新频率和累计/重置行为。 +- [ ] 形成一份脱敏结果摘要,足以支持下一轮 M8 Planning。 + +如果只能确认 GJ、没有独立生活热水 m³,这也是有效结论,不视为 Pre-M8 失败。 + +## 6. 失败分类 + +- 完全无数据:优先检查 USB 识别、串口权限、P1 request line、线材方向/供电。 +- 输出乱码或不成帧:优先检查串口参数、信号反相和线材兼容性。 +- 原始帧完整但解析失败:保存脱敏样本,调整 parser/字段映射。 +- 解析成功但面板对不上:检查 capture timestamp、累计语义、单位和 WarmteLink firmware 差异。 + +## 7. 向 M8 的交付物 + +Pre-M8 只向 M8 交付事实,不交付正式架构: + +- 已脱敏的 telegram 结构与字段清单。 +- GJ / 可选 m³ 的实际 channel、OBIS、单位、精度和更新时间。 +- 串口参数、稳定设备路径与部署权限要求。 +- parser 适配结论以及需要保留的异常样本。 +- 对“一个来源包含几个可用计量通道”的实测结论。 diff --git a/docs/roadmap.md b/docs/roadmap.md index 066dc60..251200d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -2,7 +2,7 @@ 本文档记录 `home-automation` 在 `v1.0.3` 之后的下一阶段规划。这一阶段不是小修补,而是几次较大的结构性改动:单库化、前端重写、以及远期的移动端试水。 -> 每个里程碑的**可执行原子任务**展开在 [`docs/design/`](./design/README.md):M1 [`m1-db-consolidation.md`](./design/m1-db-consolidation.md)、M2 [`m2-frontend-v2.md`](./design/m2-frontend-v2.md)、M3 [`m3-token-mobile.md`](./design/m3-token-mobile.md)、M4 [`m4-login-hardening.md`](./design/m4-login-hardening.md)、M5 [`m5-iot-energy.md`](./design/m5-iot-energy.md)、M6 [`m6-tibber-dynamic-energy.md`](./design/m6-tibber-dynamic-energy.md)、M7 [`m7-meter-epochs-archival.md`](./design/m7-meter-epochs-archival.md)。这些文档为 Orchestrator→Implementer→Reviewer 的多模型流水线设计。 +> 每个里程碑的设计与**可执行原子任务**展开在 [`docs/design/`](./design/README.md):M1 [`m1-db-consolidation.md`](./design/m1-db-consolidation.md)、M2 [`m2-frontend-v2.md`](./design/m2-frontend-v2.md)、M3 [`m3-token-mobile.md`](./design/m3-token-mobile.md)、M4 [`m4-login-hardening.md`](./design/m4-login-hardening.md)、M5 [`m5-iot-energy.md`](./design/m5-iot-energy.md)、M6 [`m6-tibber-dynamic-energy.md`](./design/m6-tibber-dynamic-energy.md)、M7 [`m7-meter-epochs-archival.md`](./design/m7-meter-epochs-archival.md)、Pre-M8 [`pre-m8-warmtelink-p1-poc.md`](./design/pre-m8-warmtelink-p1-poc.md)、M8 [`m8-warmtelink-energy.md`](./design/m8-warmtelink-energy.md)。Pre-M8/M8 当前仍是验证与 Planning 占位,尚无可派发的实现任务卡。 ## 当前基线(v1.0.3) @@ -40,6 +40,8 @@ | **M5** ✅ | IoT / 能耗采集 | 通用 Modbus 采集(YAML profile + JSON readings)+ MQTT/HA Discovery + 前端侧边栏 + Energy 视图 | | **M6** ✅ | 通用电价层 + DSMR 接入 + 实时电费计算 | 通用电价层(manual/tibber profile + 合同版本)+ DSMR 实时电表接入 + 每 15min 寄存器差×价计量电费(不可变快照)+ 日/月/年汇总 + 反哺 HA Energy + 前端合同/价格/费用视图 | | **M7** ✅ | 电表生命周期 / 换表归档 | 引入 Meter epoch,计费永不跨表算 delta,跨表/无表/异常 delta 一律降级,累计按当前表归零,追溯换表可重算,Meter CRUD API + 前端管理 UI | +| **Pre-M8** ⏳ | WarmteLink P1 真机概念验证 | USB→P1 到货后用 workspace venv 只读采集实际 telegram,校验 CRC/解析,并与热力表和水表面板对照 | +| **M8** 📝 | WarmteLink P1 与多数据源 Meter | 等 Pre-M8 后规划直接 P1 采集、区域供暖读数及 Meter 与数据源的可配置关系;当前仅占位 | | **M3** | 开放与移动端(远期试水) | token 鉴权 + React Native 移动端 | 排序原则:**先清地基,再在干净结构上盖楼。** M2 的新 API 和 React 必须建立在合并后的单库之上;M4 是公网安全加固,在 M5 IoT 集成之前先堵住裸密码这个洞;M5 在安全基座就绪后再做 IoT 接入。 @@ -257,6 +259,30 @@ httpx / paho-mqtt / pyyaml / apscheduler 均为 M5 已有依赖,M6 复用, --- +## Pre-M8 — WarmteLink P1 真机概念验证(⏳ 等待硬件) + +### 目标 + +USB→P1 线到货后,先在 workspace virtual environment 中运行只读 probe,直接采集 Vattenfall WarmteLink 的实际 telegram。验证完整帧、CRC、OBIS/M-Bus channel、单位、精度和更新频率,并把解析出的 GJ 与热力表面板、可选 m³ 与水表面板进行人工对照。 + +本阶段不落库、不接 API/前端/HA,也不决定正式 Device/Source/Meter 关系。它只向 M8 提供脱敏的真机事实,避免在未知 firmware/字段语义上提前设计。 + +> 验证计划与通过条件:[`docs/design/pre-m8-warmtelink-p1-poc.md`](./design/pre-m8-warmtelink-p1-poc.md) + +--- + +## M8 — WarmteLink P1 与多数据源 Meter(📝 Planning 占位) + +### 候选目标 + +在 Pre-M8 事实基础上,把 WarmteLink P1 的区域供暖 GJ、以及真机确认存在时的生活热水 m³ 接入 Energy 模块,并讨论 Meter 如何与实际数据源建立可配置关系。 + +当前不锁定数据库、API、后台 worker 或 UI 结构;特别是 DSMR MQTT source、P1 serial source、Device/Data Source 的定义和多 channel 映射,都留到下一轮 Planning 讨论后再拆原子任务。 + +> Planning 占位与待决问题:[`docs/design/m8-warmtelink-energy.md`](./design/m8-warmtelink-energy.md) + +--- + ## M3 — 开放与移动端(远期试水) ### 目标