소프트웨어 엔지니어를 위한 IEC 61850: 스마트 그리드 통신
2003년 9월, 유럽의 전력망에 계단식 결함이 발생하여 정전이 발생했습니다. 이탈리아, 스위스, 오스트리아 및 기타 국가: 5,600만 명 전기 공급 중단 몇 시간 동안. 그 사건은 변전소 통신의 조용한 혁명을 가속화시켰습니다. 표준의 글로벌 채택으로 정점에 도달 IEC 61850. 20년 후, 이 프로토콜과 변전소 자동화를 위한 사실상의 표준으로 90개 이상의 국가에서 수십 개가 사용됩니다. 수천 개의 운영 설치와 벤더 생태계, 오픈 소스 도구 및 인증 여기에는 전 세계 수십만 명의 엔지니어가 참여합니다.
에너지 부문에서 일하고 있거나 일하고 싶어하는 소프트웨어 엔지니어의 경우 IEC 61850에 대한 지식 더 이상 선택 사항이 아닙니다. 그만큼 디지털 변전소 현대 시스템은 복잡한 분산 시스템입니다. 4밀리초의 지연 시간으로 실시간 통신하는 지능형 전자 장치(IED), 구조화된 XML 구성 파일, 이더넷을 통한 게시/구독 아키텍처, 통합 SCADA 및 히스토리언, IEC 62351 및 NIS2와 같은 규정에 의해 정의된 보안 제약 조건. 나는 정확히 현대 소프트웨어 엔지니어의 전문 분야이지만 인프라에 적용됩니다. 도시, 산업, 병원에 활력을 불어넣는 비판.
전 세계 변전소 자동화 시장이 앞섰습니다. 2024년 21억 달러 2032년에는 38억 명에 이를 것으로 예상됩니다. (CAGR 7.8%). 이탈리아에서는 Terna와 e-distribuzione가 디지털 변전소에 막대한 투자를 하고 있습니다. 간헐적인 재생 가능 에너지원을 통합해야 하는 필요성에 따라 IEC 61850 기술을 사용하여 점점 더 복잡해지는 유통 네트워크를 충족하고 지침의 사이버 보안 요구 사항을 충족합니다. NIS2는 2024년에 구현됩니다.
이 기사에서는 이더넷 물리적 계층에서 컨테이너화된 마이크로서비스 아키텍처까지 안내합니다. 데이터 모델, MMS 및 GOOSE 프로토콜, SCL 구성, 사이버 보안 및 테스트를 다룹니다. 매 섹션에는 작동 중인 Python 코드, 실제 XML 예제, 설치 시 테스트된 아키텍처가 포함되어 있습니다. 생산적이다.
이 기사에서 배울 내용
- IEC 61850 계층적 데이터 모델: 논리 노드, 논리 장치, 데이터 개체, 데이터 속성
- XML 스키마 유효성 검사를 통해 SCL(ICD, SCD, CID) 파일을 읽고 쓰는 방법
- 세 가지 주요 프로토콜: MMS 클라이언트-서버, GOOSE 멀티캐스트 실시간, SV 샘플링 값
- GOOSE 심층 분석: L2 이더넷 게시/구독 아키텍처, 재전송, VLAN 우선순위
- MMS 심층 분석: libiec61850 및 Python을 사용한 연결, 보고, 로깅
- SCADA 통합: DNP3/IEC 104에 대한 IEC 61850 게이트웨이, 데이터 매핑, 히스토리언
- 사이버 보안 IEC 62351: MMS를 통한 TLS, GOOSE 인증, RBAC, 네트워크 분할
- 테스트 및 시뮬레이션: libiec61850, OpenMUC, 자동화된 적합성 테스트
- 최신 아키텍처: 마이크로서비스, 컨테이너화 및 변전소 엣지 컴퓨팅
- 이탈리아어 맥락: Terna, 전자 배포, 파일럿 프로젝트 및 로드맵 2025-2030
EnergyTech 시리즈 - 시리즈에서의 위치
| # | Articolo | 상태 |
|---|---|---|
| 1 | 스마트 그리드 및 재생 에너지: 기술 아키텍처 | 게시됨 |
| 2 | 에너지 모니터링을 위한 MQTT 및 InfluxDB | 게시됨 |
| 3 | 배터리 관리 시스템: 알고리즘 및 프로토콜 | 게시됨 |
| 4 | DERMS: 분산 에너지 자원 관리 | 게시됨 |
| 5 | 현재 위치 - 소프트웨어 엔지니어를 위한 IEC 61850 | 현재의 |
| 6 | EV 부하 분산 및 V2G: 최적화 알고리즘 | 다음 |
| 7 | ML을 통한 재생 에너지 예측 | 곧 출시 예정 |
| 8 | 탄소 회계 및 범위 배출 | 곧 출시 예정 |
| 9 | P2P 에너지 거래를 위한 블록체인 | 곧 출시 예정 |
| 10 | 전력망의 디지털 트윈 | 곧 출시 예정 |
IEC 61850: 변전소를 디지털화한 표준
IEC 61850은 단순한 통신 프로토콜이 아닙니다. 규제 생태계 완료 이는 데이터를 모델링, 구성, 전달 및 보호하는 방법을 정의합니다. 전기 변전소 및 최신 버전에서는 모든 전기 네트워크 인프라 풍력 발전 단지, 태양광 발전 시스템, BESS(배터리 에너지 저장 시스템) 시스템 등이 포함됩니다.
표준은 10개의 주요 부분으로 나누어져 있으며 IEC(국제 전기기술위원회):
IEC 61850 표준의 구조
| 부분 | 제목 | 주요 내용 |
|---|---|---|
| 61850-1 | 소개 및 개요 | 원칙, 요구사항, 일반 아키텍처 |
| 61850-2 | 어휘 | 용어 및 정의 |
| 61850-3 | 일반 요구 사항 | 품질, 신뢰성, EMC 요구 사항 |
| 61850-4 | 시스템 및 프로젝트 관리 | 수명주기, 프로젝트 단계 |
| 61850-5 | 통신 요구 사항 | 기능 및 장치 요구 사항 |
| 61850-6 | SCL 구성 언어 | 변전소 구성을 위한 XML |
| 61850-7 | 기본 통신 구조 | 데이터 모델, ACSI, 서비스 |
| 61850-8 | SCSM: MMS 및 GOOSE | 이더넷을 통해 MMS, GOOSE에 매핑 |
| 61850-9 | SCSM: 샘플링된 값 | 이더넷을 통해 샘플링된 값 |
| 61850-10 | 적합성 테스트 | 규정 준수 절차 및 요구 사항 |
현재 버전은 에디션 2.1, 2024년 12월 최초 인증 PCM600 및 IET600 도구를 사용하는 Hitachi Energy의 제품입니다. 에디션 2.1에는 상당한 개선 사항이 도입되었습니다. DER(분산 에너지 자원), BESS 관리 및 클라우드 시스템에 대한 통신, 에너지 전환의 요구에 맞춰 표준을 조정합니다.
IEC 61850은 다른 산업 프로토콜과 다르기 때문에
IEC 61850 이전에는 각 IED 공급업체(ABB, Siemens, GE, Schneider)가 독점 프로토콜을 사용했습니다. 다양한 공급업체의 장치에서 데이터를 수집해야 하는 SCADA 시스템에는 다양한 드라이버, 변환기 및 해결 방법. IEC 61850은 세 가지 혁신을 도입했습니다. 이를 구별하는 기본 사항:
-
표준화되고 공급업체에 구애받지 않는 데이터 모델: 각 보호 기능은,
측정 또는 제어하고 사전 정의된 논리 노드로 설명됩니다. 스위치는 항상
XCBR, 활성 및 상시 전력 측정MMXU.W, 상관없이 공급 업체에 의해. 이렇게 하면 사용자 정의 매핑이 필요하지 않습니다. - SCL을 사용한 선언적 구성: 전체 변전소, 토폴로지, 설치된 장치, 데이터 세트 및 GOOSE 구독은 XML 파일에 설명되어 있습니다. 표준화(SCD). 이는 상호 운용 가능한 엔지니어링 도구와 재현성을 가능하게 합니다. 구성.
- 추상 모델과 전송 간의 분리: ACSI(추상 커뮤니케이션) 서비스 인터페이스) 수행할 수 있는 작업(값 읽기, 보고서 수신, 전송)을 정의합니다. 명령). SCSM(특정 통신 서비스 매핑)은 이것이 수행되는 방법을 정의합니다. MMS, GOOSE 또는 SV. 이러한 분리를 통해 새로운 매핑(예: 웹 서비스)을 추가할 수 있습니다. 데이터 모델을 변경하지 않고.
IEC 61850 데이터 모델: 계층 구조에서 명명까지
IEC 61850의 데이터 모델을 이해하는 것은 모든 작업의 기본 전제 조건입니다. 이 표준. 계층 구조는 5개 수준으로 구성되며 각 수준에는 명명 규칙이 적용됩니다. 정확함:
IEC 61850 데이터 모델 계층 구조
| 수준 | 두문자어 | Esempio | 설명 |
|---|---|---|---|
| IED | 지능형 전자 장치 | SEL-487E | 물리적 장치(보호, 측정, 제어) |
| LD | 논리적 장치 | PROT | IED 내 기능 그룹화 |
| LN | 논리 노드 | XCBR1 | 데이터를 교환하는 최소한의 기능 |
| DO | 데이터 객체 | 포스 | 관련 속성 그룹 |
| DA | 데이터 속성 | stVal | 원자 값(boolean, int, float...) |
Il 완전한 참조 데이터 조각에 다음 패턴을 따릅니다.
IEDName/LDInst/LNClass.LNInst.DOName.DAName.
예를 들어, 호출된 IED에서 스위치 위치 1의 부울 값
"BAY1_PROT"는 다음과 같습니다.
BAY1_PROT/PROT/XCBR1.Pos.stVal
| | | | |
IED name LD LN DO DA
inst class inst
+num
논리 노드: 기능 분류
IEC 61850-7-4는 첫 문자로 그룹화된 90개 이상의 논리 노드 클래스를 정의합니다.
범주별 논리 노드 접두사
| 접두사 | 범주 | Esempi |
|---|---|---|
| A | 자동제어 | ARCO(아크 보호), ATCC(탭 체인저 Ctrl) |
| C | 감독 통제 | CILO(연동), CSWI(스위치 Ctrl) |
| G | 일반 함수 | GAPC(일반 APC), GGIO(일반 I/O) |
| L | 시스템 논리 노드 | LLN0(LN 제로), LPHD(물리적 장치) |
| M | 계량 및 측정 | MMXU(3상 측정), MMTR(계량) |
| P | 보호 | PDIF(차동), PDIS(거리), PDIR(방향) |
| R | 보호 관련 | RBRF(차단기 고장), RDIR(방향 요소) |
| S | 센서 | SARC(아크 센서), SIMG(절연 모니터링) |
| T | 계기용 변압기 | TCTR(변류기), TVTR(전압) |
| X | 배전반 | XCBR(회로 차단기), XSWI(단로기) |
| Y | 전력 변압기 | YPTR(전력 변압기), YPSH(위상 변이) |
| Z | 추가 전력 장비 | ZBSH(버스바), ZCAP(커패시터 뱅크) |
XCBR: 회로 차단기 상세 정보
논리 노드에 대한 연구 XCBR (Circuit Breaker)가 최고의 출발점입니다.
데이터 모델의 구조를 이해합니다. XCBR은 스위치를 완벽하게 모델링합니다.
상태, 명령, 측정 및 진단을 포함한 자동:
XCBR1 (Logical Node - Circuit Breaker)
|
├── ST (Status Data Class - dati di stato)
│ ├── Pos - Posizione (DPC: double point control)
│ │ ├── stVal [BOOLEAN] - Stato aperto/chiuso
│ │ ├── q [Quality] - Validita del dato
│ │ └── t [Timestamp] - Timestamp UTC con ms
│ ├── BlkOpn - Blocco apertura (SPC)
│ ├── BlkCls - Blocco chiusura (SPC)
│ └── CBOpCap - capacità operativa (ENS enum)
│
├── MX (Measured Values)
│ └── OpCnt [INS] - Contatore operazioni
│
└── CF (Configuration)
├── CBOpTmms [INT32U] - Tempo apertura [ms]
└── ModBlkOpn [BOOLEAN] - Modalità blocco apertura
Functional Constraints (FC):
ST = status, MX = measured, CF = config,
DC = description, EX = extended def,
CO = control, SP = setpoint
MMXU: 3상 측정
논리 노드 MMXU (측정 단위)는 피더의 3상 측정을 모델링합니다.
변압기. 모니터링 및 데이터 분석 시스템에서 가장 많이 사용되는 논리 노드는 다음과 같습니다.
MMXU1 (Measurement Unit - 3-phase)
|
├── MX (Measured Values - Functional Constraint)
│ ├── TotW [MV] - Potenza attiva totale [W]
│ │ ├── mag.f [FLOAT32] - Valore float
│ │ ├── q [Quality] - validity, source, detail
│ │ └── t [Timestamp]
│ ├── TotVAr [MV] - Potenza reattiva totale [VAr]
│ ├── TotPF [MV] - Power Factor totale
│ ├── Hz [MV] - Frequenza [Hz]
│ ├── A [WYE] - Correnti trifase
│ │ ├── phsA.cVal.mag.f [FLOAT32] - Fase A [A]
│ │ ├── phsB.cVal.mag.f [FLOAT32] - Fase B [A]
│ │ └── phsC.cVal.mag.f [FLOAT32] - Fase C [A]
│ └── PhV [WYE] - Tensioni di fase [V]
│ ├── phsA.cVal.mag.f
│ ├── phsB.cVal.mag.f
│ └── phsC.cVal.mag.f
│
└── CF (Configuration)
└── AngRef - Angular reference (VA, VB, VC, AA...)
Naming esempio completo:
BAY1_PROT/MEAS/MMXU1.MX.TotW.mag.f
^IED ^LD ^LN ^FC ^DO ^DA ^sub-DA
SCL: 변전소 구성 언어
Il 변전소 구성 언어 (SCL)이며 IEC 61850-6에서 다음과 같이 정의됩니다. 변전소의 전체 구성을 설명하는 표준 XML 형식: 토폴로지 물리학, 설치된 장치, 데이터 모델, GOOSE 데이터 세트 및 연결 FDI 사이의 논리적. SCL은 변전소 엔지니어링에서 가장 비용이 많이 드는 문제 중 하나를 해결합니다. 는 수동 재구성 추가 또는 교체 시 각 장치의 이전에는 몇 주간의 전문 작업이 필요했던 작업인 IED입니다.
네 가지 유형의 SCL 파일
- ICD(IED 기능 설명): 공급업체에서 제공하며 기능을 설명합니다. 완전한 IED: 지원되는 모든 논리 노드, 구성 가능한 데이터 세트, 보고서 및 로그를 사용할 수 있습니다. 그리고 장치의 "카탈로그"입니다.
- SSD(시스템 사양 설명): 토폴로지를 설명합니다. 할당하기 전에 변전소(전압 레벨, 베이, 전도 장비) 특정 장치. 그리고 변전소의 논리적 설계.
- SCD(변전소 구성 설명): "마스터" 파일의 완전히 구성된 변전소. 모든 IED, 사이의 통신을 포함합니다. GOOSE 데이터 세트, 보고서 및 토폴로지입니다. 그리고 시운전 중에 사용된 파일입니다.
- CID(구성된 IED 설명): 단일 IED에 대한 SCD에서 추출합니다. 해당 장치에 필요한 정보(기능, 데이터세트)만 포함되어 있습니다. 게시하는 사람, 그가 구독하는 GOOSE. 그리고 IED에 물리적으로 로드되는 파일입니다.
SCD 파일의 XML 구조
SCD 파일은 IEC 61850-6에 정의된 엄격한 XML 스키마를 따릅니다. 키가 큰 구조 수준 및 다음:
<?xml version="1.0" encoding="UTF-8"?>
<SCL xmlns="http://www.iec.ch/61850/2003/SCL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2007" revision="B" release="4">
<!-- Header: identificazione e versione -->
<Header id="SCD_Substation_Nord_Milano"
version="1.0"
revision="3"
toolID="OpenSCD v0.22.0"
nameStructure="IEDName">
<History>
<Hitem version="1.0" revision="3" when="2025-03-09"
who="f.calo@utility.it"
what="Updated GOOSE subscriptions for BAY3"/>
</History>
</Header>
<!-- Substation: topologia elettrica -->
<Substation name="SNord" desc="Sottostazione Nord Milano 150/20kV">
<VoltageLevel name="VL_150kV" desc="Livello 150kV">
<Voltage unit="V" multiplier="k">150</Voltage>
<Bay name="BAY1" desc="Feeder 1 - Linea Torino">
<ConductingEquipment type="CBR" name="QA1"
desc="Circuit Breaker Bay1">
<Terminal name="T1" connectivityNode="SNord/VL_150kV/BAY1/BusbarSection1"/>
</ConductingEquipment>
<ConductingEquipment type="DIS" name="QA2"
desc="Disconnector Bay1"/>
</Bay>
</VoltageLevel>
</Substation>
<!-- Communication: indirizzi IP e GOOSE/VLAN -->
<Communication>
<SubNetwork name="MMS_LAN" type="8-MMS" desc="MMS Client-Server LAN">
<ConnectedAP iedName="BAY1_PROT" apName="S1">
<Address>
<P type="IP">192.168.1.10</P>
<P type="IP-MASK">255.255.255.0</P>
<P type="IP-GATEWAY">192.168.1.1</P>
</Address>
</ConnectedAP>
<ConnectedAP iedName="BAY2_PROT" apName="S1">
<Address>
<P type="IP">192.168.1.11</P>
<P type="IP-MASK">255.255.255.0</P>
</Address>
</ConnectedAP>
</SubNetwork>
<SubNetwork name="GOOSE_LAN" type="8-MMS"
desc="GOOSE Process Bus VLAN 100">
<ConnectedAP iedName="BAY1_PROT" apName="P1">
<Address>
<P type="MAC-Address">01-0C-CD-01-00-01</P>
<P type="VLAN-ID">100</P>
<P type="VLAN-PRIORITY">4</P>
<P type="APPID">0001</P>
</Address>
</ConnectedAP>
</SubNetwork>
</Communication>
<!-- IED: configurazione dispositivo BAY1_PROT -->
<IED name="BAY1_PROT" type="SEL-487E"
manufacturer="Schweitzer Engineering" configVersion="1.2">
<AccessPoint name="S1">
<Server>
<Authentication none="true" password="false" certificate="true"/>
<LDevice inst="PROT" desc="Protection Logical Device">
<LN0 lnClass="LLN0" inst="" lnType="LLN0_type1">
<DataSet name="DSStatusProt" desc="Protection Status Dataset">
<FCDA ldInst="PROT" prefix="" lnClass="XCBR"
lnInst="1" doName="Pos" daName="stVal" fc="ST"/>
<FCDA ldInst="PROT" prefix="" lnClass="XCBR"
lnInst="1" doName="Pos" daName="q" fc="ST"/>
</DataSet>
<GSEControl name="GCBStatusProt"
desc="GOOSE Control Block - Status"
type="GOOSE"
appID="GOOSE_BAY1_PROT_STATUS"
confRev="1"
datSet="DSStatusProt">
</GSEControl>
</LN0>
<LN lnClass="XCBR" inst="1" lnType="XCBR_type1"
prefix="" desc="Circuit Breaker 1">
</LN>
<LN lnClass="MMXU" inst="1" lnType="MMXU_type1"
prefix="" desc="3-Phase Measurement Feeder1">
</LN>
<LN lnClass="PDIF" inst="1" lnType="PDIF_type1"
prefix="" desc="Differential Protection">
</LN>
</LDevice>
</Server>
</AccessPoint>
</IED>
<!-- DataTypeTemplates: definizione tipi LN, DO, DA -->
<DataTypeTemplates>
<LNodeType id="XCBR_type1" lnClass="XCBR">
<DO name="Pos" type="DPC_type"/>
<DO name="BlkOpn" type="SPC_type"/>
<DO name="BlkCls" type="SPC_type"/>
<DO name="OpCnt" type="INS_type"/>
</LNodeType>
<DOType id="DPC_type" cdc="DPC">
<DA name="stVal" bType="Dbpos" fc="ST"/>
<DA name="q" bType="Quality" fc="ST"/>
<DA name="t" bType="Timestamp" fc="ST"/>
<DA name="ctlVal" bType="BOOLEAN" fc="CO"/>
</DOType>
</DataTypeTemplates>
</SCL>
SCL 유효성 검사: XML 구문 분석만으로는 충분하지 않습니다.
구문적으로 유효한 SCL 파일(잘 구성된 XML)에는 심각한 의미 오류가 포함될 수 있습니다. GOOSE 구독에 존재하지 않는 IED에 대한 참조, 중복된 MAC 주소, GOOSE APPID DataTypeTemplate과 인스턴스 간의 충돌, 불일치. 항상 도구를 사용하세요 다음과 같은 특정 검증 오픈SCD (오픈 소스, 브라우저 기반) 또는 libIEC61850 SCL 파서 업로드하기 전에 XSD 스키마 검증을 통해 실제 IED의 구성.
Python으로 SCL 구문 분석
SCL 구성을 시스템에 통합하려면(데이터 매핑, CMDB, 설명서 자동), Python으로 SCL 파일을 구문 분석하는 방법을 아는 것이 유용합니다. 다음은 실제 예입니다.
"""
Parser SCL IEC 61850 - Estrae IED, Logical Devices e Logical Nodes
Richiede: pip install lxml
"""
from lxml import etree
from dataclasses import dataclass, field
from typing import Optional
# Namespace SCL standard
SCL_NS = "http://www.iec.ch/61850/2003/SCL"
@dataclass
class LogicalNode:
ln_class: str
inst: str
ln_type: str
prefix: str = ""
desc: str = ""
@dataclass
class LogicalDevice:
inst: str
desc: str
logical_nodes: list[LogicalNode] = field(default_factory=list)
@dataclass
class IEDConfig:
name: str
manufacturer: str
ied_type: str
logical_devices: list[LogicalDevice] = field(default_factory=list)
def parse_scl(file_path: str) -> list[IEDConfig]:
"""Parsa un file SCL e restituisce la lista degli IED configurati."""
tree = etree.parse(file_path)
root = tree.getroot()
ns = {"scl": SCL_NS}
ieds: list[IEDConfig] = []
for ied_elem in root.findall("scl:IED", ns):
ied = IEDConfig(
name=ied_elem.get("name", ""),
manufacturer=ied_elem.get("manufacturer", ""),
ied_type=ied_elem.get("type", ""),
)
for ap in ied_elem.findall(".//scl:AccessPoint/scl:Server/scl:LDevice", ns):
ld = LogicalDevice(
inst=ap.get("inst", ""),
desc=ap.get("desc", ""),
)
# LN0 (obbligatorio, sempre presente)
ln0 = ap.find("scl:LN0", ns)
if ln0 is not None:
ld.logical_nodes.append(LogicalNode(
ln_class="LLN0",
inst="",
ln_type=ln0.get("lnType", ""),
desc=ln0.get("desc", ""),
))
# LN instances
for ln_elem in ap.findall("scl:LN", ns):
ld.logical_nodes.append(LogicalNode(
ln_class=ln_elem.get("lnClass", ""),
inst=ln_elem.get("inst", ""),
ln_type=ln_elem.get("lnType", ""),
prefix=ln_elem.get("prefix", ""),
desc=ln_elem.get("desc", ""),
))
ied.logical_devices.append(ld)
ieds.append(ied)
return ieds
def extract_goose_publishers(file_path: str) -> list[dict]:
"""Estrae tutti i GOOSE Control Block dal file SCD."""
tree = etree.parse(file_path)
root = tree.getroot()
ns = {"scl": SCL_NS}
goose_list = []
for ied in root.findall("scl:IED", ns):
ied_name = ied.get("name")
for gse in ied.findall(".//scl:GSEControl", ns):
goose_list.append({
"ied": ied_name,
"name": gse.get("name"),
"appID": gse.get("appID"),
"datSet": gse.get("datSet"),
"confRev": gse.get("confRev"),
})
return goose_list
# Utilizzo
if __name__ == "__main__":
ieds = parse_scl("substation_nord.scd")
for ied in ieds:
print(f"IED: {ied.name} ({ied.manufacturer})")
for ld in ied.logical_devices:
print(f" LD: {ld.inst}")
for ln in ld.logical_nodes:
ref = f"{ied.name}/{ld.inst}/{ln.ln_class}{ln.inst}"
print(f" {ref}")
MMS: 제조 메시지 사양
프로토콜 MMS (제조 메시지 사양, ISO 9506) 및 IEC 61850의 클라이언트-서버 통신 백본. 다음 용도로 사용됩니다.
- 값 읽기 및 쓰기(읽기, 쓰기)
- 원치 않는 신고 접수(보고)
- IED에서 기록 로그 검색(로깅)
- 제어 명령 보내기(Commands)
- IED 파일 시스템 복구(파일 전송)
MMS는 기본 포트를 사용하여 TCP/IP 위의 애플리케이션 계층에서 작동합니다. 102 (ISO COTP TCP를 통해). 연결은 협상과 함께 MMS 연결(세션과 유사)을 사용합니다. 최대 미해결 요청 수 및 최대 PDU 크기와 같은 매개변수.
보고서 제어 블록: 실시간 모니터링의 핵심
모니터링 및 모니터링을 위한 MMS의 가장 중요한 메커니즘 보고서 제어 블록 (RCB). 지속적으로 폴링하는 대신 SCADA는 IED의 RCB를 구독하여 다음을 지정합니다. 트리거 조건. IED는 상황이 발생하면 자동으로 보고서를 보냅니다.
RCB에는 두 가지 유형이 있습니다.
- BRCB(버퍼 RCB): 클라이언트가 e인 경우에도 버퍼 보고서 연결이 끊어졌습니다. 이벤트가 누락되지 않도록 보장합니다. 각 클라이언트에는 자체 인스턴스가 있습니다. BRCB. 보호 이벤트 및 알람에 사용됩니다.
- URCB(버퍼되지 않은 RCB): 해당 클라이언트에 연결된 클라이언트에만 보고서를 보냅니다. 순간. 더 가볍습니다. 아날로그 값을 주기적으로 모니터링하는 데 사용됩니다.
libiec61850 Python을 사용한 실제 예
"""
Client MMS IEC 61850 con libiec61850 Python bindings
Richiede: pip install pyiec61850 oppure build da sorgenti
Documentazione: https://libiec61850.com/documentation/
"""
import iec61850 # Python wrapper per libiec61850
import time
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class IEC61850Client:
"""Client MMS per comunicazione con IED IEC 61850."""
def __init__(self, host: str, port: int = 102):
self.host = host
self.port = port
self.connection: Optional[iec61850.IedConnection] = None
def connect(self) -> bool:
"""Stabilisce connessione MMS con IED."""
self.connection = iec61850.IedConnection_create()
error = iec61850.IedClientError()
iec61850.IedConnection_connect(
self.connection, error, self.host, self.port
)
if error.value != iec61850.IED_ERROR_OK:
logger.error(f"Connessione fallita a {self.host}:{self.port} "
f"- Errore: {error.value}")
return False
logger.info(f"Connesso a IED {self.host}:{self.port}")
return True
def read_boolean(self, object_ref: str) -> Optional[bool]:
"""Legge un attributo booleano (es. stato interruttore)."""
error = iec61850.IedClientError()
value = iec61850.IedConnection_readBooleanValue(
self.connection, error, object_ref,
iec61850.IEC61850_FC_ST # Functional Constraint: ST = Status
)
if error.value != iec61850.IED_ERROR_OK:
logger.error(f"Errore lettura {object_ref}: {error.value}")
return None
return bool(value)
def read_float(self, object_ref: str,
fc: int = iec61850.IEC61850_FC_MX) -> Optional[float]:
"""Legge un valore float (es. potenza attiva)."""
error = iec61850.IedClientError()
value = iec61850.IedConnection_readFloatValue(
self.connection, error, object_ref, fc
)
if error.value != iec61850.IED_ERROR_OK:
return None
return float(value)
def subscribe_reports(self, rcb_ref: str,
callback, client_id: str = "SCADA_01") -> bool:
"""
Iscrive a un Buffered Report Control Block per ricevere eventi.
rcb_ref esempio: "BAY1_PROT/PROT/LLN0.BR.brcbStatus01"
"""
error = iec61850.IedClientError()
# Abilita il report
iec61850.IedConnection_setRCBValues(
self.connection, error, rcb_ref,
iec61850.RCB_ELEMENT_RPT_ENA | iec61850.RCB_ELEMENT_DATA_SET,
True, None
)
# Installa handler per i report in ingresso
iec61850.IedConnection_installReportHandler(
self.connection, rcb_ref, client_id, callback, None
)
if error.value != iec61850.IED_ERROR_OK:
logger.error(f"Errore iscrizione RCB {rcb_ref}")
return False
logger.info(f"Iscritto a RCB: {rcb_ref}")
return True
def send_select_operate(self, ctrl_ref: str, value: bool) -> bool:
"""
Invia un comando Select-Before-Operate (SBO) per controllare un
interruttore. Più sicuro del Direct Operate per comandi critici.
ctrl_ref esempio: "BAY1_PROT/PROT/CSWI1.Pos"
"""
error = iec61850.IedClientError()
ctrl = iec61850.ControlObjectClient_create(ctrl_ref, self.connection)
# Prima la SELECT
iec61850.ControlObjectClient_selectWithValue(ctrl, None)
if error.value != iec61850.IED_ERROR_OK:
logger.error(f"SELECT fallita per {ctrl_ref}")
return False
# Poi OPERATE entro il timeout (tipicamente 30s)
iec61850.ControlObjectClient_operate(ctrl, value, 0)
if error.value != iec61850.IED_ERROR_OK:
logger.error(f"OPERATE fallita per {ctrl_ref}")
return False
logger.info(f"Comando SBO inviato: {ctrl_ref} = {value}")
return True
def disconnect(self):
"""Chiude la connessione MMS."""
if self.connection:
iec61850.IedConnection_destroy(self.connection)
self.connection = None
# Report handler callback
def on_report_received(report, param):
"""Callback chiamata quando l'IED invia un report."""
dataset_dir = iec61850.ClientReport_getDataSetDirectory(report)
values = iec61850.ClientReport_getDataSetValues(report)
logger.info(f"Report ricevuto - Dataset: {dataset_dir}")
# Elabora i valori del report
for i in range(iec61850.MmsValue_getArraySize(values)):
element = iec61850.MmsValue_getElement(values, i)
logger.info(f" Valore[{i}]: {iec61850.MmsValue_printToBuffer(element, 256)}")
# Esempio utilizzo
if __name__ == "__main__":
client = IEC61850Client(host="192.168.1.10", port=102)
if client.connect():
# Leggi stato interruttore
breaker_pos = client.read_boolean(
"BAY1_PROT/PROT/XCBR1.ST.Pos.stVal"
)
logger.info(f"Posizione interruttore: {'CHIUSO' if breaker_pos else 'APERTO'}")
# Leggi potenza attiva [MW]
active_power = client.read_float(
"BAY1_PROT/MEAS/MMXU1.MX.TotW.mag.f"
)
logger.info(f"Potenza attiva: {active_power / 1e6:.2f} MW")
# Iscrizione report per eventi di protezione
client.subscribe_reports(
"BAY1_PROT/PROT/LLN0.BR.brcbProt01",
on_report_received,
"SCADA_PRIMARY"
)
# Loop principale
try:
while True:
time.sleep(0.1) # 100ms polling loop
except KeyboardInterrupt:
pass
finally:
client.disconnect()
GOOSE: 보호 및 연동을 위한 실시간 프로토콜
거위 (Generic Object Oriented Substation Event) 및 가장 중요한 프로토콜 보호 애플리케이션에 대한 IEC 61850. MMS는 다음과 같은 오버헤드가 있는 TCP/IP를 사용합니다. 연결, GOOSE 작동 이더넷 레이어 2를 통해 직접, 레벨 제거 보다 낮은 대기 시간을 달성하기 위한 네트워크 및 전송 4밀리초 이벤트부터 구독한 IED의 수신까지.
이 지연 시간 요구 사항은 임의적이지 않으며 최대 허용 시간에 해당합니다. 보호 계전기 간 트립 신호 교환 표준(성능 범주) IEC 61850-5의 P1 및 P2). 결함을 감지한 계전기는 이를 인접한 IED에 전달해야 합니다. 4ms 이내에 보호 조정이 가능합니다.
GOOSE 아키텍처: 이더넷을 통한 게시/구독
Architettura GOOSE Publisher/Subscriber
┌─────────────────┐ GOOSE multicast ┌─────────────────┐
│ IED Publisher │ ──────────────────────▶│ IED Subscriber 1│
│ (BAY1_PROT) │ EtherType: 0x88B8 │ (BAY2_PROT) │
│ │ MAC: 01-0C-CD-01-* └─────────────────┘
│ APPID: 0x0001 │ VLAN: 100 ┌─────────────────┐
│ confRev: 5 │ PCP: 4 (high prio) ─│ IED Subscriber 2│
└─────────────────┘ │ (BAY3_PROT) │
└─────────────────┘
Frame Ethernet GOOSE:
┌──────────┬──────────┬────────┬───────┬─────────────────────────┐
│ Dest MAC │ Src MAC │802.1Q │EthType│ GOOSE PDU (ASN.1) │
│6 bytes │6 bytes │4 bytes │0x88B8 │ appID|len|reserved|PDU │
└──────────┴──────────┴────────┴───────┴─────────────────────────┘
GOOSE PDU (contenuto):
- gocbRef: riferimento al GOOSE Control Block
- timeAllowedToLive: timeout per ritenere il publisher down [ms]
- datSet: riferimento al dataset
- goID: identificatore univoco
- t: timestamp dell'evento (UTC con ms)
- stNum: state number (incrementa ad ogni cambio di stato)
- sqNum: sequence number (incrementa ad ogni retransmission)
- simulation: flag per modalità test
- confRev: revision numero della configurazione
- ndsCom: needs commissioning flag
- numDatSetEntries: numero di entry nel dataset
- allData: i valori del dataset (array MMS)
재전송 메커니즘
GOOSE는 승인이나 TCP를 사용하지 않습니다. 암호화 전략으로 신뢰성이 보장됩니다. 지수 재전송. 이벤트(상태 변화)가 발생하면 IED 게시자는 간격을 늘려 메시지의 여러 복사본을 보냅니다.
Retransmission GOOSE dopo un evento (stato cambio a t=0):
t=0ms: TX immediata (stNum=N, sqNum=0)
t=2ms: TX (stNum=N, sqNum=1) - T1 = 2ms
t=6ms: TX (stNum=N, sqNum=2) - T1 = 4ms
t=14ms: TX (stNum=N, sqNum=3) - T1 = 8ms
t=30ms: TX (stNum=N, sqNum=4) - T1 = 16ms
t=62ms: TX (stNum=N, sqNum=5) - T1 = 32ms
...
t=MaxTx: TX periodica con T0 (es. 1000ms, "heartbeat")
stNum: incrementa SOLO quando lo stato cambia
sqNum: incrementa ad ogni retransmission dello stesso stato
Un subscriber che riceve GOOSE con sqNum=0 e stNum diverso
dal precedente sa che c'è stato un cambio di stato.
Un subscriber che non riceve per più di timeAllowedToLive
mette il segnale in qualità "LOST".
Python과 Scapy를 사용한 GOOSE 분석
GOOSE 네트워크 디버깅, 테스트 및 모니터링을 위한 Python with Scapy 및 도구 강력하다. 다음은 캡처된 이더넷 프레임을 디코딩하는 GOOSE 파서입니다. 네트워크 인터페이스(또는 pcap 파일에서):
"""
GOOSE Analyzer - Cattura e analizza frame GOOSE IEC 61850
Richiede: pip install scapy pyasn1
Richiede privilegio root/admin per cattura live
"""
from scapy.all import sniff, Ether, Dot1Q, Raw
from pyasn1.codec.ber import decoder as ber_decoder
from pyasn1.type import univ
import struct
import datetime
import logging
from dataclasses import dataclass
logger = logging.getLogger(__name__)
# EtherType GOOSE
GOOSE_ETHERTYPE = 0x88B8
@dataclass
class GOOSEFrame:
"""Rappresentazione di un frame GOOSE decodificato."""
src_mac: str
dst_mac: str
vlan_id: int
vlan_priority: int
app_id: int
gocb_ref: str
time_allowed_to_live: int
dat_set: str
go_id: str
timestamp: datetime.datetime
st_num: int # State number
sq_num: int # Sequence number
simulation: bool
conf_rev: int
num_entries: int
raw_values: list
def parse_goose_time(raw_t: bytes) -> datetime.datetime:
"""Decodifica timestamp GOOSE (6 byte: 4 secondi + 3 fraz + flags)."""
if len(raw_t) < 4:
return datetime.datetime.utcnow()
seconds = struct.unpack(">I", raw_t[:4])[0]
# Epoch GOOSE: 1970-01-01 UTC (stesso Unix epoch)
return datetime.datetime.utcfromtimestamp(seconds)
def decode_goose_pdu(payload: bytes) -> Optional[GOOSEFrame]:
"""
Decodifica il PDU GOOSE dal payload Ethernet.
Il formato e: APPID(2) + Length(2) + Reserved1(2) + Reserved2(2) + ASN.1 BER
"""
if len(payload) < 8:
return None
app_id = struct.unpack(">H", payload[0:2])[0]
length = struct.unpack(">H", payload[2:4])[0]
# payload[4:8] = Reserved1 + Reserved2
asn1_data = payload[8:length]
try:
# ASN.1 BER decoding del PDU GOOSE
# Tag 0x61 = IECGoosePdu (context class, primitive)
goose_pdu = {
"app_id": app_id,
"gocb_ref": "",
"time_allowed_to_live": 0,
"dat_set": "",
"go_id": "",
"st_num": 0,
"sq_num": 0,
"simulation": False,
"conf_rev": 0,
"num_entries": 0,
}
# Parsing manuale TLV (Type-Length-Value) BER per tag GOOSE
idx = 0
# Skip outer GOOSE PDU wrapper (tag 0x61)
if asn1_data[0] == 0x61:
if asn1_data[1] > 127: # long form length
len_bytes = asn1_data[1] - 128
idx = 2 + len_bytes
else:
idx = 2
while idx < len(asn1_data) - 1:
tag = asn1_data[idx]
idx += 1
length_byte = asn1_data[idx]
idx += 1
if length_byte > 127:
extra = length_byte - 128
value_length = int.from_bytes(asn1_data[idx:idx+extra], 'big')
idx += extra
else:
value_length = length_byte
value = asn1_data[idx:idx+value_length]
idx += value_length
# Tag mapping IEC 61850 GOOSE PDU
if tag == 0x80: # gocbRef [0]
goose_pdu["gocb_ref"] = value.decode("ascii", errors="replace")
elif tag == 0x81: # timeAllowedToLive [1]
goose_pdu["time_allowed_to_live"] = int.from_bytes(value, 'big')
elif tag == 0x82: # datSet [2]
goose_pdu["dat_set"] = value.decode("ascii", errors="replace")
elif tag == 0x83: # goID [3]
goose_pdu["go_id"] = value.decode("ascii", errors="replace")
elif tag == 0x84: # t [4] timestamp
goose_pdu["timestamp"] = parse_goose_time(value)
elif tag == 0x85: # stNum [5]
goose_pdu["st_num"] = int.from_bytes(value, 'big')
elif tag == 0x86: # sqNum [6]
goose_pdu["sq_num"] = int.from_bytes(value, 'big')
elif tag == 0x87: # simulation [7]
goose_pdu["simulation"] = value[0] != 0
elif tag == 0x88: # confRev [8]
goose_pdu["conf_rev"] = int.from_bytes(value, 'big')
elif tag == 0x8A: # numDatSetEntries [10]
goose_pdu["num_entries"] = int.from_bytes(value, 'big')
return goose_pdu
except Exception as e:
logger.warning(f"Errore parsing GOOSE PDU: {e}")
return None
def goose_packet_handler(packet):
"""Handler Scapy per ogni pacchetto catturato."""
if Ether in packet:
eth = packet[Ether]
payload = bytes(packet[Raw]) if Raw in packet else b""
# Verifica EtherType GOOSE (con o senza VLAN tag)
ethertype = eth.type
vlan_id = 0
vlan_prio = 0
if ethertype == 0x8100 and Dot1Q in packet: # VLAN tagged
vlan_id = packet[Dot1Q].vlan
vlan_prio = packet[Dot1Q].prio
ethertype = packet[Dot1Q].type
payload = bytes(packet[Dot1Q].payload)
if ethertype != GOOSE_ETHERTYPE:
return
goose_pdu = decode_goose_pdu(payload)
if goose_pdu:
sim_flag = "[SIM]" if goose_pdu.get("simulation") else ""
print(f"{sim_flag} GOOSE | "
f"VLAN={vlan_id}(prio={vlan_prio}) | "
f"AppID=0x{goose_pdu['app_id']:04X} | "
f"GoCBRef={goose_pdu['gocb_ref']} | "
f"stNum={goose_pdu['st_num']} sqNum={goose_pdu['sq_num']} | "
f"TAL={goose_pdu['time_allowed_to_live']}ms")
def capture_live(interface: str = "eth0", count: int = 100):
"""Cattura GOOSE live da interfaccia di rete."""
print(f"Avvio cattura GOOSE su {interface}...")
sniff(
iface=interface,
prn=goose_packet_handler,
count=count,
store=False,
)
def analyze_pcap(file_path: str):
"""Analizza frame GOOSE da file pcap."""
from scapy.all import rdpcap
packets = rdpcap(file_path)
for pkt in packets:
goose_packet_handler(pkt)
if __name__ == "__main__":
# Analisi da file pcap (per test senza hardware)
analyze_pcap("goose_capture_substation.pcap")
GOOSE와 MMS: 언제 어느 것을 사용해야 할까요?
| 특성 | 거위 | MMS |
|---|---|---|
| 숨어 있음 | < 4ms(범주 P1) | 일반 10-100ms |
| 수송 | 이더넷 L2 멀티캐스트 | 유니캐스트 TCP/IP |
| 신뢰할 수 있음 | 지수 재전송 | TCP는 전달을 보장합니다 |
| 라우팅 | 라우팅 불가(L2만 해당) | 라우팅 가능(L3 IP) |
| 연결 | 비연결 | 연결 지향 |
| 일반적인 사용 | 트립, 인터록, 보호 | SCADA, 모니터링, 명령 |
| 확장성 | 제한됨(1개의 세그먼트 L2) | 분산 WAN 네트워크 |
| 보안 | IEC 62351-6(X.509 서명) | TLS(IEC 62351-3/4) |
샘플링된 값: 프로세스 버스의 디지털 샘플링
IEC 61850의 세 번째 프로토콜과 샘플링된 값 (SV, 정의됨 IEC 61850-9-2). 그 목적은 전류와 전압의 디지털 샘플을 운반하는 것입니다. 에서 병합 장치 (MU) 보호 및 측정 IED로 교체 통신이 가능한 계기용 변압기(CT/VT)의 보조 케이블 이더넷. 이것이 컨셉의 핵심이다 프로세스 버스 에서 디지털 변전소.
IEC 61850-9-2LE(Light Edition, 유럽에서 가장 널리 퍼져 있음):
- 샘플링 속도: 80개 샘플/사이클(50Hz에서 4000개 샘플/초)
- 샘플당 데이터: 4개 전류(IA, IB, IC, IN) + 4개 전압(UA, UB, UC, UN)
- 해결: 채널당 32비트
- 최대 대기 시간: 아날로그 측정부터 IED 수신까지 1ms 미만
- VLAN 우선순위: 4 (보호를 위한 GOOSE와 동일)
- 대역폭: 스트림당 약 3Mbit/s(계산: 80샘플/s x 8채널 x 32비트 + 오버헤드)
SCADA와의 통합: 게이트웨이, 데이터 매핑 및 역사가
IEC 61850 변전소는 고립되어 있지 않습니다. 시스템과 통신해야 합니다. SCADA 감독 및 전송 수준의 네트워크 관리 시스템 (EMS - 에너지 관리 시스템) 또는 배전(DMS - 배전 관리 시스템). 이러한 시스템은 종종 다음과 같은 레거시 프로토콜을 사용합니다. IEC 60870-5-104 (IEC 104) TCP/IP 네트워크용 또는 DNP3 직렬/IP 통신용.
패턴 게이트웨이 IEC 61850 - IEC 104
두 세계 사이를 변환하는 구성요소와 프로토콜 게이트웨이, 일반적으로 변전소의 전용 하드웨어에 있는 소프트웨어입니다. 게이트웨이:
- 다음과 같은 IED에 연결됩니다. MMS 클라이언트 보고서를 구독합니다.
- GOOSE 이벤트를 수신하고 이를 IEC 104 정보 개체에 매핑합니다.
- 노출하다 IEC 104 서버 (또는 DNP3 아웃스테이션) 중앙 SCADA 방향
- 하나를 유지 로컬 데이터베이스 폴링을 위한 현재 값
"""
Gateway semplificato IEC 61850 MMS -> IEC 104
Gestisce il mapping e la pubblicazione verso SCADA
Dipendenze: pip install pyiec61850 lib60870-python
"""
import asyncio
import logging
from dataclasses import dataclass, field
from typing import Callable
from datetime import datetime
logger = logging.getLogger(__name__)
@dataclass
class DataPoint:
"""Punto dati IEC 104 mappato da un riferimento IEC 61850."""
# IEC 104
common_address: int # ASDU address
ioa: int # Information Object Address
type_id: int # M_ME_TF_1 (float), M_SP_TB_1 (bool), etc.
# IEC 61850 sorgente
ied_host: str
object_ref: str # es. BAY1_PROT/PROT/MMXU1.MX.TotW.mag.f
fc: str # ST, MX, CF...
# Stato corrente
value: float = 0.0
quality: int = 0 # 0 = good, 1 = invalid
timestamp: datetime = field(default_factory=datetime.utcnow)
# Callback per notifica cambio valore
change_callbacks: list[Callable] = field(default_factory=list)
class IEC61850ToIEC104Gateway:
"""
Gateway che mappa dati IEC 61850 verso Information Objects IEC 104.
Architettura:
IED IEC61850 --[MMS/GOOSE]--> Gateway --[IEC104]--> SCADA
"""
def __init__(self):
self.data_points: dict[int, DataPoint] = {} # IOA -> DataPoint
self._61850_clients: dict[str, object] = {}
self._iec104_server = None
self._running = False
def add_mapping(self, point: DataPoint):
"""Aggiunge un mapping IEC61850 -> IEC104."""
self.data_points[point.ioa] = point
logger.info(
f"Mapping aggiunto: IOA={point.ioa} "
f"<-- {point.ied_host}/{point.object_ref}"
)
async def start(self):
"""Avvia il gateway."""
self._running = True
# Raggruppa i data points per IED host
ied_groups: dict[str, list[DataPoint]] = {}
for dp in self.data_points.values():
ied_groups.setdefault(dp.ied_host, []).append(dp)
# Connetti a ogni IED in parallelo
tasks = [
self._connect_and_poll_ied(host, points)
for host, points in ied_groups.items()
]
await asyncio.gather(*tasks)
async def _connect_and_poll_ied(
self, host: str, points: list[DataPoint]
):
"""Connette a un IED e mantiene i valori aggiornati."""
logger.info(f"Connessione a IED {host}...")
# In produzione: usa libiec61850 per connessione reale
# Qui mostriamo la logica di polling
while self._running:
try:
for dp in points:
# Simula lettura MMS
new_value = await self._read_ied_value(host, dp)
if new_value is not None and new_value != dp.value:
old_value = dp.value
dp.value = new_value
dp.timestamp = datetime.utcnow()
dp.quality = 0 # Good quality
logger.debug(
f"IOA {dp.ioa}: "
f"{old_value} -> {new_value}"
)
# Notifica il server IEC 104
await self._publish_to_iec104(dp)
await asyncio.sleep(0.5) # 500ms polling cycle
except ConnectionError as e:
logger.error(f"IED {host} disconnesso: {e}")
# Marca tutti i punti come invalid
for dp in points:
dp.quality = 0x20 # INVALID flag IEC 104
await self._publish_to_iec104(dp)
await asyncio.sleep(5) # Retry dopo 5s
async def _read_ied_value(
self, host: str, dp: DataPoint
) -> Optional[float]:
"""Legge un valore da IED via MMS."""
# Implementazione reale usa libiec61850
# Per test: return mock value
return None
async def _publish_to_iec104(self, dp: DataPoint):
"""Pubblica un cambio di valore verso il server IEC 104."""
if self._iec104_server:
# lib60870 API per aggiornare il punto nell'ASDU
logger.debug(
f"IEC104 update: CA={dp.common_address} "
f"IOA={dp.ioa} v={dp.value}"
)
def get_point_value(self, ioa: int) -> Optional[DataPoint]:
"""Restituisce il valore corrente di un punto per IOA."""
return self.data_points.get(ioa)
# Configurazione mapping esempio
gateway = IEC61850ToIEC104Gateway()
# Potenza attiva BAY1 -> IOA 1001
gateway.add_mapping(DataPoint(
common_address=1,
ioa=1001,
type_id=0x0D, # M_ME_TF_1: Short Float + Timestamp
ied_host="192.168.1.10",
object_ref="BAY1_PROT/MEAS/MMXU1.MX.TotW.mag.f",
fc="MX",
))
# Stato interruttore BAY1 -> IOA 2001
gateway.add_mapping(DataPoint(
common_address=1,
ioa=2001,
type_id=0x03, # M_SP_TB_1: Single-point + Timestamp
ied_host="192.168.1.10",
object_ref="BAY1_PROT/PROT/XCBR1.ST.Pos.stVal",
fc="ST",
))
사이버 보안: 중요 인프라를 위한 IEC 62351 및 NIS2
IEC 61850 디지털 변전소는 다음과 같이 분류됩니다. 중요 인프라 NIS2 지침에 따라(이탈리아에서 입법령 138/2024로 시행되고 총리령 시행) 이는 다음을 의미합니다. 전력망 사업자(송전용 Terna, 배전용 e-distribuzione) 전 세계 매출액의 최대 2%에 해당하는 벌금을 부과하는 법적 사이버 보안 의무가 있습니다. 비준수.
기술적인 측면에서는, IEC 62351 그리고 그것이 정의하는 보완적인 표준 세트 IEC 61850 프로토콜(및 기타 산업 프로토콜)과 관련된 보안 조치 IEC 60870-5-101/104에 따른 에너지):
IEC 62351의 관련 부분
| 부분 | 제목 | IEC 61850 적용 |
|---|---|---|
| 62351-3 | TCP/IP 기반 프로토콜용 TLS | MMS를 통한 TLS 1.3(포트 102) |
| 62351-4 | MMS 인증 | MMS 연결을 위한 상호 인증 X.509 |
| 62351-6 | GOOSE/SV에 대한 보안 | GOOSE 및 SV 프레임의 HMAC/X.509 서명 |
| 62351-7 | 네트워크 및 시스템 관리 | IED 안전 모니터링 |
| 62351-8 | 전력 시스템용 RBAC | IED에 대한 역할 기반 액세스 제어 |
| 62351-9 | 키 관리 | PKI, X.509 인증서, 해지 |
TLS를 사용한 MMS 보안
IEC 62351-3에서는 보호를 위해 TLS(최소 버전 1.2, 권장 1.3) 사용을 지정합니다. MMS 연결. 권장 구성에는 다음이 포함됩니다.
"""
Configurazione TLS per connessione MMS sicura
Basato su IEC 62351-3 requirements
"""
import ssl
import socket
from pathlib import Path
def create_iec62351_tls_context(
cert_file: str,
key_file: str,
ca_cert_file: str,
require_client_cert: bool = True
) -> ssl.SSLContext:
"""
Crea un contesto TLS conforme IEC 62351-3.
Certificati devono essere X.509 v3 con:
- Subject: CN=<IED-name>, O=<Utility-name>
- Extended Key Usage: id-kp-serverAuth (server) / id-kp-clientAuth (client)
- Key: RSA 2048+ o ECDSA P-256+
"""
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# TLS 1.2 minimo, TLS 1.3 preferito
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
# Suite crittografiche approvate IEC 62351
# Priorità: ECDHE > DHE, AES-256-GCM > AES-128-GCM
ctx.set_ciphers(
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"DHE-RSA-AES256-GCM-SHA384"
)
# Certificato del dispositivo locale
ctx.load_cert_chain(certfile=cert_file, keyfile=key_file)
# CA trust store per verificare il peer
ctx.load_verify_locations(cafile=ca_cert_file)
# Autenticazione mutua obbligatoria (client cert required)
if require_client_cert:
ctx.verify_mode = ssl.CERT_REQUIRED
# Disabilita verifiche non sicure
ctx.check_hostname = True
ctx.verify_mode = ssl.CERT_REQUIRED
return ctx
def check_tls_compliance(cert_path: str) -> dict:
"""
Verifica la conformità di un certificato X.509 con IEC 62351.
Controlla validita, algoritmo chiave, estensioni richieste.
"""
import subprocess
import json
result = subprocess.run(
["openssl", "x509", "-in", cert_path,
"-noout", "-text", "-nameopt", "RFC2253"],
capture_output=True, text=True
)
report = {
"file": cert_path,
"tls12_compliant": False,
"key_length_ok": False,
"not_expired": False,
"has_client_auth": False,
"details": result.stdout[:500]
}
output = result.stdout
# Chiave RSA >= 2048 bit o ECDSA P-256
if "Public-Key: (2048 bit)" in output or \
"Public-Key: (3072 bit)" in output or \
"P-256" in output:
report["key_length_ok"] = True
# TLS Client Authentication estensione
if "TLS Web Client Authentication" in output:
report["has_client_auth"] = True
report["tls12_compliant"] = (
report["key_length_ok"] and report["has_client_auth"]
)
return report
# Network Segmentation - zone di sicurezza IEC 62351
SECURITY_ZONES = {
"zone_0_internet": {
"access": "none",
"description": "Internet - accesso vietato dalla sottostazione"
},
"zone_1_enterprise": {
"access": "through_dmz_only",
"description": "Rete aziendale - solo via DMZ con proxy"
},
"zone_2_control": {
"access": "restricted",
"description": "SCADA e sistemi di controllo - solo TLS mutual auth"
},
"zone_3_substation": {
"access": "local_only",
"description": "LAN sottostazione - MMS + GOOSE, firewall dedicato"
},
"zone_4_process": {
"access": "air_gapped_preferred",
"description": "Process bus - solo GOOSE/SV, nessun IP routing"
}
}
GOOSE 보안: 레이어 2 인증 문제
기본 버전(IEC 62351-6 제외)의 GOOSE 프로토콜에는 인증이 없습니다. 변전소 네트워크에 물리적으로 접근할 수 있는 공격자가 프레임을 주입할 수 있음 GOOSE 가짜(GOOSE 스푸핑), 어떤 방식으로든 스위치를 열거나 닫을 가능성이 있음 사기. IEC 62351-6은 GOOSE 프레임의 HMAC-SHA256 디지털 서명을 통해 이 문제를 해결합니다. 하지만 구현하면 대기 시간이 약 0.5-1ms 증가합니다.
IEC 61850 네트워크의 특정 공격 벡터
- 거위 스푸핑: stNum이 높은 GOOSE 프레임 주입 신호 상태를 덮어씁니다. 완화: IEC 62351-6, 포트 기반 802.1X, VLAN 분리.
- MMS 재생 공격: MMS 명령을 캡처하고 재전송합니다. 완화: 재생 보호 기능이 있는 TLS, 명령의 타임스탬프.
- SCL 파일 변조: 다음에 대한 SCD 구성 파일 편집 FDI의 행동을 바꾸십시오. 완화 방법: SCL 파일에 디지털 서명, SHA-256 해시를 사용한 변경 관리.
- 불량 IED: 승인되지 않은 IED를 네트워크에 연결 프로세스. 완화: 802.1X 포트 인증, MAC 화이트리스트, 인증서 고정.
- GOOSE에 대한 지연 공격: 네트워크를 범람시켜 트래픽을 증가시킵니다. 4ms 이상의 GOOSE 대기 시간으로 인해 보호 기능이 무효화됩니다. 완화: 엄격한 QoS 우선 순위, 프로세스 전용 VLAN, IEC 61850-3 스위치.
테스트 및 시뮬레이션: 테스트 벤치에서 자동화까지
IEC 61850 시스템 테스트는 특정 도구가 필요한 전문 영역입니다. 표준 준수 여부를 확인하기 위해 일반 도구를 사용하는 것은 불가능합니다. GOOSE 데이터 세트의 정확성 또는 로드 중인 동작.
오픈 소스 테스트 스택
값비싼 상용 도구를 구입할 예산이 없는 소프트웨어 엔지니어 팀의 경우, 오픈 소스 생태계는 견고한 솔루션을 제공합니다.
-
libiec61850 (MZ Automation, GPLv3): Python/Java 바인딩이 포함된 C 라이브러리
IEC 61850 클라이언트 및 서버 개발에 가장 많이 사용됩니다. 다음에 대한 전체 예제가 포함되어 있습니다.
표준의 모든 기능. 저장소:
github.com/mz-automation/libiec61850 - 오픈SCD (openscd/open-scd): SCL/SCD 파일용 브라우저 기반 편집기, 스키마 검증 및 토폴로지 시각화가 포함됩니다. 엔지니어링 및 정밀검사에 이상적 구성.
- 오픈MUC (Fraunhofer ISE): 게이트웨이, 데이터 로거 생성을 위한 Java 프레임워크 모듈형 드라이버 아키텍처를 갖춘 IEC 61850 애플리케이션.
- IEC 61850 해부자를 사용한 Wireshark: Wireshark에는 기본 해부자가 포함되어 있습니다. GOOSE(EtherType 0x88B8), SV(0x88BA) 및 MMS용. 문제 디버깅에 필수 의사소통의.
GOOSE 자동 컴플라이언스 테스트
"""
Suite di test automatizzati per conformità GOOSE IEC 61850
Verifica: timing, retransmission, stNum/sqNum logic, TAL
"""
import time
import threading
import unittest
from dataclasses import dataclass
from scapy.all import sniff, sendp, Ether, Dot1Q, Raw
import struct
@dataclass
class GOOSETestResult:
test_name: str
passed: bool
measured_latency_ms: float = 0.0
expected_latency_ms: float = 4.0
details: str = ""
class GOOSEConformanceTest(unittest.TestCase):
"""
Test di conformità GOOSE secondo IEC 61850-8-1.
Richiede accesso diretto all'interfaccia di rete.
"""
def setUp(self):
"""Configura l'interfaccia e i parametri di test."""
self.interface = "eth0" # Interfaccia collegata alla rete GOOSE
self.goose_vlan = 100
self.goose_appid = 0x0001
self.captured_frames: list[dict] = []
self.capture_lock = threading.Lock()
def _start_capture(self, duration_s: float = 5.0):
"""Avvia cattura GOOSE in background."""
def capture():
from et_iec61850_test_utils import goose_packet_handler
sniff(
iface=self.interface,
prn=lambda p: self._capture_handler(p),
timeout=duration_s,
store=False
)
t = threading.Thread(target=capture, daemon=True)
t.start()
return t
def _capture_handler(self, packet):
"""Cattura frame GOOSE e aggiunge alla lista."""
if Ether in packet and Raw in packet:
# Verifica EtherType GOOSE (semplificato)
raw = bytes(packet)
if len(raw) > 14:
with self.capture_lock:
self.captured_frames.append({
"timestamp": time.time(),
"raw": raw,
"length": len(raw)
})
def test_retransmission_pattern(self):
"""
Verifica che il pattern di retransmission segua la
progressione esponenziale definita in IEC 61850-8-1.
T1, T2=2*T1, T4=2*T2, fino a T0 (heartbeat).
"""
# Reset frame list
self.captured_frames = []
# Avvia cattura per 2 secondi dopo evento
capture_thread = self._start_capture(2.0)
# Attendi evento GOOSE dall'IED (o inietta evento di test)
# In un test reale si aspetta un cambio di stato noto
capture_thread.join(timeout=3.0)
# Analizza intervalli di retransmission
if len(self.captured_frames) < 3:
self.skipTest("Insufficienti frame catturati")
intervals = []
for i in range(1, len(self.captured_frames)):
dt_ms = (self.captured_frames[i]["timestamp"] -
self.captured_frames[i-1]["timestamp"]) * 1000
intervals.append(dt_ms)
# Verifica progressione: ogni intervallo deve essere > del precedente
# (fase di retransmission) fino al heartbeat
if len(intervals) >= 2:
# I primi intervalli dovrebbero essere piccoli (< 50ms)
self.assertLess(
intervals[0], 50.0,
f"Prima retransmission troppo lenta: {intervals[0]:.1f}ms"
)
def test_initial_latency_requirement(self):
"""
Verifica che la latenza iniziale GOOSE sia < 4ms
per messaggi di categoria P1 (protezione critica).
Nota: richiede hardware preciso per misurazione accurata.
"""
# In un test reale si usa un timestamp di riferimento
# dall'IED (campo 't' nel PDU GOOSE)
# Qui simuliamo la logica di verifica
simulated_latency_ms = 2.3 # Da misurare con hardware preciso
result = GOOSETestResult(
test_name="Initial Latency P1",
passed=simulated_latency_ms < 4.0,
measured_latency_ms=simulated_latency_ms,
expected_latency_ms=4.0,
details=f"Latenza: {simulated_latency_ms}ms (max: 4ms)"
)
self.assertTrue(
result.passed,
f"Latenza GOOSE {result.measured_latency_ms}ms supera 4ms"
)
def test_timeallowedtolive_validity(self):
"""
Verifica che TAL (TimeAllowedToLive) sia configurato
ragionevolmente rispetto al periodo di heartbeat T0.
Regola: TAL deve essere > 2 * T0 per tollerare una
perdita di heartbeat.
"""
# Valori tipici: T0=1000ms, TAL=2000ms
t0_ms = 1000 # Periodo heartbeat
tal_ms = 2000 # TimeAllowedToLive dal GOOSE PDU
self.assertGreater(
tal_ms, 2 * t0_ms,
f"TAL {tal_ms}ms dovrebbe essere > 2*T0={2*t0_ms}ms"
)
def test_vlan_priority(self):
"""
Verifica che i frame GOOSE abbiano la priorità VLAN
corretta (PCP=4 per protezione, come da IEC 61850-8-1).
"""
# Costruisci un frame di test GOOSE e verifica
test_frame = (
Ether(dst="01:0c:cd:01:00:01", src="00:11:22:33:44:55") /
Dot1Q(vlan=100, prio=4) /
Raw(b"\x88\xb8\x00\x01\x00\x10\x00\x00\x00\x00")
)
# Estrai VLAN priority dal frame
if Dot1Q in test_frame:
pcp = test_frame[Dot1Q].prio
self.assertEqual(
pcp, 4,
f"VLAN PCP deve essere 4 per GOOSE, trovato: {pcp}"
)
if __name__ == "__main__":
unittest.main(verbosity=2)
현대 아키텍처: 디지털 변전소 및 마이크로서비스
La 디지털 변전소 현대는 단순한 변전소가 아니다 디지털 IED의 전통적인 방식입니다. 그리고 분리하는 완전한 건축학적 재해석 플랫폼의 보호, 제어, 모니터링 및 통신 기능 분산 소프트웨어. IEC 61850 Edition 2.1은 이러한 변화의 중추입니다.
소프트웨어 정의 변전소를 향한 진화
Evoluzione architetturale della sottostazione:
GENERAZIONE 1 (pre-2005): Wired Hardened
┌─────────────────────────────────────────┐
│ CT/VT ──wire──▶ Relay ──wire──▶ CB │
│ Cavi di rame per ogni segnale │
│ Manutenzione: sostituzione cavi │
└─────────────────────────────────────────┘
GENERAZIONE 2 (2005-2015): IEC 61850 Edition 1
┌──────────────────────────────────────────┐
│ CT/VT ──▶ IED ──[MMS/GOOSE Ethernet]──▶│
│ Process Bus opzionale │
│ SCADA via MMS │
└──────────────────────────────────────────┘
GENERAZIONE 3 (2015-2023): Full Digital
┌──────────────────────────────────────────────┐
│ CT/VT ──▶ Merging Unit ──[SV]──▶ IED │
│ Process Bus: solo fibra ottica │
│ Station Bus: Ethernet ridondato (PRP/HSR) │
│ Gateway verso SCADA/EMS │
└──────────────────────────────────────────────┘
GENERAZIONE 4 (2023+): Software-Defined Substation
┌────────────────────────────────────────────────────┐
│ Merging Unit ──[SV via TSN]──▶ COMPUTE CLUSTER │
│ Funzioni protezione su software (IEC 61850-7-90) │
│ Containerizzazione (K3s edge cluster) │
│ Digital Twin real-time │
│ Edge AI per fault analysis │
│ API REST/gRPC verso cloud EMS/DERMS │
└────────────────────────────────────────────────────┘
변전소의 컨테이너화
업계의 새로운 추세는 소프트웨어 기능의 컨테이너화입니다. 다음과 같은 플랫폼을 갖춘 COTS(상용 기성품) 하드웨어의 변전소 K3 (Edge용 경량 Kubernetes) 또는 도커 작성 더 간단한 배포를 위해. 이를 통해 DevOps 패턴(CI/CD, GitOps, 모니터링 Prometheus와 함께) 전통적으로 움직이지 않는 환경에서.
# docker-compose.yml per ambiente di sviluppo/test digital substation
# Simula un ambiente di sottostazione con IED virtuali e SCADA
version: "3.8"
services:
# IED Simulato - Publisher GOOSE e Server MMS
ied-simulator:
image: mzautomation/iec61850-simulator:latest
container_name: ied_bay1_prot
networks:
- process_bus
- station_bus
environment:
- IED_NAME=BAY1_PROT
- IED_IP=192.168.10.10
- SCL_FILE=/config/bay1_prot.cid
- GOOSE_INTERFACE=eth1
volumes:
- ./config/scl:/config:ro
cap_add:
- NET_ADMIN # Per GOOSE multicast su Ethernet L2
# Gateway IEC 61850 -> IEC 104
gateway:
build: ./gateway
container_name: iec61850_gateway
networks:
- station_bus
- scada_net
environment:
- IED1_HOST=192.168.10.10
- IED1_PORT=102
- IEC104_PORT=2404
- MAPPING_FILE=/config/mapping.json
volumes:
- ./config/gateway:/config:ro
depends_on:
- ied-simulator
# SCADA/Historian - InfluxDB + Grafana
influxdb:
image: influxdb:2.7
container_name: historian
networks:
- scada_net
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_ORG=utility
- DOCKER_INFLUXDB_INIT_BUCKET=substation_data
volumes:
- influx_data:/var/lib/influxdb2
grafana:
image: grafana/grafana:latest
container_name: scada_dashboard
networks:
- scada_net
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=substation123
depends_on:
- influxdb
# SCL Validator - OpenSCD headless
scl-validator:
image: openscd/open-scd-cli:latest
container_name: scl_validator
volumes:
- ./config/scl:/workspace
command: ["validate", "/workspace/substation.scd"]
networks:
process_bus:
driver: macvlan # L2 nativo per GOOSE
driver_opts:
parent: eth1
station_bus:
driver: bridge
ipam:
config:
- subnet: 192.168.10.0/24
scada_net:
driver: bridge
ipam:
config:
- subnet: 192.168.20.0/24
volumes:
influx_data:
네트워크 이중화: PRP 및 HSR
IEC 61850 변전소 네트워크에는 다음과 같은 이중화가 필요합니다. 복구 시간 제로 (비교: 스패닝 트리의 복구 시간은 30초 이상으로 보호하기에 충분하지 않습니다.) 2개 표준은 이 문제를 해결합니다.
- PRP(병렬 이중화 프로토콜, IEC 62439-3): 장치에는 두 가지가 있습니다. 두 개의 독립적인 네트워크에 연결된 인터페이스. 두 네트워크 모두에서 모든 프레임을 보냅니다. 동시에. 수신자는 도착하는 첫 번째 항목을 수락하고 중복 항목을 삭제합니다. 전환 시간은 0이지만 하드웨어와 트래픽은 두 배입니다.
- HSR(고가용성 원활한 이중화, IEC 62439-3): 장치 그들은 고리로 연결되어 있습니다. 각 프레임은 양방향으로 실행됩니다. 보낸 사람이 버립니다. 프레임이 시작점으로 돌아올 때의 프레임입니다. 제로 전환, 링 토폴로지.
이탈리아 상황: Terna, 전자배포 및 스마트 그리드
이탈리아는 IEC 61850에 대해 특히 흥미로운 에너지 맥락을 갖고 있습니다. 에 의해 작동되는 고전압 전송 테르나 (노선 약 74,000km) 주로 운영되는 유통망 전자배포 (에넬그룹, 120만km 이상의 회선), 사업자 2명 출범 야심 찬 변전소 디지털화 프로그램.
Terna: 전송망
Terna는 대략적으로 관리합니다. 변전소 800개 고전압 및 초고전압 (380kV, 220kV, 150kV). 2025년 2월에 발표된 2025년 개발 계획은 다음을 제공합니다. 다음에 대한 상당한 투자:
- IEC 61850 자동화 시스템을 통한 변전소 현대화 (목표: 2030년까지 HV 변전소 단지 전체 커버리지)
- 네트워크 관찰을 위한 PMU(Phasor Measurement Units) 설치 동기화된 GPS 타임스탬프를 사용한 실시간(IEEE C37.118)
- IEC 61850 데이터를 직접 통합하는 차세대 EMS 시스템 AI 기반 부하 예측 기능
- 전용 보안 운영 센터(SOC)를 갖춘 NIS2 준수 사이버 보안. 중요 인프라용
Hitachi ABB Power Grids(현재 Hitachi Energy)는 디지털 솔루션을 배포했습니다. REL 및 RET 시리즈의 IED와 자동화 시스템을 갖춘 Terna 네트워크의 변전소 IEC 61850을 통해 통합된 MicroSCADA Pro.
e-distribuzione: 미래의 유통 네트워크
e-distribuzione에서 프로그램을 시행하고 있습니다. "이탈리아 네트워크", 정말 팁이네요 배전망을 관리 가능한 스마트 그리드로 전환 재생 에너지와 전기 이동성의 대규모 통합. 핵심 포인트:
- 스마트 기본 캐빈: MV/LV 1차 변전소의 변환 IEC 61850 RTU를 갖춘 지역 정보 센터, 전압 품질 센서 및 원격 조종 능력
- MT 자동화: FRTU(Feeder Remote)형 IED 설치 터미널 장치) 오류 위치에 대한 중간 전압 라인의 IEC 61850을 준수합니다. 자동 격리 및 복원(FLISR).
- 고급 DMS: 템플릿이 포함된 유통 관리 시스템 현장 IED를 향한 IEC 61970/61968 네트워크 및 IEC 61850 통신
이탈리아 에너지기술 분야 취업 기회
이탈리아에서는 IEC 61850 기술에 대한 수요가 빠르게 증가하고 있습니다. 프로필 모스트 원티드(2025)에는 다음이 포함됩니다.
- IEC 61850 시스템 엔지니어: 시스템 설계 및 시운전 변전소의 자동화. 급여: 45,000-75,000 EUR/년.
- SCADA 통합 개발자: 게이트웨이 개발, 데이터 매핑, 대시보드. Python/Java + 에너지 프로토콜이 필요합니다. 급여: 40,000-70,000 EUR/년.
- EnergyTech 플랫폼 엔지니어: SCADA/EMS 시스템용 DevOps/클라우드. 급여: 50,000-85,000 EUR/년. 가장 희귀하고 가장 높은 유료 프로필입니다.
- OT 사이버보안 전문가: IEC 62351, NIS2, 보안 평가 중요한 인프라를 위한 것입니다. 급여: 55,000-90,000 EUR/년.
주요 고용주: Terna, e-distribuzione, ABB, Siemens Energy, Hitachi Energy, GE Vernova, Schneider Electric, 전문 시스템 통합업체.
모범 사례 및 안티 패턴
소프트웨어 엔지니어를 위한 모범 사례
IEC 61850 프로젝트 체크리스트
- 시운전 전 SCL 검증: OpenSCD 또는 IEDScout를 사용하여 IEC 61850-6 XSD 구성표에 대해 SCD 파일의 유효성을 검사합니다. 잘못된 SCL 파일 IED에서 예측할 수 없는 동작이 발생할 수 있습니다.
- GOOSE 구독 문서화: 매트릭스 유지 게시자/구독자 GOOSE가 업데이트되었습니다. 20개 이상의 IED가 있는 변전소에서 문서화 및 통신 문제 진단이 불가능합니다.
- 네트워크를 물리적으로 분리합니다. 프로세스 버스(GOOSE/SV) 및 스테이션 버스 (MMS)는 별도의 VLAN 또는 별도의 물리적 네트워크에 있어야 합니다. 트래픽을 혼합하지 마십시오 기업 IT 트래픽을 갖춘 GOOSE.
- TAL 및 하트비트 모니터링: 시간이 되면 알림 구현 심장 박동을 수신하지 않고 GOOSE가 TAL/2에 접근합니다. 초기증상이에요 네트워크 문제.
- Git을 사용하여 SCL 파일 버전 관리: SCD/ICD/CID 파일은 텍스트 XML입니다. 버전 관리에 완벽하게 적합합니다. 기록을 위해 LFS와 함께 Git 사용하기 변전소 구성이 완료되었습니다.
- 스테이징 환경에서 테스트: SCL 변경 사항을 적용하기 전에 생산 중인 IED, 실제 IED 또는 시뮬레이터를 사용하여 실험실 환경에서 테스트 libiec61850.
일반적인 안티 패턴
절대 피해야 할 실수
- IP 라우팅 네트워크의 GOOSE: GOOSE 및 이더넷 L2를 통과하지 못함 라우터. 라우팅된 네트워크에서 GOOSE를 구성하고 통신하는 동안 오류가 발생했습니다. 전용 L2-L3 게이트웨이 없이는 불가능합니다.
- 중복된 GOOSE APPID: 동일한 APPID 원인을 가진 두 명의 게시자 소스를 구별할 수 없는 가입자의 충돌. APPID는 다음과 같아야 합니다. 레이어 2 브로드캐스트 도메인 전체에서 고유합니다.
- confRev가 업데이트되지 않았습니다: GOOSE 데이터 세트에 대한 모든 변경 사항은 다음과 같습니다. SCL 파일에서 confRev를 증가시키고 IED를 구성합니다. confRev가 있는 구독자 게시자가 아닌 다른 사람은 메시지를 무시합니다.
- 고속 MMS 폴링: 주파수별로 MMS 폴링 아날로그 값의 경우 1Hz보다 높고 비효율적이며 IED를 로드합니다. 보고서 사용 적절한 트리거(데이터 변경, 무결성 기간)가 있는 제어 블록.
- 품질 플래그를 무시합니다. 각 IEC 61850 데이터에는 속성이 있습니다. 품질(q). 상태를 확인하지 않고 "양호" 이외의 품질 값을 사용하십시오. 제어 시스템에서 잘못된 결정을 내릴 수 있습니다.
- CID 파일이 동기화되지 않음: IED에 업로드된 CID 파일은 다음과 같습니다. SCD 마스터 파일에서 추출됩니다. CID를 별도로 유지하고 수동으로 생성 진단하기 어려운 불일치.
결론: 전략적 역량으로서의 IEC 61850
IEC 61850은 소프트웨어 엔지니어에게 가장 흥미로운 기술 영역 중 하나를 나타냅니다. 핵심 시스템 전문 기업입니다. 이는 단순한 산업 프로토콜이 아닙니다. 에 완전한 생태계 데이터 모델링, 형식을 다룹니다. XML 구성, 실시간 프로토콜, 사이버 보안, 분산 아키텍처 클라우드 통합.
재생에너지와 에너지의 대규모 통합을 통한 지속적인 에너지 전환 그리드 유연성에 대한 필요성으로 인해 유능한 전문가에 대한 수요가 증가하고 있습니다. 사이의 경계에서 일하다 OT(운영 기술) 및 IT. 소프트웨어 IEC 61850, Python, DevOps 및 엣지 컴퓨팅 기술을 갖춘 엔지니어는 바로 이탈리아와 유럽의 에너지 부문 시장에서 누락된 프로필입니다.
이 기사 이후에 다루어야 할 주요 개념은 다음과 같습니다.
- IED/LD/LN/DO/DA 계층적 데이터 모델 및 명명 규칙은 업계 전반의 공통 어휘: 이를 학습한다는 것은 동일하게 말하는 것을 의미합니다. 벤더나 변전소 설계자의 언어.
- GOOSE와 MMS는 보완적인 목적을 제공합니다. 즉, 4ms 미만의 실시간 보호가 우선이고, SCADA는 두 번째를 모니터링하고 제어합니다. 그것들은 서로 바꿔 사용할 수 없습니다.
- SCL은 변전소 엔지니어링 자동화의 핵심입니다. 누가 구문 분석하고, SCD 파일을 검증하고 생성하는 것은 다른 파일보다 큰 경쟁 우위를 가지고 있습니다. 그는 여전히 수동으로 일합니다.
- IEC 62351 사이버 보안은 선택 사항이 아닙니다. NIS2는 이를 법적 요구 사항으로 지정합니다. 유럽의 모든 중요한 에너지 인프라 운영자를 위한 것입니다.
- 아키텍처는 소프트웨어 정의 변전소로 진화하고 있습니다. 컨테이너화, 엣지 AI 및 클라우드 네이티브 API. DevOps 기술은 이 영역에서도 점점 관련성이 높아지고 있습니다.
시리즈의 다음 기사에서 우리는 다룰 것입니다 EV 로드 밸런싱 및 V2G: 차량 충전 부하 균형을 위한 최적화 알고리즘 IEC 61850이 OCPP를 충족하는 영역인 전기 및 차량 대 그리드 통신 볼록 최적화 알고리즘.
자세히 알아볼 수 있는 리소스
-
libiec61850 - 오픈 소스 C/Python 라이브러리:
github.com/mz-automation/libiec61850 -
오픈SCD - 브라우저 기반 SCL 편집기:
github.com/openscd/open-scd - IEC 61850.com - 문서가 포함된 공식 IEC 포털 표준에 대한 기술 및 뉴스
- PAC 월드 매거진 - 보호에 관한 기술 간행물 많은 IEC 61850 기사가 포함된 자동화
- "IEC 61850 엔지니어링 가이드북" - Herb Falk 외. - 표준의 실제 구현을 위한 참고 텍스트
- EPRI 보고서 3002006451 - "IEC 61850 변전소 구현 자동화 표준' - EPRI 웹사이트에서 확인 가능
EnergyTech 시리즈 관련 기사
- 기사 2: 에너지 모니터링을 위한 MQTT 및 InfluxDB - 에너지 분야 IoT 프로토콜의 기본
- 조항 4: DERMS - 분산 에너지 자원 관리 시스템
- 기사 6: EV 로드 밸런싱 및 V2G - 시리즈의 다음 단계
시리즈 간: 보완 기술
- 데이터 및 AI 비즈니스 시리즈 - 기사 5: 제조 분야의 AI(산업 IoT, OPC-UA, 디지털 트윈)
- MLOps 시리즈 - 변전소 데이터 분석을 위한 AI 모델 배포
- 웹 보안 시리즈 - OT/ICS에 적용되는 사이버 보안 원칙







