跳到主内容

v0.18.0 版本说明

EnerOS v0.18.0

发布日期:2025年04月20日 版本代号:Scada Git Tag:v0.18.0 支持状态:稳定(Stable) Crate 总数:50(新增 4 个) 测试用例数:6920+(新增 540)

版本概述

EnerOS v0.18.0「Scada」是 EnerOS 在「现场设备接入」方向上的核心版本,本版本的核心目标是深度集成 SCADA(Supervisory Control and Data Acquisition)系统,重点增强 IEC 60870-5-104 协议栈,实现与变电站 RTU、厂站测控装置、保护装置的实时遥测采集、遥控命令下发与 SOE(Sequence of Events)事件记录,使 EnerOS 能够直接作为省级调度主站与现场设备通信。

SCADA 是电力调度的「神经末梢」,负责采集现场设备的运行状态与测量数据,并将调度指令下发至执行机构。IEC 60870-5-104 是国际标准化的远动协议(基于 TCP/IP),广泛应用于中国、欧洲、亚洲等地区的调度自动化系统。v0.9.0 曾引入基础的 Modbus 与 IEC 104 接入能力,但仅支持简单遥测读取。v0.18.0 将 IEC 104 协议栈升级为生产级实现,支持全类型遥测(TI)、遥信(DI)、电度(CI)、遥控(TC)、遥调(TI_setpoint),并内置 SOE 事件序列记录与防抖处理。

本版本引入了 eneros-scada(SCADA 核心)、eneros-scada-iec104(IEC 104 协议栈)、eneros-scada-rtu(RTU 管理)、eneros-scada-soe(SOE 事件记录)四个新 crate。设计哲学是「协议原生,数据原生」——SCADA 协议栈直接在 Rust 内核实现,避免 C 库绑定带来的安全与性能问题,采集的数据直接进入 EnerOS 时序存储与管道,无需中转。

关键数据

指标v0.9.0(基础)v0.18.0(增强)提升
IEC 104 连接数32102432x
遥测采集延迟2s80ms25x
遥控执行延迟5s150ms33x
SOE 分辨率10ms1ms10x
协议覆盖率30%95%+65pp

新特性

1. SCADA 系统集成

引入 eneros-scada crate,作为 SCADA 子系统的统一入口,管理所有 RTU/IED 连接、点表配置、数据采集任务与控制命令队列。SCADA 子系统与 EnerOS 管道、时序存储、孪生体深度集成,采集的数据自动流入后续处理链。

SCADA 主站配置

use eneros_scada::{ScadaMaster, ScadaConfig, RtuConnection};

let mut master = ScadaMaster::new(ScadaConfig {
    max_connections: 1024,
    poll_interval: Duration::milliseconds(500),
    command_timeout: Duration::seconds(5),
    soe_buffer_size: 100_000,
    auto_reconnect: true,
    reconnect_backoff: Backoff::exponential(Duration::seconds(1), Duration::minutes(5)),
})?;

// 添加 RTU 连接
master.add_rtu(RtuConnection::iec104()
    .id("rtu-substation-1")
    .address("10.20.30.1:2404")
    .common_address(1)
    .timeout(Duration::seconds(10))
    .time_sync(true))?;

// 启动 SCADA 主站
master.start().await?;

点表配置

use eneros_scada::{PointTable, PointType, PointId};

// 配置点表(遥测/遥信/电度)
let table = PointTable::new()
    // 遥测点(TI)
    .point(PointId::ti(1, 1), PointType::Float, "母线1电压", "kV")
    .point(PointId::ti(1, 2), PointType::Float, "母线1频率", "Hz")
    .point(PointId::ti(1, 3), PointType::Float, "线路12有功", "MW")
    // 遥信点(DI)
    .point(PointId::di(1, 1), PointType::Single, "断路器1状态", "")
    .point(PointId::di(1, 2), PointType::Single, "隔离开关2状态", "")
    // 电度点(CI)
    .point(PointId::ci(1, 1), PointType::Integrated, "总有功电度", "kWh")
    // 遥控点(TC)
    .point(PointId::tc(1, 1), PointType::Single, "断路器1遥控", "")
    // 遥调点(Setpoint)
    .point(PointId::sp(1, 1), PointType::Float, "AVR电压给定", "kV");

master.load_point_table(table)?;

点类型映射

IEC 类型缩写说明数据格式方向
遥测TI测量值float上行
遥信DI状态量bool上行
电度CI累计量int64上行
遥控TC单点控制bool下行
遥调SP设定值float下行

2. IEC 60870-5-104 协议增强

引入 eneros-scada-iec104 crate,实现生产级 IEC 60870-5-104 协议栈,完整支持 APCI 帧格式、ASDU 应用服务数据单元、I 帧 / S 帧 / U 帧三种帧类型,并实现平衡式与非平衡式传输模式。

协议帧结构

use eneros_scada_iec104::{Frame, FrameType};

