using CliFx; using CliFx.Attributes; using CliFx.Infrastructure; using Opc.Ua; using Opc.Ua.Client; namespace OpcUaCli.Commands; [Command("subscribe", Description = "Monitor a node for value changes")] public class SubscribeCommand : ICommand { /// /// Gets the OPC UA endpoint URL to connect to before subscribing. /// [CommandOption("url", 'u', Description = "OPC UA server endpoint URL", IsRequired = true)] public string Url { get; init; } = default!; /// /// Gets the node identifier to monitor for value changes. /// [CommandOption("node", 'n', Description = "Node ID to monitor", IsRequired = true)] public string NodeId { get; init; } = default!; /// /// Gets the sampling and publishing interval, in milliseconds, for the monitored item. /// [CommandOption("interval", 'i', Description = "Polling interval in milliseconds")] public int Interval { get; init; } = 1000; /// /// Connects to the OPC UA endpoint and streams monitored-item notifications until cancellation. /// /// The console used to display subscription updates. public async ValueTask ExecuteAsync(IConsole console) { using var session = await OpcUaHelper.ConnectAsync(Url); var subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = Interval, DisplayName = "CLI Subscription" }; var item = new MonitoredItem(subscription.DefaultItem) { StartNodeId = new NodeId(NodeId), DisplayName = NodeId, SamplingInterval = Interval }; item.Notification += (_, e) => { if (e.NotificationValue is MonitoredItemNotification notification) { console.Output.WriteLine( $"[{notification.Value.SourceTimestamp:O}] {NodeId} = {notification.Value.Value} ({notification.Value.StatusCode})"); } }; subscription.AddItem(item); session.AddSubscription(subscription); await subscription.CreateAsync(); await console.Output.WriteLineAsync( $"Subscribed to {NodeId} (interval: {Interval}ms). Press Ctrl+C to stop."); var ct = console.RegisterCancellationHandler(); try { await Task.Delay(Timeout.Infinite, ct); } catch (OperationCanceledException) { } await console.Output.WriteLineAsync("Unsubscribed."); } }