using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using OpcLabs.EasyOpc.UA; using OpcLabs.EasyOpc.UA.OperationModel; using OpcLabs.EasyOpc.UA.Services; namespace OpcLabsQuickTest { class Program { private static Dictionary _lastStates = new Dictionary(); private static EasyUAClient _client; private static IEasyUAClientConnectionMonitoring _clientConnectionMonitoring; static void Main(string[] args) { Console.WriteLine("OPC UA Subscription Test"); Console.WriteLine("========================\n"); // Configure your OPC UA server endpoint string endpointUrl = "opc.tcp://localhost:49320"; // Change to your server // Configure the nodes you want to monitor var monitoredItems = new[] { new EasyUAMonitoredItemArguments(null, endpointUrl, "ns=2;Data Type Examples.8 Bit Device.S Registers2.String1", 1000), new EasyUAMonitoredItemArguments(null, endpointUrl, "ns=2;Data Type Examples.8 Bit Device.K Registers.FloatArray1", 1000), new EasyUAMonitoredItemArguments(null, endpointUrl, "ns=2;Data Type Examples.8 Bit Device.K Registers.Long2", 1000) }; _client = new EasyUAClient(); // Obtain the client connection monitoring service _clientConnectionMonitoring = _client.GetService(); if (_clientConnectionMonitoring == null) { Console.WriteLine("The client connection monitoring service is not available."); return; } // Hook events _client.DataChangeNotification += Client_DataChangeNotification; _clientConnectionMonitoring.ServerConditionChanged += Client_ServerConditionChanged; Console.WriteLine("Subscribing to nodes...\n"); _client.SubscribeMultipleMonitoredItems(monitoredItems); Console.WriteLine("Monitoring for changes. Press Enter to exit...\n"); Console.ReadLine(); Dispose(); Console.WriteLine("Done."); } /// /// Disposes of the OPC client and cleans up resources /// private static void Dispose() { if (_client != null) { try { Console.WriteLine("\nDisposing client..."); // Unsubscribe from events _client.DataChangeNotification -= Client_DataChangeNotification; if (_clientConnectionMonitoring != null) { _clientConnectionMonitoring.ServerConditionChanged -= Client_ServerConditionChanged; } // Unsubscribe from all monitored items _client.UnsubscribeAllMonitoredItems(); // Dispose the client _client.Dispose(); _client = null; _clientConnectionMonitoring = null; } catch (Exception ex) { Console.WriteLine($"Error during disposal: {ex.Message}"); } } } /// /// Event handler for Server Condition Changed /// /// sending object /// server condition changed event args private static void Client_ServerConditionChanged(object sender, EasyUAServerConditionChangedEventArgs e) { try { // Display the event Console.WriteLine(e); } catch (Exception exception) { // Log the exception but don't let it propagate Console.WriteLine($"[ERROR] Exception in ServerConditionChanged handler: {exception.Message}"); } } private static void Client_DataChangeNotification(object sender, EasyUADataChangeNotificationEventArgs e) { string nodeId = e.Arguments.NodeDescriptor.NodeId.ToString(); string timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); if (e.Succeeded) { string currentState = e.AttributeData.StatusCode.ToString(); // Check if state changed if (_lastStates.TryGetValue(nodeId, out string lastState)) { if (lastState != currentState) { Console.WriteLine($"[{timestamp}] STATE CHANGED: {nodeId}"); Console.WriteLine($" Old State: {lastState}"); Console.WriteLine($" New State: {currentState}"); } } else { Console.WriteLine($"[{timestamp}] INITIAL STATE: {nodeId} = {currentState}"); } _lastStates[nodeId] = currentState; // Print value change Console.WriteLine($"[{timestamp}] {nodeId} = {e.AttributeData.Value} (Quality: {currentState})"); } else { Console.WriteLine($"[{timestamp}] ERROR: {nodeId} - {e.ErrorMessageBrief}"); } } } }