ソフトウェアエンジニア向け 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) ファイルを読み書きする方法
- 3 つの主要なプロトコル: MMS クライアント/サーバー、GOOSE マルチキャスト リアルタイム、SV サンプル値
- GOOSE の詳細: L2 イーサネット パブリッシュ/サブスクライブ アーキテクチャ、再送信、VLAN の優先順位
- MMS の詳細: libiec61850 と Python を使用した接続、レポート、ロギング
- SCADA 統合: DNP3/IEC 104 への IEC 61850 ゲートウェイ、データ マッピング、ヒストリアン
- サイバーセキュリティ IEC 62351: TLS over MMS、GOOSE 認証、RBAC、ネットワーク セグメンテーション
- テストとシミュレーション: libiec61850、OpenMUC、自動適合テスト
- 最新のアーキテクチャ: マイクロサービス、コンテナ化、変電所エッジ コンピューティング
- イタリアの背景: Terna、電子配信、パイロット プロジェクト、2025 年から 2030 年のロードマップ
EnergyTech シリーズ - シリーズ内での位置
| # | アイテム | Stato |
|---|---|---|
| 1 | スマートグリッドと再生可能エネルギー: 技術アーキテクチャ | 発行済み |
| 2 | エネルギー監視のための MQTT と InfluxDB | 発行済み |
| 3 | バッテリー管理システム: アルゴリズムとプロトコル | 発行済み |
| 4 | DERMS: 分散型エネルギー リソース管理 | 発行済み |
| 5 | 現在位置 - ソフトウェア エンジニア向け IEC 61850 | 現在 |
| 6 | EV ロード バランシングと V2G: 最適化アルゴリズム | Prossimo |
| 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 over Ethernet へのマッピング |
| 61850-9 | SCSM: サンプリングされた値 | イーサネット経由でのサンプリング値 |
| 61850-10 | 適合性テスト | コンプライアンスの手順と要件 |
現在のバージョンは、 エディション 2.1、2024年12月に初めて認定される 日立エナジーの PCM600 および IET600 ツールを使用します。エディション 2.1 では大幅な改良が加えられています DER (分散型エネルギー資源)、BESS 管理およびクラウド システムへの通信、 基準をエネルギー転換のニーズに合わせる。
IEC 61850 は他の産業用プロトコルとは異なるため
IEC 61850 が登場する前は、各 IED ベンダー (ABB、Siemens、GE、Schneider) が独自のプロトコルを使用していました。 さまざまなベンダーのデバイスからデータを収集する必要がある SCADA システムには、 多数のドライバー、コンバーター、および回避策。 IEC 61850 は 3 つの革新を導入しました それを区別する基本事項:
-
標準化されたベンダーに依存しないデータ モデル: それぞれの保護機能は、
測定または制御し、事前定義された論理ノードで記述されます。スイッチは常に
XCBR、アクティブかつ常時オンの電力測定MMXU.W、関係なく ベンダーによって。これにより、カスタム マッピングが不要になります。 - SCL を使用した宣言型構成: 変電所全体とそのトポロジー、 インストールされているデバイス、データセット、GOOSE サブスクリプションは XML ファイルで記述されます 標準化(SCD)。これにより、相互運用可能なエンジニアリング ツールと再現性が可能になります。 構成。
- 抽象モデルとトランスポートの分離: ACSI (抽象コミュニケーション) サービス インターフェイス)は、何ができるかを定義します(値の読み取り、レポートの受信、送信) コマンド)。 SCSM (特定の通信サービス マッピング) は、これがどのように行われるかを定義します。 MMS、グース、SV。この分離により、新しいマッピング (Web サービスなど) を追加できるようになります。 データモデルを変更することなく。
IEC 61850 データ モデル: 階層から命名まで
IEC 61850 のデータ モデルを理解することは、あらゆる作業を行うための基本的な前提条件です。 この規格。階層は 5 つのレベルで構成されており、それぞれに命名規則があります。 正確:
IEC 61850 データモデル階層
| レベル | 頭字語 | Esempio | 説明 |
|---|---|---|---|
| IED | インテリジェント電子デバイス | SEL-487E | 物理デバイス(保護、測定、制御) |
| LD | 論理デバイス | プロト | 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 (タップチェンジャー制御) |
| C | 監視制御 | CILO(連動)、CSWI(スイッチCTRL) |
| G | 汎用関数 | GAPC (汎用 APC)、GGIO (汎用 I/O) |
| L | システム論理ノード | LLN0 (LN ゼロ)、LPHD (物理デバイス) |
| M | 計量と測定 | MMXU(三相計測)、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 (サーキットブレーカー) が最良の出発点です
データモデルの構造を理解するため。 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: 三相測定
論理ノード MMXU (測定ユニット) フィーダの三相測定をモデル化するか、
変圧器。監視およびデータ分析システムで最もよく使用される論理ノード:
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 は、変電所エンジニアリングにおける最も高価な問題の 1 つを解決します。 の 手動再構成 追加・交換時の各機器の IED、以前は数週間にわたる専門的な作業が必要だった手術。
4 種類の SCL ファイル
- ICD (IED 機能の説明): ベンダーによって提供され、機能について説明します 完全な IED: サポートされているすべての論理ノード、構成可能なデータセット、レポート、 ログが利用可能です。そして、デバイスの「カタログ」。
- SSD (システム仕様の説明): のトポロジについて説明します。 割り当てる前に変電所 (電圧レベル、ベイ、伝導機器) 特定のデバイス。そして変電所の論理的な設計。
- SCD (変電所構成説明): の「マスター」ファイル 完全に構成された変電所。すべての IED、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 とインスタンス間の競合、不一致。常にツールを使用する などの具体的な検証 OpenSCD (オープンソース、ブラウザベース) または 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 のクライアント/サーバー通信バックボーン。次の用途に使用されます。
- 値の読み書き(Read、Write)
- 未承諾レポートの受信 (レポート)
- IED からの履歴ログの取得 (ロギング)
- 制御コマンドの送信(コマンド)
- IED ファイルシステムのリカバリ (ファイル転送)
MMS は、デフォルトのポートを使用して、TCP/IP 上のアプリケーション層で動作します。 102 (ISO COTP TCP経由)。接続では、ネゴシエーションを伴う MMS アソシエーション (セッションと同様) が使用されます。 未処理のリクエストの最大数や最大 PDU サイズなどのパラメータ。
レポート制御ブロック: リアルタイム監視の鍵
MMS の監視と監視のための最も重要なメカニズム レポート制御ブロック (RCB)。継続的にポーリングする代わりに、SCADA は IED 上の RCB にサブスクライブし、以下を指定します。 トリガー条件。 IED は、状況が発生すると自律的にレポートを送信します。
RCB には 2 つのタイプがあります。
- BRCB (バッファー付き RCB): クライアントが 切断されました。これにより、イベントが見逃されることがなくなります。各クライアントには独自のインスタンスがあります 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: 保護と連動のためのリアルタイム プロトコル
ガチョウ (汎用オブジェクト指向変電所イベント) および最も重要なプロトコル 保護用途向けの IEC 61850 に準拠しています。 MMS は TCP/IP を使用しますが、オーバーヘッドは 接続するとGOOSEが動作します イーサネット レイヤ 2 経由で直接、レベルを排除します ネットワークとトランスポートを使用して、 4ミリ秒 イベントから加入済み IED による受信まで。
このレイテンシー要件は任意ではありません。これは最大許容時間に相当します。 保護リレー間のトリップ信号の交換に関する規格(性能カテゴリ)から IEC 61850-5 の P1 および P2)。障害を検出したリレーは、それを隣接する IED に伝達する必要があります。 4 ミリ秒以内に保護調整を有効にします。
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 と 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の第3プロトコルと サンプリングされた値 (SV、定義: IEC 61850-9-2)。その目的は、電流と電圧のデジタル サンプルを伝送することです。 から 結合ユニット (MU) を保護および測定 IED に置き換え、 通信付計器用変圧器(CT/VT)の2次側ケーブル イーサネット。これがコンセプトの核心です プロセスバス で デジタル変電所。
IEC 61850-9-2LE (Light Edition、Light Edition、 ヨーロッパで最も普及しています):
- サンプリングレート: 80 サンプル/サイクル (50Hz で 4000 サンプル/秒)
- サンプルごとのデータ: 4 つの電流 (IA、IB、IC、IN) + 4 つの電圧 (UA、UB、UC、UN)
- 解決: チャネルあたり 32 ビット
- 最大遅延: アナログ測定から IED 受信まで 1ms 未満
- VLAN の優先順位: 4 (保護のための GOOSE と同じ)
- 帯域幅: ストリームあたり約 3 Mbit/秒 (計算: 80 サンプル/秒 x 8 チャネル x 32 ビット + オーバーヘッド)
SCADA との統合: ゲートウェイ、データ マッピング、ヒストリアン
IEC 61850 変電所は孤立して存在するのではなく、システムと通信する必要があります。 SCADA監視と送信レベルでのネットワーク管理システムを使用 (EMS - エネルギー管理システム) または配電 (DMS - 配電管理システム)。 これらのシステムでは、多くの場合、次のようなレガシー プロトコルが使用されます。 IEC 60870-5-104 (IEC 104) TCP/IP ネットワーク用、または DNP3 シリアル/IP通信用。
パターンゲートウェイ IEC 61850 から IEC 104
2 つの世界と プロトコルゲートウェイ、 通常、変電所の専用ハードウェア上のソフトウェア。ゲートウェイ:
- のようなIEDに接続します MMS クライアント レポートを購読します
- GOOSE イベントを受信し、IEC 104 情報オブジェクトにマッピングします。
- を公開します IEC 104サーバー (または DNP3 アウトステーション) 中央 SCADA に向かう
- 1つを維持します ローカルデータベース ポーリングの現在の値の
"""
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 ~ 1 ミリ秒増加します。
IEC 61850 ネットワークの特定の攻撃ベクトル
- GOOSE スプーフィング: stNum が高い GOOSE フレーム インジェクション 信号の状態を上書きします。軽減策: IEC 62351-6、ポートベースの 802.1X、 VLAN の分離。
- MMS リプレイ攻撃: MMS コマンドのキャプチャと再送信。 軽減策: リプレイ保護を備えた TLS、コマンド内のタイムスタンプ。
- SCL ファイルの改ざん: SCD 構成ファイルの編集 FDIの行動を変える。軽減策: SCL ファイルにデジタル署名します。 SHA-256 ハッシュによる変更管理。
- 不正 IED: 許可されていない IED のネットワークへの接続 プロセス。軽減策: 802.1X ポート認証、MAC ホワイトリスト、証明書 ピン留め。
- GOOSE に対するレイテンシー攻撃: ネットワークをフラッディングして増加させる GOOSE 遅延が 4 ミリ秒を超えると、保護が無効になります。軽減策: 厳格な QoS 優先順位、プロセス専用の VLAN、IEC 61850-3 スイッチ。
テストとシミュレーション: テストベンチから自動化まで
IEC 61850 システム テストは、特定のツールを必要とする特殊な領域です。 標準への準拠を検証するために汎用ツールを使用することはできません GOOSE データセットの正確性または負荷時の動作。
オープンソースのテストスタック
高価な商用ツールを購入する予算がないソフトウェア エンジニアのチームにとって、 オープンソースのエコシステムは強固なソリューションを提供します。
-
libiec61850 (MZ オートメーション、GPLv3): Python/Java バインディングを備えた C ライブラリ
IEC 61850 クライアントおよびサーバーの開発に最も一般的です。完全な例が含まれています
標準のあらゆる機能。リポジトリ:
github.com/mz-automation/libiec61850 - OpenSCD (openscd/open-scd): SCL/SCD ファイル用のブラウザベースのエディター、 スキーマ検証とトポロジ視覚化を使用します。エンジニアリングやオーバーホールに最適 構成。
- OpenMUC (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 (Commercial Off-The-Shelf) ハードウェア上の変電所 K3s (エッジ用の軽量 Kubernetes) または Docker Compose より簡単な展開のために。これにより、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): デバイスには 2 つあります 2 つの独立したネットワークに接続されたインターフェイス。両方のネットワークですべてのフレームを送信する 同時に。受信者は最初に到着したものを受け入れ、重複したものは破棄します。 スイッチオーバー時間はゼロですが、ハードウェアとトラフィックが 2 倍になります。
- HSR (高可用性シームレス冗長性、IEC 62439-3): デバイス それらはリング状に接続されています。各フレームは両方向に実行されます。送り主が破棄する 原点に戻ったときのフレーム。ゼロスイッチオーバー、リングトポロジー。
イタリアの背景: Terna、電子ディストリビューション、スマート グリッド
イタリアには、IEC 61850 に関して特に興味深いエネルギー関連の文脈があります。 高電圧送電装置によって操作される テルナ (約74,000kmの路線) および主に運営されている流通ネットワーク 電子配布 (Enel Group、120万km以上の路線)、2社のオペレーターが開始 野心的な変電所デジタル化プログラム。
Terna: 伝送グリッド
テルナは約 800の変電所 高電圧および超高電圧の (380kV、220kV、150kV)。 2025 年 2 月に発表された 2025 年開発計画では、次のことが提供されます。 以下への多額の投資:
- IEC 61850自動化システムによる変電所の近代化 (目標:2030年までにHV変電所公園を完全にカバー)
- ネットワーク可観測性のための PMU (Phasor Measurement Unit) の設置 同期された GPS タイムスタンプによるリアルタイム (IEEE C37.118)
- IEC 61850データを直接統合した新世代EMSシステム AI ベースの負荷予測機能
- 専用のセキュリティ オペレーション センター (SOC) による NIS2 準拠のサイバーセキュリティ。 重要インフラ向け
日立ABBパワーグリッド(現日立エナジー)はデジタルソリューションを展開 RELおよびRETシリーズのIEDと自動化システムを備えたTernaネットワーク内の変電所 MicroSCADA ProはIEC 61850経由で統合されています。
e-distribuzione: 未来の流通ネットワーク
電子ディストリビューションはプログラムを実施しています 「イタリアのネットワーク」、なんとヒントでしょう 配電網を管理可能なスマートグリッドに変える。 再生可能エネルギーと電動モビリティの大規模な統合。重要なポイント:
- スマートプライマリーキャビン: MV/LV 一次変電所の転換 IEC 61850 RTU、電圧品質センサーを備えた地方情報センター 遠隔操縦能力
- MT自動化: FRTU(フィーダーリモート)タイプのIEDの設置 端子ユニット)障害箇所用の中電圧線における IEC 61850 に準拠、 自動分離および復元 (FLISR)。
- 高度な DMS: テンプレートを備えた配布管理システム フィールド IED に対する IEC 61970/61968 ネットワークおよび IEC 61850 通信
イタリアのエネルギーテック分野でのキャリアのチャンス
イタリアにおける IEC 61850 スキルのニーズは急速に高まっています。プロフィール 最重要指名手配者 (2025) には次のものが含まれます。
- IEC 61850 システムエンジニア: システムの設計と試運転 変電所の自動化。給与: 年間 45,000 ~ 75,000 ユーロ。
- SCADA統合開発者: ゲートウェイの開発、データ マッピング、ダッシュボード。 Python/Java + エネルギー プロトコルが必要です。給与: 年間 40,000 ~ 70,000 ユーロ。
- EnergyTech プラットフォーム エンジニア: SCADA/EMS システム用の DevOps/クラウド。 給与: 年間 50,000 ~ 85,000 ユーロ。最も希少で最も高給取りのプロフィール。
- OT サイバーセキュリティ スペシャリスト: IEC 62351、NIS2、セキュリティ評価 重要なインフラ向け。給与: 年間 55,000 ~ 90,000 ユーロ。
主な雇用主: 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とEthernet L2は通過しない ルーター。ルーティングされたネットワーク上で GOOSE を構成し、通信中にエラーが発生する 専用の L2-to-L3 ゲートウェイがなければ不可能です。
- GOOSE APPID が重複しています: 同じ APPID を持つ 2 つのパブリッシャーが原因 サブスクライバ内で競合が発生し、ソースを区別できません。 APPID は次のとおりである必要があります レイヤ 2 ブロードキャスト ドメイン全体で一意です。
- confRev が更新されていません: GOOSE データセットに変更を加える場合は、 SCL ファイルおよび設定された IED の confRev を増分します。 confRev を持つサブスクライバ 発行者以外はメッセージを無視します。
- 高速 MMS ポーリング: 頻度で MMS をポーリングします アナログ値の場合は 1Hz を超えるため、非効率であり、IED に負荷がかかります。レポートの使用 適切なトリガー (データ変更、整合性期間) を備えた制御ブロック。
- 品質フラグを無視します: 各 IEC 61850 データには属性があります。 品質 (q)。状態を確認せずに「良好」以外の品質の値を使用する 制御システムで誤った決定が行われる可能性があります。
- CID ファイルが同期されていません: IED にアップロードされる CID ファイルは、 SCD マスターファイルから抽出されます。 CID を個別に保持し、手動で作成する 診断が難しい不一致。
結論: 戦略的能力としての IEC 61850
IEC 61850 は、ソフトウェア エンジニアにとって最も興味深い技術領域の 1 つです。 クリティカルシステムに特化した。これは単なる産業用プロトコルではありません。 ある 完全なエコシステム データモデリング、フォーマットに触れます XML 構成、リアルタイム プロトコル、サイバーセキュリティ、分散アーキテクチャ クラウド統合。
再生可能エネルギーとエネルギーの大規模な統合を伴う進行中のエネルギー転換 グリッドの柔軟性の必要性により、有能な専門家の需要が高まっています ~の間の境界で作業する OT(オペレーショナルテクノロジー)とIT。ソフトウェア IEC 61850、Python、DevOps、エッジ コンピューティングのスキルを持つエンジニアはまさに イタリアやヨーロッパのエネルギー部門市場には欠けているプロファイルです。
この記事の後に理解する重要な概念は次のとおりです。
- IED/LD/LN/DO/DA 階層データ モデルと命名規則は次のとおりです。 業界全体で共通の語彙: それらを学ぶことは同じことを話すことを意味します ベンダーまたは変電所設計者の言語。
- GOOSE と MMS は相補的な目的を果たします。まず 4ms 未満のリアルタイム保護、 2 つ目は SCADA の監視と制御です。これらは交換可能ではありません。
- SCL は変電所エンジニアリング自動化の鍵です。解析方法を知っている人はいないでしょう。 SCD ファイルの検証と生成には、それらに比べて大きな競争上の利点があります。 彼は今でも手作業で働いています。
- IEC 62351 サイバーセキュリティはオプションではありません: NIS2 により法的要件となります ヨーロッパのすべての重要なエネルギーインフラ事業者向け。
- このアーキテクチャは、ソフトウェア定義の変電所に向けて進化しています。 コンテナ化、エッジ AI、クラウドネイティブ API。 DevOps スキルは、 この分野でも関連性が高まっています。
シリーズの次の記事で取り上げます EV ロード バランシングと V2G: 車両の充電負荷のバランスをとるための最適化アルゴリズム 電気および車両間通信、IEC 61850 が OCPP を満たす分野 凸最適化アルゴリズム。
詳細を学ぶためのリソース
-
libiec61850 - オープンソースの C/Python ライブラリ:
github.com/mz-automation/libiec61850 -
OpenSCD - ブラウザベースの SCL エディタ:
github.com/openscd/open-scd - IEC 61850.com - ドキュメントを備えた公式 IEC ポータル 規格に関する技術とニュース
- PACワールドマガジン - 保護に関する技術出版物 および自動化、多くの IEC 61850 記事あり
- 「IEC 61850 エンジニアリング ガイドブック」 - Herb Falk et al. - 規格を実際に実装するための参考テキスト
- EPRI レポート 3002006451 - 「IEC 61850変電所の実装」 Automation Standard」 - EPRI Web サイトで入手可能
EnergyTech シリーズの関連記事
- 記事 2: エネルギー監視のための MQTT と InfluxDB - エネルギーにおける IoT プロトコルの基本
- 第 4 条: DERMS - 分散型エネルギー資源管理システム
- 記事 6: EV ロード バランシングと V2G - シリーズの次の記事
シリーズ間: 補完的なスキル
- データ&AIビジネスシリーズ - 記事5:製造におけるAI(産業用IoT、OPC-UA、デジタルツイン)
- MLOps シリーズ - 変電所データ分析用の AI モデルの導入
- Web セキュリティ シリーズ - OT/ICS に適用されるサイバーセキュリティ原則







