diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipDriver.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipDriver.cs index 2d6c6d06..78108f1d 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipDriver.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/AbCipDriver.cs @@ -24,7 +24,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip; /// (called in ); the library's own finalizer /// handles GC-collected tags. /// -public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, +public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IBatchSubscribable, IHostConnectivityProbe, IPerCallHostResolver, IAlarmSource, ISkippedTagReporter, IDisposable, IAsyncDisposable { /// Authored tags this driver could not build into its poll table (Gitea #541). @@ -114,6 +114,11 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery, /// Occurs when a subscribed tag's value changes. public event EventHandler? OnDataChange; + /// Occurs once per poll cycle carrying every tag that changed in that cycle. The driver raises + /// BOTH events for every burst — this one once, and once per changed tag — so + /// a consumer must subscribe to EXACTLY ONE of the two or it double-delivers. + public event EventHandler? OnDataChangeBatch; + /// Occurs when a device's host connectivity status changes. public event EventHandler? OnHostStatusChanged; @@ -151,7 +156,9 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery, onChange: (handle, tagRef, snapshot) => OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)), onError: HandlePollError, - backoffCap: PollBackoffCap); + backoffCap: PollBackoffCap, + onBatch: (handle, items) => + OnDataChangeBatch?.Invoke(this, new DataChangeBatchEventArgs(handle, items))); _alarmProjection = new AbCipAlarmProjection(this, _options.AlarmPollInterval, _logger); } diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS/FocasDriver.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS/FocasDriver.cs index 8c9aabfc..8ec0a047 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS/FocasDriver.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS/FocasDriver.cs @@ -18,7 +18,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS; /// + the default makes misconfigured servers /// fail fast. /// -public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, +public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IBatchSubscribable, IHostConnectivityProbe, IPerCallHostResolver, IAlarmSource, ISkippedTagReporter, IDisposable, IAsyncDisposable { /// Authored tags this driver could not build into its poll table (Gitea #541). FOCAS has three @@ -80,6 +80,10 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery, /// Occurs when data changes on a subscribed tag. public event EventHandler? OnDataChange; + /// Occurs once per poll cycle carrying every tag that changed in that cycle. The driver raises + /// BOTH events for every burst — this one once, and once per changed tag — so + /// a consumer must subscribe to EXACTLY ONE of the two or it double-delivers. + public event EventHandler? OnDataChangeBatch; /// Occurs when a device host connection status changes. public event EventHandler? OnHostStatusChanged; /// Occurs when an alarm event is raised. @@ -112,7 +116,9 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery, onChange: (handle, tagRef, snapshot) => OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)), onError: HandlePollError, - backoffCap: PollBackoffCap); + backoffCap: PollBackoffCap, + onBatch: (handle, items) => + OnDataChangeBatch?.Invoke(this, new DataChangeBatchEventArgs(handle, items))); } /// True when the supplied DriverConfig JSON carries a real body. The bootstrapper always passes