From 366311abdc967340ab2b949a21d0927dcf21af91 Mon Sep 17 00:00:00 2001 From: yunmei Date: Tue, 4 Aug 2026 22:44:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=20issue=20#20=20[M1]?= =?UTF-8?q?=20=E6=90=AD=E5=BB=BA=E7=BC=BA=E7=9C=81=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E7=82=B9=E4=BD=8D=E9=9B=86=EF=BC=88=E6=BC=94=E7=A4=BA=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E4=BE=9D=E8=B5=96=E5=AE=A2=E6=88=B7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/ti-cl4/point-dict/README.md | 46 ++++++++++++ templates/ti-cl4/point-dict/_sanity_check.py | 72 +++++++++++++++++++ .../ti-cl4/point-dict/point_dict.default.csv | 17 +++++ 3 files changed, 135 insertions(+) create mode 100644 templates/ti-cl4/point-dict/README.md create mode 100644 templates/ti-cl4/point-dict/_sanity_check.py create mode 100644 templates/ti-cl4/point-dict/point_dict.default.csv diff --git a/templates/ti-cl4/point-dict/README.md b/templates/ti-cl4/point-dict/README.md new file mode 100644 index 0000000..a5f525d --- /dev/null +++ b/templates/ti-cl4/point-dict/README.md @@ -0,0 +1,46 @@ +# iAOP-Template-Ti 一期 · 缺省通用点位集(Demo 点位字典) + +对应 EPIC #2「[M1] 数据接入准备」子任务 **#20**(0.5d): +搭建**缺省通用点位集**(演示用,不依赖客户数据),供 PRD 13 章 +「缺省数据策略」使用——客户 DCS 点表延迟/字段不完整时, +启用本点位集完成**演示与框架验证**,点表到位后无缝切换真实点位字典。 + +## 用途(PRD 13 章) + +| 场景 | 处理 | +| --- | --- | +| 客户 DCS 点表延迟 | 启用 `point_dict.default.csv` 先行演示(M1 截止日仍未收到完整点表时触发) | +| 点表字段不完整 | 仅接入已确认点位;未确认部分保持缺省点位占位 | +| 点表到位后 | 由配置台导入真实点位字典,**无缝切换**,网关零改动 | + +点位范围对齐 PRD 7.2「点位字典范围(一期)」: + +- **沸腾氯化炉**(`CLF-01`):炉温、炉压、氯气流量、CO/CO₂、炉层状态、进料量; +- **精制/还原工序**(`RF-01`):还原温度、真空度、TiCl₄ 纯度、杂质含量; +- **能源/公用工程**(`E-01` / `ST-01` / `CW-01`):电、蒸汽、循环水。 + +## 资产说明 + +| 资产 | 说明 | +| --- | --- | +| `point_dict.default.csv` | 缺省通用点位字典(对齐内核 CSV schema:9 列,与 `core/edge-gateway/config/point_dict.example.csv` 一致) | + +## 设计说明 + +- **不依赖客户数据**:所有点位 `protocol = simulator`,由内核模拟采集驱动 + (`core/edge-gateway/drivers/simulator_driver.py`)按点位生成确定性伪随机值, + 本地即可端到端联调(采集→spool→Kafka),无需任何现场设备/点表; +- **schema 对齐**:表头、量纲、数据类型、采样率、协议与内核点位字典 + schema(`core/edge-gateway/point_dict/schema.py`)完全一致, + `python core/edge-gateway/point_dict/validator.py` 可直接校验通过; +- **opcNode 占位**:`opcNode` 列保留典型 OPC UA 节点路径(如 `ns=2;s=CLF.Temp`), + 模拟现场点表结构;真实点表导入时按配置台校验后替换; +- **采样率**:工艺快变量 1000ms(1Hz),质量类慢变量(纯度/杂质)60000ms(1min)。 + +## 校验 + +```bash +python templates/ti-cl4/point-dict/_sanity_check.py +``` +校验:CSV 表头与内核 schema 对齐(9 列)、非空、无空行、行内列数一致、 +protocol 全部为合法协议(simulator 等)、sampleRate 为正整数。 diff --git a/templates/ti-cl4/point-dict/_sanity_check.py b/templates/ti-cl4/point-dict/_sanity_check.py new file mode 100644 index 0000000..9cc549e --- /dev/null +++ b/templates/ti-cl4/point-dict/_sanity_check.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +"""iAOP-Template-Ti 一期 · 缺省通用点位集 sanity 检查(离线基本验证)。 + +检查项: +1. 点位字典 CSV:表头与内核 `core/edge-gateway/config/point_dict.example.csv` + 对齐(9 列),且非空、无空行、每行列数一致; +2. protocol 列为合法采集协议(对齐内核 schema.VALID_PROTOCOLS); +3. sampleRate 为正整数。 + +用法:python _sanity_check.py +""" +import csv +import os +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) + +# 对齐 core/edge-gateway/config/point_dict.example.csv 表头 +EXPECTED_COLUMNS = [ + "device_id", "point_id", "name", "unit", "dataType", + "sampleRate", "qualityCode", "opcNode", "protocol", +] + +# 对齐内核 schema.VALID_PROTOCOLS(缺省点位集全部使用 simulator 演示驱动) +VALID_PROTOCOLS = { + "opcua", "s7", "modbus", "weighing", "energy", "simulator", +} + + +def main() -> int: + failures: list[str] = [] + + # 1) 点位字典 CSV + csv_path = os.path.join(HERE, "point_dict.default.csv") + with open(csv_path, "r", encoding="utf-8") as fh: + rows = list(csv.reader(fh)) + if not rows: + failures.append("point_dict.default.csv 为空") + else: + header = [c.strip() for c in rows[0]] + if header != EXPECTED_COLUMNS: + failures.append( + f"CSV 表头与内核 schema 不一致:{header} != {EXPECTED_COLUMNS}") + if len(rows) < 2: + failures.append("CSV 缺少数据行") + for i, row in enumerate(rows[1:], 2): + if not row or all(not c for c in row): + failures.append(f"CSV 第 {i} 行为空行") + elif len(row) != len(EXPECTED_COLUMNS): + failures.append(f"CSV 第 {i} 行列数异常:{len(row)}") + else: + # 2) protocol 合法 + proto = row[8].strip().lower() + if proto not in VALID_PROTOCOLS: + failures.append( + f"CSV 第 {i} 行非法协议:'{proto}'(合法值见内核 schema.VALID_PROTOCOLS)") + # 3) sampleRate 正整数 + rate = row[5].strip() + if not rate.isdigit() or int(rate) <= 0: + failures.append(f"CSV 第 {i} 行 sampleRate 必须为正整数:'{rate}'") + + if failures: + print("FAIL") + for f in failures: + print(" -", f) + return 1 + print(f"OK: 点位 {len(rows) - 1} 条,表头/协议/采样率校验通过") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/templates/ti-cl4/point-dict/point_dict.default.csv b/templates/ti-cl4/point-dict/point_dict.default.csv new file mode 100644 index 0000000..26bc910 --- /dev/null +++ b/templates/ti-cl4/point-dict/point_dict.default.csv @@ -0,0 +1,17 @@ +device_id,point_id,name,unit,dataType,sampleRate,qualityCode,opcNode,protocol +CLF-01,CLF-01.TEMP,炉温,℃,float,1000,true,ns=2;s=CLF.Temp,simulator +CLF-01,CLF-01.PRES,炉压,kPa,float,1000,true,ns=2;s=CLF.Pres,simulator +CLF-01,CLF-01.CL2,氯气流量,m³/h,float,1000,true,ns=2;s=CLF.Cl2,simulator +CLF-01,CLF-01.CO,CO含量,%,float,1000,true,ns=2;s=CLF.CO,simulator +CLF-01,CLF-01.CO2,CO₂含量,%,float,1000,true,ns=2;s=CLF.CO2,simulator +CLF-01,CLF-01.BED,炉层状态,%,float,1000,true,ns=2;s=CLF.Bed,simulator +CLF-01,CLF-01.FEED,进料量,t/h,float,1000,true,ns=2;s=CLF.Feed,simulator +RF-01,RF-01.REDT,还原温度,℃,float,1000,true,ns=2;s=RF.RedT,simulator +RF-01,RF-01.VAC,还原真空度,kPa,float,1000,true,ns=2;s=RF.Vac,simulator +RF-01,RF-01.PURITY,TiCl₄纯度,%,float,60000,true,ns=2;s=RF.Purity,simulator +RF-01,RF-01.IMP,杂质含量,%,float,60000,true,ns=2;s=RF.Imp,simulator +E-01,E-01.PWR,车间电功率,kW,float,1000,true,holding:40010,simulator +E-01,E-01.KWH,车间累计电耗,kWh,float,1000,true,holding:40012,simulator +ST-01,ST-01.STEAM,蒸汽流量,t/h,float,1000,true,ns=2;s=ST.Steam,simulator +CW-01,CW-01.FLOW,循环水流量,m³/h,float,1000,true,ns=2;s=CW.Flow,simulator +CW-01,CW-01.TEMP,循环水温度,℃,float,1000,true,ns=2;s=CW.Temp,simulator