a11ab0dc08
Part 13 defines Average/Minimum/Maximum/Range/*ActualTime over Good raw values (independent of TreatUncertainAsBad) and the SDK's calculators skip Uncertain values under the server's TreatUncertainAsBad=false. SqlServer/QuestDB value columns now use the good flag (g) instead of usable (u); new UncMin/UncMax columns feed the Part 13 Minimum/Maximum/Range status rule (Uncertain on a Bad sample or an Uncertain value beyond the Good extreme -- the SDK applies only the Bad half). An Uncertain-only interval is BadNoData. Uncertain-bearing parity datasets (in-memory + real SQL) match the SDK unmasked; the beyond-extreme divergence is pinned explicitly. Co-Authored-By: Claude <noreply@anthropic.com>
65 lines
3.4 KiB
C#
65 lines
3.4 KiB
C#
using Opc.Ua;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
|
|
|
|
/// <summary>
|
|
/// The Part 13 <see cref="AggregateConfiguration"/> processed reads are evaluated under (#677), and the rule for a
|
|
/// client-supplied one in <c>ReadProcessedDetails</c>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// The aggregate evaluators (<c>AggregateEvaluator</c> / <c>TimeWeightedAggregator</c> in
|
|
/// <c>Driver.Historian.Sql.Common</c>) are written against fixed settings, not parameterised: Uncertain time counts as
|
|
/// Good (<see cref="TreatUncertainAsBad"/> = false) in the time-weighted family; the per-sample Average / Minimum /
|
|
/// Maximum / Range / *ActualTime / Count are defined by Part 13 over Good values whatever this setting (#684), as the
|
|
/// SDK computes them under it; an interval is Good only when all of
|
|
/// it is (<see cref="PercentDataGood"/> = 100) and Bad only when none of it is non-Bad
|
|
/// (<see cref="PercentDataBad"/> = 100), otherwise <c>UncertainDataSubNormal</c>; the value past the last sample
|
|
/// is held (stepped, <see cref="UseSlopedExtrapolation"/> = false). These are also the SDK's own server defaults
|
|
/// (<c>AggregateManager.GetDefaultConfiguration</c>), which a test pins.
|
|
/// </para>
|
|
/// <para>
|
|
/// A request asking for <c>UseServerCapabilitiesDefaults</c>, or spelling out exactly these values, is served;
|
|
/// any other configuration is refused per node with <c>BadAggregateConfigurationRejected</c> rather than silently
|
|
/// answered under settings the client did not ask for (it used to be ignored).
|
|
/// </para>
|
|
/// </remarks>
|
|
public static class ServerAggregateConfiguration
|
|
{
|
|
/// <summary>Uncertain data is not treated as Bad.</summary>
|
|
public const bool TreatUncertainAsBad = false;
|
|
|
|
/// <summary>An interval is Bad only when 100 % of it is Bad.</summary>
|
|
public const byte PercentDataBad = 100;
|
|
|
|
/// <summary>An interval is Good only when 100 % of it is Good.</summary>
|
|
public const byte PercentDataGood = 100;
|
|
|
|
/// <summary>The value past the last sample is held (stepped), not sloped.</summary>
|
|
public const bool UseSlopedExtrapolation = false;
|
|
|
|
/// <summary>The server defaults as an <see cref="AggregateConfiguration"/> (explicit values, not "use defaults").</summary>
|
|
public static AggregateConfiguration Defaults => new()
|
|
{
|
|
UseServerCapabilitiesDefaults = false,
|
|
TreatUncertainAsBad = TreatUncertainAsBad,
|
|
PercentDataBad = PercentDataBad,
|
|
PercentDataGood = PercentDataGood,
|
|
UseSlopedExtrapolation = UseSlopedExtrapolation,
|
|
};
|
|
|
|
/// <summary>
|
|
/// True when a processed read with <paramref name="requested"/> can be served: none supplied,
|
|
/// <c>UseServerCapabilitiesDefaults</c>, or every setting equal to the server's.
|
|
/// </summary>
|
|
/// <param name="requested">The request's configuration (may be null).</param>
|
|
/// <returns>Whether to serve; false ⇒ <c>BadAggregateConfigurationRejected</c>.</returns>
|
|
public static bool IsServable(AggregateConfiguration? requested) =>
|
|
requested is null
|
|
|| requested.UseServerCapabilitiesDefaults
|
|
|| (requested.TreatUncertainAsBad == TreatUncertainAsBad
|
|
&& requested.PercentDataBad == PercentDataBad
|
|
&& requested.PercentDataGood == PercentDataGood
|
|
&& requested.UseSlopedExtrapolation == UseSlopedExtrapolation);
|
|
}
|