namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions; /// /// Driver capability for data-change subscriptions — covers both native subscriptions /// (Galaxy MXAccess advisory, OPC UA monitored items, TwinCAT ADS notifications) and /// driver-internal polled subscriptions (Modbus, AB CIP, S7, FOCAS). The driver owns /// its polling loop where applicable; the Core just sees /// callbacks regardless of mechanism. /// public interface ISubscribable { /// /// Subscribe to data changes for a batch of attributes. /// The driver MAY fire immediately with the current value /// (initial-data callback per OPC UA convention) and again on every change. /// /// An opaque subscription handle the caller passes to . Task SubscribeAsync( IReadOnlyList fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken); /// /// Subscribe to data changes with per-tag advanced tuning (sampling interval, queue /// size, monitoring mode, deadband filter). Drivers that don't have a native concept /// of these knobs (e.g. polled drivers like Modbus) MAY ignore the per-tag knobs and /// delegate to the simple /// /// overload — the default implementation does exactly that, so existing implementers /// compile unchanged. /// /// Per-tag subscription specs. is the driver-side full reference. /// Subscription publishing interval, applied to the whole batch. /// Cancellation. /// Opaque subscription handle for . Task SubscribeAsync( IReadOnlyList tags, TimeSpan publishingInterval, CancellationToken cancellationToken) => SubscribeAsync( tags.Select(t => t.TagName).ToList(), publishingInterval, cancellationToken); /// Cancel a subscription returned by either SubscribeAsync overload. Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken); /// /// Server-pushed data-change notification. Fires whenever a subscribed attribute changes, /// and (per OPC UA convention) on subscription establishment for current values. /// event EventHandler? OnDataChange; } /// Opaque subscription identity returned by . public interface ISubscriptionHandle { /// Driver-internal subscription identifier (for diagnostics + post-mortem). string DiagnosticId { get; } } /// Event payload for . /// The handle returned by the original call. /// Driver-side full reference of the changed attribute. /// New value + quality + timestamps. public sealed record DataChangeEventArgs( ISubscriptionHandle SubscriptionHandle, string FullReference, DataValueSnapshot Snapshot); /// /// Per-tag subscription tuning. Maps onto OPC UA MonitoredItem properties for the /// OpcUaClient driver; non-OPC-UA drivers either map a subset (e.g. ADS picks up /// ) or ignore the knobs entirely and fall back to the /// simple . /// /// Driver-side full reference (e.g. ns=2;s=Foo for OPC UA). /// /// Server-side sampling rate in milliseconds. null = use the publishing interval. /// Sub-publish-interval values let a server sample faster than it publishes (queue + /// coalesce), useful for events that change between publish ticks. /// /// Server-side notification queue depth. null = driver default (1). /// /// When the server-side queue overflows: true drops oldest, false drops newest. /// null = driver default (true — preserve recency). /// /// /// Per-item monitoring mode. Reporting = sample + publish, Sampling = sample /// but suppress publishing (useful with triggering), Disabled = neither. /// /// /// Optional data-change filter (deadband + trigger semantics). null = no filter /// (every change publishes regardless of magnitude). /// public sealed record MonitoredTagSpec( string TagName, double? SamplingIntervalMs = null, uint? QueueSize = null, bool? DiscardOldest = null, SubscriptionMonitoringMode? MonitoringMode = null, DataChangeFilterSpec? DataChangeFilter = null); /// /// OPC UA DataChangeFilter spec. Mirrors the OPC UA Part 4 §7.17.2 structure but /// lives in Core.Abstractions so non-OpcUaClient drivers (e.g. Modbus, S7) can accept it /// as metadata even if they ignore the deadband mechanics. /// /// When to fire: status only / status+value / status+value+timestamp. /// Deadband mode: none / absolute (engineering units) / percent of EURange. /// /// Magnitude of the deadband. For /// this is in the variable's engineering units; for /// it's a 0..100 percentage of EURange (server returns BadFilterNotAllowed if EURange isn't set). /// public sealed record DataChangeFilterSpec( DataChangeTrigger Trigger, DeadbandType DeadbandType, double DeadbandValue); /// /// OPC UA DataChangeTrigger values. Wraps the SDK enum so Core.Abstractions doesn't /// leak an OPC-UA-stack reference into every driver project. /// public enum DataChangeTrigger { /// Fire only when StatusCode changes. Status = 0, /// Fire when StatusCode or Value changes (the OPC UA default). StatusValue = 1, /// Fire when StatusCode, Value, or SourceTimestamp changes. StatusValueTimestamp = 2, } /// OPC UA deadband-filter modes. public enum DeadbandType { /// No deadband — every value change publishes. None = 0, /// Deadband expressed in the variable's engineering units. Absolute = 1, /// Deadband expressed as 0..100 percent of the variable's EURange. Percent = 2, } /// /// Per-item subscription monitoring mode. Wraps the OPC UA SDK's MonitoringMode /// so Core.Abstractions stays SDK-free. /// public enum SubscriptionMonitoringMode { /// Item is created but neither sampling nor publishing. Disabled = 0, /// Item samples and queues but does not publish (useful with triggering). Sampling = 1, /// Item samples and publishes — the OPC UA default. Reporting = 2, }