IEC60870-5-104 采集驱动开发方案

1. 概述

1.1 协议简介

IEC60870-5-104 是电力自动化系统中常用的通信协议,基于 TCP/IP 协议实现,用于监视和控制电力系统中的各种设备(如变电站、发电机、开关等)。

1.2 功能定位

本驱动实现 IEC60870-5-104 协议的 Client 端功能,支持:

功能类别 功能描述 协议引用
数据采集 遥信(单点/双点信息) 7.3, 7.4
数据采集 遥测(测量值) 7.3, 7.4
数据采集 遥脉(累计量/电度召唤) 7.8
总召唤 召唤设备所有数据 7.5
时钟同步 定期向设备发送时钟同步请求 7.6
遥控遥调 单点/双点遥控、步调节、设定值 7.7
链路管理 启动/停止链路、测试链路 5.1, 5.2, 5.3

1.3 设计原则

  • 一致性: 遵循项目统一的驱动接口规范,与 S7、EtherNet/IP 等驱动保持一致的设计风格
  • 可扩展性: 模块化设计,便于后续功能扩展
  • 可靠性: 完善的错误处理和重连机制
  • 可测试性: 支持依赖注入,便于单元测试

2. 技术架构

2.1 整体架构

┌─────────────────────────────────────────────────────────────────┐
│                      EdgeX Foundry                             │
├─────────────────────────────────────────────────────────────────┤
│                    Device Service Layer                         │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐           │
│   │  DriverMgr  │  │  Schedule   │  │  ConfigMgr  │           │
│   └──────┬──────┘  └─────────────┘  └─────────────┘           │
│          │                                                      │
├──────────┼──────────────────────────────────────────────────────┤
│                    Protocol Driver Layer                        │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                    ICE104Driver                         │   │
│   │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────┐  │   │
│   │  │ transport│◄─│ scheduler│◄─│ decoder  │  │ config │  │   │
│   │  │ (TCP连接) │  │ (读写调度)│  │ (编解码) │  │        │  │   │
│   │  └────┬─────┘  └──────────┘  └──────────┘  └────────┘  │   │
│   │       │                                                 │   │
│   └───────┼─────────────────────────────────────────────────┘   │
├───────────┼──────────────────────────────────────────────────────┤
│                    Network Layer                                │
│                        TCP/IP                                  │
└───────────┴──────────────────────────────────────────────────────┘

2.2 模块划分

模块 文件 职责 对应参考
驱动主模块 ice104.go 实现 Driver 接口,协调整体流程 s7.go, ethernetip.go
传输层 transport.go TCP 连接管理、协议帧收发、心跳检测 transport.go
调度器 scheduler.go 批量点位读写调度、总召唤管理、遥脉召唤 scheduler.go
解码器 decoder.go 地址解析、数据编解码、TypeID 映射 decoder.go

2.3 核心类/结构体设计

2.3.1 ICE104Driver(驱动主类)

type ICE104Driver struct {
    config    model.DriverConfig
    transport *ICE104Transport
    decoder   *ICE104Decoder
    scheduler *ICE104Scheduler
}

2.3.2 ICE104Transport(传输层)

type ICE104Transport struct {
    cfg               map[string]any
    conn              net.Conn
    connected         atomic.Bool
    connectTime       time.Time
    lastDisconnectTime time.Time
    reconnectCount    atomic.Int32
    localAddr         string
    remoteAddr        string
    
    // 协议定时器(IEC60870-5-104 5.1)
    t0                time.Duration  // 连接建立超时
    t1                time.Duration  // I帧响应超时
    t2                time.Duration  // S帧发送间隔
    t3                time.Duration  // 测试帧发送间隔
    w                 int            // 未确认I帧最大数量
    
    // 心跳/定时器管理
    t1Timer           *time.Timer
    t2Timer           *time.Timer
    t3Timer           *time.Timer
    stopTimers        chan struct{}
    
    // 帧序列号
    sendSeq           atomic.Uint16
    recvSeq           atomic.Uint16
    
    // 接收缓冲区
    recvBuf           []byte
    recvMu            sync.Mutex
}

2.3.3 ICE104Scheduler(调度器)

