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,
}