using Opc.Ua; using Opc.Ua.Client; using Opc.Ua.Configuration; using System.Security.Cryptography.X509Certificates; namespace OpcConnectionTest { class Program { [Obsolete] static async Task Main(string[] args) { Console.WriteLine("=== Experion OPC UA Connection Test ===\n"); // ⚠️ Experion 서버 IP 주소 수정 string endpoint = "opc.tcp://192.168.0.20:4840"; string pfxPath = Path.Combine(Directory.GetCurrentDirectory(), "pki/own/certs/OpcTestClient.pfx"); X509Certificate2 clientCertificate = new X509Certificate2(pfxPath, ""); Console.WriteLine($"Server: {endpoint}\n"); ISession? session = null; try { // 1. Configuration 생성 var config = new ApplicationConfiguration() { ApplicationName = "OPC Test Client", ApplicationType = ApplicationType.Client, ApplicationUri = "urn:OpcTestClient", SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = Path.GetFullPath("pki/own"), SubjectName = "CN=OpcTestClient" }, TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = Path.GetFullPath("pki/trusted") }, TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = Path.GetFullPath("pki/issuers") }, RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = Path.GetFullPath("pki/rejected") }, AutoAcceptUntrustedCertificates = true, RejectSHA1SignedCertificates = false, AddAppCertToTrustedStore = true }, TransportConfigurations = new TransportConfigurationCollection(), TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 } }; await config.ValidateAsync(ApplicationType.Client); Console.WriteLine("Step 1: Discovering endpoints..."); // 2. Endpoint 검색 var endpointConfig = EndpointConfiguration.Create(config); endpointConfig.OperationTimeout = 10000; var discoveryClient = await DiscoveryClient.CreateAsync( new Uri(endpoint), endpointConfig, config, DiagnosticsMasks.None, CancellationToken.None); var endpoints = await discoveryClient.GetEndpointsAsync(null); discoveryClient.Dispose(); if (endpoints == null || endpoints.Count == 0) { Console.WriteLine("❌ No endpoints found!"); return; } Console.WriteLine($"✅ Found {endpoints.Count} endpoint(s)"); foreach (var ep in endpoints) { Console.WriteLine($" - {ep.EndpointUrl} ({ep.SecurityMode})"); } Console.WriteLine("\nStep 2: Creating session..."); // 3. ConfiguredEndpoint 생성 var selectedEndpoint = endpoints[0]; var configuredEndpoint = new ConfiguredEndpoint( null, selectedEndpoint, EndpointConfiguration.Create(config)); // Session.Create 호출 직전에 추가 var cert = await config.SecurityConfiguration.ApplicationCertificate.Find(true); if (cert == null) { Console.WriteLine("❌ [Internal Error] 코드가 인증서 파일을 찾지 못했습니다!"); Console.WriteLine($"확인 경로: {Path.GetFullPath(config.SecurityConfiguration.ApplicationCertificate.StorePath)}"); return; } else { Console.WriteLine($"✅ 인증서 로드 성공: {cert.Subject}"); } // 4. Session 생성 (최신 API) session = await Session.Create( config, configuredEndpoint, false, "OPC Test Session", 60000, new UserIdentity(new AnonymousIdentityToken()), null); Console.WriteLine($"✅ Connected!"); Console.WriteLine($" Session ID: {session.SessionId}"); Console.WriteLine("\nStep 3: Reading server info..."); await ReadServerInfoAsync(session); Console.WriteLine("\nStep 4: Checking redundancy..."); await CheckRedundancyAsync(session); Console.WriteLine("\nStep 5: Browsing nodes..."); await BrowseNodesAsync(session); Console.WriteLine("\n✅ All tests completed!"); } catch (Exception ex) { Console.WriteLine($"\n❌ Error: {ex.Message}"); Console.WriteLine($"Type: {ex.GetType().Name}"); if (ex.InnerException != null) { Console.WriteLine($"Inner: {ex.InnerException.Message}"); } } finally { if (session != null) { try { Console.WriteLine("\nClosing session..."); await session.CloseAsync(); session.Dispose(); Console.WriteLine("✅ Session closed"); } catch { } } } Console.WriteLine("\nPress Enter to exit..."); Console.ReadLine(); } static async Task ReadServerInfoAsync(ISession session) { try { // Server State var state = await session.ReadValueAsync( new NodeId(Variables.Server_ServerStatus_State)); Console.WriteLine($" State: {state.Value}"); // Server Time var time = await session.ReadValueAsync( new NodeId(Variables.Server_ServerStatus_CurrentTime)); Console.WriteLine($" Time: {time.Value}"); } catch (Exception ex) { Console.WriteLine($" Error: {ex.Message}"); } } static async Task CheckRedundancyAsync(ISession session) { try { var serviceLevel = await session.ReadValueAsync( new NodeId(Variables.Server_ServiceLevel)); byte level = Convert.ToByte(serviceLevel.Value); Console.WriteLine($" Service Level: {level}"); if (level >= 200) Console.WriteLine(" ✅ PRIMARY server"); else if (level > 0) Console.WriteLine(" ⚠️ SECONDARY server"); else Console.WriteLine(" ℹ️ STANDALONE"); } catch (Exception ex) { Console.WriteLine($" Error: {ex.Message}"); } } static async Task BrowseNodesAsync(ISession session) { try { var browser = new Browser(session) { BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences, IncludeSubtypes = true, NodeClassMask = (int)(NodeClass.Object | NodeClass.Variable) }; var references = await browser.BrowseAsync(ObjectIds.ObjectsFolder); Console.WriteLine($" Found {references.Count} top-level nodes:"); int count = 0; foreach (var r in references) { Console.WriteLine($" {r.DisplayName} ({r.NodeClass})"); if (++count >= 5) { Console.WriteLine($" ... and {references.Count - 5} more"); break; } } } catch (Exception ex) { Console.WriteLine($" Error: {ex.Message}"); } } } }