// I 帧(信息帧):承载数据
let i_frame = Frame::i(
    send_seq: 1024,
    recv_seq: 512,
    asdu: Asdu::single_point_info(
        common_address: 1,
        ioa: 1,
        value: true,
        quality: Quality::ok(),
        time: Some(now()),
    ),
);

// S 帧(监视帧):确认接收
let s_frame = Frame::s(recv_seq: 1024);

// U 帧(控制帧):启动/停止/测试
let u_frame = Frame::u(FrameType::StartDt);

ASDU 类型支持

类型码名称方向说明
<1>单点遥信上行DI 单点
<3>双点遥信上行DI 双点
<9>归一化遥测上行TI 标度值
<13>浮点遥测上行TI IEEE 754
<15>累计电度上行CI
<30>单点 SOE上行带时标 DI
<45>单点遥控下行TC
<50>设定值下行SP
<70>时钟同步下行对时

链路层管理

use eneros_scada_iec104::{LinkLayer, LinkConfig};

let link = LinkLayer::new(LinkConfig {
    t1: Duration::seconds(15),     // 等待 ACK 超时
    t2: Duration::seconds(10),     // 发送 ACK 延迟
    t3: Duration::seconds(20),     // 空闲测试间隔
    k: 12,                          // 未确认 I 帧上限
    w: 8,                           // 收到 I 帧后发 S 帧阈值
});

// 自动链路维护
link.on_disconnect(|rtu_id| {
    log::warn!("RTU {} 链路断开", rtu_id);
    alert::notify(format!("RTU {} 通信中断", rtu_id));
});

link.on_reconnect(|rtu_id| {
    log::info!("RTU {} 链路恢复", rtu_id);
});

3. 实时遥测数据采集

SCADA 主站持续轮询 RTU 的遥测数据,并通过 EnerOS 管道实时发布,时序存储与孪生体同步消费。采集支持周期轮询与突变上报两种模式,兼顾实时性与带宽效率。

数据采集流程

use eneros_scada::collector::Collector;

let collector = Collector::new(&master)
    // 周期采集:每 500ms 采集所有遥测
    .poll(PollConfig {
        interval: Duration::milliseconds(500),
        strategy: PollStrategy::grouped_by_rtu,
    })
    // 突变上报:变化超过阈值时立即上报
    .spontaneous(SpontaneousConfig {
        enable: true,
        deadband: Deadband::relative(0.01),  // 1% 变化
        min_interval: Duration::milliseconds(100),
    })
    // 采集回调
    .on_telemetry(|point| {
        // 发布到管道
        pipeline.publish(
            Topic::of(format!("telemetry.rtu.{}.{}", point.rtu_id, point.ioa)),
            Event::telemetry(point),
        )?;
        Ok(())
    });

collector.start().await?;

采集性能指标

采集模式RTU 数点数采集延迟带宽占用
周期 500ms102450万80ms12 Mbps
周期 1s102450万120ms6 Mbps
突变上报102450万20ms2 Mbps
混合模式102450万50ms4 Mbps

数据质量标记

use eneros_scada::Quality;

// 每个遥测点附带质量标记
match point.quality {
    Quality::Ok => { /* 数据有效 */ }
    Quality::Invalid => { /* 数据无效 */ }
    Quality::NonTopical => { /* 数据非当前 */ }
    Quality::Substituted => { /* 数据被替换 */ }
    Quality::Blocked => { /* 数据被阻塞 */ }
    Quality::Overflow => { /* 数据溢出 */ }
}

4. 遥控命令下发

支持通过 IEC 104 协议向 RTU 下发遥控命令(单点遥控、双点遥控、设定值),所有命令经过 Guardian 守卫校验,并支持「选择-执行(Select-Before-Operate)」两步操作,防止误操作。

遥控操作

use eneros_scada::command::{Command, SelectOperate};

// 单点遥控:合闸
let cmd = Command::single_point(
    rtu_id: "rtu-substation-1",
    common_address: 1,
    ioa: 1,
    value: true,  // 合闸
);

// 选择-执行模式(SBO)
let so = SelectOperate::new(&master)
    .select(&cmd).await?      // 选择
    .confirm_within(Duration::seconds(10))  // 10秒内确认
    .operate().await?;        // 执行

match so.result {
    Ok(()) => log::info!("遥控成功: {}", cmd),
    Err(e) => log::error!("遥控失败: {}", e),
}

直接执行模式

// 直接执行(仅限非关键操作,需 Guardian 授权)
let cmd = Command::set_point(
    rtu_id: "rtu-substation-1",
    common_address: 1,
    ioa: 1,
    value: 110.0,  // 电压给定 110kV
);

// 经 Guardian 校验后直接下发
ctx.guardian().check(&cmd).await?;
master.execute_direct(&cmd).await?;

遥控操作模式对比

模式步骤安全性适用场景
SBO选择→确认→执行关键操作
直接执行直接下发设定值调整
预置执行预置→执行较高批量操作

5. SOE 事件记录

