/// <summary> /// Initializes <see cref="VirtualInputAdapter"/>. /// </summary> public override void Initialize() { // In case user defines no inputs or outputs for virutal adapter, we "turn off" interaction with any // other real-time adapters by removing this virtual adapter from external routes. To accomplish this // we expose I/O demands for an undefined measurement. Leaving values assigning to null would mean // that this adapter desires a full "broadcast" of all data - and hence routing demands from all. // User can override if desired using standard connection string parameters for I/O measurements. InputMeasurementKeys = new MeasurementKey[] { MeasurementKey.Undefined }; OutputMeasurements = new Measurement[] { Measurement.Undefined }; base.Initialize(); }
private void QueryData() { DateTime currentTime = StartTimeConstraint; while (currentTime <= StopTimeConstraint) { try { DateTime endTime = currentTime.AddMinutes(m_queryTimeSpan); List<IMeasurement> measToAdd = new List<IMeasurement>(); foreach (PIPoint point in m_points) { PIValues values = point.Data.RecordedValues(currentTime.ToLocalTime(), endTime.ToLocalTime()); foreach (PIValue value in values) { if (!value.Value.GetType().IsCOMObject) { Measurement measurement = new Measurement(); measurement.Key = m_tagKeyMap[point.Name]; measurement.ID = measurement.Key.SignalID; measurement.Value = (double)value.Value; measurement.Timestamp = value.TimeStamp.LocalDate.ToUniversalTime(); measToAdd.Add(measurement); } } } if (measToAdd.Any()) { lock (m_measurements) { foreach (IMeasurement meas in measToAdd) { m_measurements.Add(meas); m_processedMeasurements++; } } } currentTime = endTime; m_queryTime = currentTime; } catch (ThreadAbortException) { throw; } catch (Exception e) { OnProcessException(e); } Thread.Sleep(33); } }
static void ProcessMeasurements(object state) { while (true) { List<Measurement> measurements = new List<Measurement>(); Measurement measurement; for (int i = 1; i < 11; i++) { measurement = new Measurement() { Key = new MeasurementKey(Guid.Empty, (uint)i, "DEVARCHIVE"), Value = TVA.Security.Cryptography.Random.Between(-65535.0D, 65536.0D), Timestamp = DateTime.UtcNow.Ticks }; measurements.Add(measurement); } publisher.QueueMeasurementsForProcessing(measurements); Thread.Sleep(33); } }
// 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", true) == 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.ID = Guid.Empty; measurement.Key = MeasurementKey.Undefined; 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")) measurement.ID = new Guid(fields[m_columns["Signal ID"]]); if (m_columns.ContainsKey("Measurement Key")) measurement.Key = MeasurementKey.Parse(fields[m_columns["Measurement Key"]], measurement.ID); 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(ex); } return true; }
/// <summary> /// Initializes this <see cref="CsvInputAdapter"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary<string, string> settings = Settings; string setting; // Load optional parameters if (settings.TryGetValue("fileName", out setting)) m_fileName = 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("transverse", out setting) || settings.TryGetValue("transverseMode", out setting)) m_transverse = setting.ParseBoolean(); if (settings.TryGetValue("autoRepeat", out setting)) m_autoRepeat = setting.ParseBoolean(); 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(); if (m_transverse) { // 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.InvariantCultureIgnoreCase)) 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() + 1; // 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.ID = id; measurement.Key = MeasurementKey.LookupBySignalID(id); } else if (MeasurementKey.TryParse(measurementID, Guid.Empty, out key)) { measurement.Key = key; measurement.ID = key.SignalID; } 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; } else { throw new InvalidOperationException("Column mappings must be defined when using transverse format: e.g., columnMappings={0=Timestamp; 1=PPA:12; 2=PPA13}."); } } // 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; } }
// Processes measurements in the queue. private void ProcessMeasurements(IEnumerable<IMeasurement> measurements) { List<Alarm> alarms; List<Alarm> raisedAlarms; List<IMeasurement> alarmEvents; IMeasurement alarmEvent; long processedMeasurements; // Create the collection that will store // alarm events to be sent into the system alarmEvents = new List<IMeasurement>(); processedMeasurements = 0L; foreach (IMeasurement measurement in measurements) { lock (m_alarms) { // Get alarms that apply to the measurement being processed if (!m_alarmLookup.TryGetValue(measurement.ID, out alarms)) alarms = new List<Alarm>(); // Get alarms that triggered events raisedAlarms = alarms.Where(a => a.Test(measurement)).ToList(); } // Create event measurements to be sent into the system foreach (Alarm alarm in raisedAlarms) { alarmEvent = new Measurement() { Timestamp = measurement.Timestamp, Value = (int)alarm.State }; if ((object)alarm.AssociatedMeasurementID != null) { alarmEvent.ID = alarm.AssociatedMeasurementID.Value; alarmEvent.Key = MeasurementKey.LookupBySignalID(alarmEvent.ID); } alarmEvents.Add(alarmEvent); m_eventCount++; } // Increment processed measurement count processedMeasurements++; } // Send new alarm events into the system, // then reset the collection for the next // group of measurements OnNewMeasurements(alarmEvents); // Increment total count of processed measurements IncrementProcessedMeasurements(processedMeasurements); }
/// <summary> /// Returns a new measurement equivalent to the one being wrapped. /// </summary> /// <returns>The wrapped measurement.</returns> public IMeasurement GetMeasurement() { Guid signalID = Guid.Parse(this.SignalID); IMeasurement measurement = new Measurement() { Adder = this.Adder, ID = signalID, Key = new MeasurementKey(signalID, unchecked((uint)this.ID), this.Source), Multiplier = this.Multiplier, TagName = this.TagName, Timestamp = this.Timestamp, Value = this.Value }; return measurement; }
private void PipeOnOnNewValue() { List<IMeasurement> measurements = new List<IMeasurement>(); PIEventObject eventobject; PointValue pointvalue; for (int i = 0; i < m_pipe.Count; i++) { eventobject = m_pipe.Take(); // we will publish measurements for every action except deleted (possible dupes on updates) if (eventobject.Action != EventActionConstants.eaDelete) { try { pointvalue = (PointValue)eventobject.EventData; double value = Convert.ToDouble(pointvalue.PIValue.Value); MeasurementKey key = m_tagKeyMap[pointvalue.PIPoint.Name]; Measurement measurement = new Measurement(); measurement.ID = key.SignalID; measurement.Key = key; measurement.Timestamp = pointvalue.PIValue.TimeStamp.LocalDate.ToUniversalTime(); measurement.Value = value; measurement.StateFlags = MeasurementStateFlags.Normal; if (measurement.Timestamp > m_lastReceivedTimestamp.Ticks) m_lastReceivedTimestamp = measurement.Timestamp; measurements.Add(measurement); } catch { /* squelch any errors on digital state data that can't be converted to a double */ } } eventobject = null; } if (measurements.Any()) { OnNewMeasurements(measurements); m_processedMeasurements += measurements.Count; } }
/// <summary> /// Reads values from the connection string and prepares this <see cref="PIRTInputAdapter"/> for connecting to PI /// </summary> public override void Initialize() { base.Initialize(); m_measurements = new List<IMeasurement>(); Dictionary<string, string> settings = Settings; string setting; if (!settings.TryGetValue("ServerName", out m_servername)) throw new InvalidOperationException("Server name is a required setting for PI connections. Please add a server in the format ServerName=myservername to the connection string."); if (!settings.TryGetValue("UserName", out setting)) m_userName = setting; else m_userName = null; if (!settings.TryGetValue("Password", out setting)) m_password = setting; else m_password = null; if (!settings.TryGetValue("AutoAddOutput", out setting)) AutoAddOutput = false; else AutoAddOutput = bool.Parse(setting); if (settings.TryGetValue("UseEventPipes", out setting)) UseEventPipes = bool.Parse(setting); else UseEventPipes = true; if (settings.TryGetValue("QueryTimeSpan", out setting)) QueryTimeSpan = Convert.ToInt32(setting); else QueryTimeSpan = 5; if (AutoAddOutput) { var measurements = from row in DataSource.Tables["ActiveMeasurements"].AsEnumerable() where row["PROTOCOL"].ToString() == "PI" select row; List<IMeasurement> outputMeasurements = new List<IMeasurement>(); foreach (DataRow row in measurements) { var measurement = new Measurement(); measurement.ID = new Guid(row["SIGNALID"].ToString()); measurement.Key = new MeasurementKey(measurement.ID, uint.Parse(row["ID"].ToString().Split(':')[1]), row["ID"].ToString().Split(':')[0]); outputMeasurements.Add(measurement); } OutputMeasurements = outputMeasurements.ToArray(); OnOutputMeasurementsUpdated(); } }