Riwayat revisi (versi pertama, diterbitkan pada 1 Nov 2026)
- Publikasi pertama
Mengutip artikel ini(DOI: 10.5281/zenodo.23968405)
Artikel ini diarsipkan di Zenodo. Berikut DOI yang selalu mengarah ke versi terbaru dan DOI yang terikat pada versi yang sedang Anda baca.
Go Komura (2026). Pengantar OPC UA ── Mengumpulkan data PLC dan peralatan di aplikasi Windows. KomuraSoft LLC. https://doi.org/10.5281/zenodo.23968405 https://comcomponent.com/id/blog/opc-ua-windows-data-collection/
- DOI (versi terbaru)
- 10.5281/zenodo.23968405
- DOI (versi ini)
- 10.5281/zenodo.23968406
Saat mengumpulkan data PLC atau peralatan ke aplikasi Windows, jika peralatan itu memiliki server OPC UA, terkadang Anda tidak perlu membuat komunikasi yang berbeda untuk setiap produsen. Namun, terhubung lalu membaca nilai saja tidak cukup. Jika Anda tidak memahami status dan stempel waktu yang dikembalikan bersama nilai, langganan yang memberi tahu perubahan, izin koneksi dengan sertifikat, dan cara pulih dari pemutusan, data yang terkumpul tidak bisa dipercaya di kemudian hari.
Artikel ini menjelaskan bagian-bagian OPC UA yang diperlukan untuk pengumpulan data, beserta hasil menjalankan klien C# secara nyata. Klien memakai pustaka .NET dari OPC Foundation, dan lawannya adalah server yang menyimulasikan peralatan. Pengujian tidak dilakukan pada PLC atau peralatan tertentu. Periksa pengaturan masing-masing peralatan di dokumentasi peralatan tersebut.
Pengumpulan gambar dari kamera GigE Vision dan USB3 Vision dibahas di “Dropped Frames with GigE Vision and USB3 Vision Cameras”, dan peralatan dengan komunikasi serial di “Serial Communication App Pitfalls”.
Perbedaan OPC UA dan OPC Classic
Spesifikasi OPC Classic bertukar data antarkomponen perangkat lunak dengan memakai COM/DCOM Windows. OPC DA untuk data proses, OPC A&E untuk alarm, dan OPC HDA untuk riwayat ditetapkan sebagai spesifikasi yang terpisah1.
OPC Foundation menerbitkan OPC UA (Unified Architecture) pada 2008. OPC UA adalah arsitektur berorientasi layanan yang tidak bergantung pada platform tertentu dan menyatukan fungsi dari setiap spesifikasi Classic. Sebagai alasan perancangan ulang, OPC Foundation menyebutkan antara lain bahwa Microsoft mulai lebih mengutamakan mekanisme lintas platform daripada COM/DCOM, bahwa OPC perlu berjalan juga di sistem non-Microsoft dan perangkat tertanam, dan bahwa koneksi perlu dibuat dengan aman melewati firewall1.
Spesifikasi OPC UA juga sudah dijadikan standar oleh IEC sebagai seri IEC 625412. Untuk port komunikasinya, IANA mendaftarkan 4840/TCP sebagai opcua-tcp3.
flowchart TB
accTitle: Perbedaan OPC Classic dan OPC UA
accDescr: Diagram yang menunjukkan bahwa OPC Classic dibangun di atas COM dan DCOM Windows dan terbagi menjadi spesifikasi DA, A&E, dan HDA yang terpisah, sedangkan OPC UA menyatukan fungsi-fungsi itu dalam satu spesifikasi yang tidak bergantung pada platform.
C["OPC Classic"] --> D["Berjalan di atas COM/DCOM (Windows)"]
D --> DA["Spesifikasi terpisah DA, A&E, HDA"]
DA -->|"Menyatukan fungsi"| U["OPC UA (2008)"]
U --> P["Tidak bergantung pada platform tertentu"]
P --> S["Distandarkan sebagai IEC 62541"]
Gambar 1: OPC Classic terdiri atas spesifikasi terpisah di atas COM/DCOM, dan OPC UA menyatukannya menjadi satu.
Jika fasilitas yang sudah ada hanya memiliki server OPC DA, diperlukan mekanisme di sisi yang memakai COM/DCOM. Artikel ini hanya membahas OPC UA.
Pada diagram, garis utuh menunjukkan relasi yang selalu berlaku dan garis putus-putus menunjukkan relasi bersyarat (syaratnya ada pada penjelasan masing-masing relasi di halaman rincian). Daftar lengkap relasi (total 13, beserta bukti dan tingkat kepastian) serta definisi konsep utama dikumpulkan di halaman rincian peta pengetahuan (dalam bahasa Jepang). Data: JSON-LD / Turtle
Konfigurasi yang diuji
Berikut konfigurasi yang dijalankan.
| Peran | Yang dipakai |
|---|---|
| Klien | C#, .NET 10 SDK 10.0.114, paket NuGet OPCFoundation.NetStandard.Opc.Ua.Client 2.0.1 |
| Server | Peralatan simulasi yang dibuat dengan Python 3.13 dan asyncua 2.1.0 (port 4840 di PC yang sama) |
| OS | Linux (eksekusi di Windows tidak diuji) |
Pustaka klien adalah implementasi .NET yang diterbitkan OPC Foundation. Cara pemakaian seri 2.0 mengikuti Getting started di repositori yang sama4.
flowchart TB
accTitle: Konfigurasi yang diuji
accDescr: Diagram yang menunjukkan klien C# yang memakai pustaka .NET dari OPC Foundation dan terhubung lewat koneksi terenkripsi ke server peralatan simulasi berbasis asyncua yang mendengarkan di port 4840.
A["Klien C# (LineCollector)"] -->|"opc.tcp, SignAndEncrypt"| B["Server peralatan simulasi (asyncua)"]
A -.-> L["Pustaka .NET OPC Foundation 2.0.1"]
B -.-> V["Empat variabel Line1"]
Gambar 2: Di dalam PC yang sama, klien C# terhubung ke server peralatan simulasi.
Server peralatan simulasi
Sebagai pengganti peralatan, dibuat server kecil dengan asyncua5. Di bawah objek bernama Line1 terdapat empat variabel: suhu (Temperature), jumlah produksi (PartCount), status beroperasi (Running), dan nilai setelan (Setpoint). Suhu berubah setiap 0,5 detik dan jumlah produksi setiap 2 detik. Untuk keamanan, disiapkan dua pilihan: tanpa enkripsi (None) dan dengan tanda tangan serta enkripsi (SignAndEncrypt dari Basic256Sha256).
# Peralatan simulasi untuk pengujian. Bukan pengganti peralatan atau PLC produksi.
import asyncio, math, random, socket
from pathlib import Path
from cryptography.x509.oid import ExtendedKeyUsageOID
from asyncua import Server, ua
from asyncua.crypto.cert_gen import setup_self_signed_certificate
HERE = Path(__file__).parent
APP_URI = "urn:komurasoft:demo-plc"
async def main():
key, cert = HERE / "server_key.pem", HERE / "server_cert.der"
await setup_self_signed_certificate(
key, cert, APP_URI, socket.gethostname(),
[ExtendedKeyUsageOID.SERVER_AUTH], {"commonName": "DemoPlcServer"})
server = Server()
await server.init()
server.set_endpoint("opc.tcp://0.0.0.0:4840/demo/")
server.set_server_name("DemoPlcServer")
await server.set_application_uri(APP_URI)
server.set_security_policy([
ua.SecurityPolicyType.NoSecurity,
ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
])
await server.load_certificate(str(cert))
await server.load_private_key(str(key))
ns = await server.register_namespace("urn:komurasoft:demo-plc:line1")
line1 = await server.nodes.objects.add_object(ua.NodeId("Line1", ns), "Line1")
temperature = await line1.add_variable(ua.NodeId("Line1.Temperature", ns), "Temperature", 25.0)
part_count = await line1.add_variable(
ua.NodeId("Line1.PartCount", ns), "PartCount", ua.Variant(0, ua.VariantType.UInt32))
await line1.add_variable(ua.NodeId("Line1.Running", ns), "Running", True)
setpoint = await line1.add_variable(ua.NodeId("Line1.Setpoint", ns), "Setpoint", 30.0)
await setpoint.set_writable()
async with server:
print("listening", flush=True)
t, count = 0, 0
while True:
await asyncio.sleep(0.5)
t += 1
value = 25.0 + 2.0 * math.sin(t / 4) + random.uniform(-0.05, 0.05)
await temperature.write_value(round(value, 2))
if t % 4 == 0:
count += 1
await part_count.write_value(ua.Variant(count, ua.VariantType.UInt32))
asyncio.run(main())
Server ini menerima sertifikat klien yang terhubung tanpa memeriksanya. Ini pengaturan untuk pengujian dan berbeda dari perilaku peralatan produksi.
Klien C#
Di file proyek dimasukkan dua paket berikut.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
</ItemGroup>
</Project>
Klien melakukan koneksi, penjelajahan (browse), pembacaan, penulisan, dan langganan secara berurutan. Arti setiap bagian dijelaskan berurutan mulai dari bagian berikutnya.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Client.Subscriptions;
using Opc.Ua.Client.Subscriptions.Streaming;
using MonitoredItemOptions = Opc.Ua.Client.Subscriptions.MonitoredItems.MonitoredItemOptions;
string url = args.Length > 0 ? args[0] : "opc.tcp://localhost:4840/demo/";
int notifications = args.Length > 1 ? int.Parse(args[1]) : 6;
const string LineNamespace = "urn:komurasoft:demo-plc:line1";
HostApplicationBuilder builder = Host.CreateApplicationBuilder();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
builder.Services
.AddOpcUa()
.AddClient(options =>
{
options.ApplicationName = "LineCollector";
options.ApplicationUri = "urn:localhost:LineCollector";
options.ProductUri = "urn:komurasoft:LineCollector";
options.PkiRoot = Path.Combine(AppContext.BaseDirectory, "pki");
})
.AddDiscoveryAndConnect(options =>
{
options.DiscoveryUrl = url;
options.SecurityMode = MessageSecurityMode.SignAndEncrypt;
options.SecurityPolicyUri = SecurityPolicies.Basic256Sha256;
});
using IHost host = builder.Build();
await host.StartAsync();
using var timeout = new CancellationTokenSource(TimeSpan.FromMinutes(2));
CancellationToken ct = timeout.Token;
try
{
var connect = host.Services
.GetRequiredService<Func<CancellationToken, Task<ManagedSession>>>();
ManagedSession session = await connect(ct);
await using (session)
{
Console.WriteLine($"接続: {session.ConfiguredEndpoint?.EndpointUrl}");
// Indeks namespace ditentukan oleh server. Cari dari URI, lalu buat NodeId dengannya
ushort ns = (ushort)session.NamespaceUris.GetIndex(LineNamespace);
var line1 = new NodeId("Line1", ns);
var temperature = new NodeId("Line1.Temperature", ns);
var partCount = new NodeId("Line1.PartCount", ns);
var setpoint = new NodeId("Line1.Setpoint", ns);
// Browse: tampilkan daftar variabel di bawah Line1
var browser = new Browser(session)
{
BrowseDirection = BrowseDirection.Forward,
ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences,
IncludeSubtypes = true,
NodeClassMask = (uint)NodeClass.Variable,
};
Console.WriteLine("Line1 の変数:");
foreach (ReferenceDescription child in await browser.BrowseAsync(line1, ct))
{
Console.WriteLine($" {child.DisplayName} {child.NodeId}");
}
// Baca: lihat bukan hanya nilai, tetapi juga status dan dua stempel waktu
DataValue t = await session.ReadValueAsync(temperature, ct);
Console.WriteLine($"Temperature = {t.WrappedValue} 状態 {t.StatusCode}");
Console.WriteLine($" Source {Hms(t.SourceTimestamp)} / Server {Hms(t.ServerTimestamp)}");
// Membaca node yang tidak ada mengembalikan status Bad, bukan nilai
try
{
await session.ReadValueAsync(new NodeId("Line1.Pressure", ns), ct);
}
catch (ServiceResultException ex)
{
Console.WriteLine($"Line1.Pressure の読み取り: {ex.StatusCode}");
}
// Tulis: ubah Setpoint menjadi 32.5
var write = new WriteValue
{
NodeId = setpoint,
AttributeId = Attributes.Value,
Value = new DataValue(new Variant(32.5)),
};
WriteResponse wr = await session.WriteAsync(null, new[] { write }, ct);
Console.WriteLine($"Setpoint の書き込み: {wr.Results[0]}");
// Langganan: minta server mengambil sampel setiap 500 ms dan memberi tahu perubahan
Console.WriteLine($"購読({notifications}件まで):");
await foreach (DataValueChange change in session.DefaultStreaming
.SubscribeDataChangesAsync(new[] { temperature, partCount }, options: new MonitoredItemOptions
{
SamplingInterval = TimeSpan.FromMilliseconds(500),
QueueSize = 5,
}, ct: ct)
.TakeAsync(notifications)
.WithCancellation(ct))
{
DataValue v = change.Value;
string name = change.MonitoredItem?.Name.Split("s=")[^1] ?? "?";
Console.WriteLine($" {Hms(v.SourceTimestamp)} {name,-17} {v.WrappedValue,6} {v.StatusCode}");
}
}
}
catch (ServiceResultException ex)
{
Console.Error.WriteLine($"OPC UA エラー {ex.StatusCode}: {ex.Message}");
Environment.ExitCode = 1;
}
finally
{
await host.StopAsync();
}
static string Hms(DateTimeUtc time) => time.ToDateTime().ToString("HH:mm:ss.fff");
Pada eksekusi pertama, koneksi gagal. Alasannya dijelaskan di bagian “Mengizinkan koneksi dengan sertifikat”. Berikut keluaran setelah sertifikat server dipercaya. Log peringatan dari pustaka dihilangkan.
接続: opc.tcp://localhost:4840/demo/
Line1 の変数:
Temperature ns=2;s=Line1.Temperature
PartCount ns=2;s=Line1.PartCount
Running ns=2;s=Line1.Running
Setpoint ns=2;s=Line1.Setpoint
Temperature = 23.09 状態 Good [0x00000000]
Source 13:40:51.302 / Server 13:40:51.302
Line1.Pressure の読み取り: BadNodeIdUnknown [0x80340000]
Setpoint の書き込み: Good [0x00000000]
購読(6件まで):
13:40:51.302 Line1.Temperature 23.09 Good [0x00000000]
13:40:50.801 Line1.PartCount 67 Good [0x00000000]
13:40:51.802 Line1.Temperature 23.05 Good [0x00000000]
13:40:52.304 Line1.Temperature 23.07 Good [0x00000000]
13:40:52.806 Line1.Temperature 23.2 Good [0x00000000]
13:40:52.806 Line1.PartCount 68 Good [0x00000000]
Waktunya dalam UTC.
Data peralatan terlihat sebagai node di ruang alamat
Server OPC UA memublikasikan data yang dimilikinya sebagai kumpulan node. Kumpulan ini disebut ruang alamat (address space). Node memiliki beberapa jenis, seperti objek yang mewakili folder atau peralatan dan variabel yang memiliki nilai, dan node saling terhubung melalui referensi. Klien menelusuri referensi dengan layanan Browse untuk mengetahui node apa saja yang ada6.
Pada keluaran di atas, klien menelusuri referensi hierarkis dari Line1 dan menemukan empat variabel.
flowchart TB
accTitle: Ruang alamat peralatan simulasi
accDescr: Diagram yang menunjukkan bahwa di bawah folder Objects terdapat objek Line1, dan di bawahnya terdapat empat variabel, yaitu Temperature, PartCount, Running, dan Setpoint.
O["Objects"] --> L["Line1 (objek)"]
L --> T["Temperature (variabel)"]
L --> P["PartCount (variabel)"]
L --> R["Running (variabel)"]
L --> S["Setpoint (variabel, dapat ditulis)"]
Gambar 3: Ruang alamat peralatan simulasi. Klien menemukan node dengan menelusuri referensi lewat Browse.
NodeId terdiri atas namespace dan pengenal
Node diidentifikasi dengan NodeId. ns=2;s=Line1.Temperature pada keluaran berarti indeks namespace-nya 2 dan pengenalnya adalah string Line1.Temperature.
Wujud sebenarnya dari namespace adalah URI. Spesifikasi menetapkan bahwa di dalam layanan, URI namespace dinyatakan dengan angka, dan angka itu sesuai dengan posisi di NamespaceArray milik server. Indeks 0 adalah namespace OPC UA, yaitu http://opcfoundation.org/UA/7.
Karena itu, alih-alih menulis angka indeks langsung di kode, indeks dicari dari URI. Pada kode di atas, session.NamespaceUris.GetIndex(LineNamespace) mencari angka 2 dari URI, lalu NodeId dibuat dari situ.
flowchart TB
accTitle: Alur membuat NodeId dari URI namespace
accDescr: Diagram yang menunjukkan bahwa klien mencari URI namespace di NamespaceArray server untuk mendapatkan indeks, lalu menggabungkan indeks itu dengan pengenal untuk membuat NodeId.
U["URI namespace"] --> A["NamespaceArray milik server"]
A --> I["Indeks (dalam contoh ini 2)"]
I --> N["NodeId ns=2;s=Line1.Temperature"]
K["Pengenal Line1.Temperature"] --> N
Gambar 4: Indeks namespace dicari dari URI, lalu digabungkan dengan pengenal menjadi NodeId.
Pembacaan dan penulisan mengembalikan status dan stempel waktu bersama nilai
Nilai variabel dibaca dan ditulis dengan layanan Read dan Write8. Pembacaan tidak hanya mengembalikan nilai. Yang dikembalikan adalah struktur bernama DataValue, berisi nilai, kode status, stempel waktu sumber, dan stempel waktu server9.
| Butir | Arti |
|---|---|
| Nilai | Nilai variabel. Jika kode status menunjukkan galat, nilai diabaikan dan server mengisinya dengan null |
| Kode status (StatusCode) | Apakah server berhasil mendapatkan dan menyediakan nilai itu |
| SourceTimestamp | Waktu yang diberikan sumber data pada nilai |
| ServerTimestamp | Waktu server menerima nilai, atau mengetahui bahwa nilai itu benar |
Dua bit teratas kode status menyatakan Good (berhasil), Uncertain (berhasil sebagian; bergantung pada penggunaannya, mungkin tidak bisa dipakai), atau Bad (gagal)10. Good [0x00000000] pada keluaran adalah Good.
Saat membaca Line1.Pressure yang tidak ada, yang dikembalikan adalah BadNodeIdUnknown [0x80340000], bukan nilai. ReadValueAsync di pustaka ini melemparkan pengecualian jika statusnya Bad4. Pada sistem yang mencatat nilai, menyimpan kode status di samping nilai memungkinkan Anda membedakan, di kemudian hari, nilai yang tercatat selama statusnya Bad.
flowchart TB
accTitle: Isi DataValue
accDescr: Diagram yang menunjukkan bahwa DataValue yang dikembalikan oleh pembacaan dan notifikasi memiliki empat butir, yaitu nilai, kode status, stempel waktu sumber, dan stempel waktu server, dan bahwa nilai diabaikan jika kode status Bad.
D["DataValue"] --> V["Nilai"]
D --> S["Kode status"]
D --> TS["SourceTimestamp (waktu sumber)"]
D --> TV["ServerTimestamp (waktu server)"]
S -->|"Jika Bad"| X["Nilai diabaikan"]
Gambar 5: Hasil pembacaan tidak hanya berisi nilai, tetapi juga kode status dan dua stempel waktu.
Pada penulisan, 32.5 ditulis ke Setpoint, dan kode status hasilnya Good. Apakah suatu variabel dapat ditulis atau tidak ditentukan oleh server. Di server simulasi ini, hanya Setpoint yang dapat ditulis. Apakah nilai setelan peralatan boleh diubah dari luar menyangkut desain keselamatan peralatan, sehingga tidak dibahas dalam artikel ini.
Menerima notifikasi perubahan: langganan dan MonitoredItem
Untuk mengikuti perubahan nilai, klien bisa saja mengulang Read pada interval tetap. Selain itu, OPC UA memiliki mekanisme lain: pemantauan nilai diserahkan ke server, lalu server memberi tahu perubahannya. Mekanisme itu adalah langganan (subscription) dan MonitoredItem.
MonitoredItem adalah satu objek yang dipantau, dan memiliki interval pengambilan sampel. Interval pengambilan sampel adalah interval tercepat server mengambil sampel nilai dari sumbernya, dan spesifikasi menyebutnya sebagai periode “upaya terbaik” (best effort)11. Jika sampel memenuhi syarat filter, notifikasi dibuat. Jika filter tidak ditentukan, notifikasi dikirim saat nilai atau status berubah12.
Notifikasi masuk dulu ke antrean MonitoredItem. Untuk saat antrean meluap, ditentukan apakah yang dibuang yang lama atau yang baru, dan jika ukuran antrean 2 atau lebih, bit Overflow yang menandakan adanya pembuangan dinyalakan di kode status13.
Langganan mengelompokkan beberapa MonitoredItem dan, setiap interval publikasi, mengirim ke klien notifikasi yang belum dikirim. Jika beberapa periode berturut-turut tidak ada notifikasi yang perlu dikirim, langganan mengirim keep-alive untuk memberi tahu bahwa langganan masih hidup14.
flowchart TB
accTitle: Alur langganan dan MonitoredItem
accDescr: Diagram yang menunjukkan bahwa MonitoredItem mengambil sampel nilai sumber pada interval pengambilan sampel, memasukkan notifikasi yang lolos filter ke antrean, lalu langganan mengirimkannya sekaligus ke klien setiap interval publikasi, dan mengirim keep-alive jika tidak ada notifikasi.
S["Sumber (nilai peralatan)"] --> M["MonitoredItem"]
M -->|"Interval pengambilan sampel"| F["Filter (bawaan: perubahan nilai atau status)"]
F --> Q["Antrean (jika meluap, Overflow)"]
Q --> SUB["Langganan"]
SUB -->|"Interval publikasi"| C["Klien"]
SUB -.->|"Jika tidak ada notifikasi"| K["Keep-alive"]
Gambar 6: MonitoredItem mengambil sampel dan menampungnya di antrean, lalu langganan mengirimkannya sekaligus ke klien.
Pada kode di atas, Temperature dan PartCount dilanggan dengan interval pengambilan sampel 500 milidetik dan ukuran antrean 515. Pada keluaran, suhu tiba kira-kira setiap 0,5 detik dan jumlah produksi kira-kira setiap 2 detik. Dua notifikasi pertama adalah nilai yang dimiliki masing-masing variabel saat langganan dimulai. 13:40:50.801 pada jumlah produksi adalah waktu nilai berubah sebelum langganan dimulai. Karena waktu notifikasi menampilkan stempel waktu sumber, yang tampil adalah waktu nilai berubah, bukan waktu notifikasi diterima.
Kapan mengulang pembacaan dan kapan berlangganan
Dengan mengulang pembacaan, klien bisa menentukan intervalnya sendiri, dan mekanismenya sederhana. Sebagai gantinya, permintaan dan respons tetap bolak-balik setiap kali meskipun nilainya tidak berubah, dan perubahan yang lebih singkat dari interval akan terlewat. Dengan langganan, server mengambil sampel dan hanya mengirim perubahan, sehingga komunikasi tidak mudah bertambah untuk nilai yang jarang berubah. Namun, dengan langganan pun, perubahan yang lebih singkat dari interval pengambilan sampel bisa saja tidak diberitahukan. Spesifikasi mengizinkan pengambilan sampel lebih cepat dari yang ditentukan, tetapi tidak mewajibkannya11.
flowchart TB
accTitle: Perbedaan mengulang pembacaan dan berlangganan
accDescr: Diagram yang menunjukkan bahwa dengan mengulang pembacaan klien menentukan interval dan meminta setiap kali, sedangkan dengan langganan server mengambil sampel pada interval pengambilan sampel dan hanya mengirim perubahan, dan pada keduanya perubahan yang lebih singkat dari interval bisa tidak tertangkap.
A["Mengikuti perubahan nilai"] --> R["Mengulang pembacaan"]
A --> S["Berlangganan"]
R --> R1["Klien menentukan interval dan meminta setiap kali"]
S --> S1["Server mengambil sampel dan hanya mengirim perubahan"]
R1 --> X["Perubahan lebih singkat dari interval bisa terlewat"]
S1 --> X
Gambar 7: Dengan cara mana pun, perubahan yang lebih singkat dari interval bisa tidak tertangkap.
Mengizinkan koneksi dengan sertifikat
Pada koneksi OPC UA, tingkat perlindungan pesan dipilih dengan MessageSecurityMode. Nilainya adalah None yang tidak melindungi, Sign yang hanya menandatangani, dan SignAndEncrypt yang menandatangani dan mengenkripsi16. Kombinasi algoritme yang dipakai untuk tanda tangan dan enkripsi ditentukan oleh kebijakan keamanan, dan dalam artikel ini dipakai Basic256Sha256.
Tanda tangan dan enkripsi memakai sertifikat milik masing-masing aplikasi. Klien dan server saling memeriksa sertifikat lawannya dan menolak koneksi dengan pihak yang tidak dipercaya. Server yang dibuat dengan pustaka .NET dari OPC Foundation secara bawaan tidak menyediakan kebijakan None yang tanpa enkripsi4.
Koneksi pertama berhenti dengan BadCertificateUntrusted
Pada eksekusi pertama, klien belum memercayai sertifikat server, sehingga koneksi ditolak. Berikut sebagian keluarannya.
fail: Opc.Ua.CertificateValidationCore[91]
Certificate [Subject=CN=DemoPlcServer, CN=urn:komurasoft:demo-plc, Thumbprint=4E236DDA629FE2AB32D185BF681609FD6C525363, NotBefore=2026-11-01, NotAfter=2027-11-01, KeyAlgorithm=1.2.840.113549.1.1.1] validation failed with suppressible errors but was rejected. Reason=Id: BadCertificateUntrusted
...
OPC UA エラー BadCertificateUntrusted [0x801A0000]: [801A0000] (BadCertificateUntrusted) 'Could not verify security on OpenSecureChannel response.'
Pustaka ini menyimpan sertifikat yang ditolak di penyimpanan rejected. Jika administrator memindahkannya dari sana ke penyimpanan trusted, pustaka akan memercayai pihak tersebut17. Kali ini, sertifikat server yang ada di pki/rejected/certs dipindahkan ke pki/trusted/certs, lalu setelah dijalankan sekali lagi, koneksi berhasil. Sebelum memindahkannya, pastikan sidik jari sertifikat, yang juga tercantum di nama file, bersama administrator server4.
flowchart TB
accTitle: Alur hingga sertifikat dipercaya
accDescr: Diagram yang menunjukkan bahwa pada koneksi pertama klien menolak sertifikat server dan menyimpannya di penyimpanan rejected, lalu setelah sidik jari dipastikan dan sertifikat dipindahkan ke penyimpanan trusted, koneksi berikutnya memercayainya dan berhasil terhubung.
A["Koneksi pertama"] --> B["BadCertificateUntrusted"]
B --> C["Sertifikat disimpan di penyimpanan rejected"]
C --> D["Pastikan sidik jari bersama administrator server"]
D --> E["Pindahkan ke penyimpanan trusted"]
E --> F["Koneksi berikutnya dipercaya dan berhasil"]
Gambar 8: Jika sertifikat yang ditolak diperiksa lalu dipindahkan ke trusted, pihak tersebut akan dipercaya.
Ada juga pengaturan bernama AutoAcceptUntrustedCertificates yang otomatis menerima sertifikat yang tidak dipercaya. Nilai bawaannya false, dan dokumentasi pustaka menyebutkan bahwa pengaturan ini berguna di lingkungan pengembangan tetapi jangan dipakai di produksi17.
NotAfter=2027-11-01 pada log adalah tanggal kedaluwarsa sertifikat server simulasi. Sertifikat itu bertanda tangan sendiri (self-signed) yang dibuat dengan fungsi asyncua, dan masa berlakunya berakhir satu tahun setelah tanggal pembuatan. Sertifikat peralatan juga memiliki masa berlaku, jadi tetapkan dalam operasional prosedur untuk menggantinya sebelum kedaluwarsa dan membuat pihak lawan memercayai sertifikat baru. Penanganan penyimpanan sertifikat Windows dirangkum di “Panduan praktis penyimpanan sertifikat Windows”.
Autentikasi pengguna
Yang diperiksa dengan sertifikat adalah hubungan antaraplikasi. Terpisah dari itu, saat membuka sesi, diserahkan token yang menunjukkan pengguna. Spesifikasi menetapkan empat jenis: anonim, nama pengguna dan kata sandi, sertifikat X.509, dan token yang diterbitkan pihak luar18. Klien kali ini terhubung secara anonim. Token apa saja yang diterima server tercantum dalam informasi endpoint server tersebut19.
Titik rawan dalam pengumpulan data di lapangan
Berikut masalah yang sering muncul pada sistem yang mengumpulkan data peralatan, berdasarkan percobaan kali ini dan spesifikasi.
Nilai selama server berhenti tidak sampai
Di tengah langganan, server dihentikan lalu dijalankan kembali sekitar 15 detik kemudian. ManagedSession di pustaka ini otomatis menyambung ulang saat koneksi terputus20. Selama server berhenti, klien terus mencoba menyambung ulang.
warn: Opc.Ua.ChannelManager[6]
Reconnect failed. Endpoint=opc.tcp://localhost:4840/demo/, Attempt=3, Outcome=transient-failure, Status=BadNotConnected, ErrorMessage=Could not connect to the remote endpoint.
Ketika server kembali, notifikasi juga kembali. Berikut sebagian keluaran langganan.
13:41:13.364 Line1.Temperature 25.61 Good [0x00000000]
13:41:13.865 Line1.Temperature 25.12 Good [0x00000000]
13:41:34.285 Line1.Temperature 26.55 Good [0x00000000]
13:41:33.784 Line1.PartCount 2 Good [0x00000000]
13:41:34.786 Line1.Temperature 26.16 Good [0x00000000]
Tidak ada satu pun nilai yang sampai dari pukul 13:41:13 sampai 13:41:34. Jumlah produksi kembali dari 78 ke 2. Ini karena server simulasi dijalankan ulang dan menghitung lagi dari 0.
Pada contoh ini server itu sendiri yang berhenti, sehingga nilai selama itu tidak tersimpan di mana pun. Mekanisme koneksi ulang memulihkan koneksi, tetapi tidak mengisi belakangan nilai selama berhenti.
Lain halnya jika hanya komunikasinya yang terputus sementara server terus berjalan. Spesifikasi memiliki layanan Republish untuk meminta server mengirim ulang pesan notifikasi yang tidak sampai dari antrean pengiriman ulangnya21. Notifikasi juga tertampung di antrean MonitoredItem, tetapi yang melebihi ukuran antrean dibuang13. Dalam percobaan kali ini, kasus tersebut tidak diuji. Pada kedua kasus, catat waktu pemutusan dan koneksi ulang agar rentang waktu ketika nilai tidak datang dapat diketahui. Koneksi ulang dan desain log untuk peralatan dengan komunikasi serial juga dibahas di “Serial Communication App Pitfalls”.
flowchart TB
accTitle: Pencatatan saat server berhenti
accDescr: Diagram yang menunjukkan bahwa jika server berhenti selama langganan, klien terus mencoba koneksi ulang, dan saat server kembali notifikasi juga kembali, tetapi nilai selama berhenti tidak sampai, sehingga waktu pemutusan dan koneksi ulang dicatat.
A["Selama langganan"] --> B["Server berhenti"]
B --> C["Klien terus mencoba koneksi ulang"]
C --> D["Server kembali, notifikasi juga kembali"]
B -.-> E["Nilai selama berhenti tidak sampai"]
E -.-> F["Catat waktu pemutusan dan koneksi ulang"]
Gambar 9: Koneksi ulang memulihkan koneksi, tetapi nilai selama berhenti tidak sampai.
Stempel waktu mana yang dicatat
Menurut spesifikasi, SourceTimestamp adalah waktu yang diberikan sumber data pada nilai, dan seharusnya menunjukkan waktu nilai berubah. ServerTimestamp adalah waktu server menerima nilai, atau mengetahui bahwa nilai itu benar9. Server simulasi kali ini membuat nilainya sendiri, sehingga kedua waktu itu sama.
Jika ingin mengetahui waktu nilai berubah di peralatan, gunakan SourceTimestamp. Namun, waktu itu diberikan oleh jam sumbernya, sehingga jika jam peralatan atau server meleset, catatannya juga meleset. Jika data yang dikumpulkan akan dicocokkan dengan catatan lain, menyimpan juga waktu PC penerima di sampingnya memungkinkan selisihnya diperiksa belakangan. Sinkronisasi waktu di sisi Windows dirangkum di “Windows Time Synchronization (w32time) and Business Systems”.
Jangan langsung memperlakukan nilai yang statusnya bukan Good sebagai angka
Jika kode status Bad, nilainya harus diabaikan9. Jika Uncertain, bergantung pada penggunaannya, nilainya mungkin tidak bisa dipakai10. Sebelum memasukkan nilai ke grafik atau agregasi, pilah berdasarkan kode status dan tentukan cara memperlakukan nilai yang bukan Good. Bit Overflow saat antrean meluap juga dinyalakan di dalam kode status13. Cara menampilkan status peralatan di layar dibahas di “Best Practices for Checking and Displaying External Device State”.
Membuka port di firewall
Port OPC UA yang terdaftar di IANA adalah 4840/TCP3. Namun, tidak semua server memakai nomor ini. Contoh .NET dari OPC Foundation memakai port seperti 625414. Periksa nomor port di URL endpoint peralatan, lalu izinkan koneksi ke port tersebut. Jika server berjalan di Windows, izinkan di Windows Firewall pada mesin itu, dan jika ada perangkat jaringan di antaranya, izinkan juga di perangkat tersebut. Cara membuat aturan masuk dirangkum di “Windows Firewall dan aplikasi bisnis”.
flowchart TB
accTitle: Titik rawan dalam pengumpulan data
accDescr: Diagram yang membagi titik rawan dalam pengumpulan data peralatan menjadi isi catatan (nilai selama server berhenti tidak sampai, stempel waktu mana yang dicatat, penanganan nilai yang bukan Good) dan persiapan koneksi (port firewall, masa berlaku sertifikat).
A["Titik rawan dalam pengumpulan data"] --> R["Isi catatan"]
A --> N["Persiapan koneksi"]
R --> B["Nilai selama berhenti tidak sampai"]
B ~~~ C["Stempel waktu yang mana"]
C ~~~ D["Penanganan nilai bukan Good"]
N --> E["Port firewall"]
E ~~~ F["Masa berlaku sertifikat"]
Gambar 10: Setelah terhubung pun, periksa celah catatan, waktu, status, port, dan sertifikat.
Kapan memakai Modbus/TCP atau komunikasi khusus produsen
Untuk berkomunikasi dengan PLC dan peralatan, selain OPC UA ada juga Modbus/TCP dan komunikasi yang disediakan oleh produsen PLC.
Spesifikasi Modbus menangani data dalam empat tabel: Discrete Input 1 bit yang hanya baca, Coil 1 bit yang bisa dibaca dan ditulis, Input Register 16 bit yang hanya baca, dan Holding Register 16 bit yang bisa dibaca dan ditulis22. Di IANA, 502/TCP terdaftar sebagai protokol aplikasi Modbus (mbap)3.
Yang masuk ke tabel ini adalah bit dan word 16 bit, sehingga nilai apa yang ada di alamat mana dan dalam format apa harus diperiksa di dokumentasi peralatan lalu ditulis di sisi klien. Pada OPC UA, seperti yang sudah dibahas, server memublikasikan variabel bernama di ruang alamat, dan klien dapat menelusurinya dengan Browse. Nilai dilengkapi kode status dan stempel waktu, dan koneksi diizinkan dengan sertifikat.
Pilihan yang dipakai sering kali ditentukan oleh apa yang disediakan peralatan. Jika peralatan memiliki server OPC UA, gunakan itu; jika hanya ada Modbus/TCP, buat tabel pemetaan alamat lalu bacalah. Jika hanya ada komunikasi atau SDK dari produsen, ikuti dokumentasinya. Cara memilih metode komunikasi dengan perangkat USB dirangkum di “How to Work with USB Devices from a Windows App”.
flowchart TB
accTitle: Cara memilih komunikasi dengan peralatan
accDescr: Diagram yang menunjukkan bahwa jika peralatan memiliki server OPC UA, data dikumpulkan dengan menelusuri variabel lewat OPC UA, jika hanya ada Modbus/TCP, alamat dan format diperiksa di dokumentasi lalu register dibaca, dan jika hanya ada komunikasi produsen, dokumentasinya diikuti.
A["Komunikasi yang disediakan peralatan"] --> B{"Apa yang tersedia?"}
B -->|"Server OPC UA"| C["Telusuri variabel lalu kumpulkan"]
B -->|"Hanya Modbus/TCP"| D["Periksa alamat dan format di dokumentasi"]
B -->|"Hanya komunikasi produsen"| E["Ikuti dokumentasi dan SDK produsen"]
D --> F["Baca register lalu ubah menjadi nilai"]
Gambar 11: Dengan apa data dikumpulkan sering kali ditentukan oleh apa yang disediakan peralatan.
Artikel terkait
- Dropped Frames with GigE Vision and USB3 Vision Cameras — Locating the Cause and the Windows Settings to Review
- Serial Communication App Pitfalls - Through Reconnection and Log Design
- Best Practices for Checking and Displaying External Device State
- How to Work with USB Devices from a Windows App
- Windows Firewall dan aplikasi bisnis
- Panduan praktis penyimpanan sertifikat Windows
- Windows Time Synchronization (w32time) and Business Systems
Referensi
-
OPC Foundation, Classic. Bahwa OPC Classic didasarkan pada COM/DCOM, spesifikasi DA, A&E, dan HDA, penerbitan OPC UA pada 2008, serta alasan perancangan ulang. ↩ ↩2
-
IEC, IEC TR 62541-1:2020 OPC Unified Architecture - Part 1: Overview and concepts. Bagian 1 dari seri IEC 62541 yang membahas konsep dan gambaran umum OPC UA (sudah digantikan oleh edisi penerusnya). ↩
-
IANA, Service Name and Transport Protocol Port Number Registry. Pendaftaran
opcua-tcppada 4840/TCP danmbappada 502/TCP. ↩ ↩2 ↩3 -
OPC Foundation, UA-.NETStandard 2.0.1: Getting started. Cara menulis klien seri 2.0, bahwa
ReadValueAsyncmelemparkan pengecualian saat Bad, penyimpanan untuk sertifikat yang ditolak dan yang dipercaya, bahwa server secara bawaan tidak menyediakanNone, serta nomor port contoh. ↩ ↩2 ↩3 ↩4 ↩5 -
FreeOpcUa, asyncua (PyPI). Pustaka OPC UA untuk Python yang dipakai untuk server peralatan simulasi. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 5.9.2 Browse. Layanan untuk menelusuri referensi node. ↩
-
OPC Foundation, OPC 10000-3 v1.05, 8.2.2 NamespaceIndex. Bahwa di dalam layanan URI namespace dinyatakan dengan angka, dan angka itu sesuai dengan posisi di NamespaceArray. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 5.11 Attribute Service Set. Layanan Read dan Write. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 7.11 DataValue. Definisi nilai, kode status, SourceTimestamp, dan ServerTimestamp. ↩ ↩2 ↩3
-
OPC Foundation, OPC 10000-4 v1.05, 7.38.1 StatusCode General. Good, Uncertain, dan Bad yang ditunjukkan oleh dua bit teratas. ↩ ↩2
-
OPC Foundation, OPC 10000-4 v1.05, 5.13.1.2 Sampling interval. Bahwa interval pengambilan sampel adalah periode upaya terbaik. ↩ ↩2
-
OPC Foundation, OPC 10000-4 v1.05, 7.22.2 DataChangeFilter. Bahwa tanpa filter, notifikasi dikirim saat nilai atau status berubah. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 5.13.1.5 Queue parameters. Ukuran antrean, cara membuang, dan bit Overflow. ↩ ↩2 ↩3
-
OPC Foundation, OPC 10000-4 v1.05, 5.14.1.1 Subscription model. Interval publikasi dan keep-alive. ↩
-
OPC Foundation, UA-.NETStandard 2.0.1: Subscriptions and Monitored Items Service Set.
SubscribeDataChangesAsyncserta interval pengambilan sampel dan ukuran antrean padaMonitoredItemOptions. ↩ -
OPC Foundation, OPC 10000-4 v1.05, 7.20 MessageSecurityMode. Arti None, Sign, dan SignAndEncrypt. ↩
-
OPC Foundation, UA-.NETStandard 2.0.1: Certificates. Praktik memindahkan sertifikat dari penyimpanan rejected ke penyimpanan yang dipercaya, dan bahwa
AutoAcceptUntrustedCertificatesjangan dipakai di produksi. ↩ ↩2 -
OPC Foundation, OPC 10000-4 v1.05, 7.40 UserIdentityToken parameters. Empat jenis: anonim, nama pengguna, X.509, dan token yang diterbitkan. ↩
-
OPC Foundation, OPC 10000-4 v1.05, 7.14 EndpointDescription. Daftar token pengguna yang diterima endpoint (userIdentityTokens). ↩
-
OPC Foundation, UA-.NETStandard 2.0.1: Sessions, Reconnection, and Subscription Engines. Bahwa
ManagedSessionmemiliki mekanisme koneksi ulang bawaan. ↩ -
OPC Foundation, OPC 10000-4 v1.05, 5.14.6.1 Republish. Layanan untuk meminta pesan notifikasi dikirim ulang dari antrean pengiriman ulang langganan. ↩
-
Modbus-IDA, MODBUS Application Protocol Specification V1.1b (salinan yang disimpan di server University of Chicago). Model data di bagian 4.3 (Discrete Input, Coil, Input Register, Holding Register). ↩
Artikel terkait
Artikel terbaru dengan tag yang sama untuk mendalami topik-topik yang lebih dekat.
Praktik terbaik multithreading di lapangan: edisi .NET — yang harus diputuskan sebelum menambah thread
Merangkum pola desain .NET/C# agar aplikasi multithread tidak sesekali crash atau macet: jangan membuat thread sendiri, bertumpu pada Tas...
Memakai WMI/CIM dari C# dan PowerShell — panduan praktis pengambilan informasi perangkat keras, pemantauan proses, dan kueri jarak jauh
Cara klasik mengambil nomor seri PC, memantau ruang disk, dan mendeteksi proses yang mulai adalah WMI/CIM. Artikel ini menjelaskan pemaka...
Kedalaman I/O Windows (bagian 4) — Cache Manager: kapan WriteFile Anda sampai ke disk
Bagian 4 seri yang menjelaskan Cache Manager Windows dengan diagram. Artikel ini merangkai cache yang diimplementasikan sebagai file mapp...
Named pipe dalam praktik — IPC andalan Windows, dari desain sampai keamanan
Penjelasan praktis named pipe, IPC andalan di Windows. Dari sumber primer: memilih mode byte versus mode pesan, desain server yang menang...
Spurious wakeup — mengapa condition variable "bangun tanpa notifikasi" dan cara menunggu yang benar di Windows
wait pada condition variable dapat bangun meskipun notifikasi tidak datang (spurious wakeup). Artikel ini mengurai alasan spesifikasi men...
Topik terkait
Ini adalah halaman topik yang dekat dengan tema ini. Dari artikel, Anda dapat melanjutkan ke layanan terkait dan artikel lainnya.
Topik teknis Windows
Pintu masuk yang merangkum topik teknis tentang pengembangan Windows, investigasi bug, dan pemanfaatan aset yang ada.
Layanan yang terkait dengan topik ini
Artikel ini terhubung ke halaman layanan berikut. Silakan lihat dari pintu masuk yang dekat dengan situasi Anda.
Pengembangan aplikasi Windows
Jika Anda ingin membuat aplikasi Windows yang mengumpulkan data dari peralatan, termasuk pengaturan langganan, koneksi ulang, serta pencatatan stempel waktu dan status, kami dapat menanganinya sebagai pengembangan aplikasi Windows.
Konsultasi teknis dan tinjauan desain
Jika Anda ingin memutuskan apakah akan mengumpulkan data dengan OPC UA atau memakai Modbus/TCP atau komunikasi khusus dari produsen, serta bagaimana mengelola sertifikat, kami dapat menanganinya sebagai konsultasi teknis dan tinjauan desain.
Pertanyaan yang sering diajukan
Pertanyaan yang sering muncul dalam konsultasi tentang topik artikel ini.
- Apa beda OPC UA dan OPC Classic (OPC DA)?
- OPC Classic adalah kumpulan spesifikasi yang bertukar data melalui COM/DCOM Windows. OPC UA adalah spesifikasi yang diterbitkan pada 2008, tidak bergantung pada sistem operasi tertentu, dan menyatukan fungsi-fungsi Classic. Klien OPC UA juga berjalan di luar Windows dan tidak memerlukan pengaturan DCOM.
- Saat mengumpulkan nilai dengan OPC UA, apakah cukup membacanya pada interval tetap?
- Jika nilainya sedikit dan intervalnya panjang, nilai bisa dikumpulkan dengan membacanya. Untuk mengikuti perubahan nilai, ada cara lain, yaitu langganan: pengambilan sampel diserahkan ke server dan server memberi tahu setiap perubahan. Cara mana pun yang dipakai, catat kode status dan stempel waktu yang dikembalikan bersama nilai.
- Mengapa saat terhubung muncul BadCertificateUntrusted?
- Karena klien belum memercayai sertifikat server. Pustaka .NET dari OPC Foundation menyimpan sertifikat yang ditolak di penyimpanan rejected. Pastikan sidik jari sertifikat bersama administrator server, lalu pindahkan ke penyimpanan trusted. Batasi pengaturan yang menerima sertifikat secara otomatis untuk lingkungan pengembangan saja.
- Berapa nomor port OPC UA?
- IANA mendaftarkan 4840/TCP sebagai opcua-tcp. Namun, server yang sebenarnya bisa saja memakai port lain, jadi periksa di pengaturan peralatan. Jika server berjalan di Windows, lalu lintas ke port itu harus diizinkan di Windows Firewall, dan jika ada perangkat jaringan di antaranya, juga di perangkat tersebut.
Profil penulis
Halaman perkenalan penulis artikel.
Go Komura
Perwakilan KomuraSoft LLC
Berfokus pada pengembangan perangkat lunak Windows, konsultasi teknis, dan investigasi bug, dengan keunggulan pada proyek yang masih memiliki aset yang sudah ada dan investigasi gangguan yang penyebabnya sulit terlihat.