# -*- coding: utf-8 -*- """采集驱动抽象基类 —— 模板化封装的协议插槽。 安全约束(PRD 9 章:边缘网关严格只读、零控制指令下发): - 驱动仅暴露只读接口 `read_points()`,没有任何写/控制方法; - 引擎只依赖本抽象,具体协议由子类实现,新增协议不改引擎代码。 """ from __future__ import annotations from abc import ABC, abstractmethod from typing import Dict, List, Optional, Union from point_dict.loader import Point SampleValue = Union[float, int, bool, None] class Driver(ABC): """只读采集驱动基类。""" protocol: str = "base" # 协议名:opcua / s7 / modbus / weighing / energy / simulator def __init__(self, config: Optional[dict] = None): self.config = config or {} @abstractmethod def connect(self) -> None: """建立连接(幂等)。失败应抛出 ConnectionError 供引擎重试。""" @abstractmethod def read_points(self, points: List[Point]) -> Dict[str, SampleValue]: """批量读取测点值(只读)。 Args: points: 本驱动负责的测点列表。 Returns: {point_id: value};读失败的点可返回 None 或省略, 由引擎按“未读到”计入丢失率。 """ @abstractmethod def close(self) -> None: """关闭连接,释放资源。""" # ------------------------------------------------------------------ # 模板化辅助 # ------------------------------------------------------------------ @classmethod def from_template(cls, protocol: str, config: Optional[dict] = None) -> "Driver": """按模板配置实例化驱动(协议 → 实现类注册表)。""" from . import _DRIVER_REGISTRY if protocol not in _DRIVER_REGISTRY: raise KeyError( f"未注册的采集协议: '{protocol}',已注册: {sorted(_DRIVER_REGISTRY)}。" f"如需支持新协议,实现 Driver 子类并注册。" ) return _DRIVER_REGISTRY[protocol](config)