引入 eneros-scada-soe crate,记录电网事件序列(SOE),支持 1ms 级事件分辨率,用于故障分析与事故追溯。SOE 事件带 GPS 时标,确保全站事件时间一致性。

SOE 记录

use eneros_scada_soe::{SoeLog, SoeEvent};

let soe = SoeLog::new(SoeConfig {
    buffer_size: 1_000_000,
    resolution: Duration::milliseconds(1),
    time_source: TimeSource::gps(),
    debounce: DebounceConfig::disabled(),  // SOE 不防抖
});

// 自动记录事件
soe.on_event(|event| {
    let evt = SoeEvent {
        timestamp: event.time,  // GPS 时标
        rtu_id: event.rtu_id,
        ioa: event.ioa,
        value: event.value,
        description: point_table.describe(event.rtu_id, event.ioa),
    };
    
    // 写入持久存储
    soe.persist(&evt).await?;
    
    // 发布到管道
    pipeline.publish("soe.event", Event::soe(evt))?;
});

SOE 检索

// 检索故障期间的事件序列
let events = soe.query()
    .rtu("rtu-substation-1")
    .range("2025-04-20T14:30:00Z", "2025-04-20T14:35:00Z")
    .order(OrderBy::Ascending)
    .execute()?;

for evt in events {
    println!("{:?} RTU={} IOA={} {} = {}",
        evt.timestamp, evt.rtu_id, evt.ioa, evt.description, evt.value);
}

事件序列示例

时间戳RTUIOA描述
14:30:00.123rtu-15主变差动保护跳闸
14:30:00.125rtu-112主变高压侧开关
14:30:00.128rtu-23备自投装置动作
14:30:00.135rtu-27母联开关

改进

  • 时序存储:时序写入路径优化,支持 SCADA 高频写入(50 万点/秒)
  • 孪生体:孪生体直接订阅 SCADA 管道,状态同步延迟降至 80ms
  • 守卫系统:遥控命令自动经过 Guardian 校验,危险操作拦截
  • 仪表盘:新增 SCADA 监控面板,实时展示 RTU 连接状态与数据质量

Bug 修复

  • 修复 eneros-scada-iec104 在 RTU 数量超过 256 时连接泄漏的问题(#1809)
  • 修复 eneros-scada 遥控命令在 SBO 模式下超时未释放选择锁的问题(#1815)
  • 修复 eneros-scada-soe 在 GPS 时钟跳变时事件乱序的问题(#1821)
  • 修复 eneros-scada-iec104 在链路重连后 ASDU 序号错乱的问题(#1827)

破坏性变更

  • Gateway::add_iec104:迁移至 ScadaMaster::add_rtu,原方法废弃
  • PointTable::load:改为 async,需 .await
  • Command::execute:默认改为 SBO 模式,直接执行需 execute_direct

性能提升

  • IEC 104 连接数从 32 提升至 1024(提升 32 倍)
  • 遥测采集延迟从 2s 降至 80ms(提升 25 倍)
  • 遥控执行延迟从 5s 降至 150ms(提升 33 倍)
  • SOE 事件分辨率从 10ms 提升至 1ms(提升 10 倍)

贡献者

本版本由 22 位贡献者共同完成,提交 388 次。特别感谢:

  • @scada-core:SCADA 主站与点表管理
  • @iec104-implementer:IEC 104 协议栈 Rust 实现
  • @rtu-manager:RTU 连接与链路维护
  • @soe-master:SOE 事件序列与 GPS 对时

升级指南

从 v0.17.0 升级

1. 更新依赖

# Cargo.toml
[dependencies]
eneros-scada = { version = "0.18" }
eneros-scada-iec104 = { version = "0.18" }
eneros-scada-rtu = { version = "0.18" }
eneros-scada-soe = { version = "0.18" }

2. 迁移 SCADA 配置

// v0.9.0 旧写法
gateway.add_iec104("rtu-1", "10.20.30.1:2404")?;

// v0.18.0 新写法
master.add_rtu(RtuConnection::iec104()
    .id("rtu-1")
    .address("10.20.30.1:2404")
    .common_address(1))?;

3. 配置点表

# eneros.toml
[scada]
enabled = true
max_connections = 1024
poll_interval_ms = 500

[[scada.rtu]]
id = "rtu-substation-1"
address = "10.20.30.1:2404"
common_address = 1
time_sync = true

[[scada.points]]
id = "ti:1:1"
type = "float"
name = "母线1电压"
unit = "kV"

4. 启用 SOE 记录

建议生产环境启用 SOE 记录,并配置 GPS 时钟源,确保事件序列精度满足事故分析要求:

[scada.soe]
enabled = true
buffer_size = 1000000
resolution_ms = 1
time_source = "gps"

5. 遥控安全配置

所有遥控操作建议启用 SBO 模式,并接入 Guardian 守卫校验:

let so = SelectOperate::new(&master)
    .guardian(ctx.guardian())  // 接入守卫
    .select(&cmd).await?
    .confirm_within(Duration::seconds(10))
    .operate().await?;