@@ -20,7 +20,29 @@ public interface ISubscribable
|
||||
TimeSpan publishingInterval,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>Cancel a subscription returned by <see cref="SubscribeAsync"/>.</summary>
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <see cref="SubscribeAsync(IReadOnlyList{string}, TimeSpan, CancellationToken)"/>
|
||||
/// overload — the default implementation does exactly that, so existing implementers
|
||||
/// compile unchanged.
|
||||
/// </summary>
|
||||
/// <param name="tags">Per-tag subscription specs. <see cref="MonitoredTagSpec.TagName"/> is the driver-side full reference.</param>
|
||||
/// <param name="publishingInterval">Subscription publishing interval, applied to the whole batch.</param>
|
||||
/// <param name="cancellationToken">Cancellation.</param>
|
||||
/// <returns>Opaque subscription handle for <see cref="UnsubscribeAsync"/>.</returns>
|
||||
Task<ISubscriptionHandle> SubscribeAsync(
|
||||
IReadOnlyList<MonitoredTagSpec> tags,
|
||||
TimeSpan publishingInterval,
|
||||
CancellationToken cancellationToken)
|
||||
=> SubscribeAsync(
|
||||
tags.Select(t => t.TagName).ToList(),
|
||||
publishingInterval,
|
||||
cancellationToken);
|
||||
|
||||
/// <summary>Cancel a subscription returned by either <c>SubscribeAsync</c> overload.</summary>
|
||||
Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -30,7 +52,7 @@ public interface ISubscribable
|
||||
event EventHandler<DataChangeEventArgs>? OnDataChange;
|
||||
}
|
||||
|
||||
/// <summary>Opaque subscription identity returned by <see cref="ISubscribable.SubscribeAsync"/>.</summary>
|
||||
/// <summary>Opaque subscription identity returned by <see cref="ISubscribable.SubscribeAsync(IReadOnlyList{string}, TimeSpan, CancellationToken)"/>.</summary>
|
||||
public interface ISubscriptionHandle
|
||||
{
|
||||
/// <summary>Driver-internal subscription identifier (for diagnostics + post-mortem).</summary>
|
||||
@@ -38,10 +60,99 @@ public interface ISubscriptionHandle
|
||||
}
|
||||
|
||||
/// <summary>Event payload for <see cref="ISubscribable.OnDataChange"/>.</summary>
|
||||
/// <param name="SubscriptionHandle">The handle returned by the original <see cref="ISubscribable.SubscribeAsync"/> call.</param>
|
||||
/// <param name="SubscriptionHandle">The handle returned by the original <see cref="ISubscribable.SubscribeAsync(IReadOnlyList{string}, TimeSpan, CancellationToken)"/> call.</param>
|
||||
/// <param name="FullReference">Driver-side full reference of the changed attribute.</param>
|
||||
/// <param name="Snapshot">New value + quality + timestamps.</param>
|
||||
public sealed record DataChangeEventArgs(
|
||||
ISubscriptionHandle SubscriptionHandle,
|
||||
string FullReference,
|
||||
DataValueSnapshot Snapshot);
|
||||
|
||||
/// <summary>
|
||||
/// Per-tag subscription tuning. Maps onto OPC UA <c>MonitoredItem</c> properties for the
|
||||
/// OpcUaClient driver; non-OPC-UA drivers either map a subset (e.g. ADS picks up
|
||||
/// <see cref="SamplingIntervalMs"/>) or ignore the knobs entirely and fall back to the
|
||||
/// simple <see cref="ISubscribable.SubscribeAsync(IReadOnlyList{string}, TimeSpan, CancellationToken)"/>.
|
||||
/// </summary>
|
||||
/// <param name="TagName">Driver-side full reference (e.g. <c>ns=2;s=Foo</c> for OPC UA).</param>
|
||||
/// <param name="SamplingIntervalMs">
|
||||
/// Server-side sampling rate in milliseconds. <c>null</c> = 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.
|
||||
/// </param>
|
||||
/// <param name="QueueSize">Server-side notification queue depth. <c>null</c> = driver default (1).</param>
|
||||
/// <param name="DiscardOldest">
|
||||
/// When the server-side queue overflows: <c>true</c> drops oldest, <c>false</c> drops newest.
|
||||
/// <c>null</c> = driver default (true — preserve recency).
|
||||
/// </param>
|
||||
/// <param name="MonitoringMode">
|
||||
/// Per-item monitoring mode. <c>Reporting</c> = sample + publish, <c>Sampling</c> = sample
|
||||
/// but suppress publishing (useful with triggering), <c>Disabled</c> = neither.
|
||||
/// </param>
|
||||
/// <param name="DataChangeFilter">
|
||||
/// Optional data-change filter (deadband + trigger semantics). <c>null</c> = no filter
|
||||
/// (every change publishes regardless of magnitude).
|
||||
/// </param>
|
||||
public sealed record MonitoredTagSpec(
|
||||
string TagName,
|
||||
double? SamplingIntervalMs = null,
|
||||
uint? QueueSize = null,
|
||||
bool? DiscardOldest = null,
|
||||
SubscriptionMonitoringMode? MonitoringMode = null,
|
||||
DataChangeFilterSpec? DataChangeFilter = null);
|
||||
|
||||
/// <summary>
|
||||
/// OPC UA <c>DataChangeFilter</c> 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.
|
||||
/// </summary>
|
||||
/// <param name="Trigger">When to fire: status only / status+value / status+value+timestamp.</param>
|
||||
/// <param name="DeadbandType">Deadband mode: none / absolute (engineering units) / percent of EURange.</param>
|
||||
/// <param name="DeadbandValue">
|
||||
/// Magnitude of the deadband. For <see cref="OtOpcUa.Core.Abstractions.DeadbandType.Absolute"/>
|
||||
/// this is in the variable's engineering units; for <see cref="OtOpcUa.Core.Abstractions.DeadbandType.Percent"/>
|
||||
/// it's a 0..100 percentage of EURange (server returns BadFilterNotAllowed if EURange isn't set).
|
||||
/// </param>
|
||||
public sealed record DataChangeFilterSpec(
|
||||
DataChangeTrigger Trigger,
|
||||
DeadbandType DeadbandType,
|
||||
double DeadbandValue);
|
||||
|
||||
/// <summary>
|
||||
/// OPC UA <c>DataChangeTrigger</c> values. Wraps the SDK enum so Core.Abstractions doesn't
|
||||
/// leak an OPC-UA-stack reference into every driver project.
|
||||
/// </summary>
|
||||
public enum DataChangeTrigger
|
||||
{
|
||||
/// <summary>Fire only when StatusCode changes.</summary>
|
||||
Status = 0,
|
||||
/// <summary>Fire when StatusCode or Value changes (the OPC UA default).</summary>
|
||||
StatusValue = 1,
|
||||
/// <summary>Fire when StatusCode, Value, or SourceTimestamp changes.</summary>
|
||||
StatusValueTimestamp = 2,
|
||||
}
|
||||
|
||||
/// <summary>OPC UA deadband-filter modes.</summary>
|
||||
public enum DeadbandType
|
||||
{
|
||||
/// <summary>No deadband — every value change publishes.</summary>
|
||||
None = 0,
|
||||
/// <summary>Deadband expressed in the variable's engineering units.</summary>
|
||||
Absolute = 1,
|
||||
/// <summary>Deadband expressed as 0..100 percent of the variable's EURange.</summary>
|
||||
Percent = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Per-item subscription monitoring mode. Wraps the OPC UA SDK's <c>MonitoringMode</c>
|
||||
/// so Core.Abstractions stays SDK-free.
|
||||
/// </summary>
|
||||
public enum SubscriptionMonitoringMode
|
||||
{
|
||||
/// <summary>Item is created but neither sampling nor publishing.</summary>
|
||||
Disabled = 0,
|
||||
/// <summary>Item samples and queues but does not publish (useful with triggering).</summary>
|
||||
Sampling = 1,
|
||||
/// <summary>Item samples and publishes — the OPC UA default.</summary>
|
||||
Reporting = 2,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user