type ICE104Scheduler struct {
    transport     *ICE104Transport
    decoder       *ICE104Decoder
    
    // 总召唤配置
    generalCallInterval time.Duration
    lastGeneralCallTime time.Time
    
    // 时钟同步配置
    clockSyncInterval time.Duration
    lastClockSyncTime time.Time
    
    // 遥脉召唤配置
    pulseInterval time.Duration
    lastPulseTime time.Time
    
    // 统计
    totalRequests int64
    successCount  int64
    failureCount  int64
    mu            sync.Mutex
}

2.3.4 ICE104Decoder(解码器)

type ICE104Decoder struct {
    // TypeID 到数据类型的映射
    typeIDMap map[uint8]TypeIDInfo
}

type TypeIDInfo struct {
    Name       string
    Direction  Direction  // Monitor 或 Control
    DataTypes  []string   // 支持的数据类型
}

type Direction int
const (
    DirectionMonitor Direction = iota
    DirectionControl
)

3. 接口定义

3.1 驱动接口(实现 driver.Driver

方法 功能 参数 返回值
Init(cfg model.DriverConfig) error 初始化驱动 cfg: 驱动配置 error: 错误信息
Connect(ctx context.Context) error 建立TCP连接 ctx: 上下文 error: 错误信息
Disconnect() error 断开连接 error: 错误信息
ReadPoints(ctx, points) (map, error) 批量读取点位 points: 点位列表 map[string]model.Value: 读取结果
WritePoint(ctx, point, value) error 写入单个点位 point: 点位, value: 值 error: 错误信息
Health() driver.HealthStatus 获取健康状态 HealthStatus: 健康状态
SetSlaveID(slaveID uint8) error 设置从站ID slaveID: 从站地址 error: 错误信息
SetDeviceConfig(config map[string]any) error 设置设备配置 config: 配置参数 error: 错误信息
GetConnectionMetrics() (...) 获取连接指标 连接时长、重连次数、地址信息

3.2 内部接口

3.2.1 传输层接口

方法 功能
SendFrame(frame *Frame) error 发送协议帧
RecvFrame(ctx context.Context) (*Frame, error) 接收协议帧
SendTestFrame() error 发送测试帧
SendACK(seq uint16) error 发送确认帧
SendGeneralCall(ca uint8) error 发送总召唤命令
SendClockSync() error 发送时钟同步命令
SendPulseCall(ca uint8) error 发送遥脉召唤命令
SendControlCommand(cmd *ControlCommand) error 发送控制命令

3.2.2 调度器接口

方法 功能
ReadPoints(ctx, points) 批量读取点位
WritePoint(ctx, point, value) 写入点位
TriggerGeneralCall() 触发总召唤
TriggerClockSync() 触及时钟同步
TriggerPulseCall() 触发遥脉召唤
GetStats() 获取统计信息

3.2.3 解码器接口

方法 功能
ParseAddress(addr string) (*IOAInfo, error) 解析IOA地址
DecodeAPDU(data []byte) (*APDU, error) 解码APDU
EncodeAPDU(apdu *APDU) ([]byte, error) 编码APDU
DecodeValue(asdu *ASDU) (interface{}, error) 解码ASDU值
EncodeControlCommand(cmd *ControlCommand) (*ASDU, error) 编码控制命令

4. 配置参数

4.1 设备配置项

参数名 类型 默认值 说明
ip string - 设备IPv4地址(必填)
port int 2404 设备端口号
commonAddress uint8 1 公共地址(CA),唯一标识数据对象
generalCallInterval int 300 总召唤间隔(秒),0表示禁用
clockSyncInterval int 600 时钟同步间隔(秒),0表示禁用
pulseInterval int 300 遥脉召唤间隔(秒),0表示禁用
t0 int 10 T0超时时间(秒),TCP连接建立超时
t1 int 15 T1超时时间(秒),等待I帧响应超时
t2 int 10 T2超时时间(秒),S帧发送间隔
t3 int 20 T3超时时间(秒),测试帧发送间隔
w int 7 未确认I帧最大数量
maxRetries int 3 连接重试次数
retryInterval int 1000 重试间隔(毫秒)

4.2 点位配置

4.2.1 地址格式

点位地址为纯数字 IOA(Information Object Address),范围 0-65535。

4.2.2 点位属性

属性 说明 适用场景
Read 主动读取模式,根据采集组间隔定期读取 周期性数据采集
Subscribe 订阅模式,设备主动上报变化数据 实时性要求高的数据
Write 写入模式,支持EdgeX主动写入数据到设备 遥控遥调操作

注意: 104协议的读地址与写地址是分离的,一个IOA要么是读点位要么是写点位,不存在同时可读可写的点位。

4.2.3 支持的TypeIDs

监控方向(Monitor)

TypeID 名称 支持数据类型 说明
1 M_SP_NA_1 BIT, BOOL 单点信息
2 M_SP_TB_1 BIT, BOOL 带时标的单点信息
3 M_DP_NA_1 UINT8 双点信息
4 M_DP_TB_1 UINT8 带时标的双点信息
5 M_ST_NA_1 INT8 步位置信息
6 M_ST_TB_1 INT8 带时标的步位置信息
7 M_BO_NA_1 UINT32, INT32 32比特串
8 M_BO_TB_1 UINT32, INT32 带时标的32比特串
9 M_ME_NA_1 FLOAT 测量值(归一化)
10 M_ME_TD_1 FLOAT 带时标的测量值(归一化)
11 M_ME_NB_1 UINT16, INT16 测量值(标度化)
12 M_ME_TE_1 UINT16, INT16 带时标的测量值(标度化)
13 M_ME_NC_1 FLOAT 测量值(短浮点)
14 M_ME_TF_1 FLOAT 带时标的测量值(短浮点)
21 M_IT_NA_1 UINT32, INT32 累计量
23 M_ME_ND_1 FLOAT 测量值(归一化,无品质)

控制方向(Control)

TypeID 名称 支持数据类型 说明
45 C_SC_NA_1 BIT, BOOL 单点遥控
46 C_DC_NA_1 UINT8 双点遥控
47 C_RC_NA_1 INT8 步调节命令
48 C_SE_NA_1 FLOAT (-1.0~1.0) 设置归一化值
49 C_SE_NB_1 UINT16, INT16 设置标度化值
50 C_SE_NC_1 FLOAT 设置短浮点数
51 C_BO_NA_1 UINT32, INT32 设置32比特串

注意: 不支持带时标的控制信息对象(如 C_SC_TA_1、C_DC_TA_1 等)。


5. 数据处理流程

5.1 连接建立流程

EdgeX                          Device (104 Server)
  |                               |
  |--- TCP Connect -------------->|
  |                               |
  |<-- TCP ACK -------------------|
  |                               |
  |--- TESTFRM (C_IA_1) --------->|  T0启动
  |                               |
  |<-- TESTFRM ACK ---------------|  T0停止,连接建立
  |                               |
  |--- STARTDT (C_IC_1) --------->|  请求启动数据传输
  |                               |
  |<-- STARTDT ACK ---------------|  数据传输开始

5.2 点位读取流程

5.2.1 Read 模式(主动读取)

┌─────────────────────────────────────────────────────────────┐
│                    采集组定时触发                             │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Scheduler: 按 TypeID 分组点位                                │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Transport: 发送 SINGLE 或 GROUP 召唤命令                     │
│  (C_IC_1 / C_CI_1)                                          │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Transport: 接收 ASDU 响应帧                                  │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Decoder: 解码数据,转换为 model.Value                         │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  返回结果到 Device Service                                    │
└─────────────────────────────────────────────────────────────┘

5.2.2 Subscribe 模式(订阅上报)

Device (104 Server)            EdgeX
        |                        |
        |--- ASDU (变化数据) --->|  设备主动上报
        |                        |
        |<-- S帧确认 ------------|  确认接收
        |                        |
        |                        ▼
        |            ┌─────────────────────────────┐
        |            │ Decoder: 解码数据            │
        |            └────────────┬────────────────┘
        |                         ▼
        |            ┌─────────────────────────────┐
        |            │ 触发北向数据上报               │
        |            └─────────────────────────────┘

5.3 总召唤流程

EdgeX                          Device
  |                               |
  |--- C_IC_1 (GENERAL CALL) ---->|
  |                               |
  |<-- M_*_NA_1 (遥信/遥测数据) ---|  设备返回所有数据
  |<-- M_*_NA_1 ...               |
  |<-- M_IT_NA_1 (累计量) --------|
  |                               |
  |<-- M_EI_NA_1 (结束标识) ------|  总召唤结束
  |                               |
  |--- C_CI_1 (确认) ------------>|

5.4 遥控遥调流程

EdgeX                          Device
  |                               |
  |--- C_SC_NA_1 (选择) --------->|  SCO = 0
  |                               |
  |<-- C_SC_NA_1 (确认) ----------|  SCO = 1
  |                               |
  |--- C_SC_NA_1 (执行) --------->|  SCO = 2
  |                               |
  |<-- C_SC_NA_1 (执行确认) ------|  SCO = 3

6. 错误处理机制

6.1 错误分类

错误类型 触发条件 处理策略
连接错误 TCP连接失败、超时 自动重连(带指数退避)
帧错误 帧格式错误、校验失败 记录日志,丢弃错误帧
协议错误 TypeID不支持、参数错误 返回错误,不发送请求
超时错误 T1/T2/T3超时 发送确认或测试帧
设备错误 设备返回否定确认 记录日志,标记点位质量为Bad

6.2 重连机制

// 重连策略
maxRetries    int           // 最大重试次数
retryInterval time.Duration // 基础重试间隔
maxBackoff    time.Duration // 最大退避时间

// 重试间隔计算(指数退避)
wait = retryInterval * (2^attempt)
if wait > maxBackoff:
    wait = maxBackoff

6.3 帧超时处理

定时器 超时动作 处理流程
T0 连接建立超时 关闭连接,触发重连
T1 I帧响应超时 重传未确认I帧
T2 S帧发送超时 发送S帧确认
T3 测试帧超时 发送测试帧验证链路

7. 与其他系统集成

7.1 EdgeX Device Service 集成

驱动通过 driver.RegisterDriver 注册,Device Service 通过统一接口调用:

func init() {
    driver.RegisterDriver("iec60870-5-104", func() driver.Driver {
        return NewICE104Driver()
    })
}

7.2 数据流向

┌──────────────┐      ┌──────────────┐      ┌──────────────┐
│  Device      │─────>│  ICE104      │─────>│  EdgeX       │
│  (104 Server)│      │  Driver      │      │  Core Data   │
└──────────────┘      └──────────────┘      └──────────────┘
     ^                      │                      │
     │                      │                      │
     │<─────────────────────│<─────────────────────│
     │    遥控命令           │    写入请求            │    北向指令

7.3 北向数据格式

驱动上报的数据点包含以下信息:

字段 类型 说明
PointID string 点位唯一标识
Value any 数据值
Quality string 品质(Good/Bad/Uncertain)
TS time.Time 时间戳
QualityInfo string 品质描述(可选)
PointTime time.Time 点位时间(可选,来自带时标数据)

8. 代码结构

internal/driver/ice104/
├── ice104.go          # 驱动主模块
├── transport.go       # 传输层(TCP连接、协议帧处理)
├── scheduler.go       # 调度器(批量读写、总召唤)
├── decoder.go         # 解码器(地址解析、数据编解码)
├── protocol.go        # 协议常量和数据结构
├── transport_test.go  # 传输层测试
├── decoder_test.go    # 解码器测试
└── scheduler_test.go  # 调度器测试

8.1 文件职责说明

文件 职责 关键功能
ice104.go 驱动入口 实现 Driver 接口,初始化各模块
transport.go 传输层 TCP连接管理、帧收发、定时器管理
scheduler.go 调度层 点位分组、批量读写、定时任务
decoder.go 编解码层 地址解析、APDU/ASDU编解码
protocol.go 协议定义 TypeID、帧结构、常量定义

9. 安全性考虑

9.1 注意事项

风险点 描述 关联模块
未授权访问 无认证机制,任何人可连接 transport
数据篡改 无消息完整性校验 decoder
拒绝服务 恶意设备可发送大量数据 transport
地址伪造 IOA地址无验证机制 decoder

9.2 建议措施

  1. 网络层面: 部署防火墙,限制访问IP
  2. 传输加密: 考虑使用 TLS 加密传输(需设备支持)
  3. 输入验证: 严格校验 IOA 地址范围和数据类型
  4. 流量控制: 实现接收缓冲区限制,防止内存溢出

10. 部署与集成

10.1 驱动注册

cmd/driver/registry.go 中添加导入:

import (
    _ "github.com/anviod/edgex/internal/driver/ice104"
)

10.2 配置示例

device:
  name: "104-Device-01"
  protocol: "iec60870-5-104"
  config:
    ip: "192.168.1.100"
    port: 2404
    commonAddress: 1
    generalCallInterval: 300
    clockSyncInterval: 600
    t0: 10
    t1: 15
    t2: 10
    t3: 20
    w: 7

10.3 点位配置示例

points:
  - name: "DI-001"
    address: "100"
    dataType: "BOOL"
    attribute: "Subscribe"
    typeID: "M_SP_NA_1"
  
  - name: "AI-001"
    address: "400"
    dataType: "FLOAT"
    attribute: "Read"
    typeID: "M_ME_NA_1"
  
  - name: "DO-001"
    address: "1000"
    dataType: "BOOL"
    attribute: "Write"
    typeID: "C_SC_NA_1"

11. 测试方案

11.1 模拟器连接测试

本章节介绍如何使用 IEC 60870-5-104 Server Simulator 进行驱动测试。该模拟器支持多种数据类型的采集以及控制写入,是开发和测试阶段的理想工具。

11.1.1 模拟器下载与安装

  1. 下载地址: 可在 模拟器官网 下载试用版
  2. 注意事项: 试用版软件每 15 分钟将会自动关闭,建议及时保存相关配置数据
  3. 安装步骤: 下载后解压,找到 IEC60870-5-104 Server Simulator 可执行文件,直接点击安装即可

11.1.2 模拟器配置

步骤1:创建 Server

打开 IEC 60870-5-104 Server Simulator,点击左上角 Add Server 创建一个 Server 实例。

步骤2:配置 Server 网络

在选项卡 IEC104-SERVER_1 中修改默认配置:

配置项 默认值 修改后 说明
Source IP Address 127.0.0.1 0.0.0.0 允许外部连接
Port 2404 2404 104协议默认端口
步骤3:添加点位

切换到 Configuration_1 选项卡,点击 Add Row 添加点位:

配置项 说明
IEC 60870-5 Group to Choose Measured Normalized 测量值(归一化)
Event Report Type ID M_ME_NA_1=9 测量值类型
IOA 1 信息对象地址
Common Address 1 公共地址

其他值保持默认即可。

步骤4:启动模拟器
  1. 点击按钮 Load Configuration 加载配置
  2. 进入 Data_Objects_1 选项卡
  3. 点击 Start Communication 启动模拟器

11.1.3 EdgeX 驱动配置

使用以下配置连接到模拟器:

device:
  name: "104-Simulator"
  protocol: "iec60870-5-104"
  config:
    ip: "127.0.0.1"
    port: 2404
    commonAddress: 1
    generalCallInterval: 300
    clockSyncInterval: 600
    t0: 10
    t1: 15
    t2: 10
    t3: 20
    w: 7

points:
  - name: "AI-Sim-001"
    address: "1"
    dataType: "FLOAT"
    attribute: "Subscribe"
    typeID: "M_ME_NA_1"

11.1.4 测试验证

测试项 验证方法 预期结果
连接测试 启动驱动后查看健康状态 HealthStatusGood
总召唤测试 触发总召唤命令 成功获取所有点位数据
数据采集测试 修改模拟器点位值 EdgeX 收到变化数据
遥控测试 发送控制命令 模拟器收到并执行命令

11.1.5 支持的测试点位类型

TypeID 名称 Group to Choose IOA示例
1 M_SP_NA_1 Single Point 100
3 M_DP_NA_1 Double Point 101
9 M_ME_NA_1 Measured Normalized 400
11 M_ME_NB_1 Measured Scaled 401
21 M_IT_NA_1 Integrated Totals 500
45 C_SC_NA_1 Single Command 1000
48 C_SE_NA_1 Setpoint Normalized 1400

附录:协议引用对照表

协议章节 功能 驱动实现
IEC60870-5-104 5.1 防止数据丢失与重复 帧序列号管理
IEC60870-5-104 5.2 测试链路功能 T3定时器、测试帧
IEC60870-5-104 5.3 启动/停止链路功能 STARTDT/STOPDT
IEC60870-5-104 7.1 链路初始化 连接建立流程
IEC60870-5-104 7.3 循环数据传输 Subscribe模式
IEC60870-5-104 7.4 事件数据传输 设备主动上报
IEC60870-5-104 7.5 总召唤 General Call
IEC60870-5-104 7.6 时钟同步 Clock Sync
IEC60870-5-104 7.7 遥控命令 Control Command
IEC60870-5-104 7.8 召唤累积量 Pulse Call