private MeasurementStateFlags ConvertStatusFlags(AFValueStatus status) { MeasurementStateFlags flags = MeasurementStateFlags.Normal; if ((status & AFValueStatus.Bad) > 0) { flags |= MeasurementStateFlags.BadData; } if ((status & AFValueStatus.Questionable) > 0) { flags |= MeasurementStateFlags.SuspectData; } if ((status & AFValueStatus.BadSubstituteValue) > 0) { flags |= MeasurementStateFlags.CalculationError | MeasurementStateFlags.BadData; } if ((status & AFValueStatus.UncertainSubstituteValue) > 0) { flags |= MeasurementStateFlags.CalculationError | MeasurementStateFlags.SuspectData; } if ((status & AFValueStatus.Substituted) > 0) { flags |= MeasurementStateFlags.CalculatedValue; } return(flags); }
protected MeasurementFlags GetMeasurementFlags(IMeasurement measurement) { MeasurementStateFlags tslFlags = measurement.StateFlags; // Time-series Library Measurement State Flags MeasurementFlags ecaflags = MeasurementFlags.Normal; // openECA Measurement Flags MeasurementStateFlags badValueFlags = MeasurementStateFlags.BadData | MeasurementStateFlags.SuspectData | MeasurementStateFlags.ReceivedAsBad | MeasurementStateFlags.DiscardedValue | MeasurementStateFlags.MeasurementError; if ((tslFlags & badValueFlags) != MeasurementStateFlags.Normal) { ecaflags |= MeasurementFlags.BadValue; } MeasurementStateFlags badTimeFlags = MeasurementStateFlags.BadTime | MeasurementStateFlags.SuspectTime | MeasurementStateFlags.LateTimeAlarm | MeasurementStateFlags.FutureTimeAlarm; if ((tslFlags & badTimeFlags) != MeasurementStateFlags.Normal) { ecaflags |= MeasurementFlags.BadTime; } MeasurementStateFlags calculatedValueFlags = MeasurementStateFlags.CalculatedValue | MeasurementStateFlags.UpSampled | MeasurementStateFlags.DownSampled; if ((tslFlags & calculatedValueFlags) != MeasurementStateFlags.Normal) { ecaflags |= MeasurementFlags.CalculatedValue; } MeasurementStateFlags unreasonableValueFlags = MeasurementStateFlags.OverRangeError | MeasurementStateFlags.UnderRangeError | MeasurementStateFlags.AlarmHigh | MeasurementStateFlags.AlarmLow | MeasurementStateFlags.WarningHigh | MeasurementStateFlags.WarningLow | MeasurementStateFlags.FlatlineAlarm | MeasurementStateFlags.ComparisonAlarm | MeasurementStateFlags.ROCAlarm | MeasurementStateFlags.CalculationError | MeasurementStateFlags.CalculationWarning | MeasurementStateFlags.SystemError | MeasurementStateFlags.SystemWarning; if ((tslFlags & unreasonableValueFlags) != MeasurementStateFlags.Normal) { ecaflags |= MeasurementFlags.UnreasonableValue; } return(ecaflags); }
public bool Update(Measurement measurement) { double value = measurement.Value; DateTime timestamp = new DateTime(measurement.Timestamp, DateTimeKind.Utc); if (StartTimestamp == default) { StartTimestamp = timestamp; } // Check for stale point if (LastTimestamp != default && (timestamp - LastTimestamp).TotalMilliseconds > s_settings.WindowSize) { Reset(); return(false); } LastTimestamp = timestamp; if (value < Minimum) { Minimum = value; } if (value > Maximum) { Maximum = value; } Total += value; Count++; Flags |= measurement.Flags; return((timestamp - StartTimestamp).TotalMilliseconds > s_settings.WindowSize); }
/// <summary> /// Initializes the adapter's settings. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; // Load required parameters if (settings.TryGetValue(nameof(SourceMeasurements), out setting)) { m_sourceMeasurements = ParseInputMeasurementKeys(DataSource, true, setting); } else { throw new ArgumentException("Missing required connection string parameter: SourceMeasurements", nameof(SourceMeasurements)); } if (settings.TryGetValue(nameof(DestinationMeasurements), out setting)) { m_destinationMeasurements = ParseInputMeasurementKeys(DataSource, true, setting); } else { throw new ArgumentException("Missing required connection string parameter: DestinationMeasurements", nameof(DestinationMeasurements)); } if (m_sourceMeasurements.Length != m_destinationMeasurements.Length) { throw new ArgumentException($"Source and destination measurements are parallel arrays, therefore their lengths must match - Src: {m_sourceMeasurements.Length}, Dst: {m_destinationMeasurements.Length}"); } InputMeasurementKeys = m_sourceMeasurements.Concat(m_destinationMeasurements).ToArray(); Dictionary <MeasurementKey, MeasurementKey> sourceToDestinationLookup = m_sourceMeasurements .Zip(m_destinationMeasurements, (Src, Dst) => new { Src, Dst }) .ToDictionary(obj => obj.Src, obj => obj.Dst); Dictionary <MeasurementKey, MeasurementStateFlags> destinationToStateLookup = m_destinationMeasurements .ToDictionary(dst => dst, dst => MeasurementStateFlags.Normal); m_sourceToDestinationLookup = sourceToDestinationLookup; m_destinationToStateLookup = new ConcurrentDictionary <MeasurementKey, MeasurementStateFlags>(destinationToStateLookup); // Load optional parameters if (!settings.TryGetValue(nameof(Flags), out setting) || !Enum.TryParse(setting, out m_flags)) { m_flags = DefaultFlags; } if (settings.TryGetValue(nameof(SupportsTemporalProcessing), out setting)) { m_supportsTemporalProcessing = setting.ParseBoolean(); } else { m_supportsTemporalProcessing = DefaultSupportsTemporalProcessing; } }
// Processes measurements in the queue. private void ProcessMeasurements(IList <IMeasurement> measurements) { SignalAlarms alarms; Alarm activeAlarm; Alarm firstRaisedAlarm; List <IMeasurement> alarmEvents; alarmEvents = new List <IMeasurement>(); foreach (IMeasurement measurement in measurements) { lock (m_alarmLock) { // Get alarms that apply to the measurement being processed if (!m_alarmLookup.TryGetValue(measurement.ID, out alarms)) { continue; } // Get the currently active alarm activeAlarm = alarms.Alarms.FirstOrDefault(alarm => alarm.State == AlarmState.Raised); // Test each alarm to determine whether their states have changed alarmEvents.AddRange(alarms.Alarms.Where(alarm => alarm.Test(measurement)).Select(alarm => CreateAlarmEvent(measurement.Timestamp, alarm))); // Get the alarm that will become the currently active alarm firstRaisedAlarm = alarms.Alarms.FirstOrDefault(alarm => alarm.State == AlarmState.Raised); } // Update alarm log to show changes in state of active alarms if (firstRaisedAlarm != activeAlarm) { LogStateChange(measurement.ID, activeAlarm, firstRaisedAlarm, measurement.Timestamp, measurement.Value); } const MeasurementStateFlags ErrorFlags = MeasurementStateFlags.BadData | MeasurementStateFlags.BadTime | MeasurementStateFlags.SystemError; Func <MeasurementStateFlags, bool> hasError = flags => (flags & ErrorFlags) != MeasurementStateFlags.Normal; if (hasError(measurement.StateFlags)) { if ((object)firstRaisedAlarm != null && firstRaisedAlarm.Severity > AlarmSeverity.None) { alarms.Statistics.IncrementCounter(firstRaisedAlarm); } } } if (alarmEvents.Count > 0) { // Update alarm history by sending // new alarm events into the system OnNewMeasurements(alarmEvents); Interlocked.Add(ref m_eventCount, alarmEvents.Count); } // Increment total count of processed measurements IncrementProcessedMeasurements(measurements.Count); }
public Measurement(System.Guid signalID, long timestamp, double value = double.NaN, MeasurementStateFlags flags = MeasurementStateFlags.Normal) { Value = value; Timestamp = timestamp; Flags = flags; this.SetSignalID(signalID); }
public void Reset() { StartTimestamp = default; LastTimestamp = default; Minimum = double.MaxValue; Maximum = double.MinValue; Total = default; Count = default; Flags = MeasurementStateFlags.Normal; }
/// <summary> /// Initializes the <see cref="BestValueSelector"/>. /// </summary> public override void Initialize() { base.Initialize(); if (OutputMeasurements?.Length != 1 && OutputMeasurements?.Length != 2) { throw new ArgumentException($"Exactly one or two output measurement must be defined. Amount defined: {OutputMeasurements?.Length ?? 0}"); } Dictionary <string, string> settings = Settings; string setting; if (settings.TryGetValue(nameof(PublishBadValues), out setting)) { m_publishBadValues = setting.ParseBoolean(); } else { m_publishBadValues = DefaultHandleZeroAsBad; } if (!settings.TryGetValue(nameof(BadFlags), out setting) || !Enum.TryParse(setting, out m_badFlags)) { m_badFlags = DefaultBadFlags; } if (settings.TryGetValue(nameof(HandleZeroAsBad), out setting)) { m_handleZeroAsBad = setting.ParseBoolean(); } else { m_handleZeroAsBad = DefaultHandleZeroAsBad; } if (settings.TryGetValue(nameof(HandleNaNAsBad), out setting)) { m_handleNaNAsBad = setting.ParseBoolean(); } else { m_handleNaNAsBad = DefaultHandleNaNAsBad; } if (settings.TryGetValue(nameof(SupportsTemporalProcessing), out setting)) { m_supportsTemporalProcessing = setting.ParseBoolean(); } else { m_supportsTemporalProcessing = DefaultSupportsTemporalProcessing; } }
/// <summary> /// Initializes the adapter's settings. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; MeasurementStateFlags flags; if (settings.TryGetValue(nameof(Flags), out setting) && Enum.TryParse(setting, out flags)) { m_flags = flags; } else { m_flags = DefaultFlags; } if (settings.TryGetValue(nameof(SupportsTemporalProcessing), out setting)) { m_supportsTemporalProcessing = setting.ParseBoolean(); } else { m_supportsTemporalProcessing = DefaultSupportsTemporalProcessing; } const string AlarmTable = "Alarms"; const string AlarmIDField = "AssociatedMeasurementID"; const string SignalIDField = "SignalID"; HashSet <MeasurementKey> inputMeasurementKeys = new HashSet <MeasurementKey>(InputMeasurementKeys); Func <DataRow, string, MeasurementKey> getKey = (row, field) => MeasurementKey.LookUpBySignalID(row.ConvertField <Guid>(field)); Dictionary <MeasurementKey, MeasurementKey> alarmToSignalLookup = DataSource.Tables[AlarmTable] .Select(AlarmIDField + " IS NOT NULL") .Select(row => new { AlarmID = getKey(row, AlarmIDField), SignalID = getKey(row, SignalIDField) }) .Where(obj => inputMeasurementKeys.Contains(obj.AlarmID)) .Where(obj => inputMeasurementKeys.Contains(obj.SignalID)) .ToDictionary(obj => obj.AlarmID, obj => obj.SignalID); HashSet <MeasurementKey> raisedAlarms = new HashSet <MeasurementKey>(AlarmAdapter.Default?.GetRaisedAlarms() .Select(alarm => alarm.AssociatedMeasurementID.GetValueOrDefault()) .Select(alarmID => MeasurementKey.LookUpBySignalID(alarmID)) ?? Enumerable.Empty <MeasurementKey>()); Dictionary <MeasurementKey, bool> signalToAlarmStateLookup = alarmToSignalLookup.Values .ToDictionary(key => key, key => raisedAlarms.Contains(key)); m_alarmToSignalLookup = alarmToSignalLookup; m_signalToAlarmStateLookup = new ConcurrentDictionary <MeasurementKey, bool>(signalToAlarmStateLookup); }
protected MeasurementFlags GetMeasurementFlags(IMeasurement measurement) { MeasurementStateFlags tslFlags = measurement.StateFlags; // Time-series Library Measurement State Flags MeasurementFlags ecaflags = MeasurementFlags.Normal; // openECA Measurement Flags if (tslFlags.HasFlag(MeasurementStateFlags.BadData) || tslFlags.HasFlag(MeasurementStateFlags.SuspectData) || tslFlags.HasFlag(MeasurementStateFlags.ReceivedAsBad) || tslFlags.HasFlag(MeasurementStateFlags.DiscardedValue) || tslFlags.HasFlag(MeasurementStateFlags.MeasurementError)) { ecaflags |= MeasurementFlags.BadValue; } if (tslFlags.HasFlag(MeasurementStateFlags.BadTime) || tslFlags.HasFlag(MeasurementStateFlags.SuspectTime) || tslFlags.HasFlag(MeasurementStateFlags.LateTimeAlarm) || tslFlags.HasFlag(MeasurementStateFlags.FutureTimeAlarm)) { ecaflags |= MeasurementFlags.BadTime; } if (tslFlags.HasFlag(MeasurementStateFlags.CalcuatedValue) || tslFlags.HasFlag(MeasurementStateFlags.UpSampled) || tslFlags.HasFlag(MeasurementStateFlags.DownSampled)) { ecaflags |= MeasurementFlags.CalculatedValue; } if (tslFlags.HasFlag(MeasurementStateFlags.OverRangeError) || tslFlags.HasFlag(MeasurementStateFlags.UnderRangeError) || tslFlags.HasFlag(MeasurementStateFlags.AlarmHigh) || tslFlags.HasFlag(MeasurementStateFlags.AlarmLow) || tslFlags.HasFlag(MeasurementStateFlags.WarningHigh) || tslFlags.HasFlag(MeasurementStateFlags.WarningLow) || tslFlags.HasFlag(MeasurementStateFlags.FlatlineAlarm) || tslFlags.HasFlag(MeasurementStateFlags.ComparisonAlarm) || tslFlags.HasFlag(MeasurementStateFlags.ROCAlarm) || tslFlags.HasFlag(MeasurementStateFlags.CalculationError) || tslFlags.HasFlag(MeasurementStateFlags.CalculationWarning) || tslFlags.HasFlag(MeasurementStateFlags.SystemError) || tslFlags.HasFlag(MeasurementStateFlags.SystemWarning)) { ecaflags |= MeasurementFlags.UnreasonableValue; } return(ecaflags); }
/// <summary> /// Gets derived quality flags from specified value and time quality. /// </summary> /// <param name="valueQualityIsGood">Flag that determines if value quality is good.</param> /// <param name="timeQualityIsGood">Flag that determines if time quality is good.</param> /// <returns>Derived quality flags.</returns> public static MeasurementStateFlags From(bool valueQualityIsGood, bool timeQualityIsGood) { MeasurementStateFlags derivedQuality = MeasurementStateFlags.Normal; if (!valueQualityIsGood) { derivedQuality |= MeasurementStateFlags.BadData; } if (!timeQualityIsGood) { derivedQuality |= MeasurementStateFlags.BadTime; } return(derivedQuality); }
public static DataQualityFlags DeriveQualityFlags(this MeasurementStateFlags stateFlags) { DataQualityFlags qualityFlags = DataQualityFlags.Normal; if (stateFlags.HasFlag(MeasurementStateFlags.BadData)) { qualityFlags |= DataQualityFlags.ValueQualityIsBad; } if (stateFlags.HasFlag(MeasurementStateFlags.BadTime)) { qualityFlags |= DataQualityFlags.TimeQualityIsBad; } return(qualityFlags); }
public static MeasurementStateFlags DeriveStateFlags(this DataQualityFlags qualityFlags) { MeasurementStateFlags stateFlags = MeasurementStateFlags.Normal; if (qualityFlags.HasFlag(DataQualityFlags.ValueQualityIsBad)) { stateFlags |= MeasurementStateFlags.BadData; } if (qualityFlags.HasFlag(DataQualityFlags.TimeQualityIsBad)) { stateFlags |= MeasurementStateFlags.BadTime; } return(stateFlags); }
private int CountFlags(MeasurementStateFlags flags) { if (flags == MeasurementStateFlags.Normal) { return(0); } uint count = (uint)flags; count = count - ((count >> 1) & 0x55555555u); count = ((count >> 2) & 0x33333333u) + (count & 0x33333333u); count = ((count >> 4) + count) & 0x0F0F0F0Fu; count = ((count >> 8) + count) & 0x00FF00FFu; count = ((count >> 16) + count) & 0x0000FFFFu; return((int)count); }
/// <summary> /// Gets derived quality flags from a set of value and time quality vectors. /// </summary> /// <param name="valueQualities">Boolean vector where flag determines if value quality is good.</param> /// <param name="timeQualities">Boolean vector where flag determines if time quality is good.</param> /// <returns>Derived quality flags.</returns> public static MeasurementStateFlags From(IEnumerable <bool> valueQualities, IEnumerable <bool> timeQualities) { MeasurementStateFlags derivedQuality = MeasurementStateFlags.Normal; bool qualityIsBad(bool qualityIsGood) => !qualityIsGood; if (valueQualities.Any(qualityIsBad)) { derivedQuality |= MeasurementStateFlags.BadData; } if (timeQualities.Any(qualityIsBad)) { derivedQuality |= MeasurementStateFlags.BadTime; } return(derivedQuality); }
/// <summary> /// Gets a <see cref="MeasurementStateFlags"/> value from a <see cref="Quality"/> value. /// </summary> /// <param name="quality"><see cref="Quality"/> value to interpret.</param> /// <returns><see cref="MeasurementStateFlags"/> value from a <see cref="Quality"/> value.</returns> public static MeasurementStateFlags MeasurementQuality(this Quality quality) { MeasurementStateFlags stateFlags = MeasurementStateFlags.Normal; if (quality == Quality.DeletedFromProcessing) { stateFlags |= MeasurementStateFlags.DiscardedValue; } if (quality == Quality.Old) { stateFlags |= MeasurementStateFlags.BadTime; } if (quality == Quality.SuspectData) { stateFlags |= MeasurementStateFlags.BadData; } return(stateFlags); }
/// <summary> /// Gets derived quality flags from a set of source measurements. /// </summary> /// <param name="measurements">Source measurements.</param> /// <returns>Derived quality flags.</returns> public static MeasurementStateFlags DeriveQualityFlags(this IEnumerable <IMeasurement> measurements) { MeasurementStateFlags derivedQuality = MeasurementStateFlags.Normal; MeasurementStateFlags[] stateFlags = measurements.Select(measurement => measurement.StateFlags).ToArray(); bool dataQualityIsBad(MeasurementStateFlags flags) => (flags & MeasurementStateFlags.BadData) > 0; bool timeQualityIsBad(MeasurementStateFlags flags) => (flags & MeasurementStateFlags.BadTime) > 0; if (stateFlags.Any(dataQualityIsBad)) { derivedQuality |= MeasurementStateFlags.BadData; } if (stateFlags.Any(timeQualityIsBad)) { derivedQuality |= MeasurementStateFlags.BadTime; } return(derivedQuality); }
private void HandleSendMeasurementsCommand(ClientConnection connection, byte[] buffer, int startIndex, int length) { int index = startIndex; if (length - index < 4) { throw new Exception("Not enough bytes in buffer to parse measurement count"); } int count = BigEndian.ToInt32(buffer, index); index += sizeof(int); if (length - index < count * 36) { throw new Exception("Not enough bytes in buffer to parse all measurements"); } List <IMeasurement> measurements = new List <IMeasurement>(count); for (int i = 0; i < count; i++) { Guid signalID = buffer.ToRfcGuid(index); index += 16; DateTime timestamp = new DateTime(BigEndian.ToInt64(buffer, index)); index += sizeof(long); double value = BigEndian.ToDouble(buffer, index); index += sizeof(double); MeasurementStateFlags stateFlags = (MeasurementStateFlags)BigEndian.ToInt32(buffer, index); index += sizeof(int); measurements.Add(new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(signalID).Metadata, Timestamp = timestamp, Value = value, StateFlags = stateFlags }); } OnNewMeasurements(measurements); }
/// <summary> /// Maps <see cref="CompactMeasurementStateFlags"/> to <see cref="MeasurementStateFlags"/>. /// </summary> /// <param name="stateFlags">Flags to map.</param> /// <returns><see cref="MeasurementStateFlags"/> mapped from <see cref="CompactMeasurementStateFlags"/>.</returns> public static MeasurementStateFlags MapToFullFlags(this CompactMeasurementStateFlags stateFlags) { MeasurementStateFlags mappedStateFlags = MeasurementStateFlags.Normal; if ((stateFlags & CompactMeasurementStateFlags.DataRange) > 0) { mappedStateFlags |= DataRangeMask; } if ((stateFlags & CompactMeasurementStateFlags.DataQuality) > 0) { mappedStateFlags |= DataQualityMask; } if ((stateFlags & CompactMeasurementStateFlags.TimeQuality) > 0) { mappedStateFlags |= TimeQualityMask; } if ((stateFlags & CompactMeasurementStateFlags.SystemIssue) > 0) { mappedStateFlags |= SystemIssueMask; } if ((stateFlags & CompactMeasurementStateFlags.CalculatedValue) > 0) { mappedStateFlags |= CalculatedValueMask; } if ((stateFlags & CompactMeasurementStateFlags.DiscardedValue) > 0) { mappedStateFlags |= DiscardedValueMask; } return(mappedStateFlags); }
/// <summary> /// Maps <see cref="MeasurementStateFlags"/> to <see cref="CompactMeasurementStateFlags"/>. /// </summary> /// <param name="stateFlags">Flags to map.</param> /// <returns><see cref="CompactMeasurementStateFlags"/> mapped from <see cref="MeasurementStateFlags"/>.</returns> public static CompactMeasurementStateFlags MapToCompactFlags(this MeasurementStateFlags stateFlags) { CompactMeasurementStateFlags mappedStateFlags = CompactMeasurementStateFlags.NoFlags; if ((stateFlags & DataRangeMask) > 0) { mappedStateFlags |= CompactMeasurementStateFlags.DataRange; } if ((stateFlags & DataQualityMask) > 0) { mappedStateFlags |= CompactMeasurementStateFlags.DataQuality; } if ((stateFlags & TimeQualityMask) > 0) { mappedStateFlags |= CompactMeasurementStateFlags.TimeQuality; } if ((stateFlags & SystemIssueMask) > 0) { mappedStateFlags |= CompactMeasurementStateFlags.SystemIssue; } if ((stateFlags & CalculatedValueMask) > 0) { mappedStateFlags |= CompactMeasurementStateFlags.CalculatedValue; } if ((stateFlags & DiscardedValueMask) > 0) { mappedStateFlags |= CompactMeasurementStateFlags.DiscardedValue; } return(mappedStateFlags); }
protected MeasurementStateFlags GetMeasurementStateFlags(MeasurementFlags ecaFlags) { MeasurementStateFlags tslFlags = MeasurementStateFlags.Normal; if (ecaFlags.HasFlag(MeasurementFlags.BadValue)) { tslFlags |= MeasurementStateFlags.BadData; } if (ecaFlags.HasFlag(MeasurementFlags.BadTime)) { tslFlags |= MeasurementStateFlags.BadTime; } if (ecaFlags.HasFlag(MeasurementFlags.CalculatedValue)) { tslFlags |= MeasurementStateFlags.CalculatedValue; } if (ecaFlags.HasFlag(MeasurementFlags.UnreasonableValue)) { tslFlags |= MeasurementStateFlags.OverRangeError | MeasurementStateFlags.UnderRangeError; } if (ecaFlags.HasFlag(MeasurementFlags.UserDefinedFlag1)) { tslFlags |= MeasurementStateFlags.UserDefinedFlag1; } if (ecaFlags.HasFlag(MeasurementFlags.UserDefinedFlag2)) { tslFlags |= MeasurementStateFlags.UserDefinedFlag2; } return(tslFlags); }
/// <summary> /// Maps <see cref="MeasurementStateFlags"/> to <see cref="StatusFlags"/>. /// </summary> /// <param name="stateFlags">Flags to map.</param> /// <param name="type">Data type of measurement.</param> /// <param name="digitalSet">Flag that determines if digital value is set.</param> /// <returns><see cref="StatusFlags"/> mapped from <see cref="MeasurementStateFlags"/>.</returns> public static StatusFlags MapToStatusFlags(this MeasurementStateFlags stateFlags, DataType type = DataType.Analog, bool digitalSet = false) { StatusFlags status = StatusFlags.RTSTAT_UNUSED; if ((stateFlags & MeasurementStateFlags.ReceivedAsBad) > 0) { status |= StatusFlags.RTSTAT_UNRELIABLE; } if ((stateFlags & MeasurementStateFlags.BadTime) > 0 || (stateFlags & MeasurementStateFlags.SuspectTime) > 0 || (stateFlags & MeasurementStateFlags.LateTimeAlarm) > 0 || (stateFlags & MeasurementStateFlags.FutureTimeAlarm) > 0 || (stateFlags & MeasurementStateFlags.SystemError) > 0 || (stateFlags & MeasurementStateFlags.SystemWarning) > 0) { status |= StatusFlags.RTSTAT_OOR; } if (type == DataType.Analog) { // Point is analog if (stateFlags == MeasurementStateFlags.Normal) { status = StatusFlags.ANALOG_OK; } else { if ((stateFlags & MeasurementStateFlags.BadData) > 0 || (stateFlags & MeasurementStateFlags.SuspectData) > 0 || (stateFlags & MeasurementStateFlags.FlatlineAlarm) > 0 || (stateFlags & MeasurementStateFlags.ComparisonAlarm) > 0 || (stateFlags & MeasurementStateFlags.ROCAlarm) > 0 || (stateFlags & MeasurementStateFlags.CalculationError) > 0 || (stateFlags & MeasurementStateFlags.CalculationWarning) > 0 || (stateFlags & MeasurementStateFlags.MeasurementError) > 0) { status |= StatusFlags.ANALOG_UNRELIABLE; } if ((stateFlags & MeasurementStateFlags.OverRangeError) > 0) { status |= StatusFlags.ANALOG_HIGH_OUT_OF_RANGE; } if ((stateFlags & MeasurementStateFlags.UnderRangeError) > 0) { status |= StatusFlags.ANALOG_LOW_OUT_OF_RANGE; } if ((stateFlags & MeasurementStateFlags.AlarmHigh) > 0) { status |= StatusFlags.ANALOG_HIGH_ALARM; } if ((stateFlags & MeasurementStateFlags.AlarmLow) > 0) { status |= StatusFlags.ANALOG_LOW_ALARM; } if ((stateFlags & MeasurementStateFlags.WarningHigh) > 0) { status |= StatusFlags.ANALOG_HIGH_WARNING; } if ((stateFlags & MeasurementStateFlags.WarningLow) > 0) { status |= StatusFlags.ANALOG_LOW_WARNING; } } } else if (type == DataType.Digital) { // Point is digital if (digitalSet) { if (stateFlags == MeasurementStateFlags.Normal) { status = StatusFlags.DIGITAL_OK_SET; } else { if ((stateFlags & MeasurementStateFlags.BadData) > 0 || (stateFlags & MeasurementStateFlags.SuspectData) > 0 || (stateFlags & MeasurementStateFlags.FlatlineAlarm) > 0 || (stateFlags & MeasurementStateFlags.ComparisonAlarm) > 0 || (stateFlags & MeasurementStateFlags.ROCAlarm) > 0 || (stateFlags & MeasurementStateFlags.CalculationError) > 0 || (stateFlags & MeasurementStateFlags.CalculationWarning) > 0 || (stateFlags & MeasurementStateFlags.MeasurementError) > 0) { status |= StatusFlags.DIGITAL_UNRELIABLE_SET; } if ((stateFlags & MeasurementStateFlags.OverRangeError) > 0 || (stateFlags & MeasurementStateFlags.UnderRangeError) > 0 || (stateFlags & MeasurementStateFlags.AlarmHigh) > 0 || (stateFlags & MeasurementStateFlags.AlarmLow) > 0 || (stateFlags & MeasurementStateFlags.WarningHigh) > 0 || (stateFlags & MeasurementStateFlags.WarningLow) > 0) { status |= StatusFlags.DIGITAL_WARNING_SET; } } } else { if (stateFlags == MeasurementStateFlags.Normal) { status = StatusFlags.DIGITAL_OK_NOT_SET; } else { if ((stateFlags & MeasurementStateFlags.BadData) > 0 || (stateFlags & MeasurementStateFlags.SuspectData) > 0 || (stateFlags & MeasurementStateFlags.FlatlineAlarm) > 0 || (stateFlags & MeasurementStateFlags.ComparisonAlarm) > 0 || (stateFlags & MeasurementStateFlags.ROCAlarm) > 0 || (stateFlags & MeasurementStateFlags.CalculationError) > 0 || (stateFlags & MeasurementStateFlags.CalculationWarning) > 0 || (stateFlags & MeasurementStateFlags.MeasurementError) > 0) { status |= StatusFlags.DIGITAL_UNRELIABLE_NOT_SET; } if ((stateFlags & MeasurementStateFlags.OverRangeError) > 0 || (stateFlags & MeasurementStateFlags.UnderRangeError) > 0 || (stateFlags & MeasurementStateFlags.AlarmHigh) > 0 || (stateFlags & MeasurementStateFlags.AlarmLow) > 0 || (stateFlags & MeasurementStateFlags.WarningHigh) > 0 || (stateFlags & MeasurementStateFlags.WarningLow) > 0) { status |= StatusFlags.DIGITAL_WARNING_NOT_SET; } } } } return(status); }
/// <summary> /// Maps <see cref="MeasurementStateFlags"/> to eDNA status (short value). /// </summary> /// <param name="stateFlags">Flags to map.</param> /// <param name="type">Data type of measurement.</param> /// <param name="digitalSet">Flag that determines if digital value is set.</param> /// <returns>eDNA status mapped from <see cref="MeasurementStateFlags"/>.</returns> public static short MapToStatus(this MeasurementStateFlags stateFlags, DataType type = DataType.Analog, bool digitalSet = false) { return((short)stateFlags.MapToStatusFlags(type, digitalSet)); }
/// <summary> /// Starts a query that will read data source values, given a set of point IDs and targets, over a time range. /// </summary> /// <param name="startTime">Start-time for query.</param> /// <param name="stopTime">Stop-time for query.</param> /// <param name="interval">Interval from Grafana request.</param> /// <param name="includePeaks">Flag that determines if decimated data should include min/max interval peaks over provided time range.</param> /// <param name="targetMap">Set of IDs with associated targets to query.</param> /// <returns>Queried data source data in terms of value and time.</returns> protected override IEnumerable <DataSourceValue> QueryDataSourceValues(DateTime startTime, DateTime stopTime, string interval, bool includePeaks, Dictionary <ulong, string> targetMap) { SnapServer server = GetAdapterInstance(InstanceName)?.Server?.Host; if (server == null) { yield break; } using (SnapClient connection = SnapClient.Connect(server)) using (ClientDatabaseBase <HistorianKey, HistorianValue> database = connection.GetDatabase <HistorianKey, HistorianValue>(InstanceName)) { if (database == null) { yield break; } if (!TryParseInterval(interval, out TimeSpan resolutionInterval)) { Resolution resolution = TrendValueAPI.EstimatePlotResolution(InstanceName, startTime, stopTime, targetMap.Keys); resolutionInterval = resolution.GetInterval(); } BaselineTimeInterval timeInterval = BaselineTimeInterval.Second; if (resolutionInterval.Ticks < Ticks.PerMinute) { timeInterval = BaselineTimeInterval.Second; } else if (resolutionInterval.Ticks < Ticks.PerHour) { timeInterval = BaselineTimeInterval.Minute; } else if (resolutionInterval.Ticks == Ticks.PerHour) { timeInterval = BaselineTimeInterval.Hour; } startTime = startTime.BaselinedTimestamp(timeInterval); stopTime = stopTime.BaselinedTimestamp(timeInterval); if (startTime == stopTime) { stopTime = stopTime.AddSeconds(1.0D); } SeekFilterBase <HistorianKey> timeFilter; // Set timestamp filter resolution if (includePeaks || resolutionInterval == TimeSpan.Zero) { // Full resolution query timeFilter = TimestampSeekFilter.CreateFromRange <HistorianKey>(startTime, stopTime); } else { // Interval query timeFilter = TimestampSeekFilter.CreateFromIntervalData <HistorianKey>(startTime, stopTime, resolutionInterval, new TimeSpan(TimeSpan.TicksPerMillisecond)); } // Setup point ID selections MatchFilterBase <HistorianKey, HistorianValue> pointFilter = PointIdMatchFilter.CreateFromList <HistorianKey, HistorianValue>(targetMap.Keys); Dictionary <ulong, ulong> lastTimes = new Dictionary <ulong, ulong>(targetMap.Count); Dictionary <ulong, Peak> peaks = new Dictionary <ulong, Peak>(targetMap.Count); ulong resolutionSpan = (ulong)resolutionInterval.Ticks; if (includePeaks) { resolutionSpan *= 2UL; } // Start stream reader for the provided time window and selected points using (TreeStream <HistorianKey, HistorianValue> stream = database.Read(SortedTreeEngineReaderOptions.Default, timeFilter, pointFilter)) { HistorianKey key = new HistorianKey(); HistorianValue value = new HistorianValue(); Peak peak = Peak.Default; while (stream.Read(key, value)) { ulong pointID = key.PointID; ulong timestamp = key.Timestamp; float pointValue = value.AsSingle; if (includePeaks) { peak = peaks.GetOrAdd(pointID, _ => new Peak()); peak.Set(pointValue, timestamp); } if (resolutionSpan > 0UL && timestamp - lastTimes.GetOrAdd(pointID, 0UL) < resolutionSpan) { continue; } // New value is ready for publication string target = targetMap[pointID]; MeasurementStateFlags flags = (MeasurementStateFlags)value.Value3; if (includePeaks) { if (peak.MinTimestamp > 0UL) { yield return(new DataSourceValue { Target = target, Value = peak.Min, Time = (peak.MinTimestamp - m_baseTicks) / (double)Ticks.PerMillisecond, Flags = flags }); } if (peak.MaxTimestamp != peak.MinTimestamp) { yield return(new DataSourceValue { Target = target, Value = peak.Max, Time = (peak.MaxTimestamp - m_baseTicks) / (double)Ticks.PerMillisecond, Flags = flags }); } peak.Reset(); } else { yield return(new DataSourceValue { Target = target, Value = pointValue, Time = (timestamp - m_baseTicks) / (double)Ticks.PerMillisecond, Flags = flags }); } lastTimes[pointID] = timestamp; } } } }
/// <summary> /// Queues a collection of measurements for processing. /// </summary> /// <param name="measurements">Collection of measurements to queue for processing.</param> /// <remarks> /// Measurements are filtered against the defined <see cref="InputMeasurementKeys"/> so we override method /// so that dynamic updates to keys will be synchronized with filtering to prevent interference. /// </remarks> // IMPORTANT: TSSC is sensitive to order - always make sure this function gets called sequentially, concurrent // calls to this function can cause TSSC parsing to get out of sequence and fail public override void QueueMeasurementsForProcessing(IEnumerable <IMeasurement> measurements) { if ((object)measurements == null) { return; } if (!m_startTimeSent && measurements.Any()) { m_startTimeSent = true; IMeasurement measurement = measurements.FirstOrDefault(m => (object)m != null); Ticks timestamp = 0; if ((object)measurement != null) { timestamp = measurement.Timestamp; } m_parent.SendDataStartTime(m_clientID, timestamp); } if (m_isNaNFiltered) { measurements = measurements.Where(measurement => !double.IsNaN(measurement.Value)); } if (!measurements.Any() || !Enabled) { return; } if (TrackLatestMeasurements) { double publishInterval; // Keep track of latest measurements base.QueueMeasurementsForProcessing(measurements); publishInterval = m_publishInterval > 0 ? m_publishInterval : LagTime; if (DateTime.UtcNow.Ticks > m_lastPublishTime + Ticks.FromSeconds(publishInterval)) { List <IMeasurement> currentMeasurements = new List <IMeasurement>(); Measurement newMeasurement; // Create a new set of measurements that represent the latest known values setting value to NaN if it is old foreach (TemporalMeasurement measurement in LatestMeasurements) { MeasurementStateFlags timeQuality = measurement.Timestamp.TimeIsValid(RealTime, measurement.LagTime, measurement.LeadTime) ? MeasurementStateFlags.Normal : MeasurementStateFlags.BadTime; newMeasurement = new Measurement { Metadata = measurement.Metadata, Value = measurement.Value, Timestamp = measurement.Timestamp, StateFlags = measurement.StateFlags | timeQuality }; currentMeasurements.Add(newMeasurement); } ProcessMeasurements(currentMeasurements); } } else { ProcessMeasurements(measurements); } }