feat: 完成 issue #21 点位字典 CSV schema 增加协议(protocol)维度

This commit is contained in:
2026-08-04 15:59:32 +08:00
parent 098125164d
commit cc7c7330cc
29 changed files with 131 additions and 27 deletions
+2 -1
View File
@@ -2,7 +2,7 @@
"""点位字典(Point Dictionary)模块:CSV schema + 加载 + 自动校验。"""
from .loader import Point, PointDict, load_point_dict_csv
from .schema import CSV_HEADERS, VALID_DATA_TYPES, VALID_UNITS
from .schema import CSV_HEADERS, VALID_DATA_TYPES, VALID_PROTOCOLS, VALID_UNITS
from .validator import ValidationIssue, ValidationReport, validate_point_dict, validate_point_dict_file
__all__ = [
@@ -11,6 +11,7 @@ __all__ = [
"load_point_dict_csv",
"CSV_HEADERS",
"VALID_DATA_TYPES",
"VALID_PROTOCOLS",
"VALID_UNITS",
"ValidationIssue",
"ValidationReport",
+2
View File
@@ -26,6 +26,7 @@ class Point:
sample_rate: int
quality_code: bool = True
opc_node: Optional[str] = None
protocol: Optional[str] = None # 点位级协议覆盖;空 = 按 YAML device_prefixes 路由
row_number: int = 0 # CSV 行号(从 2 开始,表头为第 1 行),用于报错定位
@property
@@ -88,6 +89,7 @@ def load_point_dict_csv(path: str) -> PointDict:
sample_rate=sample_rate,
quality_code=_to_bool(row["qualityCode"]) if (row.get("qualityCode") or "").strip() else True,
opc_node=((row.get("opcNode") or "").strip() or None),
protocol=((row.get("protocol") or "").strip().lower() or None),
row_number=row_number,
)
)
+18 -2
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""点位字典 CSV schema —— 对齐 PRD 5.1「边缘采集网关」字段规范表。
字段表(PRD 5.1):
字段表(PRD 5.1 + issue #21「协议」维度):
device_id string 必填,唯一 设备编号,如 CLF-01
point_id string 必填,唯一 测点编号,如 CLF-01.TEMP
name string 必填 中文名,如 炉温
@@ -10,6 +10,14 @@
sampleRate int 必填, >0 采集周期(ms)
qualityCode bool 默认 true 是否启用质量码
opcNode string 选填 OPC UA 节点路径
protocol enum 选填 采集协议(opcua/s7/modbus/weighing/energy/simulator)。
空 = 由 gateway.yaml drivers 段按设备前缀路由(模板级默认)。
协议维度说明(issue #21):
点位字典 CSV schema 覆盖「点位/设备/量纲/采样率/协议」五维。
protocol 列提供**点位级协议覆盖**:同一模板内混接多种协议时,
可在 CSV 中逐点位/逐设备显式指定协议;为空时保持模板级
(gateway.yaml drivers 段 device_prefixes)路由,向后兼容。
"""
from __future__ import annotations
@@ -24,13 +32,16 @@ VALID_UNITS: List[str] = [
# 合法数据类型集合
VALID_DATA_TYPES: List[str] = ["float", "int", "bool"]
# 合法采集协议集合(与 drivers/__init__.py 注册表对齐)
VALID_PROTOCOLS: List[str] = ["opcua", "s7", "modbus", "weighing", "energy", "simulator"]
# 必填字段
REQUIRED_FIELDS: List[str] = ["device_id", "point_id", "name", "unit", "dataType", "sampleRate"]
# CSV 表头(列顺序固定,便于实施工程师对照 DCS 点表填写)
CSV_HEADERS: List[str] = [
"device_id", "point_id", "name", "unit", "dataType", "sampleRate",
"qualityCode", "opcNode",
"qualityCode", "opcNode", "protocol",
]
@@ -44,3 +55,8 @@ def is_valid_unit(unit: str) -> bool:
def is_valid_data_type(dtype: str) -> bool:
"""数据类型合法性校验。"""
return dtype in VALID_DATA_TYPES
def is_valid_protocol(protocol: str) -> bool:
"""采集协议合法性校验(小写,须在驱动注册表内)。"""
return protocol in VALID_PROTOCOLS
+11 -3
View File
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
"""点位字典自动校验器。
校验维度(对齐 issue #3 与 PRD 5.1):
校验维度(对齐 issue #3 / #21 与 PRD 5.1):
1. 缺失字段:必填列缺失 / 必填值为空;
2. 量纲:unit 不在合法量纲集合;
3. 重复点号:point_id 重复(同一测点被定义两次);
4. 采样率:sampleRate 必须为正整数;
5. 数据类型:dataType 必须为 float/int/bool;
6. 表头:CSV 缺少必填列。
6. 表头:CSV 缺少必填列;
7. 协议:protocol 若填写必须为合法协议(opcua/s7/modbus/...),
为空表示按模板配置(YAML drivers 段)路由,不做约束。
注:同一设备下多个测点行是正常场景(如 CLF-01 的炉温/炉压),
因此 device_id 重复不做行级报错。
@@ -102,7 +104,13 @@ def validate_point_dict(point_dict: PointDict, headers: List[str]) -> Validation
ValidationIssue(code="bad_sample_rate", row=p.row_number,
message=f"第{p.row_number}行 sampleRate 必须为正整数(ms),当前: {p.sample_rate}")
)
# 5) 重复点号(同一测点被定义两次)
# 5) 协议(可选列:填写则必须合法;空 = 按模板 YAML 路由)
if p.protocol and not schema.is_valid_protocol(p.protocol):
report.issues.append(
ValidationIssue(code="bad_protocol", row=p.row_number,
message=f"第{p.row_number}行 非法协议: '{p.protocol}'(合法值见 schema.VALID_PROTOCOLS)")
)
# 6) 重复点号(同一测点被定义两次)
if p.point_id:
if p.point_id in seen_point_ids:
report.issues.append(