// Gets a measurement key based on a token which // may be either a signal ID or measurement key. private MeasurementKey GetKey(string token) { Guid signalID; return(Guid.TryParse(token, out signalID) ? MeasurementKey.LookUpBySignalID(signalID) : MeasurementKey.Parse(token)); }
protected IMeasurement MakeMeasurement(MetaValues meta, double value) { return(new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(meta.ID).Metadata, Timestamp = meta.Timestamp, Value = value, StateFlags = GetMeasurementStateFlags(meta.Flags) }); }
/// <summary> /// Queries the signal buffer for the collection of measurements /// between the dates specified by the given time range. /// </summary> /// <param name="signalID">The ID of the signal to be queried.</param> /// <param name="startTime">The beginning of the time range to be queried.</param> /// <param name="endTime">The end of the time range to be queried.</param> /// <returns>The collection of measurements for the signal that fall between the dates in the given time range.</returns> public IEnumerable <IMeasurement> QuerySignalBuffer(Guid signalID, DateTime startTime, DateTime endTime) { MeasurementKey key = MeasurementKey.LookUpBySignalID(signalID); if (key == MeasurementKey.Undefined) { return(Enumerable.Empty <IMeasurement>()); } return(QuerySignalBuffer(key, startTime, endTime)); }
/// <summary> /// Queries the signal buffer for the measurement whose timestamp is nearest the given timestamp, /// but only returns the measurement if its timestamp falls within a specified tolerance around the given timestamp. /// </summary> /// <param name="signalID">The ID of the signal to be queried.</param> /// <param name="timestamp">The timestamp of the measurement to be queried.</param> /// <param name="tolerance">The tolerance that determines whether the nearest measurement is valid.</param> /// <returns>The measurement whose timestamp is nearest the given timestamp or null if the measurement's timestamp falls outside the given tolerance.</returns> public IMeasurement QuerySignalBuffer(Guid signalID, DateTime timestamp, TimeSpan tolerance) { MeasurementKey key = MeasurementKey.LookUpBySignalID(signalID); if (key == MeasurementKey.Undefined) { return(null); } return(QuerySignalBuffer(key, timestamp, tolerance)); }
/// <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); }
// Converts the given row of CSV data to a single measurement. private IMeasurement FromCSV(string csv) { string[] split = csv.Split(','); DateTime timestamp = DateTime.Parse(split[0]); Guid signalID = Guid.Parse(split[1]); double value = double.Parse(split[2]); return(new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(signalID).Metadata, Timestamp = timestamp, Value = value }); }
private static Measurement GetMeasurement(Guid signalID) { MeasurementKey key = MeasurementKey.LookUpBySignalID(signalID); if (key.SignalID == Guid.Empty) { return(null); } Measurement measurement = new Measurement { Metadata = key.Metadata, }; return(measurement); }
// Creates an alarm event from the given alarm and measurement. private IMeasurement CreateAlarmEvent(Ticks timestamp, Alarm alarm) { IMeasurement alarmEvent = new Measurement() { Timestamp = timestamp, Value = (int)alarm.State }; if ((object)alarm.AssociatedMeasurementID != null) { Guid alarmEventID = alarm.AssociatedMeasurementID.GetValueOrDefault(); alarmEvent.Metadata = MeasurementKey.LookUpBySignalID(alarmEventID).Metadata; } return(alarmEvent); }
private void m_timer_Elapsed(object sender, ElapsedEventArgs e) { List <IMeasurement> measurements = new List <IMeasurement>(); StringBuilder columnString = new StringBuilder(); int timestampColumn = GetColumnIndex("Timestamp"); int idColumn = GetColumnIndex("SignalID"); int valueColumn = GetColumnIndex("Value"); string commandString; IDbCommand command; IDataReader reader; foreach (string columnName in s_measurementColumns) { if (columnString.Length > 0) { columnString.Append(','); } columnString.Append(columnName); } commandString = string.Format("SELECT {0} FROM Measurement LIMIT {1},{2}", columnString, m_startingMeasurement, m_measurementsPerInput); command = m_connection.CreateCommand(); command.CommandText = commandString; using (reader = command.ExecuteReader()) { while (reader.Read()) { Ticks timeStamp = m_fakeTimestamps ? new Ticks(DateTime.UtcNow) : new Ticks(reader.GetInt64(timestampColumn)); MeasurementKey key = MeasurementKey.LookUpBySignalID(reader.GetGuid(idColumn)); if (key != MeasurementKey.Undefined) { measurements.Add(new Measurement { Key = key, Value = reader.GetDouble(valueColumn), Timestamp = timeStamp }); } } } OnNewMeasurements(measurements); m_startingMeasurement += m_measurementsPerInput; }
// Gets a measurement key based on a token which // may be either a signal ID or measurement key. private MeasurementKey GetKey(string token) { Guid signalID; MeasurementKey key; if (Guid.TryParse(token, out signalID)) { // Defined using the measurement's GUID key = MeasurementKey.LookUpBySignalID(signalID); } else { // Defined using the measurement's key key = MeasurementKey.Parse(token); } return(key); }
private Measurement GetMeasurement(Guid signalID) { DataRow[] rows = DataSource.Tables["ActiveMeasurements"].Select($"SignalID = '{signalID}'"); if (!rows.Any()) { return(null); } Measurement measurement = new Measurement { Key = MeasurementKey.LookUpBySignalID(signalID), TagName = rows[0]["PointTag"].ToString(), Adder = Convert.ToDouble(rows[0]["Adder"]), Multiplier = Convert.ToDouble(rows[0]["Multiplier"]) }; return(measurement); }
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); }
private void HandleDataPacketCommand(ClientConnection connection, byte[] buffer, int startIndex, int length) { try { List <IMeasurement> measurements = new List <IMeasurement>(); int index = startIndex; int payloadByteLength = BigEndian.ToInt32(buffer, index); index += sizeof(int); string dataString = connection.Encoding.GetString(buffer, index, payloadByteLength); ConnectionStringParser <SettingAttribute> connectionStringParser = new ConnectionStringParser <SettingAttribute>(); foreach (string measurementString in dataString.ParseKeyValuePairs().Values) { ECAMeasurement measurement = new ECAMeasurement(); connectionStringParser.ParseConnectionString(measurementString, measurement); measurements.Add(new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(measurement.SignalID).Metadata, Timestamp = measurement.Timestamp, Value = measurement.Value, StateFlags = measurement.StateFlags }); } OnNewMeasurements(measurements); } catch (Exception ex) { string errorMessage = $"Data packet command failed due to exception: {ex.Message}"; OnProcessException(new Exception(errorMessage, ex)); SendClientResponse(connection.ClientID, ServerResponse.Failed, (ServerCommand)ECAServerCommand.StatusMessage, errorMessage); } }
private StatisticsCollection CreateStatistics(TableOperations <MeasurementRecord> table, MeasurementKey key, Device device, int HistorianID, SignalType type) { MeasurementRecord inMeasurement = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()); int signaltype; using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) { TableOperations <SignalTypeRecord> signalTypeTable = new TableOperations <SignalTypeRecord>(connection); signaltype = signalTypeTable.QueryRecordWhere("Acronym = {0}", "CALC").ID; } string outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SUM"; // Sum if (table.QueryRecordCountWhere("SignalReference = {0}", outputReference) < 1) { table.AddNewRecord(new MeasurementRecord { HistorianID = HistorianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SUM", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SUM", SignalTypeID = signaltype, SignalReference = outputReference, Description = inMeasurement.Description + " Summ of UBAL", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }); } // sqrdSum outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SQR"; if (table.QueryRecordCountWhere("SignalReference = {0}", outputReference) < 1) { table.AddNewRecord(new MeasurementRecord { HistorianID = HistorianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SQR", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SQR", SignalTypeID = signaltype, SignalReference = outputReference, Description = inMeasurement.Description + " Summ of Sqared UBAL", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }); } // Min outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MIN"; if (table.QueryRecordCountWhere("SignalReference = {0}", outputReference) < 1) { table.AddNewRecord(new MeasurementRecord { HistorianID = HistorianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MIN", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MIN", SignalTypeID = signaltype, SignalReference = outputReference, Description = inMeasurement.Description + " Minimum UBAL", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }); } // Max outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MAX"; if (table.QueryRecordCountWhere("SignalReference = {0}", outputReference) < 1) { table.AddNewRecord(new MeasurementRecord { HistorianID = HistorianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MAX", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MAX", SignalTypeID = signaltype, SignalReference = outputReference, Description = inMeasurement.Description + " Maximum UBAL", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }); } // Number of Points outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:NUM"; if (table.QueryRecordCountWhere("SignalReference = {0}", outputReference) < 1) { table.AddNewRecord(new MeasurementRecord { HistorianID = HistorianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:NUM", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:NUM", SignalTypeID = signaltype, SignalReference = outputReference, Description = inMeasurement.Description + " Number of Points", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }); } // Number of Points above Alert outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:ALT"; if (table.QueryRecordCountWhere("SignalReference = {0}", outputReference) < 1) { table.AddNewRecord(new MeasurementRecord { HistorianID = HistorianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:ALT", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:ALT", SignalTypeID = signaltype, SignalReference = outputReference, Description = inMeasurement.Description + " number of Alerts", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }); } StatisticsCollection result = new StatisticsCollection(); outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SUM"; result.Sum = MeasurementKey.LookUpBySignalID(table.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:SQR"; result.SqrD = MeasurementKey.LookUpBySignalID(table.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MIN"; result.Min = MeasurementKey.LookUpBySignalID(table.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:MAX"; result.Max = MeasurementKey.LookUpBySignalID(table.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:NUM"; result.Total = MeasurementKey.LookUpBySignalID(table.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); outputReference = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL:ALT"; result.Alert = MeasurementKey.LookUpBySignalID(table.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); result.Reset(); return(result); }
/// <summary> /// Initializes this <see cref="MetricImporter"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; // Load optional parameters if (settings.TryGetValue("importPath", out setting)) { m_importPath = setting; } else { throw new InvalidOperationException("No import path was specified for EPRI metric importer - this is a required setting."); } if (settings.TryGetValue("inputInterval", out setting)) { m_inputInterval = double.Parse(setting); } if (settings.TryGetValue("measurementsPerInterval", out setting)) { m_measurementsPerInterval = int.Parse(setting); } if (settings.TryGetValue("simulateTimestamp", out setting)) { m_simulateTimestamp = setting.ParseBoolean(); } if (settings.TryGetValue("timestampFormat", out setting)) { m_timestampFormat = setting; } if (settings.TryGetValue("skipRows", out setting)) { int.TryParse(setting, out m_skipRows); } if (m_skipRows < 0) { m_skipRows = 0; } settings.TryGetValue("useHighResolutionInputTimer", out setting); if (string.IsNullOrEmpty(setting)) { setting = "false"; } UseHighResolutionInputTimer = setting.ParseBoolean(); if (!UseHighResolutionInputTimer) { m_looseTimer = new System.Timers.Timer(); } // Load column mappings: if (settings.TryGetValue("columnMappings", out setting)) { Dictionary <int, string> columnMappings = new Dictionary <int, string>(); int index; foreach (KeyValuePair <string, string> mapping in setting.ParseKeyValuePairs()) { if (int.TryParse(mapping.Key, out index)) { columnMappings[index] = mapping.Value; } } if (!m_simulateTimestamp && !columnMappings.Values.Contains("Timestamp", StringComparer.OrdinalIgnoreCase)) { throw new InvalidOperationException("One of the column mappings must be defined as a \"Timestamp\": e.g., columnMappings={1=Timestamp; 2=PPA:12; 3=PPA13}."); } // In transverse mode, maximum measurements per interval is set to maximum columns in input file m_measurementsPerInterval = columnMappings.Keys.Max(); // Auto-assign output measurements based on column mappings OutputMeasurements = columnMappings.Where(kvp => string.Compare(kvp.Value, "Timestamp", true) != 0).Select(kvp => { string measurementID = kvp.Value; IMeasurement measurement = new Measurement(); MeasurementKey key; Guid id; if (Guid.TryParse(measurementID, out id)) { measurement.Key = MeasurementKey.LookUpBySignalID(id); } else if (MeasurementKey.TryParse(measurementID, out key)) { measurement.Key = key; } if (measurement.ID != Guid.Empty) { try { DataRow[] filteredRows = DataSource.Tables["ActiveMeasurements"].Select(string.Format("SignalID = '{0}'", measurement.ID)); if (filteredRows.Length > 0) { DataRow row = filteredRows[0]; // Assign other attributes measurement.TagName = row["PointTag"].ToNonNullString(); measurement.Multiplier = double.Parse(row["Multiplier"].ToString()); measurement.Adder = double.Parse(row["Adder"].ToString()); } } catch { // Failure to lookup extra metadata is not catastrophic } // Associate measurement with column index m_columnMappings[kvp.Key] = measurement; } return(measurement); }).ToArray(); int timestampColumn = columnMappings.First(kvp => string.Compare(kvp.Value, "Timestamp", true) == 0).Key; // Reserve a column mapping for timestamp value IMeasurement timestampMeasurement = new Measurement() { TagName = "Timestamp" }; m_columnMappings[timestampColumn] = timestampMeasurement; } // Override input interval based on temporal processing interval if it's not set to default if (ProcessingInterval > -1) { m_inputInterval = ProcessingInterval == 0 ? 1 : ProcessingInterval; } if ((object)m_looseTimer != null) { m_looseTimer.Interval = m_inputInterval; m_looseTimer.AutoReset = true; m_looseTimer.Elapsed += m_looseTimer_Elapsed; } m_fileSystemWatcher = new FileSystemWatcher(m_importPath, "EPRI-VS-Metrics-*.csv"); m_fileSystemWatcher.Created += m_fileSystemWatcher_Created; m_fileSystemWatcher.Renamed += m_fileSystemWatcher_Renamed; }
/// <summary> /// Gets the minimum amount of time that data should be retained in the /// signal buffer for the signal identified by the given signal ID. /// </summary> /// <param name="signalID">The ID of the signal.</param> /// <returns>The retention time of the signal.</returns> public TimeSpan GetMinimumRetentionTime(Guid signalID) { return(GetMinimumRetentionTime(MeasurementKey.LookUpBySignalID(signalID))); }
/// <summary> /// Sets the minimum retention time of the signal identified by the given signal ID. /// </summary> /// <param name="signalID">The ID of the signal.</param> /// <param name="retentionTime">The minimum retention time of the signal.</param> public void SetMinimumRetentionTime(Guid signalID, TimeSpan retentionTime) { SetMinimumRetentionTime(MeasurementKey.LookUpBySignalID(signalID), retentionTime); }
// Attempt to read the next record private bool ReadNextRecord(long currentTime) { try { List <IMeasurement> newMeasurements = new List <IMeasurement>(); long fileTime = 0; int timestampColumn = 0; string[] fields = m_inStream.ReadLine().ToNonNullString().Split(','); if (m_inStream.EndOfStream || fields.Length < m_columns.Count) { return(false); } // Read time from Timestamp column in transverse mode if (m_transverse) { if (m_simulateTimestamp) { fileTime = currentTime; } else { timestampColumn = m_columnMappings.First(kvp => string.Compare(kvp.Value.TagName, "Timestamp", StringComparison.OrdinalIgnoreCase) == 0).Key; fileTime = long.Parse(fields[timestampColumn]); } } for (int i = 0; i < m_measurementsPerInterval; i++) { IMeasurement measurement; if (m_transverse) { // No measurement will be defined for timestamp column if (i == timestampColumn) { continue; } if (m_columnMappings.TryGetValue(i, out measurement)) { measurement = Measurement.Clone(measurement); measurement.Value = double.Parse(fields[i]); } else { measurement = new Measurement(); measurement.Metadata = MeasurementKey.Undefined.Metadata; measurement.Value = double.NaN; } if (m_simulateTimestamp) { measurement.Timestamp = currentTime; } else if (m_columns.ContainsKey("Timestamp")) { measurement.Timestamp = fileTime; } } else { measurement = new Measurement(); if (m_columns.ContainsKey("Signal ID")) { Guid measurementID = new Guid(fields[m_columns["Signal ID"]]); if (m_columns.ContainsKey("Measurement Key")) { measurement.Metadata = MeasurementKey.LookUpOrCreate(measurementID, fields[m_columns["Measurement Key"]]).Metadata; } else { measurement.Metadata = MeasurementKey.LookUpBySignalID(measurementID).Metadata; } } else if (m_columns.ContainsKey("Measurement Key")) { measurement.Metadata = MeasurementKey.Parse(fields[m_columns["Measurement Key"]]).Metadata; } if (m_simulateTimestamp) { measurement.Timestamp = currentTime; } else if (m_columns.ContainsKey("Timestamp")) { measurement.Timestamp = long.Parse(fields[m_columns["Timestamp"]]); } if (m_columns.ContainsKey("Value")) { measurement.Value = double.Parse(fields[m_columns["Value"]]); } } newMeasurements.Add(measurement); } OnNewMeasurements(newMeasurements); } catch (Exception ex) { OnProcessException(MessageLevel.Warning, ex); } return(true); }
/// <summary> /// Loads configuration from the database and configures adapter to run with that configuration /// </summary> public override void Initialize() { base.Initialize(); HashSet <IMeasurement> outputMeasurements = new HashSet <IMeasurement>(); m_configuredCalculations = new List <PowerCalculation>(); m_averageCalculationsPerFrame = new RunningAverage(); m_averageCalculationTime = new RunningAverage(); m_averageTotalCalculationTime = new RunningAverage(); m_lastActivePowerCalculations = new ConcurrentQueue <IMeasurement>(); m_lastReactivePowerCalculations = new ConcurrentQueue <IMeasurement>(); m_lastApparentPowerCalculations = new ConcurrentQueue <IMeasurement>(); string query = "SELECT " + // 1 2 3 4 5 "ID, CircuitDescription, VoltageAngleSignalID, VoltageMagSignalID, CurrentAngleSignalID, CurrentMagSignalID, " + // 6 7 8 "ActivePowerOutputSignalID, ReactivePowerOutputSignalID, ApparentPowerOutputSignalID FROM PowerCalculation " + "WHERE NodeId = {0} AND Enabled <> 0 "; using (AdoDataConnection database = new AdoDataConnection("systemSettings")) using (IDataReader rdr = database.ExecuteReader(query, ConfigurationFile.Current.Settings["systemSettings"]["NodeID"].ValueAs <Guid>())) { while (rdr.Read()) { m_configuredCalculations.Add(new PowerCalculation { PowerCalculationID = rdr.GetInt32(0), CircuitDescription = rdr.GetString(1), VoltageAngleSignalID = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[2].ToString())), VoltageMagnitudeSignalID = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[3].ToString())), CurrentAngleSignalID = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[4].ToString())), CurrentMagnitudeSignalID = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[5].ToString())), ActivePowerOutputMeasurement = AddOutputMeasurement(Guid.Parse(rdr[6].ToString()), outputMeasurements), ReactivePowerOutputMeasurement = AddOutputMeasurement(Guid.Parse(rdr[7].ToString()), outputMeasurements), ApparentPowerOutputMeasurement = AddOutputMeasurement(Guid.Parse(rdr[8].ToString()), outputMeasurements) }); } } if (m_configuredCalculations.Any()) { InputMeasurementKeys = m_configuredCalculations.SelectMany(pc => new[] { pc.CurrentAngleSignalID, pc.CurrentMagnitudeSignalID, pc.VoltageAngleSignalID, pc.VoltageMagnitudeSignalID }).ToArray(); } else { throw new InvalidOperationException("Skipped initialization of power calculator: no defined power calculations..."); } if (outputMeasurements.Any()) { OutputMeasurements = outputMeasurements.ToArray(); } Dictionary <string, string> settings = Settings; string setting; if (settings.TryGetValue("AlwaysProduceResult", out setting)) { AlwaysProduceResult = setting.ParseBoolean(); } if (settings.TryGetValue("ApplySqrt3Adjustment", out setting)) { ApplySqrt3Adjustment = setting.ParseBoolean(); } if (settings.TryGetValue("RemoveSqrt3Adjustment", out setting)) { RemoveSqrt3Adjustment = setting.ParseBoolean(); } if (settings.TryGetValue("EnableTemporalProcessing", out setting)) { EnableTemporalProcessing = setting.ParseBoolean(); } }
/// <summary> /// Initializes <see cref="UnBalancedCalculation"/>. /// </summary> public override void Initialize() { new ConnectionStringParser <CalculatedMesaurementAttribute>().ParseConnectionString(ConnectionString, this); base.Initialize(); m_threePhaseComponent = new List <ThreePhaseSet>(); m_statisticsMapping = new Dictionary <Guid, StatisticsCollection>(); m_saveStats = SaveAggregates; CategorizedSettingsElementCollection reportSettings = ConfigurationFile.Current.Settings["reportSettings"]; reportSettings.Add("IUnbalanceThreshold", "4.0", "Current Unbalance Alert threshold."); reportSettings.Add("VUnbalanceThreshold", "4.0", "Voltage Unbalance Alert threshold."); double i_threshold = reportSettings["IUnbalanceThreshold"].ValueAs(1.0D); double v_threshold = reportSettings["VUnbalanceThreshold"].ValueAs(1.0D); List <Guid> processed = new List <Guid>(); using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) { TableOperations <MeasurementRecord> measurementTable = new TableOperations <MeasurementRecord>(connection); TableOperations <ActiveMeasurement> activeMeasurmentTable = new TableOperations <ActiveMeasurement>(connection); TableOperations <Device> deviceTable = new TableOperations <Device>(connection); TableOperations <SignalTypeRecord> signalTable = new TableOperations <SignalTypeRecord>(connection); Device device = deviceTable.QueryRecordWhere("Acronym = {0}", ResultDeviceName); int historianID = Convert.ToInt32(connection.ExecuteScalar("SELECT ID FROM Historian WHERE Acronym = {0}", new object[] { HistorianInstance })); // Take Care of the Device if (InputMeasurementKeys.Length < 1) { return; } m_nodeID = deviceTable.QueryRecordWhere("Id={0}", measurementTable.QueryRecordWhere("SignalID = {0}", InputMeasurementKeys[0].SignalID).DeviceID).NodeID; if (device == null) { device = CreateDefaultDevice(deviceTable); OnStatusMessage(MessageLevel.Warning, $"Default Device for Output Measurments not found. Created Device {device.Acronym}"); } if (MappingFilePath != "") { // Read Mapping File using (StreamReader reader = new StreamReader(FilePath.GetAbsolutePath(MappingFilePath))) { string line; int index = -1; while ((line = reader.ReadLine()) != null) { index++; List <string> pointTags = line.Split(',').Select(item => item.Trim()).ToList(); List <MeasurementKey> availableInputs = new List <MeasurementKey>(3); if (pointTags.Count != 3) { OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file."); continue; } OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}"); OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}"); OnStatusMessage(MessageLevel.Info, $"PointTag of Measurment 1 is: {pointTags[0]}"); // check if measurments are in inputmeasurments availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[0], activeMeasurmentTable))); availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[1], activeMeasurmentTable))); availableInputs.Add(InputMeasurementKeys.FirstOrDefault(item => item.SignalID == GetSignalID(pointTags[2], activeMeasurmentTable))); if (availableInputs[0] == null || availableInputs[1] == null || availableInputs[2] == null) { OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file. PointTag not found"); continue; } SignalType type = GetSignalType(availableInputs[0], new TableOperations <ActiveMeasurement>(connection)); MeasurementKey neg = availableInputs.FirstOrDefault(item => SearchNegative(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey pos = availableInputs.FirstOrDefault(item => SearchPositive(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey zero = availableInputs.FirstOrDefault(item => SearchZero(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type ); if (neg != null && zero != null && pos != null) { MeasurementKey unBalance; string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID).SignalReference + "-" + (type == SignalType.IPHM? "I" : "V") + "UBAL"; if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0) { // Measurement Exists unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); } else { // Add Measurment to Database and make a statement MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID); MeasurementRecord outMeasurement = new MeasurementRecord { HistorianID = historianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", SignalTypeID = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID, SignalReference = outputReference, Description = GetDescription(pos, new TableOperations <ActiveMeasurement>(connection)) + " UnBalanced", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }; measurementTable.AddNewRecord(outMeasurement); unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement"); } double threshold = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(item => item == availableInputs[0])] == SignalType.IPHM ? i_threshold : v_threshold; m_threePhaseComponent.Add(new ThreePhaseSet(pos, zero, neg, unBalance, threshold)); if (m_saveStats) { m_statisticsMapping.Add(pos.SignalID, CreateStatistics(measurementTable, pos, device, historianID, type)); } } else { OnStatusMessage(MessageLevel.Warning, $"Skipping Line {index} in mapping file. Did not find pos. neg. and zero seq."); } } } } else { foreach (MeasurementKey key in InputMeasurementKeys) { if (processed.Contains(key.SignalID)) { continue; } // ensure only magnitudes are being used if (!(GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)) == SignalType.IPHM || GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)) == SignalType.VPHM)) { continue; } bool isNeg = SearchNegative(key, new TableOperations <ActiveMeasurement>(connection)); bool isPos = SearchPositive(key, new TableOperations <ActiveMeasurement>(connection)); bool isZero = SearchZero(key, new TableOperations <ActiveMeasurement>(connection)); if (!(isNeg || isPos || isZero)) { continue; } string description = GetDescription(key, new TableOperations <ActiveMeasurement>(connection)); // Check to make sure can actually deal with this if (description == string.Empty) { OnStatusMessage(MessageLevel.Warning, "Failed to apply automatic Line bundling to " + key.SignalID); continue; } //Make sure only correct Type (V vs I) makes it here.... SignalType type = GetSignalType(key, new TableOperations <ActiveMeasurement>(connection)); MeasurementKey neg = InputMeasurementKeys.FirstOrDefault(item => GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description && SearchNegative(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey pos = InputMeasurementKeys.FirstOrDefault(item => GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description && SearchPositive(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type); MeasurementKey zero = InputMeasurementKeys.FirstOrDefault(item => GetDescription(item, new TableOperations <ActiveMeasurement>(connection)) == description && SearchZero(item, new TableOperations <ActiveMeasurement>(connection)) && GetSignalType(item, new TableOperations <ActiveMeasurement>(connection)) == type ); if (neg != null && zero != null && pos != null) { MeasurementKey unBalance; string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID).SignalReference + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL"; if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0) { // Measurement Exists unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); } else { // Add Measurment to Database and make a statement MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", pos.SignalID); MeasurementRecord outMeasurement = new MeasurementRecord { HistorianID = historianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", AlternateTag = inMeasurement.AlternateTag + "-" + (type == SignalType.IPHM ? "I" : "V") + "UBAL", SignalTypeID = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID, SignalReference = outputReference, Description = GetDescription(pos, new TableOperations <ActiveMeasurement>(connection)) + " UnBalanced", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }; measurementTable.AddNewRecord(outMeasurement); unBalance = MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID); OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement"); } double threshold = InputMeasurementKeyTypes[InputMeasurementKeys.IndexOf(item => item == key)] == SignalType.IPHM ? i_threshold : v_threshold; m_threePhaseComponent.Add(new ThreePhaseSet(pos, zero, neg, unBalance, threshold)); processed.Add(pos.SignalID); processed.Add(neg.SignalID); processed.Add(zero.SignalID); if (m_saveStats) { m_statisticsMapping.Add(pos.SignalID, CreateStatistics(measurementTable, pos, device, historianID, type)); } } else { if (pos != null) { processed.Add(pos.SignalID); } if (neg != null) { processed.Add(neg.SignalID); } if (zero != null) { processed.Add(zero.SignalID); } } } } if (m_threePhaseComponent.Count == 0) { OnStatusMessage(MessageLevel.Error, "No case with all 3 sequences was found"); } } }
/// <summary> /// Initializes this <see cref="FileImporter"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string setting; // Load optional parameters if (settings.TryGetValue("importPath", out setting)) { m_importPath = setting; } else { throw new InvalidOperationException("No import path was specified for EPRI file importer - this is a required setting."); } if (settings.TryGetValue("inputInterval", out setting)) { m_inputInterval = double.Parse(setting); } if (settings.TryGetValue("measurementsPerInterval", out setting)) { m_measurementsPerInterval = int.Parse(setting); } if (settings.TryGetValue("simulateTimestamp", out setting)) { m_simulateTimestamp = setting.ParseBoolean(); } if (settings.TryGetValue("timestampFormat", out setting)) { m_timestampFormat = setting; } if (settings.TryGetValue("skipRows", out setting)) { int.TryParse(setting, out m_skipRows); } if (m_skipRows < 0) { m_skipRows = 0; } settings.TryGetValue("useHighResolutionInputTimer", out setting); if (string.IsNullOrEmpty(setting)) { setting = "false"; } UseHighResolutionInputTimer = setting.ParseBoolean(); if (!UseHighResolutionInputTimer) { m_looseTimer = new Timer(); } // Load column mappings: if (settings.TryGetValue("columnMappings", out setting)) { Dictionary <int, string> columnMappings = new Dictionary <int, string>(); int index; foreach (KeyValuePair <string, string> mapping in setting.ParseKeyValuePairs()) { if (int.TryParse(mapping.Key, out index)) { columnMappings[index] = mapping.Value; } } if (!m_simulateTimestamp && !columnMappings.Values.Contains("Timestamp", StringComparer.OrdinalIgnoreCase)) { throw new InvalidOperationException("One of the column mappings must be defined as a \"Timestamp\": e.g., columnMappings={0=Timestamp; 1=PPA:12; 2=PPA13}."); } // In transverse mode, maximum measurements per interval is set to maximum columns in input file m_measurementsPerInterval = columnMappings.Keys.Max(); // Auto-assign output measurements based on column mappings OutputMeasurements = columnMappings.Where(kvp => string.Compare(kvp.Value, "Timestamp", StringComparison.OrdinalIgnoreCase) != 0).Select(kvp => { string measurementID = kvp.Value; IMeasurement measurement = new Measurement(); MeasurementKey key; Guid id; if (Guid.TryParse(measurementID, out id)) { key = MeasurementKey.LookUpBySignalID(id); } else { MeasurementKey.TryParse(measurementID, out key); } if (key.SignalID != Guid.Empty) { measurement.Metadata = key.Metadata; // Associate measurement with column index m_columnMappings[kvp.Key] = measurement; } return(measurement); }).ToArray(); int timestampColumn = columnMappings.First(kvp => string.Compare(kvp.Value, "Timestamp", StringComparison.OrdinalIgnoreCase) == 0).Key; // Reserve a column mapping for timestamp value IMeasurement timestampMeasurement = new Measurement { Metadata = new MeasurementMetadata(null, "Timestamp", 0, 1, null) }; m_columnMappings[timestampColumn] = timestampMeasurement; } // Override input interval based on temporal processing interval if it's not set to default if (ProcessingInterval > -1) { m_inputInterval = ProcessingInterval == 0 ? 1 : ProcessingInterval; } if ((object)m_looseTimer != null) { m_looseTimer.Interval = m_inputInterval; m_looseTimer.AutoReset = true; m_looseTimer.Elapsed += m_looseTimer_Elapsed; } m_fileSystemWatcher = new SafeFileWatcher(m_importPath, "EPRI-VS-Output-*.csv"); m_fileSystemWatcher.Created += m_fileSystemWatcher_Created; m_fileSystemWatcher.Renamed += m_fileSystemWatcher_Renamed; }
private static MeasurementKey GetTargetFromGuid(string guidID) => MeasurementKey.LookUpBySignalID(Guid.Parse(guidID));
/// <summary> /// Loads configuration from the database and configures adapter to run with that configuration /// </summary> public override void Initialize() { base.Initialize(); HashSet <IMeasurement> outputMeasurements = new HashSet <IMeasurement>(); m_configuredCalculations = new List <PowerCalculation>(); m_adjustmentStrategies = new Dictionary <MeasurementKey, VoltageAdjustmentStrategy>(); m_averageCalculationsPerFrame = new RunningAverage(); m_averageCalculationTime = new RunningAverage(); m_averageTotalCalculationTime = new RunningAverage(); m_lastActivePowerCalculations = new ConcurrentQueue <IMeasurement>(); m_lastReactivePowerCalculations = new ConcurrentQueue <IMeasurement>(); m_lastApparentPowerCalculations = new ConcurrentQueue <IMeasurement>(); if (!Settings.TryGetValue(nameof(TableName), out string tableName)) { tableName = DefaultTableName; } string query = "SELECT " + // 0 1 2 3 4 5 "ID, CircuitDescription, VoltageAngleSignalID, VoltageMagSignalID, CurrentAngleSignalID, CurrentMagSignalID, " + // 6 7 8 "ActivePowerOutputSignalID, ReactivePowerOutputSignalID, ApparentPowerOutputSignalID FROM " + tableName + " " + "WHERE NodeId = {0} AND Enabled <> 0 "; using (AdoDataConnection database = new AdoDataConnection("systemSettings")) using (IDataReader rdr = database.ExecuteReader(query, ConfigurationFile.Current.Settings["systemSettings"]["NodeID"].ValueAs <Guid>())) { while (rdr.Read()) { m_configuredCalculations.Add(new PowerCalculation { PowerCalculationID = rdr.GetInt32(0), CircuitDescription = rdr.GetString(1), VoltageAngleMeasurementKey = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[2].ToString())), VoltageMagnitudeMeasurementKey = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[3].ToString())), CurrentAngleMeasurementKey = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[4].ToString())), CurrentMagnitudeMeasurementKey = MeasurementKey.LookUpBySignalID(Guid.Parse(rdr[5].ToString())), ActivePowerOutputMeasurement = AddOutputMeasurement(Guid.Parse(rdr[6].ToString()), outputMeasurements), ReactivePowerOutputMeasurement = AddOutputMeasurement(Guid.Parse(rdr[7].ToString()), outputMeasurements), ApparentPowerOutputMeasurement = AddOutputMeasurement(Guid.Parse(rdr[8].ToString()), outputMeasurements) }); } } if (m_configuredCalculations.Any()) { InputMeasurementKeys = m_configuredCalculations.SelectMany(pc => new[] { pc.CurrentAngleMeasurementKey, pc.CurrentMagnitudeMeasurementKey, pc.VoltageAngleMeasurementKey, pc.VoltageMagnitudeMeasurementKey }).ToArray(); } else { throw new InvalidOperationException("Skipped initialization of power calculator: no defined power calculations..."); } if (outputMeasurements.Any()) { OutputMeasurements = outputMeasurements.ToArray(); } Dictionary <string, string> settings = Settings; if (settings.TryGetValue(nameof(AlwaysProduceResult), out string setting)) { AlwaysProduceResult = setting.ParseBoolean(); } if (settings.TryGetValue(nameof(AdjustmentStrategy), out setting) && Enum.TryParse(setting, out VoltageAdjustmentStrategy adjustmentStrategy)) { AdjustmentStrategy = adjustmentStrategy; } if (settings.TryGetValue(nameof(EnableTemporalProcessing), out setting)) { EnableTemporalProcessing = setting.ParseBoolean(); } // Define per power calculation line adjustment strategies foreach (PowerCalculation powerCalculation in m_configuredCalculations) { if (powerCalculation.VoltageMagnitudeMeasurementKey is null || string.IsNullOrWhiteSpace(powerCalculation.CircuitDescription)) { continue; } try { Dictionary <string, string> circuitSettings = powerCalculation.CircuitDescription.ParseKeyValuePairs(); if (circuitSettings.TryGetValue(nameof(AdjustmentStrategy), out setting) && Enum.TryParse(setting, out adjustmentStrategy)) { m_adjustmentStrategies[powerCalculation.VoltageMagnitudeMeasurementKey] = adjustmentStrategy; } } catch (Exception ex) { OnStatusMessage(MessageLevel.Warning, $"Failed to parse settings from circuit description \"{powerCalculation.CircuitDescription}\": {ex.Message}"); } } }
/// <summary> /// Initializes <see cref="ActionAdapterBase"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary <string, string> settings = Settings; string alternateDatabaseConnection; AdoDataConnection connection = null; try { // Load optional parameters if (settings.TryGetValue("AlternateDatabaseConnection", out alternateDatabaseConnection) && !string.IsNullOrEmpty(alternateDatabaseConnection)) { string connectionString, dataProviderString; settings = alternateDatabaseConnection.ParseKeyValuePairs(); settings.TryGetValue("ConnectionString", out connectionString); settings.TryGetValue("DataProviderString", out dataProviderString); if (!string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(dataProviderString)) { connection = new AdoDataConnection(connectionString, dataProviderString); } } // Fall back on current openPDC database if alternate connection was not provided if ((object)connection == null) { connection = new AdoDataConnection("systemSettings"); } // This example assumes stored procedure returns a table with a column named ID that is a Guid, each row representing an input measurement MeasurementKey[] inputKeys = connection.RetrieveData("GetMyInputsProc @param1 @param2", "param1Value", "param2Value").Rows.OfType <DataRow>() .Select(row => MeasurementKey.LookUpBySignalID(Guid.Parse(row["ID"].ToString()))).ToArray(); // Lookup signal types for defined input measurements SignalType[] inputTypes = inputKeys.Select(key => LookupSignalType(key)).ToArray(); // Segregate inputs into voltage and current phasor measurements MeasurementKey[] voltageAngles = inputKeys.Where((key, index) => inputTypes[index] == SignalType.VPHA).ToArray(); MeasurementKey[] voltageMagnitudes = inputKeys.Where((key, index) => inputTypes[index] == SignalType.VPHM).ToArray(); MeasurementKey[] currentAngles = inputKeys.Where((key, index) => inputTypes[index] == SignalType.IPHA).ToArray(); MeasurementKey[] currentMagnitudes = inputKeys.Where((key, index) => inputTypes[index] == SignalType.IPHM).ToArray(); // Validate input measurement types have quartic alignment if (voltageAngles.Length != currentAngles.Length || voltageAngles.Length != voltageMagnitudes.Length || currentAngles.Length != currentMagnitudes.Length) { throw new InvalidOperationException("A different number of voltage and current phasor input measurement keys were supplied - the current and voltage phasors inputs must be supplied in pairs to represent a line measurement set, i.e., one set of voltage phasor input measurements must be supplied for each current phasor input measurement in a consecutive sequence (e.g., VA1;VM1;IA1;IM1; VA2;VM2;IA2;IM2; ... VAn;VMn;IAn;IMn)"); } // Reduce inputs to validated set of source measurements InputMeasurementKeys = voltageAngles.Concat(voltageMagnitudes).Concat(currentAngles).Concat(currentMagnitudes).Distinct().ToArray(); // Store phasor pairs as line measurements PhasorMeasurements voltageMeasurements, currentMeasurements; m_lineMeasurements = new LineMeasurements[voltageAngles.Length]; // Needed values for a line consist of measurements for voltage phasors and current phasors for (int i = 0; i < m_lineMeasurements.Length; i++) { voltageMeasurements = new PhasorMeasurements(voltageAngles[i], voltageMagnitudes[i]); currentMeasurements = new PhasorMeasurements(currentAngles[i], currentMagnitudes[i]); m_lineMeasurements[i] = new LineMeasurements(voltageMeasurements, currentMeasurements); } // Define output measurements as defined in stored procedure OutputMeasurements = connection.RetrieveData("GetMyOutputsProc @param1 @param2", "param1Value", "param2Value").Rows.OfType <DataRow>() .Select(row => new Measurement() { Key = MeasurementKey.LookUpBySignalID(Guid.Parse(row["ID"].ToString())) }).ToArray(); } finally { if ((object)connection != null) { connection.Dispose(); } } }
// Per partition consumer read handler private void ProcessPartitionMessages(object state) { int partition = (int)state; try { Dictionary <uint, MeasurementKey> idTable = new Dictionary <uint, MeasurementKey>(); ConsumerOptions options = new ConsumerOptions(Topic, m_router); LongSynchronizedOperation cacheLastConsumerOffset = null; OffsetPosition consumerCursor = new OffsetPosition { PartitionId = partition, Offset = 0 }; long lastUpdateTime = 0; long lastMetadataUpdateCount = 0; long lastMeasurementTime = 0; options.PartitionWhitelist.Add(partition); options.Log = new TimeSeriesLogger((message, parameters) => OnStatusMessage($"P[{partition}]: " + message, parameters), OnProcessException); // Handle consumer offset tracking, i.e., adapter will start reading messages where it left off from last run if (TrackConsumerOffset) { // Parse path/filename.ext into constituent parts string[] fileParts = new string[3]; fileParts[0] = FilePath.GetDirectoryName(ConsumerOffsetFileName); // 0: path/ fileParts[1] = FilePath.GetFileNameWithoutExtension(ConsumerOffsetFileName); // 1: filename fileParts[2] = FilePath.GetExtension(ConsumerOffsetFileName); // 2: .ext // Include partition index as part of consumer offset cache file name string fileName = $"{fileParts[0]}{fileParts[1]}-P{partition}{fileParts[2]}"; if (File.Exists(fileName)) { try { // Read last consumer offset consumerCursor.Offset = long.Parse(File.ReadAllText(fileName)); } catch (Exception ex) { OnProcessException(new InvalidOperationException($"Failed to read last consumer offset from \"{fileName}\": {ex.Message}", ex)); } } cacheLastConsumerOffset = new LongSynchronizedOperation(() => { // Do not write file any more often than defined consumer offset cache interval int restTime = (int)(Ticks.FromSeconds(ConsumerOffsetCacheInterval) - (DateTime.UtcNow.Ticks - lastUpdateTime)).ToMilliseconds(); if (restTime > 0) { Thread.Sleep(restTime); } lastUpdateTime = DateTime.UtcNow.Ticks; // Write current consumer offset File.WriteAllText(fileName, consumerCursor.Offset.ToString()); }, ex => OnProcessException(new InvalidOperationException($"Failed to cache current consumer offset to \"{fileName}\": {ex.Message}", ex))) { IsBackground = true }; } using (Consumer consumer = new Consumer(options, new OffsetPosition(partition, consumerCursor.Offset))) { lock (m_consumers) m_consumers.Add(new WeakReference <Consumer>(consumer)); foreach (Message message in consumer.Consume()) { if ((object)m_metadata == null) { continue; } uint id; byte metadataVersion; IMeasurement measurement = message.KafkaDeserialize(out id, out metadataVersion); // Kick-off a refresh for new metadata if message version numbers change if (m_lastMetadataVersion != metadataVersion) { m_lastMetadataVersion = metadataVersion; m_updateMetadata.RunOnceAsync(); } // Clear all undefined items in dictionary when metadata gets updated if (lastMetadataUpdateCount < m_metadataUpdateCount) { lastMetadataUpdateCount = m_metadataUpdateCount; foreach (uint undefinedID in idTable.Where(item => item.Value.SignalID == Guid.Empty).Select(item => item.Key).ToArray()) { idTable.Remove(undefinedID); } } // Get associated measurement key, or look it up in metadata table measurement.Key = idTable.GetOrAdd(id, lookupID => MeasurementKey.LookUpBySignalID(m_metadata?.Records?.FirstOrDefault(record => record.ID == lookupID)?.ParseSignalID() ?? Guid.Empty)); // Only publish measurements with associated metadata and are assigned to this adapter if (measurement.Key != MeasurementKey.Undefined && ((object)m_outputMeasurementKeys == null || m_outputMeasurementKeys.Contains(measurement.Key))) { OnNewMeasurements(new[] { measurement }); } // Cache last consumer offset consumerCursor.Offset = message.Offset; if ((object)cacheLastConsumerOffset != null) { cacheLastConsumerOffset.RunOnceAsync(); } if (ReadDelay > -1) { // As a group of measurements transition from timestamp to another, inject configured read delay if (lastMeasurementTime != measurement.Timestamp) { Thread.Sleep(ReadDelay); } lastMeasurementTime = measurement.Timestamp; } } } } catch (Exception ex) { OnProcessException(new InvalidOperationException($"Exception while reading Kafka messages for topic \"{Topic}\" P[{partition}]: {ex.Message}", ex)); } }
/// <summary> /// Initializes <see cref="SNRComputation"/>. /// </summary> public override void Initialize() { new ConnectionStringParser <CalculatedMesaurementAttribute>().ParseConnectionString(ConnectionString, this); base.Initialize(); // Figure Output Measurement Keys m_dataWindow = new Dictionary <Guid, List <double> >(); m_refWindow = new List <double>(); m_outputMapping = new Dictionary <Guid, MeasurementKey>(); m_statisticsMapping = new Dictionary <Guid, StatisticsCollection>(); m_saveStats = SaveAggregates; if (ReportingInterval % (double)WindowLength != 0.0D) { ReportingInterval = WindowLength * (ReportingInterval / WindowLength); OnStatusMessage(MessageLevel.Warning, $"Adjusting Reporting Interval to every {ReportingInterval} frames."); } CategorizedSettingsElementCollection reportSettings = ConfigurationFile.Current.Settings["reportSettings"]; reportSettings.Add("DefaultSNRThreshold", "4.0", "Default SNR Alert threshold."); m_threshold = reportSettings["DefaultSNRThreshold"].ValueAs(m_threshold); using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) { TableOperations <MeasurementRecord> measurementTable = new TableOperations <MeasurementRecord>(connection); TableOperations <Device> deviceTable = new TableOperations <Device>(connection); TableOperations <SignalTypeRecord> signalTable = new TableOperations <SignalTypeRecord>(connection); Device device = deviceTable.QueryRecordWhere("Acronym = {0}", ResultDeviceName); int historianID = Convert.ToInt32(connection.ExecuteScalar("SELECT ID FROM Historian WHERE Acronym = {0}", new object[] { HistorianInstance })); if (!InputMeasurementKeys.Any()) { return; } m_nodeID = deviceTable.QueryRecordWhere("Id={0}", measurementTable.QueryRecordWhere("SignalID = {0}", InputMeasurementKeys[0].SignalID).DeviceID).NodeID; if (device == null) { device = CreateDefaultDevice(deviceTable); OnStatusMessage(MessageLevel.Warning, $"Default Device for Output Measurments not found. Created Device {device.Acronym}"); } foreach (MeasurementKey key in InputMeasurementKeys) { m_dataWindow.Add(key.SignalID, new List <double>()); string outputReference = measurementTable.QueryRecordWhere("SignalID = {0}", key.SignalID).SignalReference + "-SNR"; if (measurementTable.QueryRecordCountWhere("SignalReference = {0}", outputReference) > 0) { // Measurement Exists m_outputMapping.Add(key.SignalID, MeasurementKey.LookUpBySignalID(measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID)); } else { // Add Measurment to Database and make a statement MeasurementRecord inMeasurement = measurementTable.QueryRecordWhere("SignalID = {0}", key.SignalID); MeasurementRecord outMeasurement = new MeasurementRecord { HistorianID = historianID, DeviceID = device.ID, PointTag = inMeasurement.PointTag + "-SNR", AlternateTag = inMeasurement.AlternateTag + "-SNR", SignalTypeID = signalTable.QueryRecordWhere("Acronym = {0}", "CALC").ID, SignalReference = outputReference, Description = inMeasurement.Description + " SNR", Enabled = true, CreatedOn = DateTime.UtcNow, UpdatedOn = DateTime.UtcNow, CreatedBy = UserInfo.CurrentUserID, UpdatedBy = UserInfo.CurrentUserID, SignalID = Guid.NewGuid(), Adder = 0.0D, Multiplier = 1.0D }; measurementTable.AddNewRecord(outMeasurement); m_outputMapping.Add(key.SignalID, MeasurementKey.LookUpBySignalID( measurementTable.QueryRecordWhere("SignalReference = {0}", outputReference).SignalID)); OnStatusMessage(MessageLevel.Warning, $"Output measurment {outputReference} not found. Creating measurement"); } if (m_saveStats) { m_statisticsMapping.Add(key.SignalID, CreateStatistics(measurementTable, key, device, historianID)); } } if (Reference == null) { OnStatusMessage(MessageLevel.Warning, "No Reference Angle Specified"); int refIndex = InputMeasurementKeyTypes.IndexOf(item => item == SignalType.IPHA || item == SignalType.VPHA); if (refIndex > -1) { Reference = InputMeasurementKeys[refIndex]; } } if (Reference != null) { if (!InputMeasurementKeys.Contains(Reference)) { InputMeasurementKeys.AddRange(new[] { Reference }); } } } }