Pengantar OPC UA ── Mengumpulkan data PLC dan peralatan di aplikasi Windows

· · Windows, OPC UA, Manufaktur, PLC, C#, .NET, Komunikasi, Sertifikat

Posting di X
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.

Perbedaan OPC Classic dan OPC UADiagram 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.Menyatukan fungsiOPC ClassicBerjalan di atas COM/DCOM (Windows)Spesifikasi terpisah DA, A&E, HDAOPC UA (2008)Tidak bergantung pada platform tertentuDistandarkan 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.

Konfigurasi yang diujiDiagram 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.opc.tcp, SignAndEncryptKlien C# (LineCollector)Server peralatan simulasi (asyncua)Pustaka .NET OPC Foundation 2.0.1Empat 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.

Ruang alamat peralatan simulasiDiagram yang menunjukkan bahwa di bawah folder Objects terdapat objek Line1, dan di bawahnya terdapat empat variabel, yaitu Temperature, PartCount, Running, dan Setpoint.ObjectsLine1 (objek)Temperature (variabel)PartCount (variabel)Running (variabel)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.

Alur membuat NodeId dari URI namespaceDiagram yang menunjukkan bahwa klien mencari URI namespace di NamespaceArray server untuk mendapatkan indeks, lalu menggabungkan indeks itu dengan pengenal untuk membuat NodeId.URI namespaceNamespaceArray milik serverIndeks (dalam contoh ini 2)NodeId ns=2;s=Line1.TemperaturePengenal Line1.Temperature

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.

Isi DataValueDiagram 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.Jika BadDataValueNilaiKode statusSourceTimestamp (waktu sumber)ServerTimestamp (waktu server)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.

Alur langganan dan MonitoredItemDiagram 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.Interval pengambilan sampelInterval publikasiJika tidak ada notifikasiSumber (nilai peralatan)MonitoredItemFilter (bawaan: perubahan nilai atau status)Antrean (jika meluap, Overflow)LanggananKlienKeep-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.

Perbedaan mengulang pembacaan dan berlanggananDiagram 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.Mengikuti perubahan nilaiMengulang pembacaanBerlanggananKlien menentukan interval dan meminta setiap kaliServer mengambil sampel dan hanya mengirim perubahanPerubahan lebih singkat dari interval bisa terlewat

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.

Alur hingga sertifikat dipercayaDiagram 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.Koneksi pertamaBadCertificateUntrustedSertifikat disimpan di penyimpanan rejectedPastikan sidik jari bersama administrator serverPindahkan ke penyimpanan trustedKoneksi 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”.

Pencatatan saat server berhentiDiagram 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.Selama langgananServer berhentiKlien terus mencoba koneksi ulangServer kembali, notifikasi juga kembaliNilai selama berhenti tidak sampaiCatat 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”.

Titik rawan dalam pengumpulan dataDiagram 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).Titik rawan dalam pengumpulan dataIsi catatanPersiapan koneksiNilai selama berhenti tidak sampaiStempel waktu yang manaPenanganan nilai bukan GoodPort firewallMasa 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”.

Cara memilih komunikasi dengan peralatanDiagram 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.Server OPC UAHanya Modbus/TCPHanya komunikasi produsenKomunikasi yang disediakan peralatanApa yang tersedia?Telusuri variabel lalu kumpulkanPeriksa alamat dan format di dokumentasiIkuti dokumentasi dan SDK produsenBaca register lalu ubah menjadi nilai

Gambar 11: Dengan apa data dikumpulkan sering kali ditentukan oleh apa yang disediakan peralatan.

Artikel terkait

Referensi

  1. 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

  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). ↩

  3. IANA, Service Name and Transport Protocol Port Number Registry. Pendaftaran opcua-tcp pada 4840/TCP dan mbap pada 502/TCP. ↩ ↩2 ↩3

  4. OPC Foundation, UA-.NETStandard 2.0.1: Getting started. Cara menulis klien seri 2.0, bahwa ReadValueAsync melemparkan pengecualian saat Bad, penyimpanan untuk sertifikat yang ditolak dan yang dipercaya, bahwa server secara bawaan tidak menyediakan None, serta nomor port contoh. ↩ ↩2 ↩3 ↩4 ↩5

  5. FreeOpcUa, asyncua (PyPI). Pustaka OPC UA untuk Python yang dipakai untuk server peralatan simulasi. ↩

  6. OPC Foundation, OPC 10000-4 v1.05, 5.9.2 Browse. Layanan untuk menelusuri referensi node. ↩

  7. 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. ↩

  8. OPC Foundation, OPC 10000-4 v1.05, 5.11 Attribute Service Set. Layanan Read dan Write. ↩

  9. OPC Foundation, OPC 10000-4 v1.05, 7.11 DataValue. Definisi nilai, kode status, SourceTimestamp, dan ServerTimestamp. ↩ ↩2 ↩3

  10. OPC Foundation, OPC 10000-4 v1.05, 7.38.1 StatusCode General. Good, Uncertain, dan Bad yang ditunjukkan oleh dua bit teratas. ↩ ↩2

  11. OPC Foundation, OPC 10000-4 v1.05, 5.13.1.2 Sampling interval. Bahwa interval pengambilan sampel adalah periode upaya terbaik. ↩ ↩2

  12. OPC Foundation, OPC 10000-4 v1.05, 7.22.2 DataChangeFilter. Bahwa tanpa filter, notifikasi dikirim saat nilai atau status berubah. ↩

  13. OPC Foundation, OPC 10000-4 v1.05, 5.13.1.5 Queue parameters. Ukuran antrean, cara membuang, dan bit Overflow. ↩ ↩2 ↩3

  14. OPC Foundation, OPC 10000-4 v1.05, 5.14.1.1 Subscription model. Interval publikasi dan keep-alive. ↩

  15. OPC Foundation, UA-.NETStandard 2.0.1: Subscriptions and Monitored Items Service Set. SubscribeDataChangesAsync serta interval pengambilan sampel dan ukuran antrean pada MonitoredItemOptions. ↩

  16. OPC Foundation, OPC 10000-4 v1.05, 7.20 MessageSecurityMode. Arti None, Sign, dan SignAndEncrypt. ↩

  17. OPC Foundation, UA-.NETStandard 2.0.1: Certificates. Praktik memindahkan sertifikat dari penyimpanan rejected ke penyimpanan yang dipercaya, dan bahwa AutoAcceptUntrustedCertificates jangan dipakai di produksi. ↩ ↩2

  18. OPC Foundation, OPC 10000-4 v1.05, 7.40 UserIdentityToken parameters. Empat jenis: anonim, nama pengguna, X.509, dan token yang diterbitkan. ↩

  19. OPC Foundation, OPC 10000-4 v1.05, 7.14 EndpointDescription. Daftar token pengguna yang diterima endpoint (userIdentityTokens). ↩

  20. OPC Foundation, UA-.NETStandard 2.0.1: Sessions, Reconnection, and Subscription Engines. Bahwa ManagedSession memiliki mekanisme koneksi ulang bawaan. ↩

  21. OPC Foundation, OPC 10000-4 v1.05, 5.14.6.1 Republish. Layanan untuk meminta pesan notifikasi dikirim ulang dari antrean pengiriman ulang langganan. ↩

  22. 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 terbaru dengan tag yang sama untuk mendalami topik-topik yang lebih dekat.

Ini adalah halaman topik yang dekat dengan tema ini. Dari artikel, Anda dapat melanjutkan ke layanan terkait dan artikel lainnya.

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.

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.

Kembali ke blog