Skip to content

IEC 104 原理与生态

协议简介

IEC 60870-5-104(简称 IEC 104)是国际电工委员会制定的电力系统远动通信标准,是 IEC 60870-5-101(串行远动规约)在 TCP/IP 网络上的扩展版本。广泛应用于电力调度自动化、变电站自动化、储能电站与电网调度中心的通信。

IEC 60870-5 协议族:
├── IEC 101  → 串行通信(RS-232/RS-485),平衡/非平衡传输
├── IEC 102  → 电能量计费
├── IEC 103  → 继电保护设备通信
├── IEC 104  → TCP/IP 网络传输(IEC 101 的网络版)
└── IEC 107  → 测试规程

网络架构

调度中心(主站/控制中心)

    ├── 调度数据网(SDH/MPLS/专线)

    ├── 变电站 A(子站/RTU)
    │   ├── 保护装置
    │   ├── 测控装置
    │   └── 智能电表

    ├── 储能电站 B(子站)
    │   ├── EMS(能量管理系统)
    │   ├── PCS(功率变换系统)
    │   └── BMS(电池管理系统)

    └── 风电场 C(子站)

连接参数:
- 传输层:TCP
- 默认端口:2404
- 连接模式:主站主动发起连接
- 每个 TCP 连接对应一个 ASDU 地址

帧结构(APDU)

APDU(应用协议数据单元)结构:

┌──────────────────────────────────────────────────────┐
│                    APDU                               │
│  ┌────────────────────────────────────────────────┐  │
│  │                  APCI(应用规约控制信息)         │  │
│  │  Start Byte │ APDU Length │ Control Fields(4B) │  │
│  │    0x68     │   1 byte    │      4 bytes       │  │
│  └────────────────────────────────────────────────┘  │
│  ┌────────────────────────────────────────────────┐  │
│  │                  ASDU(应用服务数据单元)         │  │
│  │  Type ID │ VSQ │ COT │ CA │ IOA │ Information  │  │
│  └────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────┘

APCI 控制域格式:
- I 帧(信息帧):传输数据,含发送序号 N(S) 和接收序号 N(R)
- S 帧(监视帧):确认接收,含接收序号 N(R)
- U 帧(非编号帧):控制功能(STARTDT/STOPDT/TESTFR)

ASDU 关键字段

类型标识(Type ID)

类型 ID名称说明
1M_SP_NA_1单点遥信(不带时标)
3M_DP_NA_1双点遥信(不带时标)
9M_ME_NA_1归一化遥测值
11M_ME_NB_1标度化遥测值
13M_ME_NC_1短浮点遥测值
30M_SP_TB_1单点遥信(带 CP56Time2a 时标)
36M_ME_TF_1短浮点遥测值(带时标)
45C_SC_NA_1单命令(遥控)
46C_DC_NA_1双命令(遥控)
48C_SE_NA_1设定命令(归一化值)
50C_SE_NC_1设定命令(短浮点值)
100C_IC_NA_1总召唤命令
101C_CI_NA_1电能量召唤命令
103C_CS_NA_1时钟同步命令

传送原因(COT)

COT名称说明
1周期/循环周期性上送
2背景扫描背景扫描上送
3突发状态变化触发
5被请求响应总召唤
6激活控制命令激活
7激活确认控制命令确认
8停止激活控制命令停止
9停止激活确认停止激活确认
10激活终止控制命令执行完成
20响应站召唤响应总召唤
44未知类型标识错误响应

通信流程

连接建立

主站                              子站
  │                                │
  │──── TCP Connect ──────────────►│
  │◄─── TCP Accept ────────────────│
  │                                │
  │──── STARTDT act (U帧) ────────►│  启动数据传输
  │◄─── STARTDT con (U帧) ─────────│  确认启动
  │                                │
  │──── 总召唤 (C_IC_NA_1) ───────►│  请求全数据
  │◄─── 激活确认 ──────────────────│
  │◄─── 遥信数据 (M_SP_NA_1) ──────│  上送所有遥信
  │◄─── 遥测数据 (M_ME_NC_1) ──────│  上送所有遥测
  │◄─── 召唤结束 ──────────────────│
  │                                │
  │◄─── 变化遥信 (突发, COT=3) ────│  状态变化主动上送
  │◄─── 变化遥测 (周期, COT=1) ────│  周期性遥测

遥控流程(选择-执行)

主站                              子站
  │                                │
  │──── 选择命令 (COT=6) ─────────►│  Select
  │◄─── 选择确认 (COT=7) ──────────│  Select Confirm
  │                                │
  │──── 执行命令 (COT=6) ─────────►│  Execute
  │◄─── 执行确认 (COT=7) ──────────│  Execute Confirm
  │◄─── 激活终止 (COT=10) ─────────│  Termination
  │                                │
  │ 或:                           │
  │──── 撤销命令 (COT=8) ─────────►│  Cancel
  │◄─── 撤销确认 (COT=9) ──────────│

Python 实现示例

python
# 使用 lib60870-python 库
from lib60870 import Connection, ASDU, InformationObject
from lib60870.lib60870 import *

class IEC104Client:
    def __init__(self, host: str, port: int = 2404):
        self.host = host
        self.port = port
        self.connection = None

    def connect(self):
        self.connection = Connection.create(self.host, self.port)
        self.connection.setASDUReceivedHandler(self._on_asdu_received, None)
        self.connection.setConnectionHandler(self._on_connection_event, None)
        self.connection.connect()

    def _on_connection_event(self, connection, event, param):
        if event == ConnectionEvent.OPENED:
            print("Connected to IEC 104 server")
            # 发送总召唤
            self.send_general_interrogation()
        elif event == ConnectionEvent.CLOSED:
            print("Connection closed")

    def _on_asdu_received(self, connection, asdu, param):
        type_id = asdu.getTypeID()
        cot = asdu.getCOT()

        for i in range(asdu.getNumberOfElements()):
            io = asdu.getElement(i)
            ioa = io.getObjectAddress()

            if type_id == TypeID.M_ME_NC_1:  # 短浮点遥测
                value = io.getValue()
                quality = io.getQuality()
                print(f"IOA={ioa}, Value={value:.3f}, Quality={quality}")

            elif type_id == TypeID.M_SP_NA_1:  # 单点遥信
                value = io.getValue()
                print(f"IOA={ioa}, Status={'ON' if value else 'OFF'}")

    def send_general_interrogation(self, ca: int = 1):
        """发送总召唤"""
        asdu = ASDU.create(TypeID.C_IC_NA_1, False, CauseOfTransmission.ACTIVATION,
                           0, ca, False, False)
        io = InterrogationCommand.create(0, QOI.STATION_INTERROGATION)
        asdu.addInformationObject(io)
        self.connection.sendASDU(asdu)

    def send_single_command(self, ca: int, ioa: int, value: bool):
        """发送单命令(遥控)"""
        asdu = ASDU.create(TypeID.C_SC_NA_1, False, CauseOfTransmission.ACTIVATION,
                           0, ca, False, False)
        io = SingleCommand.create(ioa, value, False, 0)
        asdu.addInformationObject(io)
        self.connection.sendASDU(asdu)

    def send_setpoint(self, ca: int, ioa: int, value: float):
        """发送设定值命令(浮点)"""
        asdu = ASDU.create(TypeID.C_SE_NC_1, False, CauseOfTransmission.ACTIVATION,
                           0, ca, False, False)
        io = SetpointCommandShort.create(ioa, value, 0)
        asdu.addInformationObject(io)
        self.connection.sendASDU(asdu)

储能电站 IEC 104 点表设计

储能电站典型点表:

遥信(单点,Type 1/30):
IOA 1001: PCS 运行状态(0=停机, 1=运行)
IOA 1002: PCS 故障状态
IOA 1003: BMS 告警状态
IOA 1004: 消防系统状态
IOA 1005: 急停按钮状态

遥测(短浮点,Type 13/36):
IOA 2001: 系统总功率 (kW)
IOA 2002: 系统总电流 (A)
IOA 2003: 直流母线电压 (V)
IOA 2004: SOC (%)
IOA 2005: SOH (%)
IOA 2006: 最高电芯温度 (°C)
IOA 2007: 最低电芯温度 (°C)
IOA 2008: 累计充电量 (kWh)
IOA 2009: 累计放电量 (kWh)

遥控(单命令,Type 45):
IOA 3001: PCS 启动/停止
IOA 3002: 充电模式/放电模式切换
IOA 3003: 急停

设定值(浮点,Type 50):
IOA 4001: 有功功率设定值 (kW)
IOA 4002: 无功功率设定值 (kVar)
IOA 4003: SOC 上限设定 (%)
IOA 4004: SOC 下限设定 (%)

生态工具

开发库:
├── lib60870-C      → C 语言实现,跨平台
├── lib60870-Python → Python 绑定
├── j60870          → Java 实现(开源)
├── IEC60870.NET    → .NET 实现
└── OpenMRTS        → 开源 SCADA 平台

测试工具:
├── IEC 104 Tester  → 商业测试工具
├── FreyrSCADA      → 开源测试客户端
└── Wireshark       → 协议分析(支持 IEC 104 解码)

商业平台:
├── SIEMENS SICAM   → 变电站自动化
├── ABB MicroSCADA  → 电力 SCADA
├── Schneider EcoStruxure → 能源管理
└── 南瑞 PCS-9000   → 国内主流调度系统

褚成志的IoT笔记