// cd ~/projects/OpcConnectionTest // 기존 파일 삭제 // rm Program.cs // # 새 파일 생성 //cat > Program.cs << 'EOF' using Opc.Ua; using Opc.Ua.Client; using Opc.Ua.Configuration; namespace OpcConnectionTest { class Program { static async Task Main(string[] args) { Console.WriteLine("=== Experion OPC UA Connection Test ===\n"); // ⚠️ Experion 서버 IP 주소 수정 string primaryEndpoint = "opc.tcp://192.168.0.20:4840"; string secondaryEndpoint = "opc.tcp://192.168.1.20:4840"; Console.WriteLine($"Primary: {primaryEndpoint}"); Console.WriteLine($"Secondary: {secondaryEndpoint}\n"); ISession? session = null; try { var config = new ApplicationConfiguration() { ApplicationName = "OPC Test", ApplicationType = ApplicationType.Client, ApplicationUri = "urn:OpcTest", SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = "OPC Foundation/CertificateStores/MachineDefault" }, AutoAcceptUntrustedCertificates = true, RejectSHA1SignedCertificates = false }, TransportConfigurations = new TransportConfigurationCollection(), TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 } }; await config.ValidateAsync(ApplicationType.Client); Console.WriteLine("Step 1: Discovering endpoints..."); var endpoints = await DiscoverAsync(config, primaryEndpoint); if (endpoints.Count == 0) { Console.WriteLine("❌ No endpoints found!"); return; } Console.WriteLine($"✅ Found {endpoints.Count} endpoint(s)"); Console.WriteLine("\nStep 2: Connecting..."); session = await ConnectAsync(config, endpoints[0]); if (session == null) { Console.WriteLine("❌ Connection failed!"); return; } Console.WriteLine($"✅ Connected! ID: {session.SessionId}"); Console.WriteLine("\nStep 3: Reading server info..."); await ReadInfoAsync(session); Console.WriteLine("\nStep 4: Checking redundancy..."); await CheckRedundancyAsync(session); Console.WriteLine("\n✅ Test completed!"); } catch (Exception ex) { Console.WriteLine($"\n❌ Error: {ex.Message}"); } finally { if (session != null) { await session.CloseAsync(); session.Dispose(); } } Console.WriteLine("\nPress Enter to exit..."); Console.ReadLine(); } static async Task DiscoverAsync( ApplicationConfiguration config, string url) { try { var epConfig = EndpointConfiguration.Create(config); epConfig.OperationTimeout = 10000; var client = await DiscoveryClient.CreateAsync( new Uri(url), epConfig, config, DiagnosticsMasks.None, CancellationToken.None); var eps = await client.GetEndpointsAsync(null); client.Dispose(); return eps; } catch { return new EndpointDescriptionCollection(); } } static async Task ConnectAsync( ApplicationConfiguration config, EndpointDescription ep) { try { var epConfig = EndpointConfiguration.Create(config); var configEp = new ConfiguredEndpoint(null, ep, epConfig); var channel = SessionChannel.Create( config, configEp.Description, configEp.Configuration, X509CertificateValidator.TolerateAll, null); var sess = new Session(channel, config, configEp, null); await sess.OpenAsync( config.ApplicationName, 60000, new UserIdentity(new AnonymousIdentityToken()), null, CancellationToken.None); return sess; } catch { return null; } } static async Task ReadInfoAsync(ISession s) { try { var v1 = await s.ReadValueAsync(new NodeId(Variables.Server_ServerStatus_State)); Console.WriteLine($" State: {v1.Value}"); var v2 = await s.ReadValueAsync(new NodeId(Variables.Server_ServerStatus_CurrentTime)); Console.WriteLine($" Time: {v2.Value}"); } catch (Exception ex) { Console.WriteLine($" Failed: {ex.Message}"); } } static async Task CheckRedundancyAsync(ISession s) { try { var v = await s.ReadValueAsync(new NodeId(Variables.Server_ServiceLevel)); byte level = Convert.ToByte(v.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($" Failed: {ex.Message}"); } } } }