diff --git a/Dependencies/OpenXDA/FaultAlgorithms.dll b/Dependencies/OpenXDA/FaultAlgorithms.dll new file mode 100644 index 00000000..6c0bd425 Binary files /dev/null and b/Dependencies/OpenXDA/FaultAlgorithms.dll differ diff --git a/Dependencies/OpenXDA/FaultData.dll b/Dependencies/OpenXDA/FaultData.dll new file mode 100644 index 00000000..d94d4e34 Binary files /dev/null and b/Dependencies/OpenXDA/FaultData.dll differ diff --git a/Dependencies/OpenXDA/openHistorian.XDALink.dll b/Dependencies/OpenXDA/openHistorian.XDALink.dll new file mode 100644 index 00000000..5e175351 Binary files /dev/null and b/Dependencies/OpenXDA/openHistorian.XDALink.dll differ diff --git a/Dependencies/OpenXDA/openXDA.APIAuthentication.dll b/Dependencies/OpenXDA/openXDA.APIAuthentication.dll new file mode 100644 index 00000000..26807e3c Binary files /dev/null and b/Dependencies/OpenXDA/openXDA.APIAuthentication.dll differ diff --git a/Dependencies/OpenXDA/openXDA.Configuration.dll b/Dependencies/OpenXDA/openXDA.Configuration.dll new file mode 100644 index 00000000..af840746 Binary files /dev/null and b/Dependencies/OpenXDA/openXDA.Configuration.dll differ diff --git a/Dependencies/OpenXDA/openXDA.Model.dll b/Dependencies/OpenXDA/openXDA.Model.dll new file mode 100644 index 00000000..9caf0303 Binary files /dev/null and b/Dependencies/OpenXDA/openXDA.Model.dll differ diff --git a/Dependencies/OpenXDA/openXDA.PQI.dll b/Dependencies/OpenXDA/openXDA.PQI.dll new file mode 100644 index 00000000..0df0239e Binary files /dev/null and b/Dependencies/OpenXDA/openXDA.PQI.dll differ diff --git a/Dependencies/OpenXDA/openXDA.Reports.dll b/Dependencies/OpenXDA/openXDA.Reports.dll new file mode 100644 index 00000000..63684b2d Binary files /dev/null and b/Dependencies/OpenXDA/openXDA.Reports.dll differ diff --git a/Libraries/FaultAlgorithms/Conductor.cs b/Libraries/FaultAlgorithms/Conductor.cs deleted file mode 100644 index 5b5a24fe..00000000 --- a/Libraries/FaultAlgorithms/Conductor.cs +++ /dev/null @@ -1,122 +0,0 @@ -//********************************************************************************************************************* -// Conductor.cs -// Version 1.1 and subsequent releases -// -// Copyright © 2013, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// -------------------------------------------------------------------------------------------------------------------- -// -// Version 1.0 -// -// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. -// -// openFLE ("this software") is licensed under BSD 3-Clause license. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// • Redistributions of source code must retain the above copyright notice, this list of conditions and -// the following disclaimer. -// -// • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -// the following disclaimer in the documentation and/or other materials provided with the distribution. -// -// • Neither the name of the Electric Power Research Institute, Inc. (“EPRI”) nor the names of its contributors -// may be used to endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// -// This software incorporates work covered by the following copyright and permission notice: -// -// • TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov -// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. -// -// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); -// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may -// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. -// -// TVA Code Library is provided by the copyright holders and contributors "as is" and any express -// or implied warranties, including, but not limited to, the implied warranties of merchantability -// and fitness for a particular purpose are disclaimed. -// -//********************************************************************************************************************* -// -// Code Modification History: -// ------------------------------------------------------------------------------------------------------------------- -// 06/14/2012 - Stephen C. Wills, Grid Protection Alliance -// Generated original version of source code. -// -//********************************************************************************************************************* - -namespace FaultAlgorithms -{ - /// - /// Contains data for both the voltage - /// and current on a conductor. - /// - public class Conductor - { - #region [ Members ] - - // Fields - - /// - /// One cycle of voltage data. - /// - public Cycle V; - - /// - /// One cycle of current data. - /// - public Cycle I; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - public Conductor() - { - V = new Cycle(); - I = new Cycle(); - } - - /// - /// Creates a new instance of the class. - /// - /// The index of the cycle to be calculated. - /// The value to divide from the sample rate to determine the starting location of the cycle. - /// The frequency of the sine wave during this cycle. - /// The voltage data points. - /// The current data points. - public Conductor(int cycleIndex, int sampleRateDivisor, double frequency, MeasurementData voltageData, MeasurementData currentData) - { - int vStart = cycleIndex * (voltageData.SampleRate / sampleRateDivisor); - int iStart = cycleIndex * (currentData.SampleRate / sampleRateDivisor); - V = new Cycle(vStart, frequency, voltageData); - I = new Cycle(iStart, frequency, currentData); - } - - #endregion - } -} diff --git a/Libraries/FaultAlgorithms/Cycle.cs b/Libraries/FaultAlgorithms/Cycle.cs deleted file mode 100644 index 91db47e8..00000000 --- a/Libraries/FaultAlgorithms/Cycle.cs +++ /dev/null @@ -1,200 +0,0 @@ -//********************************************************************************************************************* -// Cycle.cs -// Version 1.1 and subsequent releases -// -// Copyright 2013, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// -------------------------------------------------------------------------------------------------------------------- -// -// Version 1.0 -// -// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. -// -// openFLE ("this software") is licensed under BSD 3-Clause license. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// Redistributions of source code must retain the above copyright notice, this list of conditions and -// the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -// the following disclaimer in the documentation and/or other materials provided with the distribution. -// -// Neither the name of the Electric Power Research Institute, Inc. (EPRI) nor the names of its contributors -// may be used to endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// -// This software incorporates work covered by the following copyright and permission notice: -// -// TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov -// No copyright is claimed pursuant to 17 USC 105. All Other Rights Reserved. -// -// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); -// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may -// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. -// -// TVA Code Library is provided by the copyright holders and contributors "as is" and any express -// or implied warranties, including, but not limited to, the implied warranties of merchantability -// and fitness for a particular purpose are disclaimed. -// -//********************************************************************************************************************* -// -// Code Modification History: -// ------------------------------------------------------------------------------------------------------------------- -// 05/23/2012 - J. Ritchie Carroll, Grid Protection Alliance -// Generated original version of source code. -// -//********************************************************************************************************************* - -using Gemstone; -using Gemstone.Numeric; -using Gemstone.Numeric.Analysis; -using Gemstone.Units; - -namespace FaultAlgorithms -{ - /// - /// Represents a cycle of single phase power frequency-domain data. - /// - public class Cycle - { - #region [ Members ] - - // Constants - private const double PiOverTwo = Math.PI / 2.0D; - - // Fields - - /// - /// The actual frequency of the cycle in hertz. - /// - public double Frequency; - - /// - /// The complex number representation of the RMS phasor. - /// - public ComplexNumber Complex; - - /// - /// The most extreme data point in the cycle. - /// - public double Peak; - - /// - /// The error between the sine fit and the given data values. - /// - public double Error; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - public Cycle() - { - } - - /// - /// Creates a new instance of the class. - /// - /// The index of the start of the cycle. - /// The frequency of the measured system, in Hz. - /// The time-domain data to be used to calculate frequency-domain values. - public Cycle(int startSample, double frequency, MeasurementData waveFormData) - { - long timeStart; - double[] timeInSeconds; - double[] measurements; - SineWave sineFit; - - if (startSample < 0) - throw new ArgumentOutOfRangeException("startSample"); - - if (startSample + waveFormData.SampleRate > waveFormData.Times.Length) - throw new ArgumentOutOfRangeException("startSample"); - - if (startSample + waveFormData.SampleRate > waveFormData.Measurements.Length) - throw new ArgumentOutOfRangeException("startSample"); - - timeStart = waveFormData.Times[startSample]; - timeInSeconds = new double[waveFormData.SampleRate]; - measurements = new double[waveFormData.SampleRate]; - - for (int i = 0; i < waveFormData.SampleRate; i++) - { - timeInSeconds[i] = Ticks.ToSeconds(waveFormData.Times[i + startSample] - timeStart); - measurements[i] = waveFormData.Measurements[i + startSample]; - } - - sineFit = WaveFit.SineFit(measurements, timeInSeconds, frequency); - - RMS = Math.Sqrt(measurements.Select(vi => vi * vi).Average()); - Phase = sineFit.Phase - PiOverTwo; - Peak = sineFit.Amplitude; - Frequency = frequency; - - Error = timeInSeconds - .Select(time => sineFit.CalculateY(time)) - .Zip(measurements, (calc, measurement) => Math.Abs(calc - measurement)) - .Sum(); - } - - #endregion - - #region [ Properties ] - - /// - /// Root-mean-square of the in the cycle. - /// - public double RMS - { - get - { - return Complex.Magnitude; - } - set - { - Complex.Magnitude = value; - } - } - - /// - /// Phase angle of the start of the cycle, relative to the reference angle. - /// - public Angle Phase - { - get - { - return Complex.Angle; - } - set - { - Complex.Angle = value; - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Libraries/FaultAlgorithms/CycleData.cs b/Libraries/FaultAlgorithms/CycleData.cs deleted file mode 100644 index 610d5960..00000000 --- a/Libraries/FaultAlgorithms/CycleData.cs +++ /dev/null @@ -1,177 +0,0 @@ -//********************************************************************************************************************* -// CycleData.cs -// Version 1.1 and subsequent releases -// -// Copyright © 2013, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// -------------------------------------------------------------------------------------------------------------------- -// -// Version 1.0 -// -// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. -// -// openFLE ("this software") is licensed under BSD 3-Clause license. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// • Redistributions of source code must retain the above copyright notice, this list of conditions and -// the following disclaimer. -// -// • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -// the following disclaimer in the documentation and/or other materials provided with the distribution. -// -// • Neither the name of the Electric Power Research Institute, Inc. (“EPRI”) nor the names of its contributors -// may be used to endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// -// This software incorporates work covered by the following copyright and permission notice: -// -// • TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov -// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. -// -// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); -// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may -// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. -// -// TVA Code Library is provided by the copyright holders and contributors "as is" and any express -// or implied warranties, including, but not limited to, the implied warranties of merchantability -// and fitness for a particular purpose are disclaimed. -// -//********************************************************************************************************************* -// -// Code Modification History: -// ------------------------------------------------------------------------------------------------------------------- -// 06/14/2012 - Stephen C. Wills, Grid Protection Alliance -// Generated original version of source code. -// -//********************************************************************************************************************* - -using Gemstone.Numeric; - -namespace FaultAlgorithms -{ - /// - /// Contains data for a single cycle over all three line-to-neutral conductors. - /// - public class CycleData - { - #region [ Members ] - - // Constants - - /// - /// 2 * pi - /// - public const double TwoPI = 2.0D * Math.PI; - - // a = e^((2/3) * pi * i) - private const double Rad120 = TwoPI / 3.0D; - private static readonly ComplexNumber a = new ComplexNumber(Math.Cos(Rad120), Math.Sin(Rad120)); - private static readonly ComplexNumber aSq = a * a; - - // Fields - - /// - /// A-to-neutral conductor - /// - public Conductor AN; - - /// - /// B-to-neutral conductor - /// - public Conductor BN; - - /// - /// C-to-neutral conductor - /// - public Conductor CN; - - /// - /// Timestamp of the start of the cycle. - /// - public DateTime StartTime; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - public CycleData() - { - AN = new Conductor(); - BN = new Conductor(); - CN = new Conductor(); - } - - /// - /// Creates a new instance of the class. - /// - /// The index of the cycle being created. - /// The value to divide from the sample rate to determine the index of the sample at the start of the cycle. - /// The frequency of the measured system, in Hz. - /// The data set containing voltage measurements. - /// The data set containing current measurements. - public CycleData(int cycleIndex, int sampleRateDivisor, double frequency, MeasurementDataSet voltageDataSet, MeasurementDataSet currentDataSet) - { - int sampleIndex; - - AN = new Conductor(cycleIndex, sampleRateDivisor, frequency, voltageDataSet.AN, currentDataSet.AN); - BN = new Conductor(cycleIndex, sampleRateDivisor, frequency, voltageDataSet.BN, currentDataSet.BN); - CN = new Conductor(cycleIndex, sampleRateDivisor, frequency, voltageDataSet.CN, currentDataSet.CN); - - sampleIndex = cycleIndex * (voltageDataSet.AN.SampleRate / sampleRateDivisor); - StartTime = new DateTime(voltageDataSet.AN.Times[sampleIndex]); - } - - #endregion - - #region [ Methods ] - - /// - /// Calculates the positive, negative, and zero sequence components - /// and returns them in an array with indexes 1, 2, and 0 respectively. - /// - /// The cycle of A-to-neutral data to be used. - /// The cycle of B-to-neutral data to be used. - /// The cycle of C-to-neutral data to be used. - /// An array of size 3 containing the zero sequence, positive sequence, and negative sequence components in that order. - public static ComplexNumber[] CalculateSequenceComponents(Cycle anCycle, Cycle bnCycle, Cycle cnCycle) - { - ComplexNumber an = anCycle.Complex; - ComplexNumber bn = bnCycle.Complex; - ComplexNumber cn = cnCycle.Complex; - - ComplexNumber[] sequenceComponents = new ComplexNumber[3]; - - sequenceComponents[0] = (an + bn + cn) / 3.0D; - sequenceComponents[1] = (an + a * bn + aSq * cn) / 3.0D; - sequenceComponents[2] = (an + aSq * bn + a * cn) / 3.0D; - - return sequenceComponents; - } - - #endregion - } -} \ No newline at end of file diff --git a/Libraries/FaultAlgorithms/CycleDataSet.cs b/Libraries/FaultAlgorithms/CycleDataSet.cs deleted file mode 100644 index 34b810b7..00000000 --- a/Libraries/FaultAlgorithms/CycleDataSet.cs +++ /dev/null @@ -1,303 +0,0 @@ -//********************************************************************************************************************* -// CycleDataSet.cs -// Version 1.1 and subsequent releases -// -// Copyright © 2013, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// -------------------------------------------------------------------------------------------------------------------- -// -// Version 1.0 -// -// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. -// -// openFLE ("this software") is licensed under BSD 3-Clause license. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// • Redistributions of source code must retain the above copyright notice, this list of conditions and -// the following disclaimer. -// -// • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -// the following disclaimer in the documentation and/or other materials provided with the distribution. -// -// • Neither the name of the Electric Power Research Institute, Inc. (“EPRI”) nor the names of its contributors -// may be used to endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// -// This software incorporates work covered by the following copyright and permission notice: -// -// • TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov -// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. -// -// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); -// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may -// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. -// -// TVA Code Library is provided by the copyright holders and contributors "as is" and any express -// or implied warranties, including, but not limited to, the implied warranties of merchantability -// and fitness for a particular purpose are disclaimed. -// -//********************************************************************************************************************* -// -// Code Modification History: -// ------------------------------------------------------------------------------------------------------------------- -// 06/14/2012 - Stephen C. Wills, Grid Protection Alliance -// Generated original version of source code. -// -//********************************************************************************************************************* - -using System.Collections; -using Gemstone.Numeric; -using Gemstone.Numeric.Analysis; - -namespace FaultAlgorithms -{ - /// - /// Represents a collection of all the cycles extracted from a given data set. - /// - public class CycleDataSet : IEnumerable - { - #region [ Members ] - - // Fields - private List m_cycles; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - public CycleDataSet() - { - m_cycles = new List(); - } - - /// - /// Creates a new instance of the class. - /// - /// The frequency of the measured system, in Hz. - /// The data set containing voltage data points. - /// The data set containing current data points. - public CycleDataSet(double frequency, MeasurementDataSet voltageDataSet, MeasurementDataSet currentDataSet) - { - Populate(frequency, voltageDataSet, currentDataSet); - } - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the data structure containing a - /// full cycle of data at the given index. - /// - /// The index of the cycle. - /// The cycle of data at the given index. - public CycleData this[int i] - { - get - { - return m_cycles[i]; - } - set - { - while(i >= m_cycles.Count) - m_cycles.Add(null); - - m_cycles[i] = value; - } - } - - /// - /// Gets the size of the cycle data set. - /// - public int Count - { - get - { - return m_cycles.Count; - } - } - - #endregion - - #region [ Methods ] - - /// - /// Populates the cycle data set by calculating cycle - /// data based on the given measurement data sets. - /// - /// The frequency of the measured system, in Hz. - /// Data set containing voltage waveform measurements. - /// Data set containing current waveform measurements. - public void Populate(double frequency, MeasurementDataSet voltageDataSet, MeasurementDataSet currentDataSet) - { - List measurementDataList; - int sampleRateDivisor; - int numberOfCycles; - - measurementDataList = new List() - { - voltageDataSet.AN, voltageDataSet.BN, voltageDataSet.CN, - currentDataSet.AN, currentDataSet.BN, currentDataSet.CN - }; - - sampleRateDivisor = measurementDataList - .Select(measurementData => measurementData.SampleRate) - .GreatestCommonDenominator(); - - numberOfCycles = measurementDataList - .Select(measurementData => (measurementData.Measurements.Length - measurementData.SampleRate + 1) / (measurementData.SampleRate / sampleRateDivisor)) - .Min(); - - for (int i = 0; i < numberOfCycles; i++) - m_cycles.Add(new CycleData(i, sampleRateDivisor, frequency, voltageDataSet, currentDataSet)); - } - - /// - /// Returns the index of the cycle with the largest total current. - /// - /// The index of the cycle with the largest total current. - public int GetLargestCurrentIndex() - { - int index = 0; - int bestFaultIndex = -1; - double largestCurrent = 0.0D; - - foreach (CycleData cycle in m_cycles) - { - double totalCurrent = cycle.AN.I.RMS + cycle.BN.I.RMS + cycle.CN.I.RMS; - - if (totalCurrent > largestCurrent) - { - bestFaultIndex = index; - largestCurrent = totalCurrent; - } - - index++; - } - - return bestFaultIndex; - } - - /// - /// Clears the cycle data set so that it can be repopulated. - /// - public void Clear() - { - m_cycles.Clear(); - } - - /// - /// Returns an enumerator that iterates through the collection of cycles. - /// - /// An object that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - foreach (CycleData cycle in m_cycles) - { - yield return cycle; - } - } - - /// - /// Returns an enumerator that iterates through the collection of cycles. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - - #region [ Static ] - - // Static Methods - - /// - /// Exports the given to a CSV file. - /// - /// The name of the CSV file. - /// The cycle data set to be exported. - public static void ExportToCSV(string fileName, CycleDataSet cycles) - { - const string Header = - "AN V RMS,AN V Phase,AN V Peak," + - "BN V RMS,BN V Phase,BN V Peak," + - "CN V RMS,CN V Phase,CN V Peak," + - "Pos V Magnitude,Pos V Angle," + - "Neg V Magnitude,Neg V Angle," + - "Zero V Magnitude,Zero V Angle," + - "AN I RMS,AN I Phase,AN I Peak," + - "BN I RMS,BN I Phase,BN I Peak," + - "CN I RMS,CN I Phase,CN I Peak," + - "Pos I Magnitude,Pos I Angle," + - "Neg I Magnitude,Neg I Angle," + - "Zero I Magnitude,Zero I Angle"; - - using (FileStream fileStream = File.OpenWrite(fileName)) - { - using (TextWriter fileWriter = new StreamWriter(fileStream)) - { - // Write the CSV header to the file - fileWriter.WriteLine(Header); - - // Write data to the file - foreach (CycleData cycleData in cycles.m_cycles) - fileWriter.WriteLine(ToCSV(cycleData)); - } - } - } - - // Converts the cycle data to a row of CSV data. - private static string ToCSV(CycleData cycleData) - { - ComplexNumber[] vSeq = CycleData.CalculateSequenceComponents(cycleData.AN.V, cycleData.BN.V, cycleData.CN.V); - ComplexNumber[] iSeq = CycleData.CalculateSequenceComponents(cycleData.AN.I, cycleData.BN.I, cycleData.CN.I); - - string vCsv = string.Format("{0},{1},{2}", ToCSV(cycleData.AN.V), ToCSV(cycleData.BN.V), ToCSV(cycleData.CN.V)); - string vSeqCsv = string.Format("{0},{1},{2}", ToCSV(vSeq[1]), ToCSV(vSeq[2]), ToCSV(vSeq[0])); - string iCsv = string.Format("{0},{1},{2}", ToCSV(cycleData.AN.I), ToCSV(cycleData.BN.I), ToCSV(cycleData.CN.I)); - string iSeqCsv = string.Format("{0},{1},{2}", ToCSV(iSeq[1]), ToCSV(iSeq[2]), ToCSV(iSeq[0])); - - return string.Format("{0},{1},{2},{3}", vCsv, vSeqCsv, iCsv, iSeqCsv); - } - - // Converts the cycle to CSV data. - private static string ToCSV(Cycle cycle) - { - return string.Format("{0},{1},{2}", cycle.RMS, cycle.Phase.ToDegrees(), cycle.Peak); - } - - // Converts the sequence component to CSV data. - private static string ToCSV(ComplexNumber sequenceComponent) - { - return string.Format("{0},{1}", sequenceComponent.Magnitude, sequenceComponent.Angle.ToDegrees()); - } - - #endregion - } -} diff --git a/Libraries/FaultAlgorithms/FaultAlgorithms.csproj b/Libraries/FaultAlgorithms/FaultAlgorithms.csproj deleted file mode 100644 index b8917102..00000000 --- a/Libraries/FaultAlgorithms/FaultAlgorithms.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - net9.0 - Debug;Development;Release - enable - enable - - - - - - - - diff --git a/Libraries/FaultAlgorithms/MeasurementData.cs b/Libraries/FaultAlgorithms/MeasurementData.cs deleted file mode 100644 index 04da176a..00000000 --- a/Libraries/FaultAlgorithms/MeasurementData.cs +++ /dev/null @@ -1,97 +0,0 @@ -//********************************************************************************************************************* -// MeasurementData.cs -// Version 1.1 and subsequent releases -// -// Copyright 2013, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// -------------------------------------------------------------------------------------------------------------------- -// -// Version 1.0 -// -// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. -// -// openFLE ("this software") is licensed under BSD 3-Clause license. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// Redistributions of source code must retain the above copyright notice, this list of conditions and -// the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -// the following disclaimer in the documentation and/or other materials provided with the distribution. -// -// Neither the name of the Electric Power Research Institute, Inc. (EPRI) nor the names of its contributors -// may be used to endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// -// This software incorporates work covered by the following copyright and permission notice: -// -// TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov -// No copyright is claimed pursuant to 17 USC 105. All Other Rights Reserved. -// -// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); -// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may -// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. -// -// TVA Code Library is provided by the copyright holders and contributors "as is" and any express -// or implied warranties, including, but not limited to, the implied warranties of merchantability -// and fitness for a particular purpose are disclaimed. -// -//********************************************************************************************************************* -// -// Code Modification History: -// ------------------------------------------------------------------------------------------------------------------- -// 05/23/2012 - J. Ritchie Carroll, Grid Protection Alliance -// Generated original version of source code. -// -//********************************************************************************************************************* - -namespace FaultAlgorithms -{ - /// - /// Represents a set of single phase power time-domain data. - /// - public class MeasurementData - { - #region [ Members ] - - // Fields - - /// - /// Array of times in ticks (100 nanosecond intervals). - /// - public long[] Times; - - /// - /// Array of measured values. - /// - public double[] Measurements; - - /// - /// The number of measured samples per cycle of data. - /// - public int SampleRate; - - #endregion - } -} \ No newline at end of file diff --git a/Libraries/FaultAlgorithms/MeasurementDataSet.cs b/Libraries/FaultAlgorithms/MeasurementDataSet.cs deleted file mode 100644 index 1a6c0fb0..00000000 --- a/Libraries/FaultAlgorithms/MeasurementDataSet.cs +++ /dev/null @@ -1,272 +0,0 @@ -//********************************************************************************************************************* -// MeasurementDataSet.cs -// Version 1.1 and subsequent releases -// -// Copyright 2013, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// -------------------------------------------------------------------------------------------------------------------- -// -// Version 1.0 -// -// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. -// -// openFLE ("this software") is licensed under BSD 3-Clause license. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// Redistributions of source code must retain the above copyright notice, this list of conditions and -// the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -// the following disclaimer in the documentation and/or other materials provided with the distribution. -// -// Neither the name of the Electric Power Research Institute, Inc. (EPRI) nor the names of its contributors -// may be used to endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// -// This software incorporates work covered by the following copyright and permission notice: -// -// TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov -// No copyright is claimed pursuant to 17 USC 105. All Other Rights Reserved. -// -// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); -// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may -// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. -// -// TVA Code Library is provided by the copyright holders and contributors "as is" and any express -// or implied warranties, including, but not limited to, the implied warranties of merchantability -// and fitness for a particular purpose are disclaimed. -// -//********************************************************************************************************************* -// -// Code Modification History: -// ------------------------------------------------------------------------------------------------------------------- -// 05/23/2012 - J. Ritchie Carroll, Grid Protection Alliance -// Generated original version of source code. -// -//********************************************************************************************************************* - -using Gemstone; - -namespace FaultAlgorithms -{ - /// - /// Represents a set of 3-phase line-to-neutral and line-to-line time-domain power data. - /// - public class MeasurementDataSet - { - #region [ Members ] - - // Constants - - private const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss.ffffff"; - - // Fields - - /// - /// Line-to-neutral A-phase data. - /// - public MeasurementData AN; - - /// - /// Line-to-neutral B-phase data. - /// - public MeasurementData BN; - - /// - /// Line-to-neutral C-phase data. - /// - public MeasurementData CN; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new . - /// - public MeasurementDataSet() - { - AN = new MeasurementData(); - BN = new MeasurementData(); - CN = new MeasurementData(); - } - - #endregion - - #region [ Methods ] - - /// - /// Uses system frequency to calculate the sample rate for each set - /// of in this measurement data set. - /// - /// The frequency of the measured system, in Hz. - public void CalculateSampleRates(double frequency) - { - CalculateSampleRate(frequency, AN); - CalculateSampleRate(frequency, BN); - CalculateSampleRate(frequency, CN); - } - - /// - /// Explicitly sets the sample rate for each set of - /// in this measurement data set. - /// - /// The sample rate. - public void SetSampleRate(int sampleRate) - { - AN.SampleRate = sampleRate; - BN.SampleRate = sampleRate; - CN.SampleRate = sampleRate; - } - - /// - /// Writes all voltage measurement data to a CSV file. - /// - /// Export file name. - public void ExportVoltageDataToCSV(string fileName) - { - const string Header = "Time,AN,BN,CN,AB,BC,CA"; - - using (FileStream fileStream = File.OpenWrite(fileName)) - { - using (TextWriter fileWriter = new StreamWriter(fileStream)) - { - // Write the CSV header to the file - fileWriter.WriteLine(Header); - - // Write the data to the file - for (int i = 0; i < AN.Times.Length; i++) - { - string time = new DateTime(AN.Times[i]).ToString(DateTimeFormat); - - double an = AN.Measurements[i]; - double bn = BN.Measurements[i]; - double cn = CN.Measurements[i]; - - fileWriter.Write("{0},{1},{2},{3},", time, an, bn, cn); - fileWriter.WriteLine("{0},{1},{2}", an - bn, bn - cn, cn - an); - } - } - } - } - - /// - /// Writes all current measurement data to a CSV file. - /// - /// Export file name. - public void ExportCurrentDataToCSV(string fileName) - { - const string Header = "Time,AN,BN,CN"; - - using (FileStream fileStream = File.OpenWrite(fileName)) - { - using (TextWriter fileWriter = new StreamWriter(fileStream)) - { - // Write the CSV header to the file - fileWriter.WriteLine(Header); - - // Write the data to the file - for (int i = 0; i < AN.Times.Length; i++) - { - string time = new DateTime(AN.Times[i]).ToString(DateTimeFormat); - - double an = AN.Measurements[i]; - double bn = BN.Measurements[i]; - double cn = CN.Measurements[i]; - - fileWriter.WriteLine("{0},{1},{2},{3}", time, an, bn, cn); - } - } - } - } - - private void CalculateSampleRate(double frequency, MeasurementData measurementData) - { - long[] times; - long startTicks; - long endTicks; - double cycles; - - // Get the collection of measurement timestamps - times = measurementData.Times; - - // Determine the start and end time of the data set - startTicks = times[0]; - endTicks = times[times.Length - 1]; - - // Determine the number of cycles in the file, - // based on the system frequency - cycles = frequency * Ticks.ToSeconds(endTicks - startTicks); - - // Calculate the number of samples per cycle - measurementData.SampleRate = (int)Math.Round(times.Length / cycles); - } - - #endregion - - #region [ Static ] - - // Static Methods - - /// - /// Writes all measurement data to a CSV file. - /// - /// Export file name. - /// The voltage measurement data to be written to the file. - /// The current measurement data to be written to the file. - public static void ExportToCSV(string fileName, MeasurementDataSet voltageData, MeasurementDataSet currentData) - { - const string Header = "Time,AN V,BN V,CN V,AB V,BC V,CA V,AN I,BN I,CN I"; - - using (FileStream fileStream = File.Create(fileName)) - { - using (TextWriter fileWriter = new StreamWriter(fileStream)) - { - // Write the CSV header to the file - fileWriter.WriteLine(Header); - - // Write the data to the file - for (int i = 0; i < voltageData.AN.Times.Length; i++) - { - string time = new DateTime(voltageData.AN.Times[i]).ToString(DateTimeFormat); - - double vAN = voltageData.AN.Measurements[i]; - double vBN = voltageData.BN.Measurements[i]; - double vCN = voltageData.CN.Measurements[i]; - - double iAN = currentData.AN.Measurements[i]; - double iBN = currentData.BN.Measurements[i]; - double iCN = currentData.CN.Measurements[i]; - - fileWriter.Write("{0},{1},{2},{3},", time, vAN, vBN, vCN); - fileWriter.Write("{0},{1},{2},", vAN - vBN, vBN - vCN, vCN - vAN); - fileWriter.WriteLine("{0},{1},{2}", iAN, iBN, iCN); - } - } - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Libraries/FaultData/DataAnalysis/CycleDataGroup.cs b/Libraries/FaultData/DataAnalysis/CycleDataGroup.cs deleted file mode 100644 index 3129dd76..00000000 --- a/Libraries/FaultData/DataAnalysis/CycleDataGroup.cs +++ /dev/null @@ -1,115 +0,0 @@ -//****************************************************************************************************** -// CycleDataGroup.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2014 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using openXDA.Model; - -namespace FaultData.DataAnalysis -{ - public class CycleDataGroup - { - #region [ Members ] - - // Constants - private const int RMSIndex = 0; - private const int PhaseIndex = 1; - private const int PeakIndex = 2; - private const int ErrorIndex = 3; - private Asset m_asset; - // Fields - private DataGroup m_dataGroup; - - #endregion - - #region [ Constructors ] - - public CycleDataGroup(DataGroup dataGroup, Asset asset) - { - m_dataGroup = dataGroup; - m_asset = asset; - } - - #endregion - - #region [ Properties ] - - public DataSeries RMS - { - get - { - return m_dataGroup[RMSIndex]; - } - } - - public DataSeries Phase - { - get - { - return m_dataGroup[PhaseIndex]; - } - } - - public DataSeries Peak - { - get - { - return m_dataGroup[PeakIndex]; - } - } - - public DataSeries Error - { - get - { - return m_dataGroup[ErrorIndex]; - } - } - - public Asset Asset - { - get - { - return m_asset; - } - } - #endregion - - #region [ Methods ] - - public DataGroup ToDataGroup() - { - return m_dataGroup; - } - - public CycleDataGroup ToSubGroup(int startIndex, int endIndex) - { - return new CycleDataGroup(m_dataGroup.ToSubGroup(startIndex, endIndex), m_asset); - } - - public CycleDataGroup ToSubGroup(DateTime startTime, DateTime endTime) - { - return new CycleDataGroup(m_dataGroup.ToSubGroup(startTime, endTime), m_asset); - } - - #endregion - } -} diff --git a/Libraries/FaultData/DataAnalysis/DataGroup.cs b/Libraries/FaultData/DataAnalysis/DataGroup.cs deleted file mode 100644 index 20d91b75..00000000 --- a/Libraries/FaultData/DataAnalysis/DataGroup.cs +++ /dev/null @@ -1,662 +0,0 @@ -//****************************************************************************************************** -// DataGroup.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 05/19/2014 - Stephen C. Wills -// Generated original version of source code. -// 12/23/2019 - C. Lackner -// Adjusted to read data from blob for each dataseries. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone; -using Gemstone.Data.Model; -using Ionic.Zlib; -using Microsoft.Data.SqlClient; -using openXDA.Model; - -namespace FaultData.DataAnalysis -{ - public enum DataClassification - { - Trend, - Event, - FastRMS, - Unknown - } - - public class DataGroup - { - #region [ Members ] - - // Constants - - /// - /// Maximum sample rate, in samples per minute, of data classified as . - /// - public const double TrendThreshold = 1.0D; - - // Fields - private Asset m_asset; - private DateTime m_startTime; - private DateTime m_endTime; - private int m_samples; - - private List m_dataSeries; - private List m_disturbances; - private DataClassification m_classification; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - public DataGroup() - { - m_dataSeries = new List(); - m_disturbances = new List(); - m_classification = DataClassification.Unknown; - m_asset = null; - } - - /// - /// Creates a new instance of the class. - /// - /// Asset associated with this datagroup - public DataGroup(Asset asset) - { - m_dataSeries = new List(); - m_disturbances = new List(); - m_classification = DataClassification.Unknown; - m_asset = asset; - } - - /// - /// Creates a new instance of the class. - /// - /// Collection of data series to be added to the data group. - public DataGroup(IEnumerable dataSeries) - : this() - { - foreach (DataSeries series in dataSeries) - Add(series); - } - - /// - /// Creates a new instance of the class. - /// - /// Collection of data series to be added to the data group. - /// Asset associated with this datagroup - public DataGroup(IEnumerable dataSeries, Asset asset) - : this(asset) - { - foreach (DataSeries series in dataSeries) - Add(series); - } - - #endregion - - #region [ Properties ] - - /// - /// Gets the line from which measurements were taken to create the group of data. - /// - public Asset Asset - { - get - { - return m_asset; - } - } - - /// - /// Gets the start time of the group of data. - /// - public DateTime StartTime - { - get - { - return m_startTime; - } - } - - /// - /// Gets the end time of the group of data. - /// - public DateTime EndTime - { - get - { - return m_endTime; - } - } - - /// - /// Gets the number of samples in each series. - /// - public int Samples - { - get - { - return m_samples; - } - } - - /// - /// Gets the sample rate, in samples per second, - /// of the data series in this data group. - /// - public double SamplesPerSecond - { - get - { - if (!m_dataSeries.Any()) - return double.NaN; - - return m_dataSeries[0].SampleRate; - } - } - - /// - /// Gets the duration, in seconds, - /// of the data series in this data group. - /// - public double Duration - { - get - { - if (!m_dataSeries.Any()) - return double.NaN; - - return m_dataSeries[0].Duration; - } - } - - /// - /// Gets the sample rate, in samples per hour, - /// of the data series in this data group. - /// - public double SamplesPerHour - { - get - { - return (m_samples - 1) / (m_endTime - m_startTime).TotalHours; - } - } - - /// - /// Gets flag that indicates whether the data series - /// in this data group are marked as trend channels. - /// - public bool Trend => - m_dataSeries.Any(dataSeries => dataSeries.SeriesInfo?.Channel.Trend == true); - - /// - /// Gets the channels contained in this data group. - /// - public IReadOnlyList DataSeries - { - get - { - return m_dataSeries.AsReadOnly(); - } - } - - /// - /// Gets the disturbances contained in this data group. - /// - public IReadOnlyList Disturbances - { - get - { - return m_disturbances.AsReadOnly(); - } - } - - /// - /// Gets the classification of this group of data as of the last call to . - /// - public DataClassification Classification - { - get - { - if (m_classification == DataClassification.Unknown) - Classify(); - - return m_classification; - } - } - - public DataSeries this[int index] - { - get - { - return m_dataSeries[index]; - } - } - - #endregion - - #region [ Methods ] - - /// - /// Adds a channel to the group of data. - /// - /// The channel to be added to the group. - /// - /// True if the channel was successfully added. False if the channel was excluded - /// because the channel does not match the other channels already in the data group. - /// - public bool Add(DataSeries dataSeries) - { - Asset asset; - DateTime startTime; - DateTime endTime; - int samples; - bool trend; - - // Unable to add null data series - if ((object)dataSeries == null) - return false; - - // Data series without data is irrelevant to data grouping - if (!dataSeries.DataPoints.Any()) - return false; - - // Do not add the same data series twice - if (m_dataSeries.Contains(dataSeries)) - return false; - - // Get information about the line this data is associated with - if ((object)dataSeries.SeriesInfo != null) - asset = dataSeries.SeriesInfo.Channel.Asset; - else - asset = null; - - // Get the start time, end time, number of samples, and - // trend flag for the data series passed into this function - startTime = dataSeries.DataPoints[0].Time; - endTime = dataSeries.DataPoints[dataSeries.DataPoints.Count - 1].Time; - samples = dataSeries.DataPoints.Count; - trend = dataSeries.SeriesInfo?.Channel.Trend == true; - - // If there are any disturbances in this data group that do not overlap - // with the data series, do not include the data series in the data group - if (m_disturbances.Select(disturbance => disturbance.ToRange()).Any(range => range.Start > endTime || range.End < startTime)) - return false; - - // If there are any disturbances associated with the data in this group and the data - // to be added is trending data, do not include the trending data in the data group - if (m_disturbances.Any() && CalculateSamplesPerMinute(startTime, endTime, samples) <= TrendThreshold) - return false; - - // At this point, if there is no existing data in the data - // group, add the data as the first series in the data group - if (m_dataSeries.Count == 0) - { - if (m_asset == null) - { - m_asset = asset; - } - m_startTime = startTime; - m_endTime = endTime; - m_samples = samples; - - m_dataSeries.Add(dataSeries); - m_classification = DataClassification.Unknown; - - return true; - } - - // If the data being added matches the parameters for this data group, add the data to the data group - // Note that it does not have to match Asset - if (startTime == m_startTime && endTime == m_endTime && samples == m_samples && trend == Trend) - { - m_dataSeries.Add(dataSeries); - return true; - } - - return false; - } - - /// - /// Adds a disturbance to the group of data. - /// - /// The disturbance to be added to the group. - /// True if the disturbance was successfully added. - public bool Add(ReportedDisturbance disturbance) - { - // Unable to add null disturbance - if ((object)disturbance == null) - return false; - - // Do not add the same disturbance twice - if (m_disturbances.Contains(disturbance)) - return false; - - // If the data in this data group is trending data, - // do not add the disturbance to the data group - if (Classification == DataClassification.Trend) - return false; - - // Get the start time and end time of the disturbance. - DateTime startTime = disturbance.Time; - DateTime endTime = startTime + disturbance.Duration; - - // If there are no data series and no other disturbances, - // make this the first piece of data to be added to the data group - if (!m_dataSeries.Any() && !m_disturbances.Any()) - { - m_startTime = startTime; - m_endTime = endTime; - m_disturbances.Add(disturbance); - m_classification = DataClassification.Event; - return true; - } - - // If the disturbance overlaps with - // this data group, add the disturbance - if (startTime <= m_endTime && m_startTime <= endTime) - { - // If the only data in the data group is disturbances, - // adjust the start time and end time - if (!m_dataSeries.Any() && startTime < m_startTime) - m_startTime = startTime; - - if (!m_dataSeries.Any() && endTime > m_endTime) - m_endTime = endTime; - - m_disturbances.Add(disturbance); - return true; - } - - return false; - } - - /// - /// Removes a channel from the data group. - /// - /// The channel to be removed from the data group. - /// True if the channel existed in the group and was removed; false otherwise. - public bool Remove(DataSeries dataSeries) - { - if (m_dataSeries.Remove(dataSeries)) - { - m_classification = m_disturbances.Any() - ? DataClassification.Event - : DataClassification.Unknown; - - return true; - } - - return false; - } - - /// - /// Removes a disturbance from the data group. - /// - /// THe disturbance to be removed from the data group. - /// True if the disturbance existed in the group and was removed; false otherwise. - public bool Remove(ReportedDisturbance disturbance) - { - if (m_disturbances.Remove(disturbance)) - { - if (!m_disturbances.Any()) - m_classification = DataClassification.Unknown; - - return true; - } - - return false; - } - - public DataGroup ToSubGroup(int startIndex, int endIndex) - { - DataGroup subGroup = new DataGroup(); - - foreach (DataSeries dataSeries in m_dataSeries) - subGroup.Add(dataSeries.ToSubSeries(startIndex, endIndex)); - - return subGroup; - } - - public DataGroup ToSubGroup(DateTime startTime, DateTime endTime) - { - DataGroup subGroup = new DataGroup(); - - foreach (DataSeries dataSeries in m_dataSeries) - subGroup.Add(dataSeries.ToSubSeries(startTime, endTime)); - - return subGroup; - } - - // Overwrite To Data to save Data into ChannelBlob instead of File Blob - // This needs to be done to avoid data duplication - public Dictionary ToData() - { - Dictionary result = new Dictionary(); - - var timeSeries = m_dataSeries[0].DataPoints - .Select(dataPoint => new { Time = dataPoint.Time.Ticks, Compressed = false }) - .ToList(); - - for (int i = 1; i < timeSeries.Count; i++) - { - long previousTimestamp = m_dataSeries[0][i - 1].Time.Ticks; - long timestamp = timeSeries[i].Time; - long diff = timestamp - previousTimestamp; - - if (diff >= 0 && diff <= ushort.MaxValue) - timeSeries[i] = new { Time = diff, Compressed = true }; - - - } - - int timeSeriesByteLength = timeSeries.Sum(obj => obj.Compressed ? sizeof(ushort) : sizeof(int) + sizeof(long)); - int dataSeriesByteLength = sizeof(int) + (2 * sizeof(double)) + (m_samples * sizeof(ushort)); - int totalByteLength = sizeof(int) + timeSeriesByteLength + dataSeriesByteLength; - - foreach (DataSeries dataSeries in m_dataSeries) - { - byte[] data = new byte[totalByteLength]; - int offset = 0; - - offset += LittleEndian.CopyBytes(m_samples, data, offset); - - List uncompressedIndexes = timeSeries - .Select((obj, Index) => new { obj.Compressed, Index }) - .Where(obj => !obj.Compressed) - .Select(obj => obj.Index) - .ToList(); - - for (int i = 0; i < uncompressedIndexes.Count; i++) - { - int index = uncompressedIndexes[i]; - int nextIndex = (i + 1 < uncompressedIndexes.Count) ? uncompressedIndexes[i + 1] : timeSeries.Count; - - offset += LittleEndian.CopyBytes(nextIndex - index, data, offset); - offset += LittleEndian.CopyBytes(timeSeries[index].Time, data, offset); - - for (int j = index + 1; j < nextIndex; j++) - offset += LittleEndian.CopyBytes((ushort)timeSeries[j].Time, data, offset); - } - - - if (dataSeries.Calculated) continue; - - const ushort NaNValue = ushort.MaxValue; - const ushort MaxCompressedValue = ushort.MaxValue - 1; - int seriesID = dataSeries.SeriesInfo?.ID ?? 0; - double range = dataSeries.Maximum - dataSeries.Minimum; - double decompressionOffset = dataSeries.Minimum; - double decompressionScale = range / MaxCompressedValue; - double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; - - offset += LittleEndian.CopyBytes(seriesID, data, offset); - offset += LittleEndian.CopyBytes(decompressionOffset, data, offset); - offset += LittleEndian.CopyBytes(decompressionScale, data, offset); - - foreach (DataPoint dataPoint in dataSeries.DataPoints) - { - ushort compressedValue = (ushort)Math.Round((dataPoint.Value - decompressionOffset) * compressionScale); - - if (compressedValue == NaNValue) - compressedValue--; - - if (double.IsNaN(dataPoint.Value)) - compressedValue = NaNValue; - - offset += LittleEndian.CopyBytes(compressedValue, data, offset); - } - byte[] returnArray = GZipStream.CompressBuffer(data); - returnArray[0] = 0x44; - returnArray[1] = 0x33; - - int dataSeriesID = dataSeries.SeriesInfo?.ID ?? 0; - result.Add(dataSeriesID, returnArray); - } - - return result ; - } - - public void FromData(List data) - { - FromData(null, data); - } - - public void FromData(Meter meter, List dataList) - { - var decompressed = dataList.SelectMany(d => ChannelData.Decompress(d)); - - foreach (Tuple> tuple in decompressed) - { - DataSeries dataSeries = new DataSeries(); - - if (tuple.Item1 > 0 && !(meter is null)) - dataSeries.SeriesInfo = meter.Series.FirstOrDefault(s => s.ID == tuple.Item1); - - dataSeries.DataPoints = tuple.Item2; - - Add(dataSeries); - } - } - - private void Classify() - { - if (IsTrend()) - m_classification = DataClassification.Trend; - else if (IsEvent()) - m_classification = DataClassification.Event; - else if (IsFastRMS()) - m_classification = DataClassification.FastRMS; - else - m_classification = DataClassification.Unknown; - } - - private bool IsTrend() - { - if (!m_dataSeries.Any() || m_disturbances.Any()) - return false; - - double samplesPerMinute = CalculateSamplesPerMinute(m_startTime, m_endTime, m_samples); - return samplesPerMinute <= TrendThreshold; - } - - private bool IsEvent() - { - if (m_disturbances.Any()) - return true; - - return m_dataSeries - .Where(dataSeries => (object)dataSeries.SeriesInfo != null) - .Where(IsInstantaneous) - .Where(dataSeries => dataSeries.SeriesInfo.Channel.MeasurementType.Name != "Digital") - .Any(); - } - - private bool IsInstantaneous(DataSeries dataSeries) - { - string characteristicName = dataSeries.SeriesInfo.Channel.MeasurementCharacteristic.Name; - string seriesTypeName = dataSeries.SeriesInfo.SeriesType.Name; - - return (characteristicName == "Instantaneous") && - (seriesTypeName == "Values" || seriesTypeName == "Instantaneous"); - } - - private bool IsFastRMS() - { - return m_dataSeries - .Where(dataSeries => (object)dataSeries.SeriesInfo != null) - .Where(IsRMS) - .Any(); - } - - private bool IsRMS(DataSeries dataSeries) - { - string characteristicName = dataSeries.SeriesInfo.Channel.MeasurementCharacteristic.Name; - string seriesTypeName = dataSeries.SeriesInfo.SeriesType.Name; - - return (characteristicName == "RMS") && - (seriesTypeName == "Values" || seriesTypeName == "Instantaneous"); - } - - private double CalculateSamplesPerMinute(DateTime startTime, DateTime endTime, int samples) - { - return (samples - 1) / (endTime - startTime).TotalMinutes; - } - - #endregion - } - - public static partial class TableOperationsExtensions - { - public static Event GetEvent(this TableOperations eventTable, FileGroup fileGroup, DataGroup dataGroup) - { - int fileGroupID = fileGroup.ID; - int assetID = dataGroup.Asset.ID; - DateTime startTime = dataGroup.StartTime; - DateTime endTime = dataGroup.EndTime; - int samples = dataGroup.Samples; - - IDbDataParameter startTimeParameter = new SqlParameter() - { - ParameterName = nameof(dataGroup.StartTime), - DbType = DbType.DateTime2, - Value = startTime - }; - - IDbDataParameter endTimeParameter = new SqlParameter() - { - ParameterName = nameof(dataGroup.EndTime), - DbType = DbType.DateTime2, - Value = endTime - }; - - RecordRestriction recordRestriction = - new RecordRestriction("FileGroupID = {0}", fileGroupID) & - new RecordRestriction("AssetID = {0}", assetID) & - new RecordRestriction("StartTime = {0}", startTimeParameter) & - new RecordRestriction("EndTime = {0}", endTimeParameter) & - new RecordRestriction("Samples = {0}", samples); - - return eventTable.QueryRecord(recordRestriction); - } - } -} diff --git a/Libraries/FaultData/DataAnalysis/DataSeries.cs b/Libraries/FaultData/DataAnalysis/DataSeries.cs deleted file mode 100644 index cbc7d9d1..00000000 --- a/Libraries/FaultData/DataAnalysis/DataSeries.cs +++ /dev/null @@ -1,588 +0,0 @@ -//****************************************************************************************************** -// DataSeries.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 05/15/2014 - Stephen C. Wills -// Generated original version of source code. -// 07/09/2019 - Christoph Lackner -// Added length property and Threshhold method. -// -//****************************************************************************************************** - -using Gemstone; -using Gemstone.Numeric.Interpolation; -using Ionic.Zlib; -using openXDA.Model; - -namespace FaultData.DataAnalysis -{ - /// - /// Represents a series of data points. - /// - public class DataSeries - { - #region [ Members ] - - // Fields - private Series m_seriesInfo; - private List m_dataPoints; - - private double? m_duration; - private double? m_sampleRate; - private double? m_minimum; - private double? m_maximum; - private double? m_average; - - #endregion - - #region [ Constructors ] - - public DataSeries() - { - m_dataPoints = new List(); - } - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the configuration information - /// that defines the data in this series. - /// - public Series SeriesInfo - { - get - { - return m_seriesInfo; - } - set - { - m_seriesInfo = value; - } - } - - /// - /// Gets or sets the data points that make up the series. - /// - public List DataPoints - { - get - { - return m_dataPoints; - } - set - { - m_dataPoints = value ?? new List(); - m_duration = null; - m_sampleRate = null; - m_minimum = null; - m_maximum = null; - m_average = null; - } - } - - /// - /// Gets the duration of the series, in seconds. - /// - public double Duration - { - get - { - if (m_duration.HasValue) - return m_duration.Value; - - if (!m_dataPoints.Any()) - return double.NaN; - - m_duration = m_dataPoints.Last().Time.Subtract(m_dataPoints.First().Time).TotalSeconds; - - return m_duration.Value; - } - } - - /// - /// Gets the Start Time of the dataseries. - /// - public DateTime StartTime - { - get - { - if (!m_dataPoints.Any()) - return DateTime.MinValue; - return m_dataPoints.First().Time; - } - } - - /// - /// Gets the End Time of the dataseries. - /// - public DateTime EndTime - { - get - { - if (!m_dataPoints.Any()) - return DateTime.MinValue; - return m_dataPoints.Last().Time; - } - } - - - /// - /// Gets the Length of the series, in datapoints. - /// - public int Length - { - get - { - - if (!m_dataPoints.Any()) - return 0; - - return m_dataPoints.Count; - } - } - - /// - /// Gets the sample rate of the series, in samples per second. - /// - public double SampleRate - { - get - { - if (m_sampleRate.HasValue) - return m_sampleRate.Value; - - if (!m_dataPoints.Any()) - return double.NaN; - - int index = (m_dataPoints.Count > 128) ? 128 : m_dataPoints.Count - 1; - - m_sampleRate = (Duration != 0.0D) - ? index / (m_dataPoints[index].Time - m_dataPoints[0].Time).TotalSeconds - : double.NaN; - - return m_sampleRate.Value; - } - } - - /// - /// Gets the maximum value in the series. - /// - public double Maximum - { - get - { - if (m_maximum.HasValue) - return m_maximum.Value; - - if (!m_dataPoints.Any(dataPoint => !double.IsNaN(dataPoint.Value))) - return double.NaN; - - m_maximum = m_dataPoints - .Select(point => point.Value) - .Where(value => !double.IsNaN(value)) - .Max(); - - return m_maximum.Value; - } - } - - /// - /// Gets the minimum value in the series. - /// - public double Minimum - { - get - { - if (m_minimum.HasValue) - return m_minimum.Value; - - if (!m_dataPoints.Any(dataPoint => !double.IsNaN(dataPoint.Value))) - return double.NaN; - - m_minimum = m_dataPoints - .Select(dataPoint => dataPoint.Value) - .Where(value => !double.IsNaN(value)) - .Min(); - - return m_minimum.Value; - } - } - - /// - /// Gets the average value in the series. - /// - public double Average - { - get - { - if (m_average.HasValue) - return m_average.Value; - - if (!m_dataPoints.Any(dataPoint => !double.IsNaN(dataPoint.Value))) - return double.NaN; - - m_average = m_dataPoints - .Select(dataPoint => dataPoint.Value) - .Where(value => !double.IsNaN(value)) - .Average(); - - return m_average.Value; - } - } - - public DataPoint this[int index] - { - get - { - return m_dataPoints[index]; - } - } - - /// - /// Flag that tells the DataGroup .ToData function not to add to data blob because this value is calculated. - /// - public bool Calculated { get; set; } = false; - - #endregion - - #region [ Methods ] - - - /// - /// Creates a new that is a subset. - /// - /// The index at which the new DataSeries starts. - /// The index at which the new DataSeries ends. - /// a new - public DataSeries ToSubSeries(int startIndex, int endIndex) - { - DataSeries subSeries = new DataSeries(); - int count; - - subSeries.SeriesInfo = m_seriesInfo; - - if (startIndex < 0) - startIndex = 0; - - if (endIndex >= m_dataPoints.Count) - endIndex = m_dataPoints.Count - 1; - - count = endIndex - startIndex + 1; - - if (count > 0) - subSeries.DataPoints = m_dataPoints.Skip(startIndex).Take(count).ToList(); - - return subSeries; - } - - /// - /// Creates a new that is a subset. - /// - /// The index at which the new DataSeries starts. - /// a new - public DataSeries ToSubSeries(int startSeries) => ToSubSeries(startSeries, this.Length); - - public DataSeries ToSubSeries(DateTime startTime, DateTime endTime) - { - DataSeries subSeries = new DataSeries(); - - subSeries.SeriesInfo = m_seriesInfo; - - subSeries.DataPoints = m_dataPoints - .SkipWhile(point => point.Time < startTime) - .TakeWhile(point => point.Time <= endTime) - .ToList(); - - return subSeries; - } - - /// - /// Creates a new that is a subset. - /// - /// The time at which the new DataSeries starts. - /// a new - public DataSeries ToSubSeries(DateTime startTime) => ToSubSeries(startTime, this[this.Length - 1].Time); - - public DataSeries Shift(TimeSpan timeShift) - { - DataSeries shifted = new DataSeries(); - - shifted.SeriesInfo = m_seriesInfo; - - shifted.DataPoints = m_dataPoints - .Select(dataPoint => dataPoint.Shift(timeShift)) - .ToList(); - - return shifted; - } - - public DataSeries Negate() - { - DataSeries negatedDataSeries = new DataSeries(); - - negatedDataSeries.DataPoints = m_dataPoints - .Select(point => point.Negate()) - .ToList(); - - return negatedDataSeries; - } - - public DataSeries Add(DataSeries operand) - { - DataSeries sum = new DataSeries(); - - if (m_dataPoints.Count != operand.DataPoints.Count) - throw new InvalidOperationException("Cannot take the sum of series with mismatched time values"); - - sum.DataPoints = m_dataPoints - .Zip(operand.DataPoints, Add) - .ToList(); - - return sum; - } - - public DataSeries Subtract(DataSeries operand) - { - return Add(operand.Negate()); - } - - public DataSeries Multiply(double value) - { - DataSeries result = new DataSeries(); - - result.DataPoints = m_dataPoints - .Select(point => point.Multiply(value)) - .ToList(); - - return result; - } - - public DataSeries Copy() - { - return Multiply(1.0D); - } - - public int Threshhold(double value) - { - return m_dataPoints.FindIndex(x => x.LargerThan(value)); - } - - /// - /// Downsamples the current DataSeries to requested sample count, if the - /// - /// - public void Downsample(int maxSampleCount) - { - // don't actually downsample, if it doesn't need it. - if (DataPoints.Count <= maxSampleCount) return; - - DateTime epoch = new DateTime(1970, 1, 1); - double startTime = StartTime.Subtract(epoch).TotalMilliseconds; - double endTime = EndTime.Subtract(epoch).TotalMilliseconds; - List data = new List(); - - // milliseconds per returned sampled size - int step = (int)(Duration*1000) / maxSampleCount; - if (step < 1) - step = 1; - - int index = 0; - for (double n = startTime * 1000; n <= endTime * 1000; n += 2 * step) - { - DataPoint min = null; - DataPoint max = null; - - while (index < DataPoints.Count() && DataPoints[index].Time.Subtract(epoch).TotalMilliseconds * 1000 < n + 2 * step) - { - if (min == null || min.Value > DataPoints[index].Value) - min = DataPoints[index]; - - if (max == null || max.Value <= DataPoints[index].Value) - max = DataPoints[index]; - - ++index; - } - - if (min != null) - { - if (min.Time < max.Time) - { - data.Add(min); - data.Add(max); - } - else if (min.Time > max.Time) - { - data.Add(max); - data.Add(min); - } - else - { - data.Add(min); - } - } - } - DataPoints = data; - } - - /// - /// Upsamples the current DataSeries to requested sample count, assuming the requested rate is larger than the current - /// - /// - public void Upsample(int minSamplesPerCycle, double systemFrequency) - { - // don't actually upsample, if it doesn't need it. - if (minSamplesPerCycle <= 0) - return; - TimeSpan duration = EndTime - StartTime; - double cycles = duration.TotalSeconds * systemFrequency; - int minSampleCount = (int)Math.Round(cycles * minSamplesPerCycle); - if (minSampleCount <= DataPoints.Count) - return; - - // Creating spline fit to perform upsampling - List xValues = DataPoints - .Select(point => (double) point.Time.Subtract(StartTime).Ticks) - .ToList(); - List yValues= DataPoints - .Select(point => point.Value) - .ToList(); - SplineFit splineFit = SplineFit.ComputeCubicSplines(xValues, yValues); - - List data = Enumerable - .Range(0, minSampleCount) - .Select(sample => sample * duration.Ticks / minSampleCount) - .Select(sampleTicks => - new DataPoint() - { - Time = StartTime.AddTicks(sampleTicks), - Value = splineFit.CalculateY(sampleTicks) - } - ).ToList(); - - DataPoints = data; - } - - #endregion - - #region [ Static ] - - // Static Methods - - public static DataSeries Merge(IEnumerable dataSeriesList) - { - if (dataSeriesList == null) - throw new ArgumentNullException(nameof(dataSeriesList)); - - DataSeries mergedSeries = new DataSeries(); - DateTime lastTime = default(DateTime); - - IEnumerable dataPoints = dataSeriesList - .Where(dataSeries => dataSeries != null) - .Where(dataSeries => dataSeries.DataPoints.Count != 0) - .OrderBy(dataSeries => dataSeries[0].Time) - .SelectMany(series => series.DataPoints); - - foreach (DataPoint next in dataPoints) - { - if (mergedSeries.DataPoints.Count == 0 || next.Time > lastTime) - { - mergedSeries.DataPoints.Add(next); - lastTime = next.Time; - } - } - - return mergedSeries; - } - - private static DataPoint Add(DataPoint point1, DataPoint point2) - { - return point1.Add(point2); - } - - public static DataSeries FromData(Meter meter, byte[] data) - { - - if (data == null) - return null; - - // Restore the GZip header before uncompressing - data[0] = 0x1F; - data[1] = 0x8B; - - byte[] uncompressedData = GZipStream.UncompressBuffer(data); - int offset = 0; - - int samples = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - List times = new List(); - - while (times.Count < samples) - { - int timeValues = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - long currentValue = LittleEndian.ToInt64(uncompressedData, offset); - offset += sizeof(long); - times.Add(new DateTime(currentValue)); - - for (int i = 1; i < timeValues; i++) - { - currentValue += LittleEndian.ToUInt16(uncompressedData, offset); - offset += sizeof(ushort); - times.Add(new DateTime(currentValue)); - } - } - - DataSeries dataSeries = new DataSeries(); - int seriesID = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - if (seriesID > 0 && !(meter is null)) - dataSeries.SeriesInfo = meter.Series.FirstOrDefault(s => s.ID == seriesID); - - const ushort NaNValue = ushort.MaxValue; - double decompressionOffset = LittleEndian.ToDouble(uncompressedData, offset); - double decompressionScale = LittleEndian.ToDouble(uncompressedData, offset + sizeof(double)); - offset += 2 * sizeof(double); - - for (int i = 0; i < samples; i++) - { - ushort compressedValue = LittleEndian.ToUInt16(uncompressedData, offset); - offset += sizeof(ushort); - - double decompressedValue = decompressionScale * compressedValue + decompressionOffset; - - if (compressedValue == NaNValue) - decompressedValue = double.NaN; - - dataSeries.DataPoints.Add(new DataPoint() - { - Time = times[i], - Value = decompressedValue - }); - } - - return dataSeries; - - } - - #endregion - } -} diff --git a/Libraries/FaultData/DataAnalysis/ReportedDisturbance.cs b/Libraries/FaultData/DataAnalysis/ReportedDisturbance.cs deleted file mode 100644 index a078eb5b..00000000 --- a/Libraries/FaultData/DataAnalysis/ReportedDisturbance.cs +++ /dev/null @@ -1,58 +0,0 @@ -//****************************************************************************************************** -// ReportedDisturbance.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 12/06/2017 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone; -using Gemstone.PQDIF.Logical; - -namespace FaultData.DataAnalysis -{ - public class ReportedDisturbance - { - public ReportedDisturbance(Phase phase, DateTime time, double max, double min, double avg, TimeSpan duration, QuantityUnits units) - { - Phase = phase; - Time = time; - Maximum = max; - Minimum = min; - Average = avg; - Duration = duration; - Units = units; - } - - public Phase Phase { get; } - public DateTime Time { get; } - public double Maximum { get; } - public double Minimum { get; } - public double Average { get; } - public TimeSpan Duration { get; } - public QuantityUnits Units { get; } - - public ReportedDisturbance ShiftTimestampTo(DateTime shiftedTime) => - new ReportedDisturbance(Phase, shiftedTime, Maximum, Minimum, Average, Duration, Units); - - public Range ToRange() - { - return new Range(Time, Time + Duration); - } - } -} diff --git a/Libraries/FaultData/DataAnalysis/Transform.cs b/Libraries/FaultData/DataAnalysis/Transform.cs deleted file mode 100644 index 9e4aa28d..00000000 --- a/Libraries/FaultData/DataAnalysis/Transform.cs +++ /dev/null @@ -1,358 +0,0 @@ -//****************************************************************************************************** -// Transform.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/28/2014 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Numeric.Analysis; -using openXDA.Model; - -namespace FaultData.DataAnalysis -{ - public static class Transform - { - public static DataGroup Combine(params DataGroup[] dataGroups) - { - DataGroup combination = new DataGroup(); - - foreach (DataGroup dataGroup in dataGroups) - { - foreach (DataSeries dataSeries in dataGroup.DataSeries) - combination.Add(dataSeries); - } - - return combination; - } - - public static VICycleDataGroup ToVICycleDataGroup(VIDataGroup dataGroup, double frequency, bool compress = false) - { - DataSeries[] cycleSeries = dataGroup.Data; - - return new VICycleDataGroup(cycleSeries - .Where(dataSeries => (object)dataSeries != null) - .Select(dataSeries => ToCycleDataGroup(dataSeries, frequency, compress)) - .ToList(), dataGroup.Asset); - } - - public static CycleDataGroup ToCycleDataGroup(DataSeries dataSeries, double frequency, bool compress=false) - { - if (dataSeries is null) - return null; - - DataSeries rmsSeries = new DataSeries(); - DataSeries phaseSeries = new DataSeries(); - DataSeries peakSeries = new DataSeries(); - DataSeries errorSeries = new DataSeries(); - - // Set series info to the source series info - rmsSeries.SeriesInfo = dataSeries.SeriesInfo; - phaseSeries.SeriesInfo = dataSeries.SeriesInfo; - peakSeries.SeriesInfo = dataSeries.SeriesInfo; - errorSeries.SeriesInfo = dataSeries.SeriesInfo; - - // Get samples per cycle of the data series based on the given frequency - int samplesPerCycle = CalculateSamplesPerCycle(dataSeries, frequency); - - //preinitialize size of SeriesInfo - int ncycleData = dataSeries.DataPoints.Count - samplesPerCycle + 1; - - if (ncycleData <= 0) - return null; - - rmsSeries.DataPoints.Capacity = ncycleData; - phaseSeries.DataPoints.Capacity = ncycleData; - peakSeries.DataPoints.Capacity = ncycleData; - errorSeries.DataPoints.Capacity = ncycleData; - - // Initialize arrays of y-values and t-values for calculating cycle data as necessary - double[] yValues = new double[samplesPerCycle]; - double[] tValues = new double[samplesPerCycle]; - - void CaptureCycle(int cycleIndex) - { - DateTime startTime = dataSeries.DataPoints[0].Time; - - for (int i = 0; i < samplesPerCycle; i++) - { - DateTime time = dataSeries.DataPoints[cycleIndex + i].Time; - double value = dataSeries.DataPoints[cycleIndex + i].Value; - tValues[i] = time.Subtract(startTime).TotalSeconds; - yValues[i] = value; - } - } - - // Obtain a list of time gaps in the data series - List gapIndexes = Enumerable.Range(0, dataSeries.DataPoints.Count - 1) - .Where(index => - { - DataPoint p1 = dataSeries[index]; - DataPoint p2 = dataSeries[index + 1]; - double cycleDiff = (p2.Time - p1.Time).TotalSeconds * frequency; - - // Detect gaps larger than a quarter cycle. - // Tolerance of 0.000062 calculated - // assuming 3.999 samples per cycle - return (cycleDiff > 0.250062); - }) - .ToList(); - - double sum = 0; - - if (dataSeries.DataPoints.Count >= samplesPerCycle) - { - CaptureCycle(0); - sum = yValues.Sum(y => y * y); - - DateTime cycleTime = dataSeries.DataPoints[0].Time; - SineWave sineFit = WaveFit.SineFit(yValues, tValues, frequency); - double phase = sineFit.Phase; - - double ComputeSineError() => tValues - .Select(sineFit.CalculateY) - .Zip(yValues, (estimate, value) => Math.Abs(estimate - value)) - .Sum(); - - double sineError = ComputeSineError(); - double previousSineError = sineError; - - rmsSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = Math.Sqrt(sum / samplesPerCycle) - }); - - phaseSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = phase - }); - - peakSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = sineFit.Amplitude - }); - - errorSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = sineError - }); - - // Reduce RMS to max 2 pt per cycle to get half cycle RMS - int step = 1; - if (compress) - step = (int)Math.Floor(samplesPerCycle / 2.0D); - if (step == 0) - step = 1; - - for (int cycleIndex = step; cycleIndex < dataSeries.DataPoints.Count - samplesPerCycle + 1; cycleIndex += step) - { - for (int j = 0; j < step; j++) - { - int oldIndex = cycleIndex - step + j; - int newIndex = oldIndex + samplesPerCycle; - double oldValue = dataSeries.DataPoints[oldIndex].Value; - double newValue = dataSeries.DataPoints[newIndex].Value; - sum += newValue * newValue - oldValue * oldValue; - } - - // If the cycle following i contains a data gap, do not calculate cycle data - if (gapIndexes.Any(index => cycleIndex <= index && (cycleIndex + samplesPerCycle - 1) > index)) - continue; - - phase += 2 * Math.PI * frequency * (dataSeries.DataPoints[cycleIndex].Time - cycleTime).TotalSeconds; - - // Use the time of the first data point in the cycle as the time of the cycle - cycleTime = dataSeries.DataPoints[cycleIndex].Time; - - CaptureCycle(cycleIndex); - - if (compress) - sineError = ComputeSineError(); - - if (!compress || Math.Abs(previousSineError - sineError) > sineError * 0.0001) - { - sineFit = WaveFit.SineFit(yValues, tValues, frequency); - phase = sineFit.Phase; - sineError = ComputeSineError(); - } - - previousSineError = sineError; - - rmsSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = Math.Sqrt(sum / samplesPerCycle) - }); - - phaseSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = phase - }); - - peakSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = sineFit.Amplitude - }); - - errorSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = sineError - }); - } - } - - // Add a series to the data group for each series of cycle data - DataGroup dataGroup = new DataGroup(); - dataGroup.Add(rmsSeries); - dataGroup.Add(phaseSeries); - dataGroup.Add(peakSeries); - dataGroup.Add(errorSeries); - - return new CycleDataGroup(dataGroup, dataSeries.SeriesInfo.Channel.Asset); - } - - public static DataSeries ToRMS(DataSeries dataSeries, double frequency, bool compress = false) - { - DataSeries rmsSeries = new DataSeries(); - - int samplesPerCycle; - double[] yValues; - double[] tValues; - double sum; - - DateTime cycleTime; - - if ((object)dataSeries == null) - return null; - - // Set series info to the source series info - rmsSeries.SeriesInfo = dataSeries.SeriesInfo; - - - // Get samples per cycle of the data series based on the given frequency - samplesPerCycle = Transform.CalculateSamplesPerCycle(dataSeries, frequency); - - //preinitialize size of SeriesInfo - int ncycleData = dataSeries.DataPoints.Count - samplesPerCycle; - rmsSeries.DataPoints = new List(ncycleData); - - - - // Initialize arrays of y-values and t-values for calculating cycle data as necessary - yValues = new double[samplesPerCycle]; - tValues = new double[samplesPerCycle]; - - // Obtain a list of time gaps in the data series - List gapIndexes = Enumerable.Range(0, dataSeries.DataPoints.Count - 1) - .Where(index => - { - DataPoint p1 = dataSeries[index]; - DataPoint p2 = dataSeries[index + 1]; - double cycleDiff = (p2.Time - p1.Time).TotalSeconds * frequency; - - // Detect gaps larger than a quarter cycle. - // Tolerance of 0.000062 calculated - // assuming 3.999 samples per cycle - return (cycleDiff > 0.250062); - }) - .ToList(); - - sum = 0; - - if (dataSeries.DataPoints.Count > samplesPerCycle) - { - sum = dataSeries.DataPoints.Take(samplesPerCycle).Sum(pt => pt.Value * pt.Value); - - rmsSeries.DataPoints.Add(new DataPoint() - { - Time = dataSeries.DataPoints[0].Time, - Value = Math.Sqrt(sum / samplesPerCycle) - }); - - cycleTime = dataSeries.DataPoints[0].Time; - - // Reduce RMS to max 2 pt per cycle to get half cycle RMS - int step = 1; - if (compress) - step = (int)Math.Floor(samplesPerCycle / 2.0D); - if (step == 0) - step = 1; - - for (int i = step; i < dataSeries.DataPoints.Count - samplesPerCycle; i = i + step) - { - - for (int j = 0; j < step; j++) - { - sum = sum - dataSeries.DataPoints[i - step + j].Value * dataSeries.DataPoints[i - step + j].Value; - sum = sum + dataSeries.DataPoints[i - step + j + samplesPerCycle].Value * dataSeries.DataPoints[i - step + j + samplesPerCycle].Value; - } - - // If the cycle following i contains a data gap, do not calculate cycle data - if (gapIndexes.Any(index => i <= index && (i + samplesPerCycle - 1) > index)) - continue; - - // Use the time of the first data point in the cycle as the time of the cycle - cycleTime = dataSeries.DataPoints[i].Time; - - rmsSeries.DataPoints.Add(new DataPoint() - { - Time = cycleTime, - Value = Math.Sqrt(sum / samplesPerCycle) - }); - - } - } - - return rmsSeries; - } - - public static List ToValues(DataSeries series) - { - return series.DataPoints - .Select(dataPoint => dataPoint.Value) - .ToList(); - } - - public static int CalculateSamplesPerCycle(DataSeries dataSeries, double frequency) - { - return CalculateSamplesPerCycle(dataSeries.SampleRate, frequency); - } - - public static int CalculateSamplesPerCycle(double samplesPerSecond, double frequency) - { - int[] commonSampleRates = - { - 4, 8, 16, 32, - 80, 96, 100, 200, - 64, 128, 256, 512, 1024 - }; - - int calculatedRate = (int)Math.Round(samplesPerSecond / frequency); - int nearestCommonRate = commonSampleRates.MinBy(rate => Math.Abs(calculatedRate - rate)); - int diff = Math.Abs(calculatedRate - nearestCommonRate); - return (diff < nearestCommonRate * 0.1D) ? nearestCommonRate : calculatedRate; - } - } -} diff --git a/Libraries/FaultData/DataAnalysis/VICycleDataGroup.cs b/Libraries/FaultData/DataAnalysis/VICycleDataGroup.cs deleted file mode 100644 index d913f052..00000000 --- a/Libraries/FaultData/DataAnalysis/VICycleDataGroup.cs +++ /dev/null @@ -1,476 +0,0 @@ -//****************************************************************************************************** -// VICycleDataGroup.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2014 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using FaultAlgorithms; -using openXDA.Model; - -namespace FaultData.DataAnalysis -{ - public class VICycleDataGroup - { - #region [ Members ] - - // Fields - private List m_vIndices; - private Asset m_asset; - - private int m_iaIndex; - private int m_ibIndex; - private int m_icIndex; - private int m_irIndex; - - private List m_cycleDataGroups; - - private class VIndices - { - public int Va; - public int Vb; - public int Vc; - - public int Vab; - public int Vbc; - public int Vca; - - public int distance; - public VIndices() - { - Va = -1; - Vb = -1; - Vc = -1; - Vab = -1; - Vbc = -1; - Vca = -1; - - distance = -1; - } - - public int DefinedNeutralVoltages - { - get - { - return ((Va > -1) ? 1 : 0) + ((Vb > -1) ? 1 : 0) + ((Vc > -1) ? 1 : 0); - } - } - - public int DefinedLineVoltages - { - get - { - return ((Vab > -1) ? 1 : 0) + ((Vbc > -1) ? 1 : 0) + ((Vca > -1) ? 1 : 0); - } - } - - public bool allVoltagesDefined - { - get - { - return ((Vab > -1) && (Vbc > -1) && (Vca > -1) && - (Va > -1) && (Vb > -1) && (Vc > -1)); - } - } - - } - - - public double VBase => m_asset.VoltageKV; - - #endregion - - #region [ Constructors ] - - public VICycleDataGroup(DataGroup dataGroup) - { - m_vIndices = new List(); - m_asset = dataGroup.Asset; - - m_cycleDataGroups = dataGroup.DataSeries - .Select((dataSeries, index) => new { DataSeries = dataSeries, Index = index }) - .GroupBy(obj => obj.Index / 4) - .Where(grouping => grouping.Count() >= 4) - .Select(grouping => grouping.Select(obj => obj.DataSeries)) - .Select(grouping => new CycleDataGroup(new DataGroup(grouping, dataGroup.Asset), dataGroup.Asset)) - .ToList(); - - MapIndexes(); - } - - public VICycleDataGroup(List cycleDataGroups, Asset asset) - { - m_vIndices = new List(); - m_cycleDataGroups = new List(cycleDataGroups); - m_asset = asset; - MapIndexes(); - } - - #endregion - - #region [ Properties ] - - public CycleDataGroup VA - { - get - { - return (m_vIndices.Count > 0 && m_vIndices[0].Va >= 0) ? m_cycleDataGroups[m_vIndices[0].Va] : null; - } - } - - public CycleDataGroup VB - { - get - { - return (m_vIndices.Count > 0 && m_vIndices[0].Vb >= 0) ? m_cycleDataGroups[m_vIndices[0].Vb] : null; - } - } - - public CycleDataGroup VC - { - get - { - return (m_vIndices.Count > 0 && m_vIndices[0].Vc >= 0) ? m_cycleDataGroups[m_vIndices[0].Vc] : null; - } - } - - public CycleDataGroup VAB - { - get - { - return (m_vIndices.Count > 0 && m_vIndices[0].Vab >= 0) ? m_cycleDataGroups[m_vIndices[0].Vab] : null; - } - } - - public CycleDataGroup VBC - { - get - { - return (m_vIndices.Count > 0 && m_vIndices[0].Vbc >= 0) ? m_cycleDataGroups[m_vIndices[0].Vbc] : null; - } - } - - public CycleDataGroup VCA - { - get - { - return (m_vIndices.Count > 0 && m_vIndices[0].Vca >= 0) ? m_cycleDataGroups[m_vIndices[0].Vca] : null; - } - } - - public CycleDataGroup IA - { - get - { - return (m_iaIndex >= 0) ? m_cycleDataGroups[m_iaIndex] : null; - } - } - - public CycleDataGroup IB - { - get - { - return (m_ibIndex >= 0) ? m_cycleDataGroups[m_ibIndex] : null; - } - } - - public CycleDataGroup IC - { - get - { - return (m_icIndex >= 0) ? m_cycleDataGroups[m_icIndex] : null; - } - } - - public CycleDataGroup IR - { - get - { - return (m_irIndex >= 0) ? m_cycleDataGroups[m_irIndex] : null; - } - } - - public List CycleDataGroups { - get { - return m_cycleDataGroups; - } - } - - #endregion - - #region [ Methods ] - - public DataGroup ToDataGroup() - { - return Transform.Combine(m_cycleDataGroups - .Select(cycleDataGroup => cycleDataGroup.ToDataGroup()) - .ToArray()); - } - - public VICycleDataGroup ToSubSet(int startIndex, int endIndex) - { - return new VICycleDataGroup(m_cycleDataGroups - .Select(cycleDataGroup => cycleDataGroup.ToSubGroup(startIndex, endIndex)) - .ToList(), m_asset); - } - - public VICycleDataGroup ToSubSet(DateTime startTime, DateTime endTime) - { - return new VICycleDataGroup(m_cycleDataGroups - .Select(cycleDataGroup => cycleDataGroup.ToSubGroup(startTime, endTime)) - .ToList(), m_asset); - } - - public void PushDataTo(CycleDataSet cycleDataSet) - { - FaultAlgorithms.CycleData cycleData; - Cycle[] cycles; - CycleDataGroup[] cycleDataGroups; - - cycleDataGroups = new CycleDataGroup[] { VA, VB, VC, IA, IB, IC }; - cycles = new Cycle[cycleDataGroups.Length]; - - for (int i = 0; i < VA.ToDataGroup().Samples; i++) - { - cycleData = new FaultAlgorithms.CycleData(); - - cycles[0] = cycleData.AN.V; - cycles[1] = cycleData.BN.V; - cycles[2] = cycleData.CN.V; - cycles[3] = cycleData.AN.I; - cycles[4] = cycleData.BN.I; - cycles[5] = cycleData.CN.I; - - for (int j = 0; j < cycles.Length; j++) - { - if (cycleDataGroups[j] == null) - continue; - - cycles[j].RMS = cycleDataGroups[j].RMS[i].Value; - cycles[j].Phase = cycleDataGroups[j].Phase[i].Value; - cycles[j].Peak = cycleDataGroups[j].Peak[i].Value; - cycles[j].Error = cycleDataGroups[j].Error[i].Value; - } - - cycleDataSet[i] = cycleData; - } - } - - private void MapIndexes() - { - - m_iaIndex = -1; - m_ibIndex = -1; - m_icIndex = -1; - m_irIndex = -1; - - List vaIndices = new List(); - List vbIndices = new List(); - List vcIndices = new List(); - List vabIndices = new List(); - List vbcIndices = new List(); - List vcaIndices = new List(); - - for (int i = 0; i < m_cycleDataGroups.Count; i++) - { - if (isVoltage("AN", m_cycleDataGroups[i])) - vaIndices.Add(i); - else if (isVoltage("BN", m_cycleDataGroups[i])) - vbIndices.Add(i); - else if (isVoltage("CN", m_cycleDataGroups[i])) - vcIndices.Add(i); - else if (isVoltage("AB", m_cycleDataGroups[i])) - vabIndices.Add(i); - else if (isVoltage("BC", m_cycleDataGroups[i])) - vbcIndices.Add(i); - else if (isVoltage("CA", m_cycleDataGroups[i])) - vcaIndices.Add(i); - - } - - //Walk through all Va and try to get corresponding Vb and Vc... - List ProcessedIndices = new List(); - foreach (int? VaIndex in vaIndices) - { - int assetID = m_cycleDataGroups[(int)VaIndex].Asset.ID; - - int VbIndex = vbIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VcIndex = vcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VabIndex = vabIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VbcIndex = vbcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VcaIndex = vcaIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - - VIndices set = new VIndices(); - ProcessedIndices.Add(VaIndex); - set.Va = (int)VaIndex; - - if (VbIndex > -1) - { - ProcessedIndices.Add(VbIndex); - set.Vb = VbIndex; - } - if (VcIndex > -1) - { - ProcessedIndices.Add(VcIndex); - set.Vc = VcIndex; - } - - if (VabIndex > -1) - { - ProcessedIndices.Add(VabIndex); - set.Vab = VabIndex; - } - if (VbcIndex > -1) - { - ProcessedIndices.Add(VbcIndex); - set.Vbc = VbcIndex; - } - if (VcaIndex > -1) - { - ProcessedIndices.Add(VcaIndex); - set.Vca = VcaIndex; - } - - - if (assetID == m_asset.ID) - { - set.distance = 0; - } - else - { - set.distance = m_asset.DistanceToAsset(assetID); - } - - m_vIndices.Add(set); - } - - // Also walk though all Vab to catch Leftover Cases where Va is not present - foreach (int? VabIndex in vabIndices) - { - int assetID = m_cycleDataGroups[(int)VabIndex].Asset.ID; - - int VaIndex = vaIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VbIndex = vbIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VcIndex = vcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - - int VbcIndex = vbcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - int VcaIndex = vcaIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; - - VIndices set = new VIndices(); - ProcessedIndices.Add(VabIndex); - set.Vab = (int)VabIndex; - - if (VbIndex > -1) - { - ProcessedIndices.Add(VbIndex); - set.Vb = VbIndex; - } - if (VcIndex > -1) - { - ProcessedIndices.Add(VcIndex); - set.Vc = VcIndex; - } - - if (VaIndex > -1) - { - ProcessedIndices.Add(VaIndex); - set.Va = VaIndex; - } - if (VbcIndex > -1) - { - ProcessedIndices.Add(VbcIndex); - set.Vbc = VbcIndex; - } - if (VcaIndex > -1) - { - ProcessedIndices.Add(VcaIndex); - set.Vca = VcaIndex; - } - - - if (assetID == m_asset.ID) - { - set.distance = 0; - } - else - { - set.distance = m_asset.DistanceToAsset(assetID); - } - - m_vIndices.Add(set); - } - - for (int i = 0; i < m_cycleDataGroups.Count; i++) - { - string measurementType = m_cycleDataGroups[i].RMS.SeriesInfo.Channel.MeasurementType.Name; - string phase = m_cycleDataGroups[i].RMS.SeriesInfo.Channel.Phase.Name; - - - if (measurementType == "Current" && phase == "AN") - m_iaIndex = i; - else if (measurementType == "Current" && phase == "BN") - m_ibIndex = i; - else if (measurementType == "Current" && phase == "CN") - m_icIndex = i; - else if (measurementType == "Current" && phase == "RES") - m_irIndex = i; - } - } - - #endregion - - #region [ Static ] - - // Static Methods - - private static bool isVoltage(string phase, CycleDataGroup dataGroup) - { - - string measurementType = dataGroup.RMS.SeriesInfo.Channel.MeasurementType.Name; - string seriesPhase = dataGroup.RMS.SeriesInfo.Channel.Phase.Name; - - if (measurementType != "Voltage") - return false; - - if (seriesPhase != phase) - return false; - - return true; - - } - - private static bool isCurrent(string phase, CycleDataGroup dataGroup) - { - string measurementType = dataGroup.RMS.SeriesInfo.Channel.MeasurementType.Name; - string seriesPhase = dataGroup.RMS.SeriesInfo.Channel.Phase.Name; - - if (measurementType != "Current") - return false; - - if (seriesPhase != phase) - return false; - - return true; - - } - - #endregion - - } -} diff --git a/Libraries/FaultData/DataAnalysis/VIDataGroup.cs b/Libraries/FaultData/DataAnalysis/VIDataGroup.cs deleted file mode 100644 index ae088e05..00000000 --- a/Libraries/FaultData/DataAnalysis/VIDataGroup.cs +++ /dev/null @@ -1,521 +0,0 @@ -//****************************************************************************************************** -// VIDataGroup.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2014 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data; -using openXDA.Model; - -namespace FaultData.DataAnalysis -{ - public class VIDataGroup - { - #region [ Members ] - - // Fields - private List m_vIndices; - - private int m_iaIndex; - private int m_ibIndex; - private int m_icIndex; - private int m_irIndex; - - private DataGroup m_dataGroup; - - private class VIndices - { - public int Va { get; set; } = -1; - public int Vb { get; set; } = -1; - public int Vc { get; set; } = -1; - - public int Vab { get; set; } = -1; - public int Vbc { get; set; } = -1; - public int Vca { get; set; } = -1; - - public int Distance { get; set; } = -1; - - public int DefinedNeutralVoltages => - (Va >= 0 ? 1 : 0) + - (Vb >= 0 ? 1 : 0) + - (Vc >= 0 ? 1 : 0); - - public int DefinedLineVoltages => - (Vab >= 0 ? 1 : 0) + - (Vbc >= 0 ? 1 : 0) + - (Vca >= 0 ? 1 : 0); - - public bool AllVoltagesDefined => - (Va >= 0) && (Vb >= 0) && (Vc >= 0) && - (Vab >= 0) && (Vbc >= 0) && (Vca >= 0); - } - - #endregion - - #region [ Constructors ] - - public VIDataGroup(DataGroup dataGroup) - { - - // Initialize each of - // the indexes to -1 - m_vIndices = new List(); - - m_iaIndex = -1; - m_ibIndex = -1; - m_icIndex = -1; - m_irIndex = -1; - - // Initialize the data group - m_dataGroup = new DataGroup(dataGroup.DataSeries, dataGroup.Asset); - - HashSet connectedAssets = new HashSet(dataGroup.Asset.ConnectedAssets.Select(item => item.ID)); - - var groupings = dataGroup.DataSeries - .Select((DataSeries, Index) => new { DataSeries, Index }) - .Where(item => !(item.DataSeries.SeriesInfo is null)) - .Where(item => item.DataSeries.SeriesInfo.Channel.MeasurementCharacteristic.Name == "Instantaneous") - .Where(item => new[] { "Instantaneous", "Values" }.Contains(item.DataSeries.SeriesInfo.SeriesType.Name)) - .GroupBy(item => item.DataSeries.SeriesInfo.Channel.AssetID) - .OrderBy(grouping => grouping.Key == dataGroup.Asset.ID ? 0 : 1) - .ThenBy(grouping => connectedAssets.Contains(grouping.Key) ? 0 : 1) - .ToList(); - - foreach (var grouping in groupings) - { - VIndices set = new VIndices() { Distance = 0 }; - - int assetID = grouping.Key; - - if (assetID != dataGroup.Asset.ID) - set.Distance = dataGroup.Asset.DistanceToAsset(assetID); - - foreach (var item in grouping) - { - string measurementType = item.DataSeries.SeriesInfo.Channel.MeasurementType.Name; - string phase = item.DataSeries.SeriesInfo.Channel.Phase.Name; - - if (measurementType == "Voltage" && phase == "AN") - set.Va = item.Index; - - if (measurementType == "Voltage" && phase == "BN") - set.Vb = item.Index; - - if (measurementType == "Voltage" && phase == "CN") - set.Vc = item.Index; - - if (measurementType == "Voltage" && phase == "AB") - set.Vab = item.Index; - - if (measurementType == "Voltage" && phase == "BC") - set.Vbc = item.Index; - - if (measurementType == "Voltage" && phase == "CA") - set.Vca = item.Index; - - if (m_iaIndex < 0 && measurementType == "Current" && phase == "AN") - m_iaIndex = item.Index; - - if (m_ibIndex < 0 && measurementType == "Current" && phase == "BN") - m_ibIndex = item.Index; - - if (m_icIndex < 0 && measurementType == "Current" && phase == "CN") - m_icIndex = item.Index; - - if (m_irIndex < 0 && measurementType == "Current" && phase == "RES") - m_irIndex = item.Index; - } - - if (set.DefinedLineVoltages + set.DefinedNeutralVoltages > 0) - m_vIndices.Add(set); - } - - if (m_vIndices.Count() == 0) - m_vIndices.Add(new VIndices()); - - CalculateMissingCurrentChannel(); - CalculateMissingLLVoltageChannels(); - - m_vIndices.Sort((a, b) => - { - if (b.AllVoltagesDefined && !a.AllVoltagesDefined) - return 1; - if (a.AllVoltagesDefined && !b.AllVoltagesDefined) - return -1; - if (!(a.Distance >= 0 && b.Distance >= 0)) - return b.Distance.CompareTo(a.Distance); - return a.Distance.CompareTo(b.Distance); - }); - } - - private VIDataGroup() - { - } - - #endregion - - #region [ Properties ] - - public DataSeries VA => (m_vIndices[0].Va >= 0) - ? m_dataGroup[m_vIndices[0].Va] - : null; - - public DataSeries VB => (m_vIndices[0].Vb >= 0) - ? m_dataGroup[m_vIndices[0].Vb] - : null; - - public DataSeries VC => (m_vIndices[0].Vc >= 0) - ? m_dataGroup[m_vIndices[0].Vc] - : null; - - public DataSeries VAB => (m_vIndices[0].Vab >= 0) - ? m_dataGroup[m_vIndices[0].Vab] - : null; - - public DataSeries VBC => (m_vIndices[0].Vbc >= 0) - ? m_dataGroup[m_vIndices[0].Vbc] - : null; - - public DataSeries VCA => (m_vIndices[0].Vca >= 0) - ? m_dataGroup[m_vIndices[0].Vca] - : null; - - public DataSeries IA => (m_iaIndex >= 0) - ? m_dataGroup[m_iaIndex] - : null; - - public DataSeries IB => (m_ibIndex >= 0) - ? m_dataGroup[m_ibIndex] - : null; - - public DataSeries IC => (m_icIndex >= 0) - ? m_dataGroup[m_icIndex] - : null; - - public DataSeries IR => (m_irIndex >= 0) - ? m_dataGroup[m_irIndex] - : null; - - public int DefinedNeutralVoltages => m_vIndices - .Select(item => item.DefinedNeutralVoltages) - .FirstOrDefault(); - - public int DefinedLineVoltages => m_vIndices - .Select(item => item.DefinedLineVoltages) - .FirstOrDefault(); - - public int DefinedCurrents => - CurrentIndexes.Count(index => index >= 0); - - public int DefinedPhaseCurrents => - PhaseCurrentIndexes.Count(index => index >= 0); - - public bool AllVIChannelsDefined => - m_vIndices[0].AllVoltagesDefined && - CurrentIndexes.All(index => index >= 0); - - private int[] CurrentIndexes => - new int[] { m_iaIndex, m_ibIndex, m_icIndex, m_irIndex }; - - private int[] PhaseCurrentIndexes => - new int[] { m_iaIndex, m_ibIndex, m_icIndex }; - - public Asset Asset => m_dataGroup.Asset; - - public DataSeries[] Data - { - get - { - List result = new List(); - - foreach (VIndices Vindex in m_vIndices) - { - if (Vindex.Va > -1) - result.Add(m_dataGroup[Vindex.Va]); - if (Vindex.Vb > -1) - result.Add(m_dataGroup[Vindex.Vb]); - if (Vindex.Vc > -1) - result.Add(m_dataGroup[Vindex.Vc]); - - if (Vindex.Vab > -1) - result.Add(m_dataGroup[Vindex.Vab]); - if (Vindex.Vbc > -1) - result.Add(m_dataGroup[Vindex.Vbc]); - if (Vindex.Vca > -1) - result.Add(m_dataGroup[Vindex.Vca]); - } - - if (m_iaIndex > -1) - result.Add(m_dataGroup[m_iaIndex]); - if (m_ibIndex > -1) - result.Add(m_dataGroup[m_ibIndex]); - if (m_icIndex > -1) - result.Add(m_dataGroup[m_icIndex]); - if (m_irIndex > -1) - result.Add(m_dataGroup[m_irIndex]); - - return result.ToArray(); - } - } - - #endregion - - #region [ Methods ] - - /// - /// Given three of the four current channels, calculates the - /// missing channel based on the relationship IR = IA + IB + IC. - /// - private void CalculateMissingCurrentChannel() - { - Meter meter; - DataSeries missingSeries; - - // If the data group does not have exactly 3 channels, - // then there is no missing channel or there is not - // enough data to calculate the missing channel - if (DefinedCurrents != 3) - return; - - // Get the meter associated with the channels in this data group - meter = (IA ?? IB).SeriesInfo.Channel.Meter; - - if (m_iaIndex == -1) - { - // Calculate IA = IR - IB - IC - missingSeries = IR.Add(IB.Negate()).Add(IC.Negate()); - missingSeries.SeriesInfo = GetSeriesInfo(meter, IR.SeriesInfo.Channel.Asset, "Current", "AN", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_iaIndex = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - else if (m_ibIndex == -1) - { - // Calculate IB = IR - IA - IC - missingSeries = IR.Add(IA.Negate()).Add(IC.Negate()); - missingSeries.SeriesInfo = GetSeriesInfo(meter, IR.SeriesInfo.Channel.Asset, "Current", "BN", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_ibIndex = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - else if (m_icIndex == -1) - { - // Calculate IC = IR - IA - IB - missingSeries = IR.Add(IA.Negate()).Add(IB.Negate()); - missingSeries.SeriesInfo = GetSeriesInfo(meter, IR.SeriesInfo.Channel.Asset, "Current", "CN", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_icIndex = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - else - { - // Calculate IR = IA + IB + IC - missingSeries = IA.Add(IB).Add(IC); - missingSeries.SeriesInfo = GetSeriesInfo(meter, IA.SeriesInfo.Channel.Asset, "Current", "RES", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_irIndex = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - } - - private void CalculateMissingLLVoltageChannels() - { - Meter meter; - DataSeries missingSeries; - - //Do this for every Voltage set - for (int i = 0; i < m_vIndices.Count(); i++) - { - // If all line voltages are already present or there are not - // at least 2 lines we will not perform line to line calculations - if (m_vIndices[i].DefinedLineVoltages == 3 || m_vIndices[i].DefinedNeutralVoltages < 2) - continue; - - // Get the meter associated with the channels in this data group - DataSeries VA = null; - DataSeries VB = null; - DataSeries VC = null; - - if (m_vIndices[i].Va > -1) - VA = m_dataGroup[m_vIndices[i].Va]; - if (m_vIndices[i].Vb > -1) - VB = m_dataGroup[m_vIndices[i].Vb]; - if (m_vIndices[i].Vc > -1) - VC = m_dataGroup[m_vIndices[i].Vc]; - - meter = (VA ?? VB ?? VC).SeriesInfo.Channel.Meter; - - if (m_vIndices[i].Vab == -1 && !(VA is null) && !(VB is null)) - { - // Calculate VAB = VA - VB - missingSeries = VA.Add(VB.Negate()); - missingSeries.SeriesInfo = GetSeriesInfo(meter, VA.SeriesInfo.Channel.Asset, "Voltage", "AB", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_vIndices[i].Vab = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - - if (m_vIndices[i].Vbc == -1 && !(VB is null) && !(VC is null)) - { - // Calculate VBC = VB - VC - missingSeries = VB.Add(VC.Negate()); - missingSeries.SeriesInfo = GetSeriesInfo(meter, VB.SeriesInfo.Channel.Asset, "Voltage", "BC", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_vIndices[i].Vbc = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - - if (m_vIndices[i].Vca == -1 && !(VC is null) && !(VA is null)) - { - // Calculate VCA = VC - VA - missingSeries = VC.Add(VA.Negate()); - missingSeries.SeriesInfo = GetSeriesInfo(meter, VC.SeriesInfo.Channel.Asset, "Voltage", "CA", m_dataGroup.SamplesPerHour); - missingSeries.Calculated = true; - m_vIndices[i].Vca = m_dataGroup.DataSeries.Count; - m_dataGroup.Add(missingSeries); - } - } - } - - public DataGroup ToDataGroup() - { - return new DataGroup(m_dataGroup.DataSeries, m_dataGroup.Asset); - } - - public VIDataGroup ToSubGroup(int startIndex, int endIndex) - { - VIDataGroup subGroup = new VIDataGroup(); - - subGroup.m_vIndices = m_vIndices; - subGroup.m_iaIndex = m_iaIndex; - subGroup.m_ibIndex = m_ibIndex; - subGroup.m_icIndex = m_icIndex; - subGroup.m_irIndex = m_irIndex; - - subGroup.m_dataGroup = m_dataGroup.ToSubGroup(startIndex, endIndex); - - return subGroup; - } - - public VIDataGroup ToSubGroup(DateTime startTime, DateTime endTime) - { - VIDataGroup subGroup = new VIDataGroup(); - - subGroup.m_vIndices = m_vIndices; - subGroup.m_iaIndex = m_iaIndex; - subGroup.m_ibIndex = m_ibIndex; - subGroup.m_icIndex = m_icIndex; - subGroup.m_irIndex = m_irIndex; - - subGroup.m_dataGroup = m_dataGroup.ToSubGroup(startTime, endTime); - - return subGroup; - } - - #endregion - - #region [ Static ] - - // Static Methods - private static Series GetSeriesInfo(Meter meter, Asset asset, string measurementTypeName, string phaseName, double samplesPerHour) - { - string measurementCharacteristicName = "Instantaneous"; - string seriesTypeName = "Values"; - - char typeDesignation = (measurementTypeName == "Current") ? 'I' : measurementTypeName[0]; - string phaseDesignation = (phaseName == "RES") ? "R" : phaseName.TrimEnd('N'); - string channelName = string.Concat(typeDesignation, phaseDesignation); - - ChannelKey channelKey = new ChannelKey(asset.ID, 0, channelName, measurementTypeName, measurementCharacteristicName, phaseName); - SeriesKey seriesKey = new SeriesKey(channelKey, seriesTypeName); - - Channel dbChannel = (meter.ConnectionFactory is null) - ? meter.Channels.FirstOrDefault(channel => channelKey.Equals(new ChannelKey(channel))) - : FastSearch(meter, channelKey); - - Series dbSeries = dbChannel?.Series - .FirstOrDefault(series => seriesKey.Equals(new SeriesKey(series))); - - if (dbSeries is null) - { - if (dbChannel is null) - { - MeasurementType measurementType = new MeasurementType() { Name = measurementTypeName }; - MeasurementCharacteristic measurementCharacteristic = new MeasurementCharacteristic() { Name = measurementCharacteristicName }; - Phase phase = new Phase() { Name = phaseName }; - - dbChannel = new Channel() - { - MeterID = meter.ID, - AssetID = asset.ID, - MeasurementTypeID = measurementType.ID, - MeasurementCharacteristicID = measurementCharacteristic.ID, - PhaseID = phase.ID, - Name = channelKey.Name, - SamplesPerHour = samplesPerHour, - Description = string.Concat(measurementCharacteristicName, " ", measurementTypeName, " ", phaseName), - Enabled = true, - - Meter = meter, - Asset = asset, - MeasurementType = measurementType, - MeasurementCharacteristic = measurementCharacteristic, - Phase = phase, - Series = new List() - }; - - meter.Channels.Add(dbChannel); - } - - SeriesType seriesType = new SeriesType() { Name = seriesTypeName }; - - dbSeries = new Series() - { - ChannelID = dbChannel.ID, - SeriesTypeID = seriesType.ID, - SourceIndexes = string.Empty, - - Channel = dbChannel, - SeriesType = seriesType - }; - - dbChannel.Series.Add(dbSeries); - } - - return dbSeries; - } - - private static Channel FastSearch(Meter meter, ChannelKey channelKey) - { - using (AdoDataConnection connection = meter.ConnectionFactory()) - { - Channel search = channelKey.Find(connection, meter.ID); - - if (search is null) - return null; - - return meter.Channels - .FirstOrDefault(channel => channel.ID == search.ID); - } - } - - #endregion - } -} diff --git a/Libraries/FaultData/FaultData.csproj b/Libraries/FaultData/FaultData.csproj deleted file mode 100644 index b19aaa40..00000000 --- a/Libraries/FaultData/FaultData.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - net9.0 - Debug;Development;Release - enable - enable - - - - - - - - - - - - - - - diff --git a/Libraries/openHistorian.XDALink/Historian.cs b/Libraries/openHistorian.XDALink/Historian.cs deleted file mode 100644 index a7517018..00000000 --- a/Libraries/openHistorian.XDALink/Historian.cs +++ /dev/null @@ -1,203 +0,0 @@ -//****************************************************************************************************** -// Historian.cs - Gbtc -// -// Copyright © 2015, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/23/2015 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone; -using Gemstone.WordExtensions; -using openHistorian.Net; -using openHistorian.Queues; -using openHistorian.Snap; -using SnapDB.Snap; -using SnapDB.Snap.Filters; -using SnapDB.Snap.Services; -using SnapDB.Snap.Services.Reader; - -namespace openHistorian.XDALink -{ - /// - /// Series ID values. - /// - public enum SeriesID - { - Minimum = 0, - Maximum = 1, - Average = 2 - } - - public class Historian : IDisposable - { - #region [ Members ] - - // Constants - - /// - /// Default historian server port number. - /// - public const int DefaultHistorianPort = 38402; - - // Fields - private HistorianClient m_client; - private ClientDatabaseBase m_database; - private Lazy m_queue; - private List> m_treeStreams; - - private bool m_disposed; - - #endregion - - #region [ Constructors ] - - public Historian(string server, string database) - { - string[] split = server.Split(':'); - int port; - - if (split.Length == 1) - { - m_client = new HistorianClient(split[0], DefaultHistorianPort); - } - else - { - if (!int.TryParse(split[1], out port)) - throw new ArgumentException("Invalid format for server[:port]. " + server, "server"); - - m_client = new HistorianClient(split[0], port); - } - - m_database = m_client.GetDatabase(database); - m_queue = new Lazy(() => new HistorianInputQueue(() => m_database)); - m_treeStreams = new List>(); - } - - #endregion - - #region [ Methods ] - - public IEnumerable Read(IEnumerable channels, DateTime startTime, DateTime stopTime) - { - IEnumerable measurementIDs = channels.SelectMany(GetAllMeasurementIDs); - return Read(measurementIDs, startTime, stopTime); - } - - public void Write(int channelID, SeriesID seriesID, DateTime timestamp, double value) - { - HistorianKey historianKey = new HistorianKey(); - HistorianValue historianValue = new HistorianValue(); - - historianKey.PointID = ToPointID(channelID, (int)seriesID); - historianKey.TimestampAsDate = timestamp; - historianValue.AsSingle = (float)value; - - m_queue.Value.Enqueue(historianKey, historianValue); - } - - public void Flush() - { - Flush(1); - } - - public void Flush(int pollingFrequency) - { - if (m_queue.IsValueCreated) - { - while (m_queue.Value.Size > 0) - Thread.Sleep(1000 / pollingFrequency); - } - } - - public void Dispose() - { - if (!m_disposed) - { - try - { - foreach (TreeStream stream in m_treeStreams) - stream.Dispose(); - - if (m_queue.IsValueCreated) - { - Flush(10); - m_queue.Value.Dispose(); - } - - m_database.Dispose(); - m_client.Dispose(); - } - finally - { - m_disposed = true; - } - } - } - - private IEnumerable Read(IEnumerable measurementIDs, DateTime startTime, DateTime stopTime) - { - SeekFilterBase timeFilter = TimestampSeekFilter.CreateFromRange(startTime, stopTime); - MatchFilterBase pointFilter = null; - HistorianKey key = new HistorianKey(); - HistorianValue value = new HistorianValue(); - - if ((object)measurementIDs != null) - pointFilter = PointIDMatchFilter.CreateFromList(measurementIDs); - - // Start stream reader for the provided time window and selected points - using (TreeStream stream = m_database.Read(SortedTreeEngineReaderOptions.Default, timeFilter, pointFilter)) - { - m_treeStreams.Add(stream); - - while (stream.Read(key, value)) - { - yield return new TrendingDataPoint() - { - ChannelID = (int)key.PointID.HighDoubleWord(), - SeriesID = (SeriesID)(int)key.PointID.LowDoubleWord(), - Timestamp = key.TimestampAsDate, - Value = value.AsSingle - }; - } - } - } - - private IEnumerable GetAllMeasurementIDs(int channel) - { - return SeriesIDs.Select(series => ToPointID(channel, (int)series)); - } - - #endregion - - #region [ Static ] - - // Static Fields - private static readonly List SeriesIDs = Enum.GetValues(typeof(SeriesID)) - .Cast() - .ToList(); - - // Static Methods - - public static ulong ToPointID(int channel, int series) - { - return Word.MakeQuadWord((uint)channel, (uint)series); - } - - #endregion - } -} diff --git a/Libraries/openHistorian.XDALink/ImportedMeasurement.cs b/Libraries/openHistorian.XDALink/ImportedMeasurement.cs deleted file mode 100644 index e6721fb5..00000000 --- a/Libraries/openHistorian.XDALink/ImportedMeasurement.cs +++ /dev/null @@ -1,222 +0,0 @@ -//****************************************************************************************************** -// ImportedMeasurement.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/27/2017 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -#pragma warning disable 1591 - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.IO; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using Newtonsoft.Json; - -namespace openHistorian.XDALink -{ - public class ImportedMeasurement - { - public Guid? NodeID { get; set; } - - public Guid? SourceNodeID { get; set; } - - public Guid? SignalID { get; set; } - - [StringLength(200)] - public string Source { get; set; } - - public long PointID { get; set; } - - [StringLength(200)] - public string PointTag { get; set; } - - [StringLength(200)] - public string AlternateTag { get; set; } - - [StringLength(4)] - public string SignalTypeAcronym { get; set; } - - [StringLength(200)] - public string SignalReference { get; set; } - - public int? FramesPerSecond { get; set; } - - [StringLength(200)] - public string ProtocolAcronym { get; set; } - - [StringLength(200)] - [DefaultValue("Frame")] - public string ProtocolType { get; set; } - - public int? PhasorID { get; set; } - - public char? PhasorType { get; set; } - - public char? Phase { get; set; } - - [DefaultValue(0.0D)] - public double Adder { get; set; } - - [DefaultValue(1.0D)] - public double Multiplier { get; set; } - - [StringLength(200)] - public string CompanyAcronym { get; set; } - - public double? Longitude { get; set; } - - public double? Latitude { get; set; } - - public string Description { get; set; } - - [DefaultValue(false)] - public bool Enabled { get; set; } - } - - public class ImportedMeasurementsTable - { - #region [ Members ] - - // Fields - private string m_historianURL; - private string m_authString; - - #endregion - - #region [ Constructors ] - - public ImportedMeasurementsTable(string historianURL, string username, string password) - { - m_historianURL = historianURL; - - string unencodedAuthString = $"{username}:{password}"; - byte[] authBytes = Encoding.UTF8.GetBytes(unencodedAuthString); - m_authString = Convert.ToBase64String(authBytes); - } - - #endregion - - #region [ Methods ] - - public IEnumerable FindAll() - { - string url = GetURL("/api/importedmeasurements/findall"); - return RequestMeasurements(url); - } - - public IEnumerable FindByID(long pointID) - { - string url = GetURL($"/api/importedmeasurements/findbyid/{pointID}"); - return RequestMeasurements(url); - } - - public IEnumerable FindByPointTag(string pointTag) - { - string url = GetURL($"/api/importedmeasurements/findbypointtag/{pointTag}"); - return RequestMeasurements(url); - } - - public IEnumerable FindByAlternateTag(string alternateTag) - { - string url = GetURL($"/api/importedmeasurements/findbyalternatetag/{alternateTag}"); - return RequestMeasurements(url); - } - - public void ImportMeasurements(IEnumerable measurements) - { - string antiForgeryToken = GenerateAntiForgeryToken(); - string url = GetURL("/api/importedmeasurements/importmeasurements"); - - using (MemoryStream stream = new MemoryStream()) - using (StreamWriter writer = new StreamWriter(stream)) - using (JsonTextWriter jsonWriter = new JsonTextWriter(writer)) - { - JsonSerializer serializer = new JsonSerializer(); - serializer.Serialize(jsonWriter, measurements); - jsonWriter.Flush(); - - using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url)) - using (ByteArrayContent content = new ByteArrayContent(stream.ToArray())) - using (HttpClient client = CreateClient()) - { - request.Content = content; - request.Headers.Add("X-GSF-Verify", antiForgeryToken); - content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); - client.SendAsync(request).Result.Dispose(); - } - } - } - - public void DeleteMeasurement(long pointID) - { - string antiForgeryToken = GenerateAntiForgeryToken(); - string url = GetURL($"/api/importedmeasurements/deletemeasurement/{pointID}"); - - using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Delete, url)) - using (HttpClient client = CreateClient()) - { - request.Headers.Add("X-GSF-Verify", antiForgeryToken); - client.SendAsync(request).Result.Dispose(); - } - } - - private IEnumerable RequestMeasurements(string url) - { - using (HttpClient client = CreateClient()) - using (Stream response = client.GetStreamAsync(url).Result) - using (StreamReader streamReader = new StreamReader(response)) - using (JsonTextReader jsonReader = new JsonTextReader(streamReader)) - { - JsonSerializer serializer = new JsonSerializer(); - return serializer.Deserialize>(jsonReader); - } - } - - private string GenerateAntiForgeryToken() - { - string url = GetURL($"/api/importedmeasurements/generaterequestverficationtoken"); - - using (HttpClient client = CreateClient()) - { - return client.GetStringAsync(url).Result; - } - } - - private string GetURL(string relativePath) - { - string baseURL = m_historianURL.TrimEnd('/'); - string subURL = relativePath.TrimStart('/'); - return $"{baseURL}/{subURL}"; - } - - private HttpClient CreateClient() - { - HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", m_authString); - return client; - } - - #endregion - } -} diff --git a/Libraries/openHistorian.XDALink/TrendingDataPoint.cs b/Libraries/openHistorian.XDALink/TrendingDataPoint.cs deleted file mode 100644 index 6548742f..00000000 --- a/Libraries/openHistorian.XDALink/TrendingDataPoint.cs +++ /dev/null @@ -1,92 +0,0 @@ -//****************************************************************************************************** -// TrendingDataPoint.cs - Gbtc -// -// Copyright © 2015, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/23/2015 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; - -namespace openHistorian.XDALink -{ - public class TrendingDataPoint - { - #region [ Members ] - - // Fields - private int m_channelID; - private SeriesID m_seriesID; - private DateTime m_timestamp; - private double m_value; - - #endregion - - #region [ Properties ] - - public int ChannelID - { - get - { - return m_channelID; - } - set - { - m_channelID = value; - } - } - - public SeriesID SeriesID - { - get - { - return m_seriesID; - } - set - { - m_seriesID = value; - } - } - - public DateTime Timestamp - { - get - { - return m_timestamp; - } - set - { - m_timestamp = value; - } - } - - public double Value - { - get - { - return m_value; - } - set - { - m_value = value; - } - } - - #endregion - } -} diff --git a/Libraries/openHistorian.XDALink/openHistorian.XDALink.csproj b/Libraries/openHistorian.XDALink/openHistorian.XDALink.csproj deleted file mode 100644 index 5e8ee63c..00000000 --- a/Libraries/openHistorian.XDALink/openHistorian.XDALink.csproj +++ /dev/null @@ -1,48 +0,0 @@ - - - Debug - AnyCPU - Library - openHistorian.XDALink - openHistorian.XDALink - net9.0 - Debug;Development;Release - enable - true - enable - - - true - full - false - ..\..\..\Build\Output\Debug\Libraries\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\..\Build\Output\Release\Libraries\ - TRACE - prompt - 4 - - - - - - - - - - - ..\..\Dependencies\openHistorian\openHistorian.Core.dll - - - - - - - - diff --git a/Libraries/openXDA.APIAuthentication/APIQuery.cs b/Libraries/openXDA.APIAuthentication/APIQuery.cs deleted file mode 100644 index 58f8643a..00000000 --- a/Libraries/openXDA.APIAuthentication/APIQuery.cs +++ /dev/null @@ -1,311 +0,0 @@ -//****************************************************************************************************** -// APIQuery.cs - Gbtc -// -// Copyright © 2022, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/01/2022 - Christoph Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Sockets; -using System.Security.Principal; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace openXDA.APIAuthentication -{ - /// - /// Exceptions thrown during an API query. - /// - public class APIQueryException : Exception - { - /// - /// Creates a new instance of the class. - /// - /// The URL of the host that issued the failure. - /// The error message that explains the reason for the exception. - /// The exception that is the cause of the current exception. - public APIQueryException(string hostURL, string message, Exception innerException) - : base(message, innerException) - { - HostURL = hostURL; - } - - /// - /// The URL of the host that issued the failure. - /// - public string HostURL { get; } - } - - /// - /// Issues requests to the API using API authentication. - /// This class handles the GSF token and authentication - /// - public class APIQuery - { - #region [ Members ] - - // Nested Types - private class Host - { - public Host(string url) => - URL = url; - - public string URL { get; } - public string AntiForgeryToken { get; set; } - } - - private class HostUnreachableException : Exception - { - } - - // Fields - private int m_hostIndex; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - /// The API key used to identify the user of the API. - /// The token used to authenticate the user of the API. - /// URL that locates the host providing access to the API. - public APIQuery(string apiKey, string apiToken, string hostURL) - : this(apiKey, apiToken, new[] { hostURL }) - { - } - - /// - /// Creates a new instance of the class. - /// - /// The API key used to identify the user of the API. - /// The token used to authenticate the user of the API. - /// List of URLs that locate the hosts providing access to the API. - public APIQuery(string apiKey, string apiToken, IEnumerable hostURLs) - { - APIKey = apiKey; - APIToken = apiToken; - - Hosts = hostURLs - .Select(url => new Host(url)) - .ToList(); - - // Select a random host for the first API call attempt - if (Hosts.Count > 1) - Interlocked.Exchange(ref m_hostIndex, InitialHostIndex); - } - - #endregion - - #region[ Properties ] - - /// - /// The API key identifying the user of the API. - /// - public string APIKey { get; } - - /// - /// The API token used to authenticate the user. - /// - public string APIToken { get; } - - /// - /// The list of URLs that locate the hosts providing access to the API. - /// - public IEnumerable HostsURLs => Hosts - .Select(host => host.URL); - - private List Hosts { get; } - - private int InitialHostIndex => Tuple - .Create(Environment.TickCount, Environment.MachineName) - .GetHashCode() % Hosts.Count; - - #endregion - - #region [ Methods ] - - /// - /// Sends a web request to the host using the credentials for API authentication. - /// - /// Action that configures the HTTP request. - /// Path to the API endpoint locating the resource to be requested. - /// being impersonated if the APIToken supports impersonation. set to NULL for using APIAuthentication only - /// Token used to cancel the request before it has completed. - /// The HTTP response returned by the host that handled the request. - public Task SendWebRequestAsync(Action configure, string path, IPrincipal user = null, CancellationToken cancellationToken = default) => - SendWebRequestAsync(configure, path, HttpCompletionOption.ResponseContentRead, user, cancellationToken); - - /// - /// Sends a web request to the host using the credentials for API authentication. - /// - /// Action that configures the HTTP request. - /// Path to the API endpoint locating the resource to be requested. - /// When the operation should complete (as soon as a response is available or after reading the whole response content). - /// being impersonated if the APIToken supports impersonation. set to NULL for using APIAuthentication only - /// Token used to cancel the request before it has completed. - /// The HTTP response returned by the host that handled the request. - public async Task SendWebRequestAsync(Action configure, string path, HttpCompletionOption httpCompletionOption, IPrincipal user = null, CancellationToken cancellationToken = default) - { - int initialHostIndex = Interlocked.CompareExchange(ref m_hostIndex, 0, 0); - - void UpdateHostIndex(int hostIndex) => - Interlocked.CompareExchange(ref m_hostIndex, hostIndex, initialHostIndex); - - for (int i = 0; i < Hosts.Count; i++) - { - int hostIndex = (initialHostIndex + i) % Hosts.Count; - Host host = Hosts[hostIndex]; - - try - { - HttpResponseMessage response = await SendWebRequestToAsync(host, configure, path, httpCompletionOption, user, cancellationToken).ConfigureAwait(false); - UpdateHostIndex(hostIndex); - return response; - } - catch (HostUnreachableException) - { - continue; - } - catch (Exception ex) - { - UpdateHostIndex(hostIndex); - - string message = $"Failed when sending API query to host {host.URL}: {ex.Message}"; - throw new APIQueryException(host.URL, message, ex); - } - } - - return new HttpResponseMessage(HttpStatusCode.NotFound); - } - - private async Task SendWebRequestToAsync(Host host, Action configure, string path, HttpCompletionOption httpCompletionOption,IPrincipal user, CancellationToken cancellationToken) - { - using (HttpRequestMessage request = BuildRequest(host, path, configure, user)) - { - if (request.Method != HttpMethod.Get) - { - if (host.AntiForgeryToken == null) - host.AntiForgeryToken = await GetAntiForgeryTokenAsync(host, cancellationToken).ConfigureAwait(false); - - request.Headers.Add("X-GSF-Verify", host.AntiForgeryToken); - } - - return await CallAPIAsync(request, httpCompletionOption, cancellationToken).ConfigureAwait(false); - } - } - - private async Task GetAntiForgeryTokenAsync(Host host, CancellationToken cancellationToken) - { - void ConfigureTokenRequest(HttpRequestMessage tokenRequest) - { - MediaTypeWithQualityHeaderValue mediaType = new MediaTypeWithQualityHeaderValue("text/plain"); - tokenRequest.Headers.Accept.Add(mediaType); - tokenRequest.Method = HttpMethod.Get; - } - - using (HttpRequestMessage tokenRequest = BuildRequest(host, "api/rvht", ConfigureTokenRequest, null)) - using (HttpResponseMessage tokenResponse = await CallAPIAsync(tokenRequest, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false)) - { - tokenResponse.EnsureSuccessStatusCode(); - return await tokenResponse.Content.ReadAsStringAsync().ConfigureAwait(false); - } - } - - private async Task CallAPIAsync(HttpRequestMessage request, HttpCompletionOption httpCompletionOption, CancellationToken cancellationToken) - { - try - { - return await HttpClient.SendAsync(request, httpCompletionOption, cancellationToken).ConfigureAwait(false); - } - catch (HttpRequestException ex) - { - // If there are no other hosts to try, - // then we can just throw the exception as-is - if (Hosts.Count == 1) - throw; - - if (IndicatesHostIsUnreachable(ex)) - throw new HostUnreachableException(); - - throw; - } - } - - private HttpRequestMessage BuildRequest(Host host, string path, Action configure, IPrincipal user) - { - HttpRequestMessage request = new HttpRequestMessage(); - - try - { - string cleanHostURL = host.URL.Trim().TrimEnd('/'); - string cleanPath = path.Trim().TrimStart('/'); - string fullurl = $"{cleanHostURL}/{cleanPath}"; - request.RequestUri = new Uri(fullurl); - configure(request); - - string type = "XDA-API"; - string decode = $"{APIKey}:{APIToken}"; - - if (!(user is null)) - { - type= "XDA-API-IMP"; - decode = $"{decode}:{user.Identity.Name}"; - } - - Encoding utf8 = new UTF8Encoding(false); - byte[] credentialData = utf8.GetBytes(decode); - string credentials = Convert.ToBase64String(credentialData); - request.Headers.Authorization = new AuthenticationHeaderValue(type, credentials); - - return request; - } - catch - { - request.Dispose(); - throw; - } - } - - private bool IndicatesHostIsUnreachable(Exception ex) - { - if (ex is SocketException socketException) - return socketException.SocketErrorCode == SocketError.ConnectionRefused || socketException.SocketErrorCode == SocketError.TimedOut; - if (ex.InnerException is null) - return false; - return IndicatesHostIsUnreachable(ex.InnerException); - } - - #endregion - - #region [ Static ] - - private static HttpClient HttpClient { get; } - = new HttpClient(); - - #endregion - } -} diff --git a/Libraries/openXDA.APIAuthentication/IAPICredentialRetriever.cs b/Libraries/openXDA.APIAuthentication/IAPICredentialRetriever.cs deleted file mode 100644 index 3b4d8b04..00000000 --- a/Libraries/openXDA.APIAuthentication/IAPICredentialRetriever.cs +++ /dev/null @@ -1,65 +0,0 @@ -//****************************************************************************************************** -// XDAAPIHelper.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/17/2025 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Security.Claims; - -namespace openXDA.APIAuthentication -{ - /// - /// Interface of credential retriever object for . - /// - public interface IAPICredentialRetriever - { - #region [ Properties ] - - /// - /// API Token used to access OpenXDA - /// - string Token { get; } - - /// - /// API Key used to access OpenXDA - /// - string Key { get; } - - /// - /// API Key used to access OpenXDA - /// - string Host { get; } - - /// - /// Refreshes the settings from the original source. - /// - /// A flag indicating if the operation was successful. - bool TryRefreshSettings(); - - /// - /// Retrieves customer key from the claims principle. - /// - /// A value of signifies the current user is authorized to view any object the controller may retrieve. - /// A flag indicating if the operation was successful. - bool TryRetrieveCustomer(ClaimsPrincipal principal, out string customerKey); - - #endregion - } -} diff --git a/Libraries/openXDA.APIAuthentication/Properties/AssemblyInfo.cs b/Libraries/openXDA.APIAuthentication/Properties/AssemblyInfo.cs deleted file mode 100644 index 33057741..00000000 --- a/Libraries/openXDA.APIAuthentication/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("openXDA.APIAuthentication")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("GPA")] -[assembly: AssemblyProduct("openXDA.APIAuthentication")] -[assembly: AssemblyCopyright("Copyright © 2022")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("93FF1E73-CD8B-4F01-89BC-A4A242FA06A6")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyFileVersion("3.0.5.93")] diff --git a/Libraries/openXDA.APIAuthentication/XDAAPI.cs b/Libraries/openXDA.APIAuthentication/XDAAPI.cs deleted file mode 100644 index 46315a82..00000000 --- a/Libraries/openXDA.APIAuthentication/XDAAPI.cs +++ /dev/null @@ -1,232 +0,0 @@ -//****************************************************************************************************** -// XDAAPI.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/21/2025 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Claims; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace openXDA.APIAuthentication -{ - /// - /// Helper class that provides openXDA API Calls. - /// - public class XDAAPI - { - #region [ Properties ] - /// - /// Tells users if the helper has been intialized or not. - /// - public bool IsIntialized { get; private set; } - - /// - /// API Token used to access OpenXDA - /// - public string Token => SettingsRetriever.Token; - - /// - /// API Key used to access OpenXDA - /// - public string Key => SettingsRetriever.Key; - - /// - /// API Key used to access OpenXDA - /// - public string Host => SettingsRetriever.Host; - - /// - /// Object that retireves the token,key, and host of the helper. - /// - private IAPICredentialRetriever SettingsRetriever { get; set; } - - #endregion - - #region [ Methods ] - /// - /// Creates API object and registers retriever. - /// - public XDAAPI(IAPICredentialRetriever retriever) - { - SettingsRetriever = retriever; - if (!TryRefreshSettings()) - throw new ArgumentException("Unable to load settings from retriever."); - } - - /// - /// Recalls the setup settings function from to refetch settings. - /// - public bool TryRefreshSettings() - { - bool success = SettingsRetriever.TryRefreshSettings(); - if (success) - IsIntialized = true; - return success; - } - - /// - /// Retrieves customer key from the claims principle. - /// - /// A value of signifies the current user is authorized to view any object the controller may retrieve. - /// A flag indicating if the operation was successful. - public bool TryRetrieveCustomer(ClaimsPrincipal principal, out string customerKey) => SettingsRetriever.TryRetrieveCustomer(principal, out customerKey); - - /// - /// Gets Response Task from XDA - /// - /// Path to specific API request - /// The of the request - /// response as a - public Task GetResponseTask(string requestURI, HttpContent content = null) - { - if (!IsIntialized) - throw new InvalidOperationException("API helper has not been intialized."); - - APIQuery query = new APIQuery(Key, Token, Host.Split(';')); - - void ConfigureRequest(HttpRequestMessage request) - { - if (content == null) - { - request.Method = HttpMethod.Get; - request.Headers.Accept.Clear(); - request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - } - else - { - request.Method = HttpMethod.Post; - request.Content = content; - } - } - - return query.SendWebRequestAsync(ConfigureRequest, requestURI); - } - - /// - /// Makes a Get Request to OpenXDA to obtain a string - /// - /// Path to specific API request - /// string - public async Task GetAsync(string requestURI) - { - if (!IsIntialized) - throw new InvalidOperationException("API helper has not been intialized."); - - APIQuery query = new APIQuery(Key, Token, Host.Split(';')); - - void ConfigureRequest(HttpRequestMessage request) - { - request.Method = HttpMethod.Get; - request.Headers.Accept.Clear(); - request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - } - - HttpResponseMessage responseMessage = await query.SendWebRequestAsync(ConfigureRequest, requestURI).ConfigureAwait(false); - responseMessage.EnsureSuccessStatusCode(); - return await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); - } - - /// - /// Makes a Get Request to OpenXDA to obtain a stream - /// - /// Path to specific API request - /// stream - public async Task GetStreamAsync(string requestURI) - { - if (!IsIntialized) - throw new InvalidOperationException("API helper has not been intialized."); - - APIQuery query = new APIQuery(Key, Token, Host.Split(';')); - - void ConfigureRequest(HttpRequestMessage request) - { - request.Method = HttpMethod.Get; - request.Headers.Accept.Clear(); - request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - } - - HttpResponseMessage responseMessage = await query.SendWebRequestAsync(ConfigureRequest, requestURI).ConfigureAwait(false); - responseMessage.EnsureSuccessStatusCode(); - return await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false); - } - - /// - /// Makes a Get Request to OpenXDA to obtain an object - /// - /// Path to specific API request - /// a object - public async Task GetAsync(string requestURI) - { - if (!IsIntialized) - throw new InvalidOperationException("API helper has not been intialized."); - - string result = await GetAsync(requestURI).ConfigureAwait(false); - T resultObject = JsonConvert.DeserializeObject(result); - return resultObject; - } - - /// - /// Makes Post request on OpenXDA - /// - /// Path to specific API request - /// The of the request - /// response as a - public async Task PostAsync(string requestURI, HttpContent content) - { - if (!IsIntialized) - throw new InvalidOperationException("API helper has not been intialized."); - - APIQuery query = new APIQuery(Key, Token, Host.Split(';')); - - void ConfigureRequest(HttpRequestMessage request) - { - request.Method = HttpMethod.Post; - request.Content = content; - } - - HttpResponseMessage responseMessage = await query.SendWebRequestAsync(ConfigureRequest, requestURI).ConfigureAwait(false); - return await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); - } - - /// - /// Makes Post request on OpenXDA - /// - /// Path to specific API request - /// The of the request - /// response as a - public async Task PostAllAsync(string endpoint, HttpContent content) => await PostAsync(endpoint, content).ConfigureAwait(false); - - /// - /// Makes a Get Request to OpenXDA to obtain a objects - /// - /// Path to specific API request - /// a object - public async Task> GetAllAsync(string requestURI) => await GetAsync>(requestURI).ConfigureAwait(false); - - #endregion - - } -} diff --git a/Libraries/openXDA.APIAuthentication/XDAAPIHelper.cs b/Libraries/openXDA.APIAuthentication/XDAAPIHelper.cs deleted file mode 100644 index ace01df4..00000000 --- a/Libraries/openXDA.APIAuthentication/XDAAPIHelper.cs +++ /dev/null @@ -1,149 +0,0 @@ -//****************************************************************************************************** -// XDAAPIHelper.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 03/15/2024 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Security.Claims; -using System.Threading.Tasks; - -namespace openXDA.APIAuthentication -{ - /// - /// Wrapper class that turns into a static for easy use across an application. - /// - /// - /// Must be initialized with the method to fetch settings. - /// - public static class XDAAPIHelper - { - #region [ Properties ] - /// - /// Tells users if the helper has been intialized or not. - /// - public static bool IsIntialized { - get - { - return !(API is null); - } - } - - /// - /// API Token used to access OpenXDA - /// - public static string Token => API.Token; - - /// - /// API Key used to access OpenXDA - /// - public static string Key => API.Key; - - /// - /// API Key used to access OpenXDA - /// - public static string Host => API.Host; - - /// - /// Object that retireves the token, key, and host of the helper. - /// - private static XDAAPI API { get; set; } - - #endregion - - #region [ Methods ] - /// - /// Function for setup of static helper. This must be ran once before using the helper. - /// - public static void InitializeHelper(IAPICredentialRetriever retriever) - { - API = new XDAAPI(retriever); - } - - /// - /// Recalls the setup settings function from to refetch settings. - /// - public static bool TryRefreshSettings() => API.TryRefreshSettings(); - - /// - /// Retrieves customer key from the claims principle. - /// - /// A value of signifies the current user is authorized to view any object the controller may retrieve. - /// A flag indicating if the operation was successful. - public static bool TryRetrieveCustomer(ClaimsPrincipal principal, out string customerKey) => API.TryRetrieveCustomer(principal, out customerKey); - - /// - /// Gets Response Task from XDA - /// - /// Path to specific API request - /// The of the request - /// response as a - public static Task GetResponseTask(string requestURI, HttpContent content = null) => API.GetResponseTask(requestURI, content); - - /// - /// Makes a Get Request to OpenXDA to obtain a string - /// - /// Path to specific API request - /// string - public static async Task GetAsync(string requestURI) => await API.GetAsync(requestURI).ConfigureAwait(false); - - /// - /// Makes a Get Request to OpenXDA to obtain a stream - /// - /// Path to specific API request - /// stream - public static async Task GetStreamAsync(string requestURI) => await API.GetStreamAsync(requestURI).ConfigureAwait(false); - - /// - /// Makes a Get Request to OpenXDA to obtain an object - /// - /// Path to specific API request - /// a object - public static async Task GetAsync(string requestURI) => await API.GetAsync(requestURI).ConfigureAwait(false); - - /// - /// Makes Post request on OpenXDA - /// - /// Path to specific API request - /// The of the request - /// response as a - public static async Task PostAsync(string requestURI, HttpContent content) => await API.PostAsync(requestURI, content).ConfigureAwait(false); - - /// - /// Makes Post request on OpenXDA - /// - /// Path to specific API request - /// The of the request - /// response as a - public static async Task PostAllAsync(string endpoint, HttpContent content) => await API.PostAllAsync(endpoint, content).ConfigureAwait(false); - - /// - /// Makes a Get Request to OpenXDA to obtain a objects - /// - /// Path to specific API request - /// a object - public static async Task> GetAllAsync(string requestURI) => await API.GetAllAsync(requestURI).ConfigureAwait(false); - - #endregion - - } -} diff --git a/Libraries/openXDA.APIAuthentication/openXDA.APIAuthentication.csproj b/Libraries/openXDA.APIAuthentication/openXDA.APIAuthentication.csproj deleted file mode 100644 index facf64dd..00000000 --- a/Libraries/openXDA.APIAuthentication/openXDA.APIAuthentication.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - net9.0 - Debug;Development;Release - Library - false - openXDA.APIAuthentication - GPA - openXDA.APIAuthentication - Copyright © 2022 - - - ..\..\..\Build\Output\Debug\Libraries\ - ..\..\..\Build\Output\Debug\Libraries\openXDA.APIAuthentication.xml - - - ..\..\..\Build\Output\Release\Libraries\ - ..\..\..\Build\Output\Release\Libraries\openXDA.APIAuthentication.xml - - - - - - - - \ No newline at end of file diff --git a/Libraries/openXDA.Configuration/BreakerSection.cs b/Libraries/openXDA.Configuration/BreakerSection.cs deleted file mode 100644 index d6d07ff3..00000000 --- a/Libraries/openXDA.Configuration/BreakerSection.cs +++ /dev/null @@ -1,119 +0,0 @@ -//****************************************************************************************************** -// BreakerSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/02/2015 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class BreakerSection - { - #region [ Members ] - - // Constants - public const string CategoryName = "Breakers"; - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the flag that determines whether to apply additional logic - /// to help obtain more accurate breaker timing results in cases where DC - /// current gradually drains from the line after the breaker is open. - /// - [Setting] - [DefaultValue(false)] - public bool ApplyDCOffsetLogic { get; set; } - - /// - /// Gets or sets the size of the window, in cycles, - /// to use when applying the DC offset logic. - /// - [Setting] - [DefaultValue(9.0D / 8.0D)] - public double DCOffsetWindowSize { get; set; } - - /// - /// Gets or sets the maximum number of cycles that a breaker - /// operation's timing can exceed the configured breaker speed. - /// - [Setting] - [DefaultValue(0.0D)] - public double LateBreakerThreshold { get; set; } - - /// - /// Gets or sets the minimum number of cycles that the breaker is expected - /// to remain closed after receiving the trip coil energized signal. - /// - /// - /// This value helps to prevent phase timing calculations when the current - /// signal is not large enough to detect the point at which the breaker opened. - /// - [Setting] - [DefaultValue(0.0D)] - public double MinCyclesBeforeOpen { get; set; } - - /// - /// Gets or sets the minimum amount of time, in cycles, the system must wait - /// before automatically reclosing after a breaker operation has occurred. - /// - [Setting] - [DefaultValue(15.0D)] - public double MinWaitBeforeReclose { get; set; } - - /// - /// Gets or sets the maximum RMS current, in amps, - /// at which the breaker can be considered open. - /// - [Setting] - [DefaultValue(20.0D)] - public double OpenBreakerThreshold { get; set; } - - /// - /// Gets or sets the minimum duration, in cycles, for which the current must remain - /// at zero in order for a subsequent current spike to be considered a restrike. - /// - [Setting] - [DefaultValue(0.125D)] - public double MinCyclesBeforeRestrike { get; set; } - - /// - /// Gets or sets the maximum duration, in cycles, for which the current must remain - /// at zero in order for a subsequent current spike to be considered a restrike. - /// - [Setting] - [DefaultValue(70.0D)] - public double MaxCyclesBeforeRestrike { get; set; } - - /// - /// Gets or sets the flag that determines whether the system should apply the - /// BreakerOpen event type to events. - /// - [Setting] - [DefaultValue(true)] - public bool BreakerOpenEventTypeEnabled { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/COMTRADESection.cs b/Libraries/openXDA.Configuration/COMTRADESection.cs deleted file mode 100644 index e457f275..00000000 --- a/Libraries/openXDA.Configuration/COMTRADESection.cs +++ /dev/null @@ -1,67 +0,0 @@ -//****************************************************************************************************** -// COMTRADESection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/07/2019 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class COMTRADESection - { - #region [ Members ] - - // Constants - public const string CategoryName = "COMTRADE"; - - #endregion - - #region [ Properties ] - - public TimeSpan MinWaitTime { get; set; } - - [Setting] - [DefaultValue(false)] - public bool WaitForINF { get; set; } - - [Setting] - [DefaultValue(false)] - public bool UseRelaxedValidation { get; set; } - - [Setting] - [DefaultValue("SELECT ID FROM Meter WHERE Make = 'SEL'")] - public string Root2AdjustmentQuery { get; set; } - - [Setting] - [SettingName(nameof(MinWaitTime))] - [DefaultValue(15.0D)] - [EditorBrowsable(EditorBrowsableState.Never)] - public double _MinWaitTime - { - get => MinWaitTime.TotalSeconds; - set => MinWaitTime = TimeSpan.FromSeconds(value); - } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/DataAnalysisSection.cs b/Libraries/openXDA.Configuration/DataAnalysisSection.cs deleted file mode 100644 index d62142e7..00000000 --- a/Libraries/openXDA.Configuration/DataAnalysisSection.cs +++ /dev/null @@ -1,120 +0,0 @@ -//****************************************************************************************************** -// DataAnalysisSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 01/16/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class DataAnalysisSection - { - public const string CategoryName = "DataAnalysis"; - - /// - /// Gets or sets the threshold, in amps, at which the - /// current exceeds engineering reasonableness. - /// - [Setting] - [DefaultValue(0.1D)] - public double InterruptionThreshold { get; set; } - - /// - /// Gets or sets the units of measure to use - /// for lengths (line length and fault distance). - /// - [Setting] - [DefaultValue("miles")] - public string LengthUnits { get; set; } - - /// - /// Gets or sets the threshold, in amps, at which the - /// current exceeds engineering reasonableness. - /// - [Setting] - [DefaultValue(1000000.0D)] - public double MaxCurrent { get; set; } - - /// - /// Gets or sets the maximum duration, in seconds, - /// of the events processed by openXDA. - /// - [Setting] - [DefaultValue(0.0D)] - public double MaxEventDuration { get; set; } - - /// - /// Gets or sets the maximum number of hours beyond the current system time - /// before the time of the record indicates that the data is unreasonable. - /// - [Setting] - [DefaultValue(0.0D)] - public double MaxTimeOffset { get; set; } - - /// - /// Gets or sets the per-unit threshold at which the - /// voltage exceeds engineering reasonableness. - /// - [Setting] - [DefaultValue(2.0D)] - public double MaxVoltage { get; set; } - - /// - /// Gets or sets the maximum number of hours prior to the current system time - /// before the time of the record indicates that the data is unreasonable. - /// - [Setting] - [DefaultValue(0.0D)] - public double MinTimeOffset { get; set; } - - /// - /// Gets or sets the threshold, in amps, at which the - /// current exceeds engineering reasonableness. - /// - [Setting] - [DefaultValue(0.9D)] - public double SagThreshold { get; set; } - - /// - /// Gets or sets the threshold, in amps, at which the - /// current exceeds engineering reasonableness. - /// - [Setting] - [DefaultValue(1.1D)] - public double SwellThreshold { get; set; } - - /// - /// Gets or sets the system frequency. - /// - [Setting] - [DefaultValue(60.0D)] - public double SystemFrequency { get; set; } - - /// - /// Gets or sets the maximum distance, in seconds, - /// between a meter's clock and real time. - /// - [Setting] - [DefaultValue(0.5D)] - public double TimeTolerance { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/DataPusherSection.cs b/Libraries/openXDA.Configuration/DataPusherSection.cs deleted file mode 100644 index 78cd591d..00000000 --- a/Libraries/openXDA.Configuration/DataPusherSection.cs +++ /dev/null @@ -1,37 +0,0 @@ -//****************************************************************************************************** -// DataPusherSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 02/08/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class DataPusherSection - { - public const string CategoryName = "DataPusher"; - - [Setting] - [DefaultValue("systemSettings")] - public string ConnectionString { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/EMAXSection.cs b/Libraries/openXDA.Configuration/EMAXSection.cs deleted file mode 100644 index 22ba7df7..00000000 --- a/Libraries/openXDA.Configuration/EMAXSection.cs +++ /dev/null @@ -1,66 +0,0 @@ -//****************************************************************************************************** -// EMAXSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/25/2017 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class EMAXSection - { - #region [ Members ] - - // Constants - public const string CategoryName = "EMAX"; - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the value that indicates whether timestamp - /// correction should be applied when reading native EMAX files. - /// - [Setting] - [DefaultValue(true)] - public bool ApplyTimestampCorrection { get; set; } - - /// - /// Gets or sets the value that indicates whether value - /// correction should be applied when reading native EMAX files. - /// - [Setting] - [DefaultValue(true)] - public bool ApplyValueCorrection { get; set; } - - /// - /// Gets or sets the path to the directory where COMTRADE - /// exports should be located after reading an EMAX file. - /// - [Setting] - [DefaultValue("")] - public string COMTRADEExportDirectory { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/EPRICapBankAnalyticSection.cs b/Libraries/openXDA.Configuration/EPRICapBankAnalyticSection.cs deleted file mode 100644 index 41d0f1d5..00000000 --- a/Libraries/openXDA.Configuration/EPRICapBankAnalyticSection.cs +++ /dev/null @@ -1,89 +0,0 @@ -//****************************************************************************************************** -// EPRICapBankAnalyticSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/04/2020 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class EPRICapBankAnalyticSection - { - public const string CategoryName = "EPRICapBankAnalytic"; - - [Setting] - [DefaultValue(false)] - public bool Enabled { get; set; } - - [Setting] - [DefaultValue("./CapBankAnalysis/Data/")] - public string DataFileLocation { get; set; } - - [Setting] - [DefaultValue("./CapBankAnalysis/Parameter/")] - public string ParameterFileLocation { get; set; } - - [Setting] - [DefaultValue("./CapBankAnalysis/Results/")] - public string ResultFileLocation { get; set; } - - [Setting] - [DefaultValue(500.0D)] - public double VThreshhold { get; set; } - - [Setting] - [DefaultValue(4.0D)] - public double IThreshhold { get; set; } - - [Setting] - [DefaultValue(10.0D)] - public double THDLimit { get; set; } - - [Setting] - [DefaultValue(1.0D)] - public double Toffset { get; set; } - - [Setting] - [DefaultValue(true)] - public bool EvalPreInsertion { get; set; } - - [Setting] - [DefaultValue("openXDA.CapSwitchAnalysis.dll")] - public string AnalysisRoutineAssembly { get; set; } - - [Setting] - [DefaultValue("openXDA.CapSwitchAnalysis.Analyzer.RunAnalytic")] - public string AnalysisRoutineMethod { get; set; } - - [Setting] - [DefaultValue("")] - public string Analyzer { get; set; } - - [Setting] - [DefaultValue(1200000)] - public int Delay { get; set; } - - [Setting] - [DefaultValue(false)] - public bool KeepFiles { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/Edition/EditionChecker.cs b/Libraries/openXDA.Configuration/Edition/EditionChecker.cs deleted file mode 100644 index 2d4d7d73..00000000 --- a/Libraries/openXDA.Configuration/Edition/EditionChecker.cs +++ /dev/null @@ -1,98 +0,0 @@ -//****************************************************************************************************** -// EditionChecker.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/07/2024 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using Gemstone.Configuration; -using Gemstone.Data; -using Gemstone.Data.Model; -using openXDA.Model; - -namespace openXDA.Configuration -{ - /// - /// Enum to hold different editions of XDA - /// - public enum Edition - { - Base = 0, - Enterprise = 1 - } - - /// - /// Helper class that checks the edition of XDA - /// - public static class EditionChecker - { - /// - /// Current XDA Edition - /// - private static Edition CheckedEdition { get; set; } - // ToDo: Think about replacing this with a hash function instead - private static Guid MagicGuid = new Guid("aa644f0c-a82b-4cf1-ba6e-be3a1b05eb6a"); - - static EditionChecker() - { - UpdateEdition(); - } - - /// - /// Checks to see if current edition is equal to or higher than supplied - /// - /// response as a - public static bool CheckEdition(Edition editionLevel) - { - return CheckedEdition.CompareTo(editionLevel) >= 0; - } - - /// - /// Updates the current edition based on the value in the database - /// - public static void UpdateEdition() - { - using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) - { - Guid value; - try - { - value = new Guid(new TableOperations(connection).QueryRecordWhere($"Name = 'System.EditionKey'")?.Value); - } - catch - { - value = new Guid("00000000-0000-0000-0000-000000000000"); - } - if (value == MagicGuid) CheckedEdition = Edition.Enterprise; - else CheckedEdition = Edition.Base; - } - } - - /// - /// Returns the current edition - /// - /// response as a - public static Edition GetEdition() - { - return CheckedEdition; - } - - } -} diff --git a/Libraries/openXDA.Configuration/Edition/HttpEditionFilterAttribute.cs b/Libraries/openXDA.Configuration/Edition/HttpEditionFilterAttribute.cs deleted file mode 100644 index 79368e28..00000000 --- a/Libraries/openXDA.Configuration/Edition/HttpEditionFilterAttribute.cs +++ /dev/null @@ -1,57 +0,0 @@ -//****************************************************************************************************** -// HttpEditionFilterAttirbute.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/07/2024 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; - -namespace openXDA.Configuration -{ - /// - /// Defines an attribute that will disallow an http method if it does not pass the edition requirement. - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] - public class HttpEditionFilterAttribute : ActionFilterAttribute - { - /// - /// Gets the edition needed specified by attribute construction. - /// - public Edition EditionRequred { get; } - public HttpEditionFilterAttribute(Edition edition) - { - EditionRequred = edition; - } - - /// - /// Creates a new . - /// - /// Edition this http method requires. - public override void OnActionExecuting(ActionExecutingContext actionContext) - { - // Wrong edition: skip the method and return forbidden - if (!EditionChecker.CheckEdition(EditionRequred)) - actionContext.Result = new ForbidResult(); - - base.OnActionExecuting(actionContext); - } - } -} diff --git a/Libraries/openXDA.Configuration/EmailSection.cs b/Libraries/openXDA.Configuration/EmailSection.cs deleted file mode 100644 index c092607c..00000000 --- a/Libraries/openXDA.Configuration/EmailSection.cs +++ /dev/null @@ -1,111 +0,0 @@ -//****************************************************************************************************** -// EmailSection.cs - Gbtc -// -// Copyright © 2015, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/02/2015 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.StringExtensions; -using System.ComponentModel; -using System.Configuration; -using System.Security; - -namespace openXDA.Configuration -{ - public class EmailSection - { - #region [ Members ] - - // Constants - public const string CategoryName = "Email"; - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the address used by the administrator of the email system. - /// - [Setting] - [DefaultValue("xda-admin@gridprotectionalliance.org")] - public string AdminAddress { get; set; } - - /// - /// Gets or sets the address used in the To line when blind-copying recipients. - /// - [Setting] - [DefaultValue("")] - public string BlindCopyAddress { get; set; } - - /// - /// Gets or sets the hostname or IP address of the SMTP server to - /// use for sending automated email notifications when faults occur. - /// - [Setting] - [DefaultValue("")] - public string SMTPServer { get; set; } - - /// - /// Gets or sets the email address used when sending automated email notifications. - /// - [Setting] - [DefaultValue("openXDA@gridprotectionalliance.org")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the username used to authenticate to the SMTP server. - /// - [Setting] - [DefaultValue("")] - public string Username { get; set; } - - /// - /// Gets or sets the password used to authenticate to the SMTP server. - /// - [Setting] - [DefaultValue(null)] - public string Password - { - get => SecurePassword.ToUnsecureString() ?? ""; - set => SecurePassword = value?.ToSecureString() ?? new SecureString(); - } - - /// - /// Gets or sets the flag that determines whether to enable - /// SSL when establishing communications with the SMTP server. - /// - [Setting] - [DefaultValue(false)] - public bool EnableSSL { get; set; } - - /// - /// Sets the minimum number of samples in an email chart - /// - [Setting] - [DefaultValue(-1)] - public int MinimumChartSamplesPerCycle { get; set; } - - /// - /// Gets the password as a . - /// - public SecureString SecurePassword { get; private set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/EventEmailSection.cs b/Libraries/openXDA.Configuration/EventEmailSection.cs deleted file mode 100644 index 64f48794..00000000 --- a/Libraries/openXDA.Configuration/EventEmailSection.cs +++ /dev/null @@ -1,68 +0,0 @@ -//****************************************************************************************************** -// EventEmailSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 02/13/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; -using Gemstone.Configuration; - -namespace openXDA.Configuration -{ - public class EventEmailSection - { - public const string CategoryName = "EventEmail"; - - [Setting] - [DefaultValue(false)] - public bool Enabled { get; set; } - - [Setting] - [DefaultValue(0)] - public int MaxEmailCount { get; set; } - - [Setting] - [SettingName(nameof(MaxEmailSpan))] - [DefaultValue(0.0D)] - public double MaxEmailSeconds - { - get => MaxEmailSpan.TotalSeconds; - set => MaxEmailSpan = TimeSpan.FromSeconds(value); - } - - [Setting] - [DefaultValue("http://localhost:8989/RestoreEventEmail.cshtml")] - public string RestorationURL { get; set; } - - public TimeSpan MaxEmailSpan { get; set; } - - [Setting] - [SettingName(nameof(EmailDuplicateThresholdMinutes))] - [DefaultValue(0.0D)] - public double EmailDuplicateThresholdMinutes - { - get => EmailDuplicateThreshold.TotalMinutes; - set => EmailDuplicateThreshold = TimeSpan.FromMinutes(value); - } - - public TimeSpan EmailDuplicateThreshold { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/FaultLocationSection.cs b/Libraries/openXDA.Configuration/FaultLocationSection.cs deleted file mode 100644 index a9e6e72c..00000000 --- a/Libraries/openXDA.Configuration/FaultLocationSection.cs +++ /dev/null @@ -1,104 +0,0 @@ -//****************************************************************************************************** -// FaultLocationSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/02/2015 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public enum FaultCalculationCycleMethod - { - MaxCurrent, - LastFaultedCycle, - LastFaultedCycleExceptAirGapRes - } - - public class FaultLocationSection - { - #region [ Members ] - - // Constants - public const string CategoryName = "FaultLocation"; - - #endregion - - #region [ Properties ] - - [Setting] - [DefaultValue(5.0D)] - public double PrefaultTrigger { get; set; } - - [Setting] - [DefaultValue(50.0D)] - public double PrefaultTriggerAdjustment { get; set; } - - [Setting] - [DefaultValue(1.05D)] - public double MaxFaultDistanceMultiplier { get; set; } - - [Setting] - [DefaultValue(-0.05D)] - public double MinFaultDistanceMultiplier { get; set; } - - [Setting] - [DefaultValue(FaultCalculationCycleMethod.MaxCurrent)] - public FaultCalculationCycleMethod FaultCalculationCycleMethod { get; set; } - - [Setting] - [DefaultValue(1.0D)] - public double MinFaultSegmentCycles { get; set; } - - [Setting] - [DefaultValue(10)] - public int FaultClearingAdjustmentSamples { get; set; } - - [Setting] - [DefaultValue(false)] - public bool WarnMissingDetectionLogic { get; set; } - - /// - /// Indicates whether to use the default fault detection logic - /// when the line-specific fault detection logic fails. - /// - [Setting] - [DefaultValue(true)] - public bool UseDefaultFaultDetectionLogic { get; set; } - - /// - /// Indicates whether to ignore line-specific fault detection logic. - /// - [Setting] - [DefaultValue(false)] - public bool IgnoreFaultDetectionLogic { get; set; } - - [Setting] - [DefaultValue(0.8D)] - public double FaultedVoltageThreshold { get; set; } - - [Setting] - [DefaultValue(0.001D)] - public double GroundedFaultVoltageThreshold { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/FileEnumeratorSection.cs b/Libraries/openXDA.Configuration/FileEnumeratorSection.cs deleted file mode 100644 index 0c403c30..00000000 --- a/Libraries/openXDA.Configuration/FileEnumeratorSection.cs +++ /dev/null @@ -1,80 +0,0 @@ -//****************************************************************************************************** -// FileEnumeratorSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 01/16/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; -using Gemstone.IO; - -namespace openXDA.Configuration -{ - //copied from GSF.IO as there was no equivalent in Gemstone.IO - public enum FileEnumerationStrategy - { - // - // Summary: - // Enumerate all files sequentially. - Sequential, - // - // Summary: - // Enumerates the watch directories in parallel, but subdirectories are processed - // sequentially. - ParallelWatchDirectories, - // - // Summary: - // Enumerates every directory, including subdirectories, in parallel. - ParallelSubdirectories, - // - // Summary: - // Does not enumerate directories, relying only on the file watcher to handle file - // processing events. - None - } - - public class FileEnumeratorSection - { - public const string CategoryName = "FileEnumerator"; - - /// - /// Gets or sets the patterns used to determine which - /// folders to skip when enumerating watch directories. - /// - [Setting] - [DefaultValue("")] - public string FolderExclusion { get; set; } - - /// - /// Gets or sets the flag that determines whether the file watcher - /// should raise events for enumerated files in alphabetical order. - /// - [Setting] - [DefaultValue(false)] - public bool OrderedEnumeration { get; set; } - - /// - /// Gets or sets the strategy used for enumeration of files in the file watcher. - /// - [Setting] - [DefaultValue(FileEnumerationStrategy.ParallelSubdirectories)] - public FileEnumerationStrategy Strategy { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/FileProcessorSection.cs b/Libraries/openXDA.Configuration/FileProcessorSection.cs deleted file mode 100644 index 2d89b5aa..00000000 --- a/Libraries/openXDA.Configuration/FileProcessorSection.cs +++ /dev/null @@ -1,91 +0,0 @@ -//****************************************************************************************************** -// FileProcessorSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 01/16/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class FileProcessorSection - { - public const string CategoryName = "FileProcessor"; - - /// - /// Gets or sets the pattern used to parse file paths in - /// order to identify the meter that the file came from. - /// - [Setting] - [DefaultValue(/*lang=regex*/ @"(?[^\\]+)\\[^\\]+$")] - public string FilePattern { get; set; } - - /// - /// Gets or sets the pattern that identifies the part of the file path that - /// - [Setting] - [DefaultValue(/*lang=regex*/ @"^(?.*)\.[^\.]*$")] - public string FileGroupingPattern { get; set; } - - /// - /// Gets or sets the maximum number of hours prior to the current system time - /// before the file creation time indicates that the data should not be processed. - /// - [Setting] - [DefaultValue(0.0D)] - public double MaxFileCreationTimeOffset { get; set; } - - /// - /// Gets or sets the maximum file size, in MB, - /// of the files processed by openXDA. - /// - [Setting] - [DefaultValue(30.0D)] - public double MaxFileSize { get; set; } - - /// - /// Gets or sets the number of threads used - /// for processing file data concurrently. - /// - /// - /// Values less than or equal to zero will be set to the number of logical processors. - /// - [Setting] - [DefaultValue(0)] - public int ProcessingThreadCount - { - get - { - return _ProcessingThreadCount; - } - set - { - _ProcessingThreadCount = value; - - if (_ProcessingThreadCount <= 0) - _ProcessingThreadCount = Environment.ProcessorCount; - } - } - - private int _ProcessingThreadCount { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/FilePrunerSection.cs b/Libraries/openXDA.Configuration/FilePrunerSection.cs deleted file mode 100644 index 2c9a4c2b..00000000 --- a/Libraries/openXDA.Configuration/FilePrunerSection.cs +++ /dev/null @@ -1,58 +0,0 @@ -//****************************************************************************************************** -// FilePrunerSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 02/08/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class FilePrunerSection - { - public const string CategoryName = "FilePruner"; - - [Setting] - [DefaultValue("* 0 * * *")] - public string Schedule { get; set; } - - /// - /// Gets or sets the amount of time, in days, - /// the file pruner should keep files in openXDA's - /// watch directories. - /// - [Setting] - [SettingName(nameof(RetentionPeriod))] - [DefaultValue(0)] - public int RetentionPeriodDays - { - get => (int)RetentionPeriod.TotalDays; - set => RetentionPeriod = TimeSpan.FromDays(value); - } - - /// - /// Gets or sets the amount of time the file pruner - /// should keep files in openXDA's watch directories. - /// - public TimeSpan RetentionPeriod { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/FileWatcherSection.cs b/Libraries/openXDA.Configuration/FileWatcherSection.cs deleted file mode 100644 index 4b25e6c1..00000000 --- a/Libraries/openXDA.Configuration/FileWatcherSection.cs +++ /dev/null @@ -1,308 +0,0 @@ -//****************************************************************************************************** -// FileWatcherSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 01/16/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using Gemstone.IO; -using Gemstone.StringExtensions; -using System.ComponentModel; -using System.Configuration; -using System.Security; -using FileShare = openXDA.Configuration.FileWatcher.FileShare; - -namespace openXDA.Configuration -{ - namespace FileWatcher - { - /// - /// Represents a file share. - /// - public class FileShare - { - #region [ Members ] - - // Fields - private string m_name; - private string m_domain; - private string m_username; - private SecureString m_password; - - private Exception m_authenticationException; - - #endregion - - #region [ Constructors ] - - /// - /// Creates a new instance of the class. - /// - public FileShare() - { - } - - /// - /// Creates a new instance of the class. - /// - /// A string containing the file share parameters as key-value pairs. - public FileShare(string connectionString) - { - ConnectionStringParser parser = new ConnectionStringParser(); - parser.ParseConnectionString(connectionString, this); - } - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the name of the file share (\\server\share). - /// - [Setting] - [DefaultValue("")] - public string Name - { - get - { - return m_name; - } - set - { - m_name = value; - } - } - - /// - /// Gets or sets the domain of the user used to authenticate to the file share. - /// - [Setting] - [DefaultValue("")] - public string Domain - { - get - { - return m_domain; - } - set - { - m_domain = value; - } - } - - /// - /// Gets or sets the username of the user used to authenticate to the file share. - /// - [Setting] - [DefaultValue("")] - public string Username - { - get - { - return m_username; - } - set - { - string[] splitValue; - - m_username = value; - - if ((object)value != null) - { - splitValue = value.Split('\\'); - - if (splitValue.Length == 2) - { - m_domain = splitValue[0]; - m_username = splitValue[1]; - } - } - } - } - - /// - /// Gets or sets the password of the user used to authenticate to the file share. - /// - [Setting] - [DefaultValue("")] - public string Password - { - get - { - return m_password.ToUnsecureString() ?? ""; - } - set - { - m_password = value.ToSecureString() ?? new SecureString(); - } - } - - /// - /// Gets the exception encountered during the most recent authentication attempt. - /// - public Exception AuthenticationException - { - get - { - return m_authenticationException; - } - } - - #endregion - - #region [ Methods ] - - /// - /// Attempts to authenticate to the file share. - /// - public void Authenticate() - { - try - { - FilePath.ConnectToNetworkShare(m_name, m_username, Password, m_domain); - m_authenticationException = null; - } - catch (Exception ex) - { - m_authenticationException = ex; - throw; - } - } - - /// - /// Attempts to authenticate to the file share. - /// - /// True if successfully authenticated. False otherwise. - public bool TryAuthenticate() - { - try - { - Authenticate(); - return true; - } - catch - { - return false; - } - } - - #endregion - } - } - - public class FileWatcherSection - { - public const string CategoryName = "FileWatcher"; - - /// - /// Gets or sets the size of the - /// s' internal buffers. - /// - /// - [Setting] - [DefaultValue(65536)] - public int BufferSize { get; set; } - - /// - /// Gets or sets a list of parameters used - /// to authenticate to multiple file shares. - /// - [Setting] - [DefaultValue("")] - public string FileShares - { - get - { - return _FileShares; - } - set - { - _FileShares = value; - - _FileShareList = value.ToNonNullString().ParseKeyValuePairs() - .Select(kvp => kvp.Value) - .Select(fileShareString => new FileShare(fileShareString)) - .ToList(); - } - } - - /// - /// Gets a list of file shares to be authenticated at startup. - /// - public IReadOnlyCollection FileShareList => _FileShareList.AsReadOnly(); - - private string _FileShares { get; set; } - private List _FileShareList { get; set; } - - /// - /// Gets or sets the number of threads used - /// internally to the file processor. - /// - /// - /// Values less than or equal to zero will be set to the number of logical processors. - /// - [Setting] - [DefaultValue(0)] - public int InternalThreadCount - { - get => _InternalThreadCount; - set => _InternalThreadCount = (value > 0) - ? value - : Environment.ProcessorCount; - } - - private int _InternalThreadCount { get; set; } - - /// - /// Gets or sets the list of directories to watch for files. - /// - [Setting] - [DefaultValue("Watch")] - public string WatchDirectories - - { - get - { - return _WatchDirectories; - } - set - { - _WatchDirectories = value; - - if ((object)value != null) - { - _WatchDirectoryList = value - .Split(Path.PathSeparator) - .Select(path => path.Trim()) - .ToList(); - } - } - } - - /// - /// Gets a list of directories to be watched - /// for files containing fault records. - /// - public IReadOnlyCollection WatchDirectoryList => _WatchDirectoryList.AsReadOnly(); - - private string _WatchDirectories { get; set; } - private List _WatchDirectoryList { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/GrafanaSection.cs b/Libraries/openXDA.Configuration/GrafanaSection.cs deleted file mode 100644 index a6d0bc31..00000000 --- a/Libraries/openXDA.Configuration/GrafanaSection.cs +++ /dev/null @@ -1,72 +0,0 @@ -//****************************************************************************************************** -// GrafanaSection.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/18/2023 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class GrafanaSection - { - public const string CategoryName = "Grafana"; - - /// - /// Gets or sets the base path to the Grafana server executable. - /// - [Setting] - [DefaultValue(@"Grafana\bin\grafana-server.exe")] - public string ServerPath { get; set; } - - /// - /// Gets or sets the base path to the - /// folder containing the Grafana process. - /// - [Setting] - [DefaultValue("Grafana")] - public string BasePath { get; set; } - - [Setting] - [DefaultValue("http://localhost:8185")] - public string HostedURL { get; set; } - - [Setting] - [DefaultValue("admin")] - public string AdminUser { get; set; } - - [Setting] - [DefaultValue(1)] - public int OrganizationID { get; set; } - - [Setting] - [DefaultValue("X-WEBAUTH-USER")] - public string AuthProxyHeaderName { get; set; } - - [Setting] - [DefaultValue("x-last-dashboard")] - public string LastDashboardCookieName { get; set; } - - [Setting] - [DefaultValue(30)] - public int InitializationTimeout { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/LSCVSSection.cs b/Libraries/openXDA.Configuration/LSCVSSection.cs deleted file mode 100644 index 3cd00c05..00000000 --- a/Libraries/openXDA.Configuration/LSCVSSection.cs +++ /dev/null @@ -1,68 +0,0 @@ -//****************************************************************************************************** -// LSCVSSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 04/11/2022 - G. Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class LSCVSSection - { - public const string CategoryName = "LSCVS"; - - /// - /// URL string of the LSCVS report server name. - /// - [Setting] - [DefaultValue("http://localhost/LSCVSReport")] - public string URL { get; set; } - - /// - /// The API Key to use to authenticate to LSCVS - /// - [Setting] - [DefaultValue("")] - public string APIKey { get; set; } - - /// - /// The API Token to use to authenticate to LSCVS - /// - [Setting] - [DefaultValue("")] - public string APIToken { get; set; } - - /// - /// MW ratio threshold to report LSCVS event. - /// - [Setting] - [DefaultValue(0.6D)] - public double ReportingThreshold { get; set; } - - /// - /// Ratio threshold for determining type III sag faults over type II or I. - /// - [Setting] - [DefaultValue(0.95D)] - public double TypeThreshold { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/OSIPISection.cs b/Libraries/openXDA.Configuration/OSIPISection.cs deleted file mode 100644 index b5d84055..00000000 --- a/Libraries/openXDA.Configuration/OSIPISection.cs +++ /dev/null @@ -1,71 +0,0 @@ -//****************************************************************************************************** -// OSIPISection.cs - Gbtc -// -// Copyright © 2025, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 03/21/2025 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class OSIPISection - { - #region [ Members ] - - // Constants - public const string CategoryName = "OSIPI"; - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets name of the PI historian server to connect to. - /// - [Setting] - [DefaultValue("")] - public string ServerName { get; set; } - - /// - /// Gets or sets user name for logging into PI historian server. - /// - [Setting] - [DefaultValue("")] - public string UserName { get; set; } - - /// - /// Gets or sets password for logging into PI historian server. - /// - [Setting] - [DefaultValue("")] - public string Password { get; set; } - - /// - /// Gets or sets time to wait when establishing - /// connection to PI server before failing. - /// - [Setting] - [DefaultValue(30000)] - public int ConnectTimeout { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/PQDIFSection.cs b/Libraries/openXDA.Configuration/PQDIFSection.cs deleted file mode 100644 index 670a5fd0..00000000 --- a/Libraries/openXDA.Configuration/PQDIFSection.cs +++ /dev/null @@ -1,46 +0,0 @@ -//****************************************************************************************************** -// PQDIFSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/08/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class PQDIFSection - { - #region [ Members ] - - // Constants - public const string CategoryName = "PQDIF"; - - #endregion - - #region [ Properties ] - - [Setting] - [DefaultValue(false)] - public bool AllowMultipleDataSource { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/PQISection.cs b/Libraries/openXDA.Configuration/PQISection.cs deleted file mode 100644 index bbdeb1f1..00000000 --- a/Libraries/openXDA.Configuration/PQISection.cs +++ /dev/null @@ -1,66 +0,0 @@ -//****************************************************************************************************** -// PQISection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/29/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class PQISection - { - #region [ Members ] - - // Constants - public const string CategoryName = "PQI"; - - #endregion - - #region [ Properties ] - - [Setting] - [DefaultValue("https://pqiws.epri.com")] - public string BaseURL { get; set; } - - [Setting] - [DefaultValue("https://go.epri.com")] - public string PingURL { get; set; } - - [Setting] - [DefaultValue(null)] - public string ClientID { get; set; } - - [Setting] - [DefaultValue(null)] - public string ClientSecret { get; set; } - - [Setting] - [DefaultValue(null)] - public string Username { get; set; } - - [Setting] - [DefaultValue(null)] - public string Password { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/Properties/AssemblyInfo.cs b/Libraries/openXDA.Configuration/Properties/AssemblyInfo.cs deleted file mode 100644 index 0666cda4..00000000 --- a/Libraries/openXDA.Configuration/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("openXDA.Configuration")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("openXDA.Configuration")] -[assembly: AssemblyCopyright("Copyright © 2021")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("83d8122c-2bcc-4813-b449-224d9f7e5aee")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyFileVersion("3.0.5.93")] diff --git a/Libraries/openXDA.Configuration/RabbitMQSection.cs b/Libraries/openXDA.Configuration/RabbitMQSection.cs deleted file mode 100644 index 12e6900a..00000000 --- a/Libraries/openXDA.Configuration/RabbitMQSection.cs +++ /dev/null @@ -1,90 +0,0 @@ -//****************************************************************************************************** -// RabbitMQSection.cs - Gbtc -// -// Copyright © 2025, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 11/01/2025 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class RabbitMQSection - { - public const string CategoryName = "RabbitMQ"; - - /// - /// The RabbbitMQ Server Hostname or IP Address. - /// - [Setting] - [DefaultValue("localhost")] - public string Hostname { get; set; } = "localhost"; - - /// - /// Defines the port RabbitMQ is listening on. - /// - [Setting] - [DefaultValue(5672)] - public int Port { get; set; } = 5672; - - /// - /// Defines the name of the exchange to listen to. - /// - [Setting] - [DefaultValue("openxda")] - public string ExchangeName { get; set; } = "openxda"; - - /// - /// Defines the routing key used to listen for messages. - /// - [Setting] - [DefaultValue("openxda")] - public string RoutingKey { get; set; } = "openxda"; - - /// - /// Defines a flag that determines if RabbitMQ integration is enabled. - /// - [Setting] - [DefaultValue(false)] - public bool Enabled { get; set; } = false; - - - /// - /// Defines the routing key used for outbound messages. - /// - [Setting] - [DefaultValue("analytic")] - public string OutboundRoutingKey { get; set; } = "analytic"; - - /// - /// Defines the username used for authenticating to the RabbitMQ service. - /// - [Setting] - [DefaultValue("guest")] - public string UserName { get; set; } = "guest"; - - /// - /// Defines the password used for authenticating to the RabbitMQ service. - /// - [Setting] - [DefaultValue("guest")] - public string Password { get; set; } = "guest"; - } -} diff --git a/Libraries/openXDA.Configuration/SCADASection.cs b/Libraries/openXDA.Configuration/SCADASection.cs deleted file mode 100644 index acb47c91..00000000 --- a/Libraries/openXDA.Configuration/SCADASection.cs +++ /dev/null @@ -1,94 +0,0 @@ -//****************************************************************************************************** -// SCADASection.cs - Gbtc -// -// Copyright © 2025, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 03/21/2025 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class SCADASection - { - #region [ Members ] - - // Nested Types - public enum SCADAHistorian - { - None, - eDNA, - OSIPI - } - - // Constants - public const string CategoryName = "SCADA"; - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets historian used by the SCADA system. - /// - [Setting] - [DefaultValue(SCADAHistorian.None)] - public SCADAHistorian Historian { get; set; } - - /// - /// Gets or sets the database query to get the list of - /// SCADA points that indicate breaker state for the line. - /// - [Setting] - [DefaultValue("SELECT NULL AS Point WHERE 1 IS NULL")] - public string PointQuery { get; set; } - - /// - /// Gets or sets the tolerance, in seconds, that determines the - /// time range to be queried around the fault clearing point. - /// - [Setting] - [DefaultValue(4.0D)] - public double QueryTolerance { get; set; } - - /// - /// Gets or sets the value of the point representing - /// breaker state when the breaker is open. - /// - [Setting] - [DefaultValue(0.0D)] - public double BreakerOpenValue { get; set; } - - /// - /// Gets the tolerance that determines the time range - /// to be queried around the fault clearing point. - /// - public TimeSpan QueryToleranceSpan - { - get - { - return TimeSpan.FromSeconds(QueryTolerance); - } - } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/SSAMSSection.cs b/Libraries/openXDA.Configuration/SSAMSSection.cs deleted file mode 100644 index dff73793..00000000 --- a/Libraries/openXDA.Configuration/SSAMSSection.cs +++ /dev/null @@ -1,73 +0,0 @@ -//****************************************************************************************************** -// SSAMSSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 02/08/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class SSAMSSection - { - public const string CategoryName = "SSAMS"; - - private const string DefaultDataProviderString = - "AssemblyName={System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}; " + - "ConnectionType=System.Data.SqlClient.SqlConnection; " + - "AdapterType=System.Data.SqlClient.SqlDataAdapter;"; - - /// - /// Cron string frequency at which the SSAMS process is scheduled. - /// - [Setting] - [DefaultValue("* 0 * * *")] - public string Schedule { get; set; } - - /// - /// Defines the connection string of the SSAMS DB. - /// - [Setting] - [DefaultValue("Data Source=localhost; Initial Catalog=openXDA; Integrated Security=SSPI")] - public string ConnectionString { get; set; } - - /// - /// Defines the connection string of the SSAMS DB. - /// - [Setting] - [DefaultValue(DefaultDataProviderString)] - public string DataProviderString { get; set; } - - /// - /// Command or procedure name that defines the command executed by the external DB. - /// - [Setting] - [DefaultValue("sp_LogSsamEvent")] - public string DatabaseCommand { get; set; } - - /// - /// Parameters for the external DB procedure. - /// - [Setting] - [DefaultValue("1,1,'OpenXDA_HEARTBEAT','','OpenXDA adapter heartbeat at {Timestamp} UTC',''")] - public string CommandParameters { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/Subscription.cs b/Libraries/openXDA.Configuration/Subscription.cs deleted file mode 100644 index eac8f878..00000000 --- a/Libraries/openXDA.Configuration/Subscription.cs +++ /dev/null @@ -1,65 +0,0 @@ -//****************************************************************************************************** -// SubscriptionSection.cs - Gbtc -// -// Copyright © 2015, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/02/2015 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class SubscriptionSection - { - #region [ Members ] - - // Constants - public const string CategoryName = "Subscription"; - - #endregion - - #region [ Properties ] - - /// - /// Gets or sets the Subject Line used when sending the confirmation email - /// - [Setting] - [DefaultValue("OpenXDA Confirm Email")] - public string ConfirmSubject { get; set; } - - /// - /// Gets or sets the Template used when generating the Confirmation Email - /// - [Setting] - [DefaultValue("Please click the following Link to confirm your email address \n http://localhost/SystemCenterNotification/ConfirmEmail")] - public string ConfirmTemplate { get; set; } - - - /// - /// Gets or sets the flag that determines whether a confirmed Email is Required - /// when subscribing to a notification - /// - [Setting] - [DefaultValue(true)] - public bool RequireConfirmation { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/SystemSection.cs b/Libraries/openXDA.Configuration/SystemSection.cs deleted file mode 100644 index 4649edf6..00000000 --- a/Libraries/openXDA.Configuration/SystemSection.cs +++ /dev/null @@ -1,109 +0,0 @@ -//****************************************************************************************************** -// SystemSection.cs - Gbtc -// -// Copyright © 2014, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/30/2014 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - /// - /// Represents the system settings for openXDA. - /// - public class SystemSection - { - public const string CategoryName = "System"; - - /// - /// Gets or sets the time zone identifier for the time zone - /// used by meters in the system unless configured otherwise. - /// - [Setting] - [DefaultValue("UTC")] - public string DefaultMeterTimeZone - { - get => DefaultMeterTimeZoneInfo.Id; - set => DefaultMeterTimeZoneInfo = string.IsNullOrEmpty(value) - ? TimeZoneInfo.Local - : TimeZoneInfo.FindSystemTimeZoneById(value); - } - - /// - /// Gets the used by meters - /// in the system unless configured otherwise. - /// - public TimeZoneInfo DefaultMeterTimeZoneInfo { get; private set; } - - /// - /// Gets or sets the amount of time each database - /// query is given to complete, in seconds. - /// - [Setting] - [DefaultValue(120)] - public int DbTimeout { get; set; } - - /// - /// Gets or sets the time zone identifier for the - /// time zone used by openXDA to store data. - /// - /// - /// The default value for this setting (empty string) - /// causes the setting to assume the value of the local - /// time zone of the system openXDA is running on. - /// - [Setting] - [DefaultValue("UTC")] - public string XDATimeZone - { - get - { - return _XDATimeZone; - } - set - { - if (string.IsNullOrEmpty(value)) - _XDATimeZone = TimeZoneInfo.Local.Id; - else - _XDATimeZone = value; - } - } - - /// - /// Gets the for the - /// time zone used by openXDA to store data. - /// - public TimeZoneInfo XDATimeZoneInfo - { - get - { - if ((object)_XDATimeZoneInfo == null) - _XDATimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(_XDATimeZone); - - return _XDATimeZoneInfo; - } - } - - private string _XDATimeZone { get; set; } - private TimeZoneInfo _XDATimeZoneInfo { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/TaskProcessorSection.cs b/Libraries/openXDA.Configuration/TaskProcessorSection.cs deleted file mode 100644 index e42b01fc..00000000 --- a/Libraries/openXDA.Configuration/TaskProcessorSection.cs +++ /dev/null @@ -1,68 +0,0 @@ -//****************************************************************************************************** -// TaskProcessorSection.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 02/24/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class TaskProcessorSection - { - public const string CategoryName = "TaskProcessor"; - - /// - /// Gets or sets the query used to filter - /// meters when polling for analysis tasks. - /// - [Setting] - [DefaultValue("SELECT ID FROM Meter")] - public string MeterFilterQuery { get; set; } - - /// - /// Gets or sets the number of threads used - /// for processing meter data concurrently. - /// - /// - /// Values less than or equal to zero will be set to the number of logical processors. - /// - [Setting] - [DefaultValue(0)] - public int ProcessingThreadCount - { - get - { - return _ProcessingThreadCount; - } - set - { - _ProcessingThreadCount = value; - - if (_ProcessingThreadCount <= 0) - _ProcessingThreadCount = Environment.ProcessorCount; - } - } - - private int _ProcessingThreadCount { get; set; } - } -} diff --git a/Libraries/openXDA.Configuration/TrendingDataSection.cs b/Libraries/openXDA.Configuration/TrendingDataSection.cs deleted file mode 100644 index 389daad4..00000000 --- a/Libraries/openXDA.Configuration/TrendingDataSection.cs +++ /dev/null @@ -1,122 +0,0 @@ -//****************************************************************************************************** -// TrendingDataSection.cs - Gbtc -// -// Copyright © 2022, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/26/2022 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Configuration -{ - public class TrendingDataSection - { - #region [ Members ] - - // Nested Types - public class RMSSubSection - { - [Setting] - [DefaultValue(@"Trms.dat")] - public string FolderPath { get; set; } - [Setting] - [DefaultValue(null)] - public string DescriptionRegexMatchFilter { get; set; } - } - - public class FlickerSubSection - { - [Setting] - [DefaultValue(@"FkrR[0-9]*\.dat")] - public string FolderPath { get; set; } - [Setting] - [DefaultValue(null)] - public string DescriptionRegexMatchFilter { get; set; } - } - - public class TriggerSubSection - { - [Setting] - [DefaultValue(@"TrR[0-9]*\.dat")] - public string FolderPath { get; set; } - [Setting] - [DefaultValue(@"\s-\sV\S*\sRMS\s*$")] - public string DescriptionTriggerRMSMatch { get; set; } - [Setting] - [DefaultValue(@"\s-\sV\S*\sImpulse\s*$")] - public string DescriptionTriggerImpulseMatch { get; set; } - [Setting] - [DefaultValue(@"\s-\s\S+\sTHD\s*$")] - public string DescriptionTriggerTHDMatch { get; set; } - [Setting] - [DefaultValue(@"\s-\sUnbalance\s*$")] - public string DescriptionTriggerUnbalanceMatch { get; set; } - [Setting] - [DefaultValue(@"\s-\s\S*I\S*\s*$")] - public string DescriptionTriggerCurrentMatch { get; set; } - [Setting] - [DefaultValue(null)] - public string DescriptionRegexMatchFilter { get; set; } - } - - public class FrequencySubSection - { - [Setting] - [DefaultValue(@"Tfrq[0-9]*\.dat")] - public string FolderPath { get; set; } - [Setting] - [DefaultValue(null)] - public string DescriptionRegexMatchFilter { get; set; } - } - - // Constants - public const string CategoryName = "TrendingData"; - - #endregion - - #region [ Properties ] - - /// - /// Gets RMS folder path settings. - /// - [Category] - public RMSSubSection RMS { get; } = new RMSSubSection(); - - /// - /// Gets flicker folder path settings. - /// - [Category] - public FlickerSubSection Flicker { get; } = new FlickerSubSection(); - - /// - /// Gets trigger folder path settings. - /// - [Category] - public TriggerSubSection Trigger { get; } = new TriggerSubSection(); - - /// - /// Gets frequency folder path settings. - /// - [Category] - public FrequencySubSection Frequency { get; } = new FrequencySubSection(); - - #endregion - } -} diff --git a/Libraries/openXDA.Configuration/openXDA.Configuration.csproj b/Libraries/openXDA.Configuration/openXDA.Configuration.csproj deleted file mode 100644 index 3d799a9b..00000000 --- a/Libraries/openXDA.Configuration/openXDA.Configuration.csproj +++ /dev/null @@ -1,48 +0,0 @@ - - - - Debug - AnyCPU - net9.0 - Debug;Development;Release - Library - openXDA.Configuration - openXDA.Configuration - false - enable - enable - true - - - - true - full - false - ..\..\..\Build\Output\Debug\Libraries\ - DEBUG;TRACE - 4 - - - - pdbonly - true - ..\..\..\Build\Output\Release\Libraries\ - TRACE - 4 - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Libraries/openXDA.Model/Channels/Channel.cs b/Libraries/openXDA.Model/Channels/Channel.cs deleted file mode 100644 index 9d65c5bc..00000000 --- a/Libraries/openXDA.Model/Channels/Channel.cs +++ /dev/null @@ -1,629 +0,0 @@ -//****************************************************************************************************** -// Channel.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.Data; -using System.Transactions; -using IsolationLevel = System.Transactions.IsolationLevel; - -namespace openXDA.Model -{ - public class ChannelKey : IEquatable - { - #region [ Constructors ] - - public ChannelKey(int assetID, int harmonicGroup, string name, string measurementType, string measurementCharacteristic, string phase) - { - LineID = assetID; - HarmonicGroup = harmonicGroup; - Name = name; - MeasurementType = measurementType; - MeasurementCharacteristic = measurementCharacteristic; - Phase = phase; - } - - public ChannelKey(Channel channel) - : this(channel.AssetID, channel.HarmonicGroup, channel.Name, channel.MeasurementType.Name, channel.MeasurementCharacteristic.Name, channel.Phase.Name) - { - } - - #endregion - - #region [ Properties ] - - public int LineID { get; } - public int HarmonicGroup { get; } - public string Name { get; } - public string MeasurementType { get; } - public string MeasurementCharacteristic { get; } - public string Phase { get; } - - #endregion - - #region [ Methods ] - - public Channel Find(AdoDataConnection connection, int meterID) - { - const string QueryFormat = - "SELECT Channel.* " + - "FROM " + - " Channel JOIN " + - " MeasurementType ON Channel.MeasurementTypeID = MeasurementType.ID JOIN " + - " MeasurementCharacteristic ON Channel.MeasurementCharacteristicID = MeasurementCharacteristic.ID JOIN " + - " Phase ON Channel.PhaseID = Phase.ID " + - "WHERE " + - " Channel.MeterID = {0} AND " + - " Channel.AssetID = {1} AND " + - " Channel.HarmonicGroup = {2} AND " + - " Channel.Name = {3} AND " + - " MeasurementType.Name = {4} AND " + - " MeasurementCharacteristic.Name = {5} AND " + - " Phase.Name = {6}"; - - object[] parameters = - { - meterID, - LineID, - HarmonicGroup, - Name, - MeasurementType, - MeasurementCharacteristic, - Phase - }; - - using (DataTable table = connection.RetrieveData(QueryFormat, parameters)) - { - if (table.Rows.Count == 0) - return null; - - TableOperations channelTable = new TableOperations(connection); - return channelTable.LoadRecord(table.Rows[0]); - } - } - - public override int GetHashCode() - { - StringComparer stringComparer = StringComparer.OrdinalIgnoreCase; - - int hash = 1009; - hash = 9176 * hash + LineID.GetHashCode(); - hash = 9176 * hash + HarmonicGroup.GetHashCode(); - hash = 9176 * hash + stringComparer.GetHashCode(Name); - hash = 9176 * hash + stringComparer.GetHashCode(MeasurementType); - hash = 9176 * hash + stringComparer.GetHashCode(MeasurementCharacteristic); - hash = 9176 * hash + stringComparer.GetHashCode(Phase); - return hash; - } - - public override bool Equals(object obj) - { - return Equals(obj as ChannelKey); - } - - public bool Equals(ChannelKey other) - { - if (other is null) - return false; - - StringComparison stringComparison = StringComparison.OrdinalIgnoreCase; - - return - LineID.Equals(other.LineID) && - HarmonicGroup.Equals(other.HarmonicGroup) && - Name.Equals(other.Name, stringComparison) && - MeasurementType.Equals(other.MeasurementType, stringComparison) && - MeasurementCharacteristic.Equals(other.MeasurementCharacteristic, stringComparison) && - Phase.Equals(other.Phase, stringComparison); - } - - #endregion - } - - [TableName("Channel")] - public class ChannelBase - { - [PrimaryKey(true)] - public int ID { get; set; } - - [ParentKey(typeof(Meter))] - public int MeterID { get; set; } - - public int AssetID { get; set; } - - public int MeasurementTypeID { get; set; } - - public int MeasurementCharacteristicID { get; set; } - - public int PhaseID { get; set; } - - [StringLength(200)] - public string Name { get; set; } - - public double Adder { get; set; } - - [DefaultValue(1.0D)] - public double Multiplier { get; set; } = 1.0D; - - public double SamplesPerHour { get; set; } - - public double? PerUnitValue { get; set; } - - public int HarmonicGroup { get; set; } - - public string Description { get; set; } - - public bool Enabled { get; set; } - - [DefaultValue(false)] - public bool Trend { get; set; } - - [DefaultValue(0)] - public int ConnectionPriority { get; set; } = 0; - } - - public class Channel : ChannelBase - { - #region [ Members ] - - // Fields - private MeasurementType m_measurementType; - private MeasurementCharacteristic m_measurementCharacteristic; - private Phase m_phase; - private Meter m_meter; - private Asset m_asset; - private List m_series; - - #endregion - - #region [ Properties ] - - [JsonIgnore] - [NonRecordField] - public MeasurementType MeasurementType - { - get - { - if (m_measurementType is null) - m_measurementType = LazyContext.GetMeasurementType(MeasurementTypeID); - - if (m_measurementType is null) - m_measurementType = QueryMeasurementType(); - - return m_measurementType; - } - set => m_measurementType = value; - } - - [JsonIgnore] - [NonRecordField] - public MeasurementCharacteristic MeasurementCharacteristic - { - get - { - if (m_measurementCharacteristic is null) - m_measurementCharacteristic = LazyContext.GetMeasurementCharacteristic(MeasurementCharacteristicID); - - if (m_measurementCharacteristic is null) - m_measurementCharacteristic = QueryMeasurementCharacteristic(); - - return m_measurementCharacteristic; - } - set => m_measurementCharacteristic = value; - } - - [JsonIgnore] - [NonRecordField] - public Phase Phase - { - get - { - if (m_phase is null) - m_phase = LazyContext.GetPhase(PhaseID); - - if (m_phase is null) - m_phase = QueryPhase(); - - return m_phase; - } - set => m_phase = value; - } - - [JsonIgnore] - [NonRecordField] - public Meter Meter - { - get - { - if (m_meter is null) - m_meter = LazyContext.GetMeter(MeterID); - - if (m_meter is null) - m_meter = QueryMeter(); - - return m_meter; - } - set => m_meter = value; - } - - [JsonIgnore] - [NonRecordField] - public Asset Asset - { - get - { - if (m_asset is null) - m_asset = LazyContext.GetAsset(AssetID); - - if (m_asset is null) - m_asset = QueryAsset(); - - return m_asset; - } - set => m_asset = value; - } - - [JsonIgnore] - [NonRecordField] - public List Series - { - get => m_series ?? (m_series = QuerySeries()); - set => m_series = value; - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public MeasurementType GetMeasurementType(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations measurementTypeTable = new TableOperations(connection); - return measurementTypeTable.QueryRecordWhere("ID = {0}", MeasurementTypeID); - } - - public MeasurementCharacteristic GetMeasurementCharacteristic(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations measurementCharacteristicTable = new TableOperations(connection); - return measurementCharacteristicTable.QueryRecordWhere("ID = {0}", MeasurementCharacteristicID); - } - - public Phase GetPhase(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations phaseTable = new TableOperations(connection); - return phaseTable.QueryRecordWhere("ID = {0}", PhaseID); - } - - public Meter GetMeter(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations meterTable = new TableOperations(connection); - return meterTable.QueryRecordWhere("ID = {0}", MeterID); - } - - public Asset GetAsset(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetTable = new TableOperations(connection); - return assetTable.QueryRecordWhere("ID = {0}", AssetID); - } - - public IEnumerable GetSeries(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations seriesTable = new TableOperations(connection); - return seriesTable.QueryRecordsWhere("ChannelID = {0}", ID); - } - - private MeasurementType QueryMeasurementType() - { - MeasurementType measurementType; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - measurementType = GetMeasurementType(connection); - } - - return LazyContext.GetMeasurementType(measurementType); - } - - private MeasurementCharacteristic QueryMeasurementCharacteristic() - { - MeasurementCharacteristic measurementCharacteristic; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - measurementCharacteristic = GetMeasurementCharacteristic(connection); - } - - return LazyContext.GetMeasurementCharacteristic(measurementCharacteristic); - } - - private Phase QueryPhase() - { - Phase phase; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - phase = GetPhase(connection); - } - - return LazyContext.GetPhase(phase); - } - - private Meter QueryMeter() - { - Meter meter; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - meter = GetMeter(connection); - } - - if ((object)meter != null) - meter.LazyContext = LazyContext; - - return LazyContext.GetMeter(meter); - } - - private Asset QueryAsset() - { - Asset asset; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - asset = GetAsset(connection); - } - - if ((object)asset != null) - asset.LazyContext = LazyContext; - - return LazyContext.GetAsset(asset); - } - - private List QuerySeries() - { - List seriesList; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - seriesList = GetSeries(connection)? - .Select(LazyContext.GetSeries) - .ToList(); - } - - if ((object)seriesList != null) - { - foreach (Series series in seriesList) - { - series.Channel = this; - series.LazyContext = LazyContext; - } - } - - return seriesList; - } - - #endregion - } - - public class ChannelComparer : IEqualityComparer - { - public bool Equals(Channel x, Channel y) - { - if (Object.ReferenceEquals(x, y)) return true; - - //Check whether any of the compared objects is null. - if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) - return false; - - //Check whether the channels are equal. - return x.ID == y.ID; - } - - public int GetHashCode(Channel obj) - { - return obj.ID; - } - } - - [TableName("ChannelDetail")] - public class ChannelDetail : Channel - { - public string MeterName { get; set; } - - public string AssetKey { get; set; } - - public string AssetName { get; set; } - - public new string MeasurementType { get; set; } - - public new string MeasurementCharacteristic { get; set; } - - public new string Phase { get; set; } - - public string Mapping { get; set; } - - public int SeriesTypeID { get; set; } - - public string SeriesType { get; set; } - - [SearchExtension("^VoltageKV$")] - public static RecordRestriction GetVoltageKVRestriction(IRecordFilter filter) - { - return SearchRestrictionHelper.GetSearchRestriction("(SELECT VoltageKV FROM Asset WHERE Asset.ID = FullTbl.AssetID)", filter); - } - - [SearchExtension("^ChannelGroupTypeID$")] - public static RecordRestriction GetChannelGroupTypeRestriction(IRecordFilter filter) - { - RecordRestriction restriction = SearchRestrictionHelper.GetSearchRestriction("ID", filter); - - return new RecordRestriction( - $"EXISTS(SELECT * FROM ChannelGroupType WHERE {restriction.FilterExpression} AND MeasurementTypeID = FullTbl.MeasurementTypeID AND MeasurementCharacteristicID = FullTbl.MeasurementCharacteristicID)", - restriction.Parameters); - } - - [SearchExtension("^SeriesID$")] - public static RecordRestriction GetSeriesRestriction(IRecordFilter filter) - { - RecordRestriction restriction = SearchRestrictionHelper.GetSearchRestriction("Series.SeriesTypeID", filter); - - return new RecordRestriction( - $"(SELECT COUNT(Series.ID) FROM SERIES WHERE Series.ChannelID = FullTbl.ID AND {restriction.FilterExpression}) > 0", - restriction.Parameters); - } - } - - public class ChannelInfo - { - [PrimaryKey(true)] - public int ChannelID { get; set; } - - public string ChannelName { get; set; } - - public string ChannelDescription { get; set; } - - public string MeasurementType { get; set; } - - public string MeasurementCharacteristic { get; set; } - - public string Phase { get; set; } - - public string SeriesType { get; set; } - - public string Orientation { get; set; } - - public string Phasing { get; set; } - } - - public static partial class TableOperationsExtensions - { - public static DashSettings GetOrAdd(this TableOperations table, string name, string value, bool enabled = true) - { - TransactionScopeOption required = TransactionScopeOption.Required; - - TransactionOptions transactionOptions = new TransactionOptions() - { - IsolationLevel = IsolationLevel.ReadCommitted, - Timeout = TransactionManager.MaximumTimeout - }; - - DashSettings dashSettings; - - using (TransactionScope transactionScope = new TransactionScope(required, transactionOptions)) - { - if (value.Contains(",")) - dashSettings = table.QueryRecordWhere("Name = {0} AND SUBSTRING(Value, 0, CHARINDEX(',', Value)) = {1}", name, value.Split(',').First()); - else - dashSettings = table.QueryRecordWhere("Name = {0} AND Value = {1}", name, value); - - if ((object)dashSettings == null) - { - dashSettings = new DashSettings(); - dashSettings.Name = name; - dashSettings.Value = value; - dashSettings.Enabled = enabled; - - table.AddNewRecord(dashSettings); - - dashSettings.ID = table.Connection.ExecuteScalar("SELECT @@IDENTITY"); - } - - transactionScope.Complete(); - } - - return dashSettings; - } - - public static UserDashSettings GetOrAdd(this TableOperations table, string name, Guid user, string value, bool enabled = true) - { - TransactionScopeOption required = TransactionScopeOption.Required; - - TransactionOptions transactionOptions = new TransactionOptions() - { - IsolationLevel = IsolationLevel.ReadCommitted, - Timeout = TransactionManager.MaximumTimeout - }; - - UserDashSettings dashSettings; - - using (TransactionScope transactionScope = new TransactionScope(required, transactionOptions)) - { - if (value.Contains(",")) - dashSettings = table.QueryRecordWhere("Name = {0} AND SUBSTRING(Value, 0, CHARINDEX(',', Value)) = {1} AND UserAccountID = {2}", name, value.Split(',').First(), user); - else - dashSettings = table.QueryRecordWhere("Name = {0} AND Value = {1} AND UserAccountID = {2}", name, value, user); - - if ((object)dashSettings == null) - { - dashSettings = new UserDashSettings(); - dashSettings.Name = name; - dashSettings.Value = value; - dashSettings.Enabled = enabled; - dashSettings.UserAccountID = user; - - table.AddNewRecord(dashSettings); - - dashSettings.ID = table.Connection.ExecuteScalar("SELECT @@IDENTITY"); - } - - transactionScope.Complete(); - } - - return dashSettings; - } - - } - -} diff --git a/Libraries/openXDA.Model/Channels/ChannelData.cs b/Libraries/openXDA.Model/Channels/ChannelData.cs deleted file mode 100644 index 2ce28f94..00000000 --- a/Libraries/openXDA.Model/Channels/ChannelData.cs +++ /dev/null @@ -1,649 +0,0 @@ -//****************************************************************************************************** -// ChannelData.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 12/12/2019 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone; -using Gemstone.Data; -using Gemstone.Data.DataExtensions; -using Gemstone.Data.Model; -using Ionic.Zlib; - -namespace openXDA.Model -{ - [TableName("ChannelData")] - public class ChannelData - { - #region [ Members ] - - // Nested Types - private class DigitalSection - { - public DateTime Start { get; set; } - public DateTime End { get; set; } - public int NumPoints { get; set; } - public double Value { get; set; } - public static int Size => 2 * sizeof(long) + sizeof(ushort) + sizeof(int); - - public int CopyBytes(byte[] byteArray, int offset, double compressionScale, double compressionOffset) - { - ushort compressedValue = (ushort)Math.Round((Value - compressionOffset) * compressionScale); - const ushort NaNValue = ushort.MaxValue; - - if (compressedValue == NaNValue) - compressedValue--; - - if (double.IsNaN(Value)) - compressedValue = NaNValue; - - int startOffset = offset; - offset += LittleEndian.CopyBytes(Start.Ticks, byteArray, offset); - offset += LittleEndian.CopyBytes(End.Ticks, byteArray, offset); - offset += LittleEndian.CopyBytes(compressedValue, byteArray, offset); - offset += LittleEndian.CopyBytes(NumPoints, byteArray, offset); - return offset - startOffset; - } - - public static DigitalSection FromBytes(byte[] bytes, int offset, double decompressionOffset, double decompressionScale) - { - DigitalSection section = new DigitalSection(); - - section.Start = new DateTime(LittleEndian.ToInt64(bytes, offset)); - offset += sizeof(long); - - section.End = new DateTime(LittleEndian.ToInt64(bytes, offset)); - offset += sizeof(long); - - ushort compressedValue = LittleEndian.ToUInt16(bytes, offset); - section.Value = decompressionScale * compressedValue + decompressionOffset; - offset += sizeof(ushort); - - section.NumPoints = LittleEndian.ToInt32(bytes, offset); - - return section; - } - } - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public int SeriesID { get; set; } - - public int EventID { get; set; } - - public byte[] TimeDomainData { get; set; } - - public int MarkedForDeletion { get; set; } - - #endregion - - #region [ Methods ] - - /// - /// Adjusts the TimeDomain Data by Moving it a certain ammount of Time - /// - /// The number of Ticks the Data is moved. For moving it backwards in Time this needs to be < 0 - public void AdjustData(Ticks ticks) - { - // Initially we assume Data is already migrated... - if (TimeDomainData == null) - return; - - Tuple> decompressed = Decompress(TimeDomainData)[0]; - List data = decompressed.Item2; - - foreach (DataPoint dataPoint in data) - dataPoint.Time = dataPoint.Time.AddTicks(ticks); - - TimeDomainData = ToData(data, decompressed.Item1); - } - - #endregion - - #region [ Static ] - - public static List DataFromEvent(int eventID, Func connectionFactory) - { - using (AdoDataConnection connection = connectionFactory()) - { - TableOperations eventTable = new TableOperations(connection); - Event evt = eventTable.QueryRecordWhere("ID = {0}", eventID); - - TableOperations assetTable = new TableOperations(connection); - Asset asset = assetTable.QueryRecordWhere("ID = {0}", evt.AssetID); - asset.ConnectionFactory = connectionFactory; - - List channels = asset.DirectChannels - .Concat(asset.ConnectedChannels) - .Where(channel => channel.MeterID == evt.MeterID) - .ToList(); - - if (!channels.Any()) - return new List(); - - IEnumerable assetIDs = channels - .Select(channel => channel.AssetID) - .Distinct(); - - foreach (int assetID in assetIDs) - MigrateLegacyBlob(connection, evt.FileGroupID, assetID, evt.StartTime); - - // Optimization to avoid individually querying channels that don't have any data - HashSet channelsWithData = QueryChannelsWithData(connection, evt); - channels.RemoveAll(channel => !channelsWithData.Contains(channel.ID)); - - List eventData = new List(); - - foreach (Channel channel in channels) - { - const string DataQueryFormat = - "SELECT ChannelData.TimeDomainData " + - "FROM " + - " ChannelData JOIN " + - " Series ON ChannelData.SeriesID = Series.ID JOIN " + - " Event ON ChannelData.EventID = Event.ID " + - "WHERE " + - " Event.FileGroupID = {0} AND " + - " Series.ChannelID = {1} AND " + - " Event.StartTime = {2}"; - - object startTime2 = ToDateTime2(connection, evt.StartTime); - byte[] timeDomainData = connection.ExecuteScalar(DataQueryFormat, evt.FileGroupID, channel.ID, startTime2); - - if (timeDomainData is null) - continue; - - eventData.Add(timeDomainData); - } - - return eventData; - } - } - - public static byte[] DataFromEvent(int eventID, int channelID, Func connectionFactory) - { - using (AdoDataConnection connection = connectionFactory()) - { - TableOperations eventTable = new TableOperations(connection); - Event evt = eventTable.QueryRecordWhere("ID = {0}", eventID); - MigrateLegacyBlob(connection, evt); - - const string QueryFormat = - "SELECT ChannelData.TimeDomainData " + - "FROM " + - " ChannelData JOIN " + - " Series ON ChannelData.SeriesID = Series.ID " + - "WHERE " + - " ChannelData.EventID = {0} AND " + - " Series.ChannelID = {1}"; - - return connection.ExecuteScalar(QueryFormat, eventID, channelID); - } - } - - private static void MigrateLegacyBlob(AdoDataConnection connection, int fileGroupID, int assetID, DateTime startTime) - { - const string AssetQueryFilter = "FileGroupID = {0} AND AssetID = {1} AND StartTime = {2}"; - object startTime2 = ToDateTime2(connection, startTime); - - TableOperations eventTable = new TableOperations(connection); - Event evt = eventTable.QueryRecordWhere(AssetQueryFilter, fileGroupID, assetID, startTime2); - MigrateLegacyBlob(connection, evt); - } - - private static void MigrateLegacyBlob(AdoDataConnection connection, Event evt) - { - if (evt is null || evt.EventDataID is null) - return; - - int eventDataID = evt.EventDataID.GetValueOrDefault(); - byte[] timeDomainData = connection.ExecuteScalar("SELECT TimeDomainData FROM EventData WHERE ID = {0}", eventDataID); - List>> decompressedData = Decompress(timeDomainData); - - TableOperations channelDataTable = new TableOperations(connection); - - foreach (Tuple> tuple in decompressedData) - { - int seriesID = tuple.Item1; - List data = tuple.Item2; - - ChannelData channelData = new ChannelData(); - channelData.SeriesID = seriesID; - channelData.EventID = evt.ID; - channelData.TimeDomainData = ToData(data, seriesID); - channelDataTable.AddNewRecord(channelData); - } - - connection.ExecuteNonQuery("UPDATE Event SET EventDataID = NULL WHERE ID = {0}", evt.ID); - connection.ExecuteNonQuery("DELETE FROM EventData WHERE ID = {0}", eventDataID); - } - - /// - /// Turns a list of DataPoints into a blob to be saved in the database. - /// - /// The data as a - /// The SeriesID to be encoded into the blob - /// The byte array to be saved as a blob in the database. - public static byte[] ToData(List data, int seriesID) - { - // We can use Digital compression if the data changes no more than 10% of the time. - bool useDigitalCompression = data - .Skip(1) - .Zip(data, (p2, p1) => new { p1, p2 }) - .Where(obj => obj.p1.Value != obj.p2.Value) - .Select((_, index) => index + 1) - .All(nChanges => nChanges <= 0.1 * data.Count); - - if (useDigitalCompression) - return ToDigitalData(data, seriesID); - - var timeSeries = data.Select(dataPoint => new { Time = dataPoint.Time.Ticks, Compressed = false }).ToList(); - - for (int i = 1; i < timeSeries.Count; i++) - { - long previousTimestamp = data[i - 1].Time.Ticks; - long timestamp = timeSeries[i].Time; - long diff = timestamp - previousTimestamp; - - if (diff >= 0 && diff <= ushort.MaxValue) - timeSeries[i] = new { Time = diff, Compressed = true }; - } - - int timeSeriesByteLength = timeSeries.Sum(obj => obj.Compressed ? sizeof(ushort) : sizeof(int) + sizeof(long)); - int dataSeriesByteLength = sizeof(int) + (2 * sizeof(double)) + (data.Count * sizeof(ushort)); - int totalByteLength = sizeof(int) + timeSeriesByteLength + dataSeriesByteLength; - - byte[] result = new byte[totalByteLength]; - int offset = 0; - - offset += LittleEndian.CopyBytes(data.Count, result, offset); - - List uncompressedIndexes = timeSeries - .Select((obj, Index) => new { obj.Compressed, Index }) - .Where(obj => !obj.Compressed) - .Select(obj => obj.Index) - .ToList(); - - for (int i = 0; i < uncompressedIndexes.Count; i++) - { - int index = uncompressedIndexes[i]; - int nextIndex = (i + 1 < uncompressedIndexes.Count) ? uncompressedIndexes[i + 1] : timeSeries.Count; - - offset += LittleEndian.CopyBytes(nextIndex - index, result, offset); - offset += LittleEndian.CopyBytes(timeSeries[index].Time, result, offset); - - for (int j = index + 1; j < nextIndex; j++) - offset += LittleEndian.CopyBytes((ushort)timeSeries[j].Time, result, offset); - } - - const ushort NaNValue = ushort.MaxValue; - const ushort MaxCompressedValue = ushort.MaxValue - 1; - double range = data.Select(item => item.Value).Max() - data.Select(item => item.Value).Min(); - double decompressionOffset = data.Select(item => item.Value).Min(); - double decompressionScale = range / MaxCompressedValue; - double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; - - offset += LittleEndian.CopyBytes(seriesID, result, offset); - offset += LittleEndian.CopyBytes(decompressionOffset, result, offset); - offset += LittleEndian.CopyBytes(decompressionScale, result, offset); - - foreach (DataPoint dataPoint in data) - { - ushort compressedValue = (ushort)Math.Round((dataPoint.Value - decompressionOffset) * compressionScale); - - if (compressedValue == NaNValue) - compressedValue--; - - if (double.IsNaN(dataPoint.Value)) - compressedValue = NaNValue; - - offset += LittleEndian.CopyBytes(compressedValue, result, offset); - } - - byte[] returnArray = GZipStream.CompressBuffer(result); - returnArray[0] = 0x44; - returnArray[1] = 0x33; - - return returnArray; - } - - private static byte[] ToDigitalData(List data, int seriesID) - { - List digitalData = new List(); - DigitalSection currentSection = null; - foreach (DataPoint dataPoint in data) - { - if (currentSection is null) - { - currentSection = new DigitalSection() - { - Start = dataPoint.Time, - End = dataPoint.Time, - Value = dataPoint.Value, - NumPoints = 1 - }; - } - else if (currentSection.Value != dataPoint.Value) - { - digitalData.Add(currentSection); - currentSection = new DigitalSection() - { - Start = dataPoint.Time, - End = dataPoint.Time, - Value = dataPoint.Value, - NumPoints = 1 - }; - } - else - { - currentSection.NumPoints++; - currentSection.End = dataPoint.Time; - } - } - - if (!(currentSection is null)) - digitalData.Add(currentSection); - - int totalByteLength = sizeof(int) + 2 * sizeof(double) + digitalData.Count * DigitalSection.Size; - byte[] result = new byte[totalByteLength]; - int offset = 0; - - const ushort MaxCompressedValue = ushort.MaxValue - 1; - double range = data.Select(item => item.Value).Max() - data.Select(item => item.Value).Min(); - double decompressionOffset = data.Select(item => item.Value).Min(); - double decompressionScale = range / MaxCompressedValue; - double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; - - offset += LittleEndian.CopyBytes(seriesID, result, offset); - offset += LittleEndian.CopyBytes(decompressionOffset, result, offset); - offset += LittleEndian.CopyBytes(decompressionScale, result, offset); - - foreach (DigitalSection digitalSection in digitalData) - offset += digitalSection.CopyBytes(result, offset, compressionScale, decompressionOffset); - - byte[] returnArray = GZipStream.CompressBuffer(result); - returnArray[0] = DigitalHeader[0]; - returnArray[1] = DigitalHeader[1]; - return returnArray; - } - - /// - /// Decompresses a byte array into a List of DataPoints - /// - /// The byte array filled with compressed data - /// List of data series consisting of series ID and data points. - public static List>> Decompress(byte[] data) - { - List>> result = new List>>(); - - if (data == null) - return result; - // If the blob contains the GZip header, - // use the legacy deserialization algorithm - if (data[0] == LegacyHeader[0] && data[1] == LegacyHeader[1]) - { - return Decompress_Legacy(data); - } - // If this blob uses digital decompression use that algorithm - if (data[0] == DigitalHeader[0] && data[1] == DigitalHeader[1]) - { - return Decompress_Digital(data); - } - - // Restore the GZip header before uncompressing - data[0] = LegacyHeader[0]; - data[1] = LegacyHeader[1]; - - byte[] uncompressedData; - int offset; - - uncompressedData = GZipStream.UncompressBuffer(data); - offset = 0; - - int m_samples = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - List times = new List(); - - while (times.Count < m_samples) - { - int timeValues = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - long currentValue = LittleEndian.ToInt64(uncompressedData, offset); - offset += sizeof(long); - times.Add(new DateTime(currentValue)); - - for (int i = 1; i < timeValues; i++) - { - currentValue += LittleEndian.ToUInt16(uncompressedData, offset); - offset += sizeof(ushort); - times.Add(new DateTime(currentValue)); - } - } - - while (offset < uncompressedData.Length) - { - List dataSeries = new List(); - int seriesID = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - - const ushort NaNValue = ushort.MaxValue; - double decompressionOffset = LittleEndian.ToDouble(uncompressedData, offset); - double decompressionScale = LittleEndian.ToDouble(uncompressedData, offset + sizeof(double)); - offset += 2 * sizeof(double); - - for (int i = 0; i < m_samples; i++) - { - ushort compressedValue = LittleEndian.ToUInt16(uncompressedData, offset); - offset += sizeof(ushort); - - double decompressedValue = decompressionScale * compressedValue + decompressionOffset; - - if (compressedValue == NaNValue) - decompressedValue = double.NaN; - - dataSeries.Add(new DataPoint() - { - Time = times[i], - Value = decompressedValue - }); - } - - result.Add(new Tuple>(seriesID, dataSeries)); - } - - return result; - } - - private static List>> Decompress_Legacy(byte[] data) - { - List>> result = new List>>(); - byte[] uncompressedData; - int offset; - DateTime[] times; - int seriesID; - - uncompressedData = GZipStream.UncompressBuffer(data); - offset = 0; - - int m_samples = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - times = new DateTime[m_samples]; - - for (int i = 0; i < m_samples; i++) - { - times[i] = new DateTime(LittleEndian.ToInt64(uncompressedData, offset)); - offset += sizeof(long); - } - - while (offset < uncompressedData.Length) - { - seriesID = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - List points = new List(); - - for (int i = 0; i < m_samples; i++) - { - points.Add(new DataPoint() - { - Time = times[i], - Value = LittleEndian.ToDouble(uncompressedData, offset) - }); - - offset += sizeof(double); - } - - result.Add(new Tuple>(seriesID, points)); - } - return result; - } - - /// - /// Decompresses a Digital stored as compresed series of changes - /// - /// The compressed - /// a Dictionary mapping a SeriesID to a decopmressed - private static List>> Decompress_Digital(byte[] data) - { - List>> result = new List>>(); - byte[] uncompressedData; - int offset; - int seriesID; - List points = new List(); - - // Restore the GZip header before uncompressing - data[0] = LegacyHeader[0]; - data[1] = LegacyHeader[1]; - - uncompressedData = GZipStream.UncompressBuffer(data); - offset = 0; - - seriesID = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - double decompressionOffset = LittleEndian.ToDouble(uncompressedData, offset); - double decompressionScale = LittleEndian.ToDouble(uncompressedData, offset + sizeof(double)); - offset += 2 * sizeof(double); - - while(offset < uncompressedData.Length) - { - DigitalSection section = DigitalSection.FromBytes(uncompressedData, offset, decompressionOffset, decompressionScale); - offset += DigitalSection.Size; - - points.Add(new DataPoint() - { - Time = section.Start, - Value = section.Value - }); - - if (section.NumPoints == 1) - continue; - - // Use a fixed-point offset with 6 bits of additional - // precision to help avoid accumulation of rounding errors - long diff = (section.End - section.Start).Ticks << 6; - long step = diff / (section.NumPoints - 1); - long lastOffset = step; - - for (int i = 1; i < section.NumPoints - 1; i++) - { - points.Add(new DataPoint() - { - Time = section.Start.AddTicks(lastOffset >> 6), - Value = section.Value - }); - - lastOffset += step; - } - - points.Add(new DataPoint() - { - Time = section.End, - Value = section.Value - }); - } - - result.Add(new Tuple>(seriesID, points)); - - return result; - } - - private static HashSet QueryChannelsWithData(AdoDataConnection connection, Event evt) - { - const string FilterQueryFormat = - "SELECT Series.ChannelID " + - "FROM " + - " ChannelData JOIN " + - " Series ON ChannelData.SeriesID = Series.ID JOIN " + - " Event ON ChannelData.EventID = Event.ID " + - "WHERE " + - " Event.FileGroupID = {0} AND " + - " Event.StartTime = {1}"; - - object startTime2 = ToDateTime2(connection, evt.StartTime); - - using (DataTable table = connection.RetrieveData(FilterQueryFormat, evt.FileGroupID, startTime2)) - { - IEnumerable channelsWithData = table - .AsEnumerable() - .Select(row => row.ConvertField("ChannelID")); - - return new HashSet(channelsWithData); - } - } - - private static object ToDateTime2(AdoDataConnection connection, DateTime dateTime) - { - using (IDbCommand command = connection.Connection.CreateCommand()) - { - IDbDataParameter parameter = command.CreateParameter(); - parameter.DbType = DbType.DateTime2; - parameter.Value = dateTime; - return parameter; - } - } - - /// - /// The header of a datablob compressed as analog Data - /// - public static readonly byte[] AnalogHeader = { 0x11, 0x11 }; - - /// - /// The header of a datablob compressed as Digital State Changes - /// - public static readonly byte[] DigitalHeader = { 0x22, 0x22 }; - - /// - /// The header of a datablob compressed as Legacy Data - /// - public static readonly byte[] LegacyHeader = { 0x1F, 0x8B }; - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Channels/ChannelGroup.cs b/Libraries/openXDA.Model/Channels/ChannelGroup.cs deleted file mode 100644 index b5b463c2..00000000 --- a/Libraries/openXDA.Model/Channels/ChannelGroup.cs +++ /dev/null @@ -1,43 +0,0 @@ -//****************************************************************************************************** -// ChannelGroup.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/12/2020 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - - - -using Gemstone.Data.Model; -using System.ComponentModel.DataAnnotations; - -namespace openXDA.Model; - -[PostRoles("Administrator, Transmission SME")] -[PatchRoles("Administrator, Transmission SME")] -[DeleteRoles("Administrator, Transmission SME")] -public class ChannelGroup -{ - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - public string Name { get; set; } - - public string Description { get; set; } -} diff --git a/Libraries/openXDA.Model/Channels/DataPoint.cs b/Libraries/openXDA.Model/Channels/DataPoint.cs deleted file mode 100644 index 88c39332..00000000 --- a/Libraries/openXDA.Model/Channels/DataPoint.cs +++ /dev/null @@ -1,110 +0,0 @@ -//****************************************************************************************************** -// DataPoint.cs - Gbtc -// -// Copyright © 2025, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 05/15/2025 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.Model -{ - /// - /// Represents a single data point in a time series. - /// - public class DataPoint - { - #region [ Properties ] - - public DateTime Time { get; set; } - public double Value { get; set; } - - #endregion - - #region [ Methods ] - - public DataPoint Shift(TimeSpan timeShift) - { - return new DataPoint() - { - Time = Time.Add(timeShift), - Value = Value - }; - } - - public DataPoint Negate() - { - return new DataPoint() - { - Time = Time, - Value = -Value - }; - } - - public DataPoint Add(DataPoint point) - { - if (Time != point.Time) - throw new InvalidOperationException("Cannot add datapoints with mismatched times"); - - return new DataPoint() - { - Time = Time, - Value = Value + point.Value - }; - } - - public DataPoint Subtract(DataPoint point) - { - return Add(point.Negate()); - } - - public DataPoint Add(double value) - { - return new DataPoint() - { - Time = Time, - Value = Value + value - }; - } - - public DataPoint Subtract(double value) - { - return Add(-value); - } - - public DataPoint Multiply(double value) - { - return new DataPoint() - { - Time = Time, - Value = Value * value - }; - } - - public bool LargerThan(double comparison) - { - return Value > comparison; - } - - public bool LargerThan(DataPoint point) - { - return LargerThan(point.Value); - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Channels/MeasurementCharacteristic.cs b/Libraries/openXDA.Model/Channels/MeasurementCharacteristic.cs deleted file mode 100644 index a3e49898..00000000 --- a/Libraries/openXDA.Model/Channels/MeasurementCharacteristic.cs +++ /dev/null @@ -1,45 +0,0 @@ -//****************************************************************************************************** -// MeasurementCharacteristic.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel.DataAnnotations; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [PostRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - public class MeasurementCharacteristic - { - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - [DefaultSortOrder] - public string Name { get; set; } - - public string Description { get; set; } - - public bool Display { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Channels/MeasurementType.cs b/Libraries/openXDA.Model/Channels/MeasurementType.cs deleted file mode 100644 index 20d3ea30..00000000 --- a/Libraries/openXDA.Model/Channels/MeasurementType.cs +++ /dev/null @@ -1,44 +0,0 @@ -//****************************************************************************************************** -// MeasurementType.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel.DataAnnotations; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [PostRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - public class MeasurementType - { - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - [DefaultSortOrder] - public string Name { get; set; } - - public string Description { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Channels/Phase.cs b/Libraries/openXDA.Model/Channels/Phase.cs deleted file mode 100644 index 705ec274..00000000 --- a/Libraries/openXDA.Model/Channels/Phase.cs +++ /dev/null @@ -1,43 +0,0 @@ -//****************************************************************************************************** -// Phase.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel.DataAnnotations; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [PostRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - public class Phase - { - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - [DefaultSortOrder] - public string Name { get; set; } - - public string Description { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Channels/Series.cs b/Libraries/openXDA.Model/Channels/Series.cs deleted file mode 100644 index d6c96a6c..00000000 --- a/Libraries/openXDA.Model/Channels/Series.cs +++ /dev/null @@ -1,248 +0,0 @@ -//****************************************************************************************************** -// Series.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/20/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - public class SeriesKey : IEquatable - { - #region [ Constructors ] - - public SeriesKey(ChannelKey channelKey, string seriesType) - { - ChannelKey = channelKey; - SeriesType = seriesType; - } - - public SeriesKey(Series series) - : this(new ChannelKey(series.Channel), series.SeriesType.Name) - { - } - - #endregion - - #region [ Properties ] - - public ChannelKey ChannelKey { get; } - public string SeriesType { get; } - - #endregion - - #region [ Methods ] - - public Series Find(AdoDataConnection connection, int meterID) - { - const string QueryFormat = - "SELECT Series.* " + - "FROM " + - " Series JOIN " + - " Channel ON Series.ChannelID = Channel.ID JOIN " + - " MeasurementType ON Channel.MeasurementTypeID = MeasurementType.ID JOIN " + - " MeasurementCharacteristic ON Channel.MeasurementCharacteristicID = MeasurementCharacteristic.ID JOIN " + - " Phase ON Channel.PhaseID = Phase.ID JOIN " + - " SeriesType ON Series.SeriesTypeID = SeriesType.ID " + - "WHERE " + - " Channel.MeterID = {0} AND " + - " Channel.AssetID = {1} AND " + - " Channel.HarmonicGroup = {2} AND " + - " Channel.Name = {3} AND " + - " MeasurementType.Name = {4} AND " + - " MeasurementCharacteristic.Name = {5} AND " + - " Phase.Name = {6} AND " + - " SeriesType.Name = {7}"; - - object[] parameters = - { - meterID, - ChannelKey.LineID, - ChannelKey.HarmonicGroup, - ChannelKey.Name, - ChannelKey.MeasurementType, - ChannelKey.MeasurementCharacteristic, - ChannelKey.Phase, - SeriesType - }; - - using (DataTable table = connection.RetrieveData(QueryFormat, parameters)) - { - if (table.Rows.Count == 0) - return null; - - TableOperations seriesTable = new TableOperations(connection); - return seriesTable.LoadRecord(table.Rows[0]); - } - } - - public override int GetHashCode() - { - StringComparer stringComparer = StringComparer.OrdinalIgnoreCase; - - int hash = 1009; - hash = 9176 * hash + ChannelKey.GetHashCode(); - hash = 9176 * hash + stringComparer.GetHashCode(SeriesType); - return hash; - } - - public override bool Equals(object obj) - { - return Equals(obj as SeriesKey); - } - - public bool Equals(SeriesKey other) - { - if (other is null) - return false; - - StringComparison stringComparison = StringComparison.OrdinalIgnoreCase; - - return - ChannelKey.Equals(other.ChannelKey) && - SeriesType.Equals(other.SeriesType, stringComparison); - } - - #endregion - } - - public class Series - { - #region [ Members ] - - // Fields - private SeriesType m_seriesType; - private Channel m_channel; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public int ChannelID { get; set; } - - public int SeriesTypeID { get; set; } - - public string SourceIndexes { get; set; } - - [JsonIgnore] - [NonRecordField] - public SeriesType SeriesType - { - get - { - if (m_seriesType is null) - m_seriesType = LazyContext.GetSeriesType(SeriesTypeID); - - if (m_seriesType is null) - m_seriesType = QuerySeriesType(); - - return m_seriesType; - } - set => m_seriesType = value; - } - - [JsonIgnore] - [NonRecordField] - public Channel Channel - { - get - { - if (m_channel is null) - m_channel = LazyContext.GetChannel(ChannelID); - - if (m_channel is null) - m_channel = QueryChannel(); - - return m_channel; - } - set => m_channel = value; - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public SeriesType GetSeriesType(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations seriesTypeTable = new TableOperations(connection); - return seriesTypeTable.QueryRecordWhere("ID = {0}", SeriesTypeID); - } - - public Channel GetChannel(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations channelTable = new TableOperations(connection); - return channelTable.QueryRecordWhere("ID = {0}", ChannelID); - } - - private SeriesType QuerySeriesType() - { - SeriesType seriesType; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - seriesType = GetSeriesType(connection); - } - - return LazyContext.GetSeriesType(seriesType); - } - - private Channel QueryChannel() - { - Channel channel; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - channel = GetChannel(connection); - } - - if ((object)channel != null) - channel.LazyContext = LazyContext; - - return LazyContext.GetChannel(channel); - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Channels/SeriesType.cs b/Libraries/openXDA.Model/Channels/SeriesType.cs deleted file mode 100644 index c7621b5d..00000000 --- a/Libraries/openXDA.Model/Channels/SeriesType.cs +++ /dev/null @@ -1,40 +0,0 @@ -//****************************************************************************************************** -// SeriesType.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel.DataAnnotations; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [TableName("SeriesType")] - public class SeriesType - { - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - public string Name { get; set; } - - public string Description { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/DERAnalytic/DERAnalyticResult.cs b/Libraries/openXDA.Model/DERAnalytic/DERAnalyticResult.cs deleted file mode 100644 index c667215e..00000000 --- a/Libraries/openXDA.Model/DERAnalytic/DERAnalyticResult.cs +++ /dev/null @@ -1,54 +0,0 @@ -//****************************************************************************************************** -// DERAnalyticResult.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 11/09/2021 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model; - -public class DERAnalyticResult -{ - [PrimaryKey(true)] - public int ID { get; set; } - - public int? EventID { get; set; } - - public int MeterID { get; set; } - - public int AssetID { get; set; } - - public int ChannelID { get; set; } - - public string Regulation { get; set; } - - - public string Parameter { get; set; } - - public double Threshold { get; set; } - - public double Value { get; set; } - - [UseEscapedName] - public DateTime Time { get; set; } - - public string DataType { get; set; } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Events/BreakerRestrike.cs b/Libraries/openXDA.Model/Events/BreakerRestrike.cs deleted file mode 100644 index e76661d5..00000000 --- a/Libraries/openXDA.Model/Events/BreakerRestrike.cs +++ /dev/null @@ -1,65 +0,0 @@ -//****************************************************************************************************** -// BreakerRestrike.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/30/2019 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone.Data; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class BreakerRestrike - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int EventID { get; set; } - - public int PhaseID { get; set; } - - public int InitialExtinguishSample { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime InitialExtinguishTime { get; set; } - public double InitialExtinguishVoltage { get; set; } - public int RestrikeSample { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime RestrikeTime { get; set; } - public double RestrikeVoltage { get; set; } - public double RestrikeCurrentPeak { get; set; } - public double RestrikeVoltageDip { get; set; } - public int TransientPeakSample { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime TransientPeakTime { get; set; } - public double TransientPeakVoltage { get; set; } - public double PerUnitTransientPeakVoltage { get; set; } - public int FinalExtinguishSample { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime FinalExtinguishTime { get; set; } - public double FinalExtinguishVoltage { get; set; } - public double I2t { get; set; } - - } -} diff --git a/Libraries/openXDA.Model/Events/Disturbances/Disturbance.cs b/Libraries/openXDA.Model/Events/Disturbances/Disturbance.cs deleted file mode 100644 index c83ce0e6..00000000 --- a/Libraries/openXDA.Model/Events/Disturbances/Disturbance.cs +++ /dev/null @@ -1,67 +0,0 @@ -//****************************************************************************************************** -// Disturbance.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class Disturbance - { - [PrimaryKey(true)] - public int ID { get; set; } - public int EventID { get; set; } - public int EventTypeID { get; set; } - public int PhaseID { get; set; } - public double Magnitude { get; set; } - public double PerUnitMagnitude { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, Gemstone.Data.DatabaseType.SQLServer)] - public DateTime StartTime { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, Gemstone.Data.DatabaseType.SQLServer)] - public DateTime EndTime { get; set; } - - public double DurationSeconds { get; set; } - public double DurationCycles { get; set; } - public int StartIndex { get; set; } - public int EndIndex { get; set; } - public string UpdatedBy { get; set; } - } - - [TableName("DisturbanceView")] - public class DisturbanceView: Disturbance - { - public int MeterID { get; set; } - public int LineID { get; set; } - public int? SeverityCode { get; set; } - public string MeterName { get; set; } - public string PhaseName { get; set; } - } - - [TableName("DisturbanceView")] - public class DisturbancesForDay : DisturbanceView { } - - [TableName("DisturbanceView")] - public class DisturbancesForMeter : DisturbanceView { } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Events/Event.cs b/Libraries/openXDA.Model/Events/Event.cs deleted file mode 100644 index 992ad47e..00000000 --- a/Libraries/openXDA.Model/Events/Event.cs +++ /dev/null @@ -1,91 +0,0 @@ -//****************************************************************************************************** -// Event.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone.Data; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [TableName("Event")] - public class Event - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int FileGroupID { get; set; } - - public int MeterID { get; set; } - - public int AssetID { get; set; } - - public int EventTypeID { get; set; } - - public int? EventDataID { get; set; } - - public string Name { get; set; } - - public string Alias { get; set; } - - public string ShortName { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime StartTime { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime EndTime { get; set; } - - public int Samples { get; set; } - - public int TimeZoneOffset { get; set; } - - public int SamplesPerSecond { get; set; } - - public int SamplesPerCycle { get; set; } - - public string Description { get; set; } - - public int FileVersion { get; set; } - - public string UpdatedBy { get; set; } - } - - [TableName("EventView")] - public class EventView : Event - { - [PrimaryKey(true)] - public new int ID - { - get => base.ID; - set => base.ID = value; - } - - public string AssetName { get; set; } - - public string MeterName { get; set; } - - public string StationName { get; set; } - - public string EventTypeName { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Events/EventStat.cs b/Libraries/openXDA.Model/Events/EventStat.cs deleted file mode 100644 index 6e004a3e..00000000 --- a/Libraries/openXDA.Model/Events/EventStat.cs +++ /dev/null @@ -1,57 +0,0 @@ -//****************************************************************************************************** -// EventStat.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 11/07/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class EventStat - { - [PrimaryKey(true)] - public int ID { get; set; } - public int EventID { get; set; } - public double? VPeak { get; set; } - public double? VAMax { get; set; } - public double? VBMax { get; set; } - public double? VCMax { get; set; } - public double? VABMax { get; set; } - public double? VBCMax { get; set; } - public double? VCAMax { get; set; } - public double? VAMin { get; set; } - public double? VBMin { get; set; } - public double? VCMin { get; set; } - public double? VABMin { get; set; } - public double? VBCMin { get; set; } - public double? VCAMin { get; set; } - public double? IPeak { get; set; } - public double? IAMax { get; set; } - public double? IBMax { get; set; } - public double? ICMax { get; set; } - public double? IA2t { get; set; } - public double? IB2t { get; set; } - public double? IC2t { get; set; } - public double? InitialMW { get; set; } - public double? FinalMW { get; set; } - public int? PQViewID { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Events/EventType.cs b/Libraries/openXDA.Model/Events/EventType.cs deleted file mode 100644 index 3d5a0c19..00000000 --- a/Libraries/openXDA.Model/Events/EventType.cs +++ /dev/null @@ -1,42 +0,0 @@ -//****************************************************************************************************** -// EventType.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// 12/20/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model; - -public class EventType -{ - [PrimaryKey(true)] - public int ID { get; set; } - - public string Name { get; set; } - - public string Description { get; set; } - - public bool ShowInFilter { get; set; } - - public string Category { get; set; } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Events/Faults/Fault.cs b/Libraries/openXDA.Model/Events/Faults/Fault.cs deleted file mode 100644 index dbf8b955..00000000 --- a/Libraries/openXDA.Model/Events/Faults/Fault.cs +++ /dev/null @@ -1,137 +0,0 @@ -//****************************************************************************************************** -// Fault.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [TableName("FaultSummary")] - public class Fault - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int EventID { get; set; } - - public string Algorithm { get; set; } - - public int FaultNumber { get; set; } - - public int CalculationCycle { get; set; } - - public double Distance { get; set; } - - public int PathNumber { get; set; } - - public int LineSegmentID { get; set; } - - public double LineSegmentDistance { get; set; } - - public double CurrentMagnitude { get; set; } - - public double CurrentLag { get; set; } - - public double PrefaultCurrent { get; set; } - - public double PostfaultCurrent { get; set; } - - public double ReactanceRatio { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, Gemstone.Data.DatabaseType.SQLServer)] - public DateTime Inception { get; set; } - - public double DurationSeconds { get; set; } - - public double DurationCycles { get; set; } - - public string FaultType { get; set; } - - public bool IsSelectedAlgorithm { get; set; } - - public bool IsValid { get; set; } - - public bool IsSuppressed { get; set; } - } - - public class FaultSummary : Fault { } - - [TableName("FaultView")] - public class FaultView : Fault - { - public string MeterName { get; set; } - - public string ShortName { get; set; } - - public string LocationName { get; set; } - - public int MeterID { get; set; } - - public int LineID { get; set; } - - public string LineName { get; set; } - - public int Voltage { get; set; } - - public DateTime InceptionTime { get; set; } - - public double CurrentDistance { get; set; } - - public int RK { get; set; } - } - - [TableName("FaultView")] - public class FaultForMeter: FaultView { } - - public class FaultsDetailsByDate - { - public int thefaultid { get; set; } - - public string thesite { get; set; } - - public string locationname { get; set; } - - public int themeterid { get; set; } - - public int thelineid { get; set; } - - public int theeventid { get; set; } - - public string thelinename { get; set; } - - public int voltage { get; set; } - - public string theinceptiontime { get; set; } - - public string thefaulttype { get; set; } - - public double thecurrentdistance { get; set; } - - public int notecount { get; set; } - - public int rk { get; set; } - - [NonRecordField] - public string theeventtype { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Events/Faults/FaultCurve.cs b/Libraries/openXDA.Model/Events/Faults/FaultCurve.cs deleted file mode 100644 index 02268fa2..00000000 --- a/Libraries/openXDA.Model/Events/Faults/FaultCurve.cs +++ /dev/null @@ -1,250 +0,0 @@ -//****************************************************************************************************** -// FaultCurve.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/06/2017 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel.DataAnnotations; -using Gemstone; -using Gemstone.Data.Model; -using Ionic.Zlib; - -namespace openXDA.Model -{ - public class FaultCurve - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int EventID { get; set; } - - public int PathNumber { get; set; } - - [StringLength(200)] - public string Algorithm { get; set; } - - public byte[] Data { get; set; } - - public byte[] AngleData { get; set; } - - #region [Private Class] - private class DataPoint - { - public DateTime Time; - public double Value; - } - - #endregion - - #region [Methods] - - public void Adjust(Ticks ticks) - { - // If the blob contains the GZip header, - // move from Legacy Compression to normal Compression - if (this.Data[0] == 0x1F && this.Data[1] == 0x8B) - { - this.Data = MigrateCompression(this.Data); - } - - // If the blob contains the GZip header, - // move from Legacy Compression to normal Compression - if (this.AngleData[0] == 0x1F && this.AngleData[1] == 0x8B) - { - this.AngleData = MigrateCompression(this.AngleData); - } - - this.Data = ChangeTS(this.Data, ticks); - this.AngleData = ChangeTS(this.AngleData, ticks); - - - } - - private static byte[] ChangeTS(byte[] data, Ticks ticks) - { - data[0] = 0x1F; - data[1] = 0x8B; - - byte[] uncompressedData = GZipStream.UncompressBuffer(data); - byte[] resultData = new byte[uncompressedData.Length]; - - uncompressedData.CopyTo(resultData,0); - - int offset = 0; - - int m_samples = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - int timeValues = LittleEndian.ToInt32(uncompressedData, offset); - - int startTS = offset; - - offset += sizeof(int); - - long currentValue = LittleEndian.ToInt64(uncompressedData, offset); - - DateTime startTime = new DateTime(currentValue); - startTime = startTime.AddTicks(ticks); - - LittleEndian.CopyBytes(startTime.Ticks, resultData, startTS); - - resultData = GZipStream.CompressBuffer(resultData); - resultData[0] = 0x44; - resultData[1] = 0x33; - return resultData; - } - - private static byte[] MigrateCompression(byte[] data) - { - byte[] uncompressedData; - int offset; - DateTime[] times; - List series; - int seriesID = 0; - - uncompressedData = GZipStream.UncompressBuffer(data); - offset = 0; - - int m_samples = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - times = new DateTime[m_samples]; - - for (int i = 0; i < m_samples; i++) - { - times[i] = new DateTime(LittleEndian.ToInt64(uncompressedData, offset)); - offset += sizeof(long); - } - - series = new List(); - - while (offset < uncompressedData.Length) - { - - seriesID = LittleEndian.ToInt32(uncompressedData, offset); - offset += sizeof(int); - - - for (int i = 0; i < m_samples; i++) - { - series.Add(new DataPoint() - { - Time = times[i], - Value = LittleEndian.ToDouble(uncompressedData, offset) - }); - - offset += sizeof(double); - } - } - - var timeSeries = series.Select(dataPoint => new { Time = dataPoint.Time.Ticks, Compressed = false }).ToList(); - - for (int i = 1; i < timeSeries.Count; i++) - { - long previousTimestamp = series[i - 1].Time.Ticks; - long timestamp = timeSeries[i].Time; - long diff = timestamp - previousTimestamp; - - if (diff >= 0 && diff <= ushort.MaxValue) - timeSeries[i] = new { Time = diff, Compressed = true }; - - - } - - int timeSeriesByteLength = timeSeries.Sum(obj => obj.Compressed ? sizeof(ushort) : sizeof(int) + sizeof(long)); - int dataSeriesByteLength = sizeof(int) + (2 * sizeof(double)) + (m_samples * sizeof(ushort)); - int totalByteLength = sizeof(int) + timeSeriesByteLength + dataSeriesByteLength; - - - byte[] result = new byte[totalByteLength]; - offset = 0; - - offset += LittleEndian.CopyBytes(m_samples, result, offset); - - List uncompressedIndexes = timeSeries - .Select((obj, Index) => new { obj.Compressed, Index }) - .Where(obj => !obj.Compressed) - .Select(obj => obj.Index) - .ToList(); - - for (int i = 0; i < uncompressedIndexes.Count; i++) - { - int index = uncompressedIndexes[i]; - int nextIndex = (i + 1 < uncompressedIndexes.Count) ? uncompressedIndexes[i + 1] : timeSeries.Count; - - offset += LittleEndian.CopyBytes(nextIndex - index, result, offset); - offset += LittleEndian.CopyBytes(timeSeries[index].Time, result, offset); - - for (int j = index + 1; j < nextIndex; j++) - offset += LittleEndian.CopyBytes((ushort)timeSeries[j].Time, result, offset); - } - - const ushort NaNValue = ushort.MaxValue; - const ushort MaxCompressedValue = ushort.MaxValue - 1; - double range = series.Select(item => item.Value).Max() - series.Select(item => item.Value).Min(); - double decompressionOffset = series.Select(item => item.Value).Min(); - double decompressionScale = range / MaxCompressedValue; - double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; - - offset += LittleEndian.CopyBytes(seriesID, result, offset); - offset += LittleEndian.CopyBytes(decompressionOffset, result, offset); - offset += LittleEndian.CopyBytes(decompressionScale, result, offset); - - foreach (DataPoint dataPoint in series) - { - ushort compressedValue = (ushort)Math.Round((dataPoint.Value - decompressionOffset) * compressionScale); - - if (compressedValue == NaNValue) - compressedValue--; - - if (double.IsNaN(dataPoint.Value)) - compressedValue = NaNValue; - - offset += LittleEndian.CopyBytes(compressedValue, result, offset); - } - - byte[] returnArray = GZipStream.CompressBuffer(result); - returnArray[0] = 0x44; - returnArray[1] = 0x33; - - return returnArray; - - } - #endregion - } - - public class FaultCurveStatistic - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int FaultCurveID { get; set; } - - public int FaultNumber { get; set; } - - public double Maximum { get; set; } - - public double Minimum { get; set; } - - public double Average { get; set; } - - public double StandardDeviation { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Events/RelayPerformance.cs b/Libraries/openXDA.Model/Events/RelayPerformance.cs deleted file mode 100644 index 4950235e..00000000 --- a/Libraries/openXDA.Model/Events/RelayPerformance.cs +++ /dev/null @@ -1,63 +0,0 @@ -//****************************************************************************************************** -// RelayPerformance.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/10/2019 - Christoph Lackner -// Generated original version of source code. -// 08/20/2021 - Christoph Lackner -// Added additional Trip Coil Curve points. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone.Data; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class RelayPerformance - { - [PrimaryKey(true)] - public int ID { get; set; } - public int EventID { get; set; } - public int ChannelID { get; set; } - public double? Imax1 { get; set; } - public int? Tmax1 { get; set; } - public double? Imax2 { get; set; } - public int? TplungerLatch { get; set; } - public double IplungerLatch { get; set; } - public double? Idrop { get; set; } - public int? TiDrop { get; set; } - public int? Tend { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime? TripInitiate { get; set; } - public int? TripTime { get; set; } - public int? PickupTime { get; set; } - public double? TripTimeCurrent { get; set;} - public double? PickupTimeCurrent { get; set; } - public double? TripCoilCondition { get; set; } - public int TripCoilConditionTime { get; set; } - public int? ExtinctionTimeA { get; set; } - public int? ExtinctionTimeB { get; set; } - public int? ExtinctionTimeC { get; set; } - public double? I2CA { get; set; } - public double? I2CB { get; set; } - public double? I2CC { get; set; } - - } -} diff --git a/Libraries/openXDA.Model/Files/DataFile.cs b/Libraries/openXDA.Model/Files/DataFile.cs deleted file mode 100644 index 10b9d4b5..00000000 --- a/Libraries/openXDA.Model/Files/DataFile.cs +++ /dev/null @@ -1,93 +0,0 @@ -//****************************************************************************************************** -// DataFile.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Text; -using Gemstone.Data.Model; -using Gemstone.IO.Checksums; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - [Serializable] - public class DataFile - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int FileGroupID { get; set; } - - public string FilePath { get; set; } - - public int FilePathHash { get; set; } - - public long FileSize { get; set; } - - public DateTime CreationTime { get; set; } - - public DateTime LastWriteTime { get; set; } - - public DateTime LastAccessTime { get; set; } - - [NonRecordField] - [JsonIgnore] - public FileBlob FileBlob { get; set; } - - public static int GetHash(string filePath) - { - Encoding utf8 = new UTF8Encoding(false); - byte[] pathData = utf8.GetBytes(filePath); - return unchecked((int)Crc32.Compute(pathData, 0, pathData.Length)); - } - } - - [TableName("DataFile")] - public class DataFileDb : DataFile { } - - public static partial class TableOperationsExtensions - { - public static DataFile QueryDataFile(this TableOperations dataFileTable, string filePath) - { - int hashCode = DataFile.GetHash(filePath); - DataFile dataFile = QueryDataFile(dataFileTable, filePath, hashCode); - - if (dataFile != null) - return dataFile; - - int legacyHashCode = filePath.GetHashCode(); - dataFile = QueryDataFile(dataFileTable, filePath, legacyHashCode); - - if (dataFile == null) - return null; - - dataFile.FilePathHash = hashCode; - dataFileTable.UpdateRecord(dataFile); - return dataFile; - } - - private static DataFile QueryDataFile(TableOperations dataFileTable, string filePath, int hashCode) - { - IEnumerable dataFiles = dataFileTable.QueryRecordsWhere("FilePathHash = {0}", hashCode); - return dataFiles.FirstOrDefault(dataFile => dataFile.FilePath == filePath); - } - } -} diff --git a/Libraries/openXDA.Model/Files/FileBlob.cs b/Libraries/openXDA.Model/Files/FileBlob.cs deleted file mode 100644 index 00beeef8..00000000 --- a/Libraries/openXDA.Model/Files/FileBlob.cs +++ /dev/null @@ -1,38 +0,0 @@ -//****************************************************************************************************** -// FileBlob.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [Serializable] - public class FileBlob - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int DataFileID { get; set; } - - public byte[] Blob { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Files/FileGroup.cs b/Libraries/openXDA.Model/Files/FileGroup.cs deleted file mode 100644 index d6c50ab2..00000000 --- a/Libraries/openXDA.Model/Files/FileGroup.cs +++ /dev/null @@ -1,102 +0,0 @@ -//****************************************************************************************************** -// FileGroup.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [Serializable] - public class FileGroup - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int MeterID { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime DataStartTime { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime DataEndTime { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime ProcessingStartTime { get; set; } - - [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime ProcessingEndTime { get; set; } - - public int ProcessingVersion { get; set; } - - public int ProcessingStatus { get; set; } - - [NonRecordField] - public List DataFiles { get; set; } = new List(); - - public void AddFieldValue(AdoDataConnection connection, string name, string value, string description = null) - { - TableOperations fileGroupFieldTable = new TableOperations(connection); - FileGroupField fileGroupField = fileGroupFieldTable.GetOrAdd(name, description); - - TableOperations fileGroupFieldValueTable = new TableOperations(connection); - FileGroupFieldValue fileGroupFieldValue = new FileGroupFieldValue(); - fileGroupFieldValue.FileGroupID = ID; - fileGroupFieldValue.FileGroupFieldID = fileGroupField.ID; - fileGroupFieldValue.Value = value; - fileGroupFieldValueTable.AddNewRecord(fileGroupFieldValue); - } - - public void AddOrUpdateFieldValue(AdoDataConnection connection, string name, string value, string description = null) - { - TableOperations fileGroupFieldTable = new TableOperations(connection); - FileGroupField fileGroupField = fileGroupFieldTable.GetOrAdd(name, description); - - TableOperations fileGroupFieldValueTable = new TableOperations(connection); - RecordRestriction fileGroupRestriction = new RecordRestriction("FileGroupID = {0}", ID); - RecordRestriction fileGroupFieldRestriction = new RecordRestriction("FileGroupFieldID = {0}", fileGroupField.ID); - RecordRestriction queryRestriction = fileGroupRestriction & fileGroupFieldRestriction; - - FileGroupFieldValue fileGroupFieldValue = fileGroupFieldValueTable.QueryRecord(queryRestriction) ?? new FileGroupFieldValue() - { - FileGroupID = ID, - FileGroupFieldID = fileGroupField.ID - }; - - fileGroupFieldValue.Value = value; - fileGroupFieldValueTable.AddNewOrUpdateRecord(fileGroupFieldValue); - } - } - - /// - /// Number indicating the processing status of a file group. - /// - public enum FileGroupProcessingStatus - { - Created = 0, - Queued = 1, - Processing = 2, - Success = 3, - Failed = 4, - PartialSuccess = 5 - } -} diff --git a/Libraries/openXDA.Model/Files/FileGroupField.cs b/Libraries/openXDA.Model/Files/FileGroupField.cs deleted file mode 100644 index 31021f88..00000000 --- a/Libraries/openXDA.Model/Files/FileGroupField.cs +++ /dev/null @@ -1,61 +0,0 @@ -//****************************************************************************************************** -// FileGroupField.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/18/2019 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel.DataAnnotations; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class FileGroupField - { - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - public string Name { get; set; } - - public string Description { get; set; } - } - - public static partial class TableOperationsExtensions - { - public static FileGroupField GetOrAdd(this TableOperations fileGroupFieldTable, string name, string description = null) - { - FileGroupField fileGroupField = fileGroupFieldTable.QueryRecordWhere("Name = {0}", name); - - if ((object)fileGroupField == null) - { - fileGroupField = new FileGroupField(); - fileGroupField.Name = name; - fileGroupField.Description = description; - - fileGroupFieldTable.AddNewRecord(fileGroupField); - - fileGroupField.ID = fileGroupFieldTable.Connection.ExecuteScalar("SELECT @@IDENTITY"); - } - - return fileGroupField; - } - } -} diff --git a/Libraries/openXDA.Model/Files/FileGroupFieldValue.cs b/Libraries/openXDA.Model/Files/FileGroupFieldValue.cs deleted file mode 100644 index 55140bae..00000000 --- a/Libraries/openXDA.Model/Files/FileGroupFieldValue.cs +++ /dev/null @@ -1,39 +0,0 @@ -//****************************************************************************************************** -// FileGroupFieldValue.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/18/2019 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class FileGroupFieldValue - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int FileGroupID { get; set; } - - public int FileGroupFieldID { get; set; } - - public string Value { get; set; } - } -} diff --git a/Libraries/openXDA.Model/LazyContext.cs b/Libraries/openXDA.Model/LazyContext.cs deleted file mode 100644 index 6f5c7acc..00000000 --- a/Libraries/openXDA.Model/LazyContext.cs +++ /dev/null @@ -1,369 +0,0 @@ -//****************************************************************************************************** -// LazyContext.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/04/2017 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using Gemstone.Data; - -namespace openXDA.Model -{ - internal class LazyContext - { - #region [ Members ] - - // Fields - private Dictionary m_locations; - private Dictionary m_meters; - private Dictionary m_assetLocations; - private Dictionary m_sourceImpedances; - private Dictionary m_meterAssets; - private Dictionary m_channels; - private Dictionary m_series; - private Dictionary m_measurementTypes; - private Dictionary m_measurementCharacteristics; - private Dictionary m_phases; - private Dictionary m_seriesTypes; - - private Dictionary m_assets; - private Dictionary m_assetConnections; - - #endregion - - #region [ Constructors ] - - public LazyContext() - { - m_locations = new Dictionary(); - m_meters = new Dictionary(); - m_assets = new Dictionary(); - m_assetLocations = new Dictionary(); - m_sourceImpedances = new Dictionary(); - m_meterAssets = new Dictionary(); - m_channels = new Dictionary(); - m_series = new Dictionary(); - m_measurementTypes = new Dictionary(); - m_measurementCharacteristics = new Dictionary(); - m_phases = new Dictionary(); - m_seriesTypes = new Dictionary(); - m_assetConnections = new Dictionary(); - } - - #endregion - - #region [ Properties ] - - public Func ConnectionFactory { get; set; } - - #endregion - - #region [ Methods ] - - public Location GetLocation(int locationID) => - m_locations.TryGetValue(locationID, out Location location) - ? location - : null; - - public Location GetLocation(Location location) - { - Location cachedLocation; - - if ((object)location == null) - return null; - - if (location.ID == 0) - return location; - - if (m_locations.TryGetValue(location.ID, out cachedLocation)) - return cachedLocation; - - m_locations.Add(location.ID, location); - return location; - } - - public Meter GetMeter(int meterID) => - m_meters.TryGetValue(meterID, out Meter meter) - ? meter - : null; - - public Meter GetMeter(Meter meter) - { - Meter cachedMeter; - - if ((object)meter == null) - return null; - - if (meter.ID == 0) - return meter; - - if (m_meters.TryGetValue(meter.ID, out cachedMeter)) - return cachedMeter; - - m_meters.Add(meter.ID, meter); - return meter; - } - - public Asset GetAsset(int assetID) => - m_assets.TryGetValue(assetID, out Asset asset) - ? asset - : null; - - public Asset GetAsset(Asset asset) - { - Asset cachedAsset; - - if ((object)asset == null) - return null; - - if (asset.ID == 0) - return asset; - - if (m_assets.TryGetValue(asset.ID, out cachedAsset)) - return cachedAsset; - - m_assets.Add(asset.ID, asset); - return asset; - } - - public AssetLocation GetAssetLocation(int assetLocationID) => - m_assetLocations.TryGetValue(assetLocationID, out AssetLocation assetLocation) - ? assetLocation - : null; - - public AssetLocation GetAssetLocation(AssetLocation assetLocation) - { - AssetLocation cachedAssetLocation; - - if ((object)assetLocation == null) - return null; - - if (assetLocation.ID == 0) - return assetLocation; - - if (m_assetLocations.TryGetValue(assetLocation.ID, out cachedAssetLocation)) - return cachedAssetLocation; - - m_assetLocations.Add(assetLocation.ID, assetLocation); - return assetLocation; - } - - public SourceImpedance GetSourceImpedance(int sourceImpedanceID) => - m_sourceImpedances.TryGetValue(sourceImpedanceID, out SourceImpedance sourceImpedance) - ? sourceImpedance - : null; - - public SourceImpedance GetSourceImpedance(SourceImpedance sourceImpedance) - { - SourceImpedance cachedSourceImpedance; - - if ((object)sourceImpedance == null) - return null; - - if (sourceImpedance.ID == 0) - return sourceImpedance; - - if (m_sourceImpedances.TryGetValue(sourceImpedance.ID, out cachedSourceImpedance)) - return cachedSourceImpedance; - - m_sourceImpedances.Add(sourceImpedance.ID, sourceImpedance); - return sourceImpedance; - } - - public MeterAsset GetMeterAsset(int meterAssetID) => - m_meterAssets.TryGetValue(meterAssetID, out MeterAsset meterAsset) - ? meterAsset - : null; - - public MeterAsset GetMeterAsset(MeterAsset meterAsset) - { - MeterAsset cachedMeterAsset; - - if ((object)meterAsset == null) - return null; - - if (meterAsset.ID == 0) - return meterAsset; - - if (m_meterAssets.TryGetValue(meterAsset.ID, out cachedMeterAsset)) - return cachedMeterAsset; - - m_meterAssets.Add(meterAsset.ID, meterAsset); - return meterAsset; - } - - public Channel GetChannel(int channelID) => - m_channels.TryGetValue(channelID, out Channel channel) - ? channel - : null; - - public Channel GetChannel(Channel channel) - { - Channel cachedChannelLine; - - if ((object)channel == null) - return null; - - if (channel.ID == 0) - return channel; - - if (m_channels.TryGetValue(channel.ID, out cachedChannelLine)) - return cachedChannelLine; - - m_channels.Add(channel.ID, channel); - return channel; - } - - public Series GetSeries(int seriesID) => - m_series.TryGetValue(seriesID, out Series series) - ? series - : null; - - public Series GetSeries(Series series) - { - Series cachedSeriesLine; - - if ((object)series == null) - return null; - - if (series.ID == 0) - return series; - - if (m_series.TryGetValue(series.ID, out cachedSeriesLine)) - return cachedSeriesLine; - - m_series.Add(series.ID, series); - return series; - } - - public MeasurementType GetMeasurementType(int measurementTypeID) => - m_measurementTypes.TryGetValue(measurementTypeID, out MeasurementType measurementType) - ? measurementType - : null; - - public MeasurementType GetMeasurementType(MeasurementType measurementType) - { - MeasurementType cachedMeasurementTypeLine; - - if ((object)measurementType == null) - return null; - - if (measurementType.ID == 0) - return measurementType; - - if (m_measurementTypes.TryGetValue(measurementType.ID, out cachedMeasurementTypeLine)) - return cachedMeasurementTypeLine; - - m_measurementTypes.Add(measurementType.ID, measurementType); - return measurementType; - } - - public MeasurementCharacteristic GetMeasurementCharacteristic(int measurementCharacteristicID) => - m_measurementCharacteristics.TryGetValue(measurementCharacteristicID, out MeasurementCharacteristic measurementCharacteristic) - ? measurementCharacteristic - : null; - - public MeasurementCharacteristic GetMeasurementCharacteristic(MeasurementCharacteristic measurementCharacteristic) - { - MeasurementCharacteristic cachedMeasurementCharacteristicLine; - - if ((object)measurementCharacteristic == null) - return null; - - if (measurementCharacteristic.ID == 0) - return measurementCharacteristic; - - if (m_measurementCharacteristics.TryGetValue(measurementCharacteristic.ID, out cachedMeasurementCharacteristicLine)) - return cachedMeasurementCharacteristicLine; - - m_measurementCharacteristics.Add(measurementCharacteristic.ID, measurementCharacteristic); - return measurementCharacteristic; - } - - public Phase GetPhase(int phaseID) => - m_phases.TryGetValue(phaseID, out Phase phase) - ? phase - : null; - - public Phase GetPhase(Phase phase) - { - Phase cachedPhaseLine; - - if ((object)phase == null) - return null; - - if (phase.ID == 0) - return phase; - - if (m_phases.TryGetValue(phase.ID, out cachedPhaseLine)) - return cachedPhaseLine; - - m_phases.Add(phase.ID, phase); - return phase; - } - - public SeriesType GetSeriesType(int seriesTypeID) => - m_seriesTypes.TryGetValue(seriesTypeID, out SeriesType seriesType) - ? seriesType - : null; - - public SeriesType GetSeriesType(SeriesType seriesType) - { - SeriesType cachedSeriesTypeLine; - - if ((object)seriesType == null) - return null; - - if (seriesType.ID == 0) - return seriesType; - - if (m_seriesTypes.TryGetValue(seriesType.ID, out cachedSeriesTypeLine)) - return cachedSeriesTypeLine; - - m_seriesTypes.Add(seriesType.ID, seriesType); - return seriesType; - } - - public AssetConnection GetAssetConnection(int connectionID) => - m_assetConnections.TryGetValue(connectionID, out AssetConnection connection) - ? connection - : null; - - public AssetConnection GetAssetConnection(AssetConnection connection) - { - AssetConnection cachedConnection; - - if ((object)connection == null) - return null; - - if (connection.ID == 0) - return connection; - - if (m_assetConnections.TryGetValue(connection.ID, out cachedConnection)) - return cachedConnection; - - m_assetConnections.Add(connection.ID, connection); - return connection; - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Links/AssetConnection.cs b/Libraries/openXDA.Model/Links/AssetConnection.cs deleted file mode 100644 index dc03ab97..00000000 --- a/Libraries/openXDA.Model/Links/AssetConnection.cs +++ /dev/null @@ -1,176 +0,0 @@ -//****************************************************************************************************** -// AssetConnection.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 12/13/2019 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - [TableName("AssetRelationship")] - [PostRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - public class AssetConnection - { - #region [ Members ] - - // Fields - private Asset m_parent; - private Asset m_child; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public int AssetRelationshipTypeID { get; set; } - - public int ParentID { get; set; } - - public int ChildID { get; set; } - - [JsonIgnore] - [NonRecordField] - public Asset Parent - { - get - { - if (m_parent is null) - m_parent = LazyContext.GetAsset(ParentID); - - if (m_parent is null) - m_parent = QueryParent(); - - return m_parent; - } - set => m_parent = value; - } - - [JsonIgnore] - [NonRecordField] - public Asset Child - { - get - { - if (m_child is null) - m_child = LazyContext.GetAsset(ChildID); - - if (m_child is null) - m_child = QueryChild(); - - return m_child; - } - set => m_child = value; - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public Asset GetParent(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetTable = new TableOperations(connection); - Asset parent = assetTable.QueryRecordWhere("ID = {0}", ParentID); - return parent; - } - - public Asset GetChild(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetTable = new TableOperations(connection); - Asset child = assetTable.QueryRecordWhere("ID = {0}", ChildID); - - return child; - } - - public Asset QueryParent() - { - Asset parent; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - parent = GetParent(connection); - } - - if ((object)parent != null) - parent.LazyContext = LazyContext; - - return LazyContext.GetAsset(parent); - } - - public Asset QueryChild() - { - Asset child; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - child = GetChild(connection); - } - - if ((object)child != null) - child.LazyContext = LazyContext; - - return LazyContext.GetAsset(child); - } - - #endregion - } - - public class AssetConnectionDetail - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int AssetRelationshipTypeID { get; set; } - - public int ParentID { get; set; } - - public int ChildID { get; set; } - - public string ChildKey { get; set; } - - public string ParentKey { get; set; } - - public string AssetRelationshipType { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Links/MeterLine.cs b/Libraries/openXDA.Model/Links/MeterLine.cs deleted file mode 100644 index 4d44e704..00000000 --- a/Libraries/openXDA.Model/Links/MeterLine.cs +++ /dev/null @@ -1,174 +0,0 @@ -//****************************************************************************************************** -// MeterLine.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -// 12/13/2019 - C. Lackner -// Modified to fit new Asset Model Structure. -// -//****************************************************************************************************** - -using System; -using System.ComponentModel.DataAnnotations; -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - public class MeterAsset - { - #region [ Members ] - - // Fields - private Meter m_meter; - private Asset m_asset; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public int MeterID { get; set; } - - public int AssetID { get; set; } - - [JsonIgnore] - [NonRecordField] - public Meter Meter - { - get - { - if (m_meter is null) - m_meter = LazyContext.GetMeter(MeterID); - - if (m_meter is null) - m_meter = QueryMeter(); - - return m_meter; - } - set => m_meter = value; - } - - [JsonIgnore] - [NonRecordField] - public Asset Asset - { - get - { - if (m_asset is null) - m_asset = LazyContext.GetAsset(AssetID); - - if (m_asset is null) - m_asset = QueryAsset(); - - return m_asset; - } - set => m_asset = value; - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public Meter GetMeter(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations meterTable = new TableOperations(connection); - return meterTable.QueryRecordWhere("ID = {0}", MeterID); - } - - public Asset GetAsset(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetTable = new TableOperations(connection); - return assetTable.QueryRecordWhere("ID = {0}", AssetID); - } - - public Meter QueryMeter() - { - Meter meter; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - meter = GetMeter(connection); - } - - if ((object)meter != null) - meter.LazyContext = LazyContext; - - return LazyContext.GetMeter(meter); - } - - public Asset QueryAsset() - { - Asset asset; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - asset = GetAsset(connection); - } - - if ((object)asset != null) - asset.LazyContext = LazyContext; - - return LazyContext.GetAsset(asset); - } - - #endregion - } - - public class MeterAssetDetail - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int MeterID { get; set; } - - public int AssetID { get; set; } - - public string MeterKey { get; set; } - - public string AssetKey { get; set; } - - public string AssetName { get; set; } - - public string AssetType { get; set; } - - public string FaultDetectionLogic { get; set; } - } -} diff --git a/Libraries/openXDA.Model/Links/MeterLocationLine.cs b/Libraries/openXDA.Model/Links/MeterLocationLine.cs deleted file mode 100644 index 377ec143..00000000 --- a/Libraries/openXDA.Model/Links/MeterLocationLine.cs +++ /dev/null @@ -1,192 +0,0 @@ -//****************************************************************************************************** -// MeterLocationLine.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/19/2017 - Billy Ernest -// Generated original version of source code. -// 12/13/2019 - C. Lackner -// Update to reflect changes in Location and move from Line to Asset. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - public class AssetLocation - { - #region [ Members ] - - // Fields - private Location m_location; - private Asset m_asset; - private SourceImpedance m_sourceImpedance; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public int LocationID { get; set; } - - public int AssetID { get; set; } - - [JsonIgnore] - [NonRecordField] - public Location Location - { - get - { - if (m_location is null) - m_location = LazyContext.GetLocation(LocationID); - - if (m_location is null) - m_location = QueryLocation(); - - return m_location; - } - set => m_location = value; - } - - [JsonIgnore] - [NonRecordField] - public Asset Asset - { - get - { - if (m_asset is null) - m_asset = LazyContext.GetAsset(AssetID); - - if (m_asset is null) - m_asset = QueryAsset(); - - return m_asset; - } - set => m_asset = value; - } - - [JsonIgnore] - [NonRecordField] - public SourceImpedance SourceImpedance - { - get => m_sourceImpedance ?? (m_sourceImpedance ?? QuerySourceImpedance()); - set => m_sourceImpedance = value; - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public Location GetLocation(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations locationTable = new TableOperations(connection); - - try - { - return locationTable.QueryRecordWhere("ID = {0}", LocationID); - } - catch - { - return null; - } - } - - public Asset GetAsset(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetTable = new TableOperations(connection); - return assetTable.QueryRecordWhere("ID = {0}", AssetID); - } - - public SourceImpedance GetSourceImpedance(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations sourceImpedanceTable = new TableOperations(connection); - return sourceImpedanceTable.QueryRecordWhere("AssetLocationID = {0}", ID); - } - - private Location QueryLocation() - { - Location location; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - location = GetLocation(connection); - } - - if ((object)location != null) - location.LazyContext = LazyContext; - - return LazyContext.GetLocation(location); - } - - private Asset QueryAsset() - { - Asset asset; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - asset = GetAsset(connection); - } - - if ((object)asset != null) - asset.LazyContext = LazyContext; - - return LazyContext.GetAsset(asset); - } - - private SourceImpedance QuerySourceImpedance() - { - SourceImpedance sourceImpedance; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - sourceImpedance = GetSourceImpedance(connection); - } - - if ((object)sourceImpedance != null) - sourceImpedance.LazyContext = LazyContext; - - return LazyContext.GetSourceImpedance(sourceImpedance); - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Meters/AssetGroup.cs b/Libraries/openXDA.Model/Meters/AssetGroup.cs deleted file mode 100644 index 9848035e..00000000 --- a/Libraries/openXDA.Model/Meters/AssetGroup.cs +++ /dev/null @@ -1,60 +0,0 @@ -//****************************************************************************************************** -// AssetGroup.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace openXDA.Model -{ - public class AssetGroup - { - [Required] - [PrimaryKey(true)] - public int ID { get; set; } - - [Required] - [StringLength(100)] - [DefaultSortOrder] - public string Name { get; set; } - - [DefaultValue(true)] - public bool DisplayDashboard { get; set; } - - [DefaultValue(false)] - public bool DisplayEmail { get; set; } - } - - [TableName("AssetGroupView")] - [PostRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - public class AssetGroupView : AssetGroup - { - public int AssetGroups { get; set; } - public int Meters { get; set; } - public int Assets { get; set; } - public int Users { get; set; } - - } -} diff --git a/Libraries/openXDA.Model/Meters/Location.cs b/Libraries/openXDA.Model/Meters/Location.cs deleted file mode 100644 index 6c8515d1..00000000 --- a/Libraries/openXDA.Model/Meters/Location.cs +++ /dev/null @@ -1,509 +0,0 @@ -//****************************************************************************************************** -// Location.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// 12/13/2019 - Christoph Lackner -// Updated MeterLocation to more Generic Location. -// -//****************************************************************************************************** - -using System.ComponentModel.DataAnnotations; -using System.Data; -using System.Text.RegularExpressions; -using Gemstone.Collections.CollectionExtensions; -using Gemstone.Data; -using Gemstone.Data.DataExtensions; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - [PostRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - public class Location - { - #region [ Members ] - - // Nested Types - private delegate void ChannelConnector(int assetID, IEnumerable channels); - private delegate IEnumerable AssetConnectionLookup(int assetID); - - private class AssetConnectionDetail - { - #region [ Constructors ] - - public AssetConnectionDetail(int parentID, int childID, string jumpSQL, string passthroughSQL) - { - ParentID = parentID; - ChildID = childID; - JumpSQL = jumpSQL; - PassthroughSQL = passthroughSQL; - } - - #endregion - - #region [ Properties ] - - public int ParentID { get; } - public int ChildID { get; } - private string JumpSQL { get; } - private string PassthroughSQL { get; } - - private HashSet JumpChannels { get; } = new HashSet(); - private HashSet PassthroughChannels { get; } = new HashSet(); - private bool Populated { get; set; } - - #endregion - - #region [ Methods ] - - public void PopulateChannelSets(AdoDataConnection connection, int locationID, Func channelLookup) - { - if (Populated) - return; - - // lang=regex - const string Pattern = @"\{(?:parentid|childid|channelid)\}"; - string jumpSQL = Regex.Replace(JumpSQL, Pattern, ReplaceFormatParameter, RegexOptions.IgnoreCase); - string passthroughSQL = Regex.Replace(PassthroughSQL, Pattern, ReplaceFormatParameter, RegexOptions.IgnoreCase); - - string queryFormat = - $"SELECT " + - $" SourceChannel.ID ChannelID, " + - $" Jump.Value Jump, " + - $" Passthrough.Value Passthrough " + - $"FROM " + - $" Asset ParentAsset JOIN " + - $" Asset ChildAsset ON " + - $" ParentAsset.ID = {{0}} AND " + - $" ChildAsset.ID = {{1}} JOIN " + - $" Location ON Location.ID = {{2}} JOIN " + - $" Meter ON Meter.LocationID = Location.ID JOIN " + - $" Channel SourceChannel ON SourceChannel.MeterID = Meter.ID CROSS APPLY " + - $" ({jumpSQL}) Jump(Value) CROSS APPLY " + - $" ({passthroughSQL}) Passthrough(Value) " + - $"WHERE " + - $" Jump.Value <> 0 OR " + - $" Passthrough.Value <> 0"; - - using (DataTable table = connection.RetrieveData(queryFormat, ParentID, ChildID, locationID)) - { - foreach (DataRow row in table.AsEnumerable()) - { - int channelID = row.ConvertField("ChannelID"); - bool jump = row.ConvertField("Jump"); - bool passthrough = row.ConvertField("Passthrough"); - Channel channel = channelLookup(channelID); - if (channel is null) continue; - if (jump) JumpChannels.Add(channel); - if (passthrough) PassthroughChannels.Add(channel); - } - } - - Populated = true; - - string ReplaceFormatParameter(Match match) - { - switch (match.Value.ToLowerInvariant()) - { - case "{parentid}": return "ParentAsset.ID"; - case "{childid}": return "ChildAsset.ID"; - case "{channelid}": return "SourceChannel.ID"; - default: return match.Value; - } - } - } - - public bool CanJump(Channel channel) => - JumpChannels.Contains(channel); - - public bool CanPassThrough(Channel channel) => - PassthroughChannels.Contains(channel); - - #endregion - } - - private class TraversalContext - { - public AdoDataConnection Connection { get; } - public HashSet VisitedAssets { get; } - public AssetConnectionLookup FindAssetConnections { get; } - public ChannelConnector ConnectChannels { get; } - - public TraversalContext(AdoDataConnection connection, HashSet visitedAssets, AssetConnectionLookup findAssetConnections, ChannelConnector connectChannels) - { - Connection = connection; - VisitedAssets = visitedAssets; - FindAssetConnections = findAssetConnections; - ConnectChannels = connectChannels; - } - } - - // Fields - private List m_meters; - private List m_assetLocations; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(50)] - [Required] - [DefaultSortOrder] - public string LocationKey { get; set; } - - [StringLength(200)] - [Required] - public string Name { get; set; } - - [StringLength(200)] - public string Alias { get; set; } - - [StringLength(50)] - public string ShortName { get; set; } - - [Required] - public double Latitude { get; set; } - - [Required] - public double Longitude { get; set; } - - [StringLength(200)] - public string Description { get; set; } - - [JsonIgnore] - [NonRecordField] - public List Meters - { - get - { - return m_meters ?? (m_meters = QueryMeters()); - } - set - { - m_meters = value; - } - } - - [JsonIgnore] - [NonRecordField] - public List AssetLocations - { - get - { - return m_assetLocations ?? (m_assetLocations = QueryAssetLocations()); - } - set - { - m_assetLocations = value; - } - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get - { - return LazyContext.ConnectionFactory; - } - set - { - LazyContext.ConnectionFactory = value; - } - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public IEnumerable GetMeters(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations meterTable = new TableOperations(connection); - return meterTable.QueryRecordsWhere("MeterLocationID = {0}", ID); - } - - public IEnumerable GetAssetLocations(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetLocationTable = new TableOperations(connection); - return assetLocationTable.QueryRecordsWhere("LocationID = {0}", ID); - } - - private List QueryMeters() - { - List meters; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - meters = GetMeters(connection)? - .Select(LazyContext.GetMeter) - .ToList(); - } - - if ((object)meters != null) - { - foreach (Meter meter in meters) - { - meter.Location = this; - meter.LazyContext = LazyContext; - } - } - - return meters; - } - - private List QueryAssetLocations() - { - List assetLocations; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - assetLocations = GetAssetLocations(connection)? - .Select(LazyContext.GetAssetLocation) - .ToList(); - } - - if ((object)assetLocations != null) - { - foreach (AssetLocation assetLocation in assetLocations) - { - assetLocation.Location = this; - assetLocation.LazyContext = LazyContext; - } - } - - return assetLocations; - } - - public void ConnectAllChannels() - { - if (ConnectionFactory is null) - return; - - Dictionary> connectedChannelLookup = new Dictionary>(); - ChannelConnector connectChannels = CreateChannelConnector(connectedChannelLookup); - - using (AdoDataConnection connection = ConnectionFactory()) - { - TraverseAssetConnections(connection, connectChannels); - - TableOperations assetTable = new TableOperations(connection); - - foreach (KeyValuePair> kvp in connectedChannelLookup) - { - int assetID = kvp.Key; - HashSet connectedChannels = kvp.Value; - Asset asset = assetTable.QueryRecordWhere("ID = {0}", assetID); - asset = LazyContext.GetAsset(asset); - asset.ConnectedChannels = connectedChannels.ToList(); - asset.LazyContext = LazyContext; - } - } - - // Assign empty lists to any assets that were missed by the recursive search - foreach (Asset asset in AssetLocations.Select(al => al.Asset)) - EnsureConnectedChannels(asset); - } - - private void TraverseAssetConnections(AdoDataConnection connection, ChannelConnector connectChannels) - { - List allChannels = RetrieveAllChannels(connection).ToList(); - List allAssetConnections = RetrieveAllAssetConnections(connection).ToList(); - AssetConnectionLookup findAssetConnections = CreateAssetConnectionLookup(connection, allChannels, allAssetConnections); - - foreach (IGrouping rootChannels in allChannels.GroupBy(channel => channel.AssetID)) - { - int rootAssetID = rootChannels.Key; - - // Initialize an empty set of connected channels in case the root asset has no connected channels - connectChannels(rootAssetID, Enumerable.Empty()); - - foreach (AssetConnectionDetail assetConnection in findAssetConnections(rootAssetID)) - { - List jumpChannels = rootChannels - .Where(assetConnection.CanJump) - .ToList(); - - if (jumpChannels.Count == 0) - continue; - - int connectedAssetID = assetConnection.ChildID; - connectChannels(connectedAssetID, jumpChannels); - - HashSet visitedAssets = new HashSet() { rootAssetID }; - TraversalContext context = new TraversalContext(connection, visitedAssets, findAssetConnections, connectChannels); - TraverseAssetConnections(context, jumpChannels, connectedAssetID); - } - } - } - - private void TraverseAssetConnections(TraversalContext context, List connectedChannels, int visitedAssetID) - { - AdoDataConnection connection = context.Connection; - HashSet visitedAssets = context.VisitedAssets; - AssetConnectionLookup findAssetConnections = context.FindAssetConnections; - ChannelConnector connectChannels = context.ConnectChannels; - - visitedAssets.Add(visitedAssetID); - - foreach (AssetConnectionDetail assetConnection in findAssetConnections(visitedAssetID)) - { - int connectedAssetID = assetConnection.ChildID; - - if (visitedAssets.Contains(connectedAssetID)) - continue; - - List passthroughChannels = connectedChannels - .Where(assetConnection.CanPassThrough) - .ToList(); - - if (passthroughChannels.Count == 0) - continue; - - connectChannels(connectedAssetID, passthroughChannels); - TraverseAssetConnections(context, passthroughChannels, connectedAssetID); - } - - visitedAssets.Remove(visitedAssetID); - } - - private IEnumerable RetrieveAllChannels(AdoDataConnection connection) - { - const string QueryFormat = - "SELECT Channel.* " + - "FROM " + - " Channel JOIN " + - " Meter ON Channel.MeterID = Meter.ID " + - "WHERE Meter.LocationID = {0}"; - - TableOperations channelTable = new TableOperations(connection); - - using (DataTable table = connection.RetrieveData(QueryFormat, ID)) - { - foreach (DataRow row in table.AsEnumerable()) - { - Channel channel = channelTable.LoadRecord(row); - channel = LazyContext.GetChannel(channel); - yield return channel; - } - } - } - - private IEnumerable RetrieveAllAssetConnections(AdoDataConnection connection) - { - const string QueryFormat = - "SELECT " + - " AssetConnection.ParentID, " + - " AssetConnection.ChildID, " + - " AssetRelationshipType.JumpConnection JumpSQL, " + - " AssetRelationshipType.PassThrough PassthroughSQL " + - "FROM " + - " Location JOIN " + - " AssetConnection ON Location.ID = {0} JOIN " + - " AssetRelationshipType ON AssetConnection.AssetRelationshipTypeID = AssetRelationshipType.ID JOIN " + - " AssetLocation ParentLocation ON " + - " ParentLocation.LocationID = Location.ID AND " + - " ParentLocation.AssetID = AssetConnection.ParentID JOIN " + - " AssetLocation ChildLocation ON " + - " ChildLocation.LocationID = Location.ID AND " + - " ChildLocation.AssetID = AssetConnection.ChildID"; - - using (DataTable table = connection.RetrieveData(QueryFormat, ID)) - { - foreach (DataRow row in table.AsEnumerable()) - { - int parentID = row.ConvertField("ParentID"); - int childID = row.ConvertField("ChildID"); - string jumpSQL = row.ConvertField("JumpSQL"); - string passthroughSQL = row.ConvertField("PassthroughSQL"); - yield return new AssetConnectionDetail(parentID, childID, jumpSQL, passthroughSQL); - yield return new AssetConnectionDetail(childID, parentID, jumpSQL, passthroughSQL); - } - } - } - - private AssetConnectionLookup CreateAssetConnectionLookup(AdoDataConnection connection, List allChannels, List allAssetConnections) - { - Dictionary channelLookup = allChannels.ToDictionary(channel => channel.ID); - ILookup assetConnectionLookup = allAssetConnections.ToLookup(conn => conn.ParentID); - return findAssetConnection; - - Channel findChannel(int channelID) => - channelLookup.TryGetValue(channelID, out Channel channel) - ? channel - : null; - - IEnumerable findAssetConnection(int assetID) - { - foreach (AssetConnectionDetail assetConnection in assetConnectionLookup[assetID]) - { - assetConnection.PopulateChannelSets(connection, ID, findChannel); - yield return assetConnection; - } - } - } - - #endregion - - #region [ Static ] - - // Static Methods - private static ChannelConnector CreateChannelConnector(Dictionary> connectedChannelLookup) - { - return (assetID, channels) => - { - HashSet connectedChannels = connectedChannelLookup.GetOrAdd(assetID, _ => new HashSet()); - connectedChannels.UnionWith(channels); - }; - } - - private static void EnsureConnectedChannels(Asset asset) - { - Func connectionFactory = asset.ConnectionFactory; - - try - { - asset.ConnectionFactory = null; - - if (asset.ConnectedChannels is null) - asset.ConnectedChannels = new List(); - } - finally - { - asset.ConnectionFactory = connectionFactory; - } - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Meters/Meter.cs b/Libraries/openXDA.Model/Meters/Meter.cs deleted file mode 100644 index 47c6b517..00000000 --- a/Libraries/openXDA.Model/Meters/Meter.cs +++ /dev/null @@ -1,338 +0,0 @@ -//****************************************************************************************************** -// Meter.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -// 12/13/2019 - C. Lackner -// Updated to fit in new Asset based model structure. -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using Gemstone.ComponentModel.DataAnnotations; -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - [PostRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - public class Meter - { - #region [ Members ] - - // Fields - private Location m_location; - private List m_meterAssets; - private List m_channels; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - [Required] - [StringLength(50)] - [DefaultSortOrder] - public string AssetKey { get; set; } - - [Required] - [Label("Location")] - public int LocationID { get; set; } - - [Required] - [StringLength(200)] - public string Name { get; set; } - - [StringLength(200)] - public string Alias { get; set; } - - [StringLength(12)] - public string ShortName { get; set; } - - [Required] - [StringLength(200)] - public string Make { get; set; } - - [Required] - [StringLength(200)] - public string Model { get; set; } - - - [StringLength(200)] - public string TimeZone { get; set; } - - public string Description { get; set; } - - [JsonIgnore] - [NonRecordField] - public Location Location - { - get - { - if (m_location is null) - m_location = LazyContext.GetLocation(LocationID); - - if (m_location is null) - m_location = QueryLocation(); - - return m_location; - } - set => m_location = value; - } - - [JsonIgnore] - [NonRecordField] - public List MeterAssets - { - get => m_meterAssets ?? (m_meterAssets = QueryMeterAssets()); - set => m_meterAssets = value; - } - - [JsonIgnore] - [NonRecordField] - public List Channels - { - get => m_channels ?? (m_channels = QueryChannels()); - set => m_channels = value; - } - - public List Series - { - get - { - List channels = Channels; - - if (channels is null) - return null; - - bool IsQueryRequired() - { - var connectionFactory = ConnectionFactory; - - try - { - // Don't trigger individual queries for each channel - ConnectionFactory = null; - return channels.Any(channel => channel.Series is null); - } - finally - { - ConnectionFactory = connectionFactory; - } - } - - if (IsQueryRequired()) - return QuerySeries(); - - return channels - .SelectMany(channel => channel.Series) - .ToList(); - } - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public Location GetLocation(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations locationTable = new TableOperations(connection); - return locationTable.QueryRecordWhere("ID = {0}", LocationID); - } - - public IEnumerable GetMeterAssets(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations meterAssetTable = new TableOperations(connection); - return meterAssetTable.QueryRecordsWhere("MeterID = {0}", ID); - } - - public IEnumerable GetChannels(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations channelTable = new TableOperations(connection); - return channelTable.QueryRecordsWhere("MeterID = {0}", ID); - } - - public IEnumerable GetSeries(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations seriesTable = new TableOperations(connection); - return seriesTable.QueryRecordsWhere("ChannelID IN (SELECT ID FROM Channel WHERE MeterID = {0})", ID); - } - - public TimeZoneInfo GetTimeZoneInfo(TimeZoneInfo defaultTimeZone) - { - if (!string.IsNullOrEmpty(TimeZone)) - return TimeZoneInfo.FindSystemTimeZoneById(TimeZone); - - return defaultTimeZone; - } - - private Location QueryLocation() - { - Location location; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - location = GetLocation(connection); - } - - if ((object)location != null) - location.LazyContext = LazyContext; - - return LazyContext.GetLocation(location); - } - - private List QueryMeterAssets() - { - List meterAssets; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - meterAssets = GetMeterAssets(connection)? - .Select(LazyContext.GetMeterAsset) - .ToList(); - } - - if ((object)meterAssets != null) - { - foreach (MeterAsset meterAsset in meterAssets) - { - meterAsset.Meter = this; - meterAsset.LazyContext = LazyContext; - } - } - - return meterAssets; - } - - private List QueryChannels() - { - List channels; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - channels = GetChannels(connection)? - .Select(LazyContext.GetChannel) - .ToList(); - } - - if ((object)channels != null) - { - foreach (Channel channel in channels) - { - channel.Meter = this; - channel.LazyContext = LazyContext; - } - } - - return channels; - } - - private List QuerySeries() - { - List seriesList; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - seriesList = GetSeries(connection)? - .Select(LazyContext.GetSeries) - .ToList(); - } - - if (!(seriesList is null)) - { - ILookup seriesLookup = seriesList.ToLookup(series => series.ChannelID); - - foreach (Channel channel in Channels) - { - channel.Series = seriesLookup[channel.ID].ToList(); - - foreach (Series series in channel.Series) - { - series.Channel = channel; - series.LazyContext = LazyContext; - } - } - } - - return seriesList; - } - - #endregion - } - - public class MeterDetail : Meter - { - public new string Location { get; set; } - - public string TimeZoneLabel - { - get - { - try - { - if (TimeZone != "UTC") - return TimeZoneInfo.FindSystemTimeZoneById(TimeZone).ToString(); - } - catch - { - // Do not fail if the time zone cannot be found -- - // instead, fall through to the logic below to - // find the label for UTC - } - - return TimeZoneInfo.GetSystemTimeZones() - .Where(info => info.Id == "UTC") - .DefaultIfEmpty(TimeZoneInfo.Utc) - .First() - .ToString(); - } - } - } -} diff --git a/Libraries/openXDA.Model/Note.cs b/Libraries/openXDA.Model/Note.cs deleted file mode 100644 index dd2407cf..00000000 --- a/Libraries/openXDA.Model/Note.cs +++ /dev/null @@ -1,63 +0,0 @@ -//****************************************************************************************************** -// Note.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 01/14/2020 - Billy Ernest -// Generated original version of source code. -// 05/16/2021 - C. Lackner -// Merged notes model from SystemCenter. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; -using Gemstone.Web.APIController; -using Microsoft.AspNetCore.Mvc; - -namespace openXDA.Model; - -[TableName("Note"), UseEscapedName] -[PostRoles("Administrator, Transmission SME, PQ Data Viewer")] -[DeleteRoles("Administrator, Transmission SME")] -[PatchRoles("Administrator, Transmission SME")] -public class Notes -{ - [PrimaryKey(true)] - public int ID { get; set; } - public int NoteTypeID { get; set; } - public int NoteApplicationID { get; set; } = 2; - public int NoteTagID { get; set; } = 1; - public int ReferenceTableID { get; set; } - public string Note { get; set; } - public string UserAccount { get; set; } - - [DefaultSortOrder(false)] - public DateTime Timestamp { get; set; } -} - -public class NotesController : ModelController where T : Notes, new() -{ - public override async Task Post([FromBody] T record, CancellationToken cancellationToken) - { - using AdoDataConnection connection = CreateConnection(); - - record.UserAccount = User.Identity.Name; - - int result = new TableOperations(connection).AddNewRecord(record); - return Ok(result); - } -} diff --git a/Libraries/openXDA.Model/PQDigest/HomeScreenWidget.cs b/Libraries/openXDA.Model/PQDigest/HomeScreenWidget.cs deleted file mode 100644 index ee826388..00000000 --- a/Libraries/openXDA.Model/PQDigest/HomeScreenWidget.cs +++ /dev/null @@ -1,44 +0,0 @@ -//****************************************************************************************************** -// HomeScreenWidget.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/10/2020 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace PQDigest.Model -{ - /// - /// Defines a widget used in PQDigest Home Screen - /// - [TableName("PQDigest.HomeScreenWidget"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class HomeScreenWidget : Widget - { - #region [ Properties ] - - public int TimeFrame { get; set; } - - #endregion - } - -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/PQDigest/Widget.cs b/Libraries/openXDA.Model/PQDigest/Widget.cs deleted file mode 100644 index 6042dea0..00000000 --- a/Libraries/openXDA.Model/PQDigest/Widget.cs +++ /dev/null @@ -1,51 +0,0 @@ -//****************************************************************************************************** -// Widget.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/10/2020 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace PQDigest.Model -{ - /// - /// Defines a widget used in PQDigest - /// - [TableName("PQDigest.EventViewWidget"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class Widget - { - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public string Name { get; set; } - - public string Setting { get; set; } - - public string Type { get; set; } - - #endregion - } - -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Reports/Report.cs b/Libraries/openXDA.Model/Reports/Report.cs deleted file mode 100644 index a4b4dea7..00000000 --- a/Libraries/openXDA.Model/Reports/Report.cs +++ /dev/null @@ -1,46 +0,0 @@ -//****************************************************************************************************** -// Report.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/02/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; -using System.ComponentModel.DataAnnotations; - -namespace openXDA.Model -{ - public class Report - { - [PrimaryKey(true)] - public int ID { get; set; } - - [Required] - public int MeterID { get; set; } - [Required] - public int Month { get; set; } - [Required] - public int Year { get; set; } - [Required] - [StringLength(4)] - public string Results { get; set; } - - public byte[] PDF { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/SEBrowser/DetailedSeries.cs b/Libraries/openXDA.Model/SEBrowser/DetailedSeries.cs deleted file mode 100644 index b3280421..00000000 --- a/Libraries/openXDA.Model/SEBrowser/DetailedSeries.cs +++ /dev/null @@ -1,37 +0,0 @@ -//****************************************************************************************************** -// DetailedSeries.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/31/2025 - G. Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace SEBrowser.Model -{ - public class DetailedSeries - { - [PrimaryKey(true)] - public int ID { get; set; } - [DefaultSortOrder] - public int ChannelID { get; set; } - public string TypeName { get; set; } - public string TypeDescription { get; set; } - } -} diff --git a/Libraries/openXDA.Model/SEBrowser/TrendChannel.cs b/Libraries/openXDA.Model/SEBrowser/TrendChannel.cs deleted file mode 100644 index 6b084f6a..00000000 --- a/Libraries/openXDA.Model/SEBrowser/TrendChannel.cs +++ /dev/null @@ -1,48 +0,0 @@ -//****************************************************************************************************** -// TrendChannel.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/31/2025 - G. Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace SEBrowser.Model -{ - public class TrendChannel - { - [PrimaryKey(true)] - public string ID { get; set; } - public int ChannelID { get; set; } - [DefaultSortOrder] - public string Name { get; set; } - public string Description { get; set; } - public int AssetID { get; set; } - public string AssetKey { get; set; } - public string AssetName { get; set; } - public int MeterID { get; set; } - public string MeterKey { get; set; } - public string MeterName { get; set; } - public string MeterShortName { get; set; } - public string Phase { get; set; } - public string ChannelGroup { get; set; } - public string ChannelGroupType { get; set; } - public string Unit { get; set; } - } -} diff --git a/Libraries/openXDA.Model/SEBrowser/Widget.cs b/Libraries/openXDA.Model/SEBrowser/Widget.cs deleted file mode 100644 index dcf2b368..00000000 --- a/Libraries/openXDA.Model/SEBrowser/Widget.cs +++ /dev/null @@ -1,61 +0,0 @@ -//****************************************************************************************************** -// Widget.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/10/2020 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace SEBrowser.Model -{ - /// - /// Defines a widget used in SEBrowser - /// - [TableName("SEBrowser.Widget"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class Widget - { - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public string Name { get; set; } - - public string Setting { get; set; } - - public string Type { get; set; } - - #endregion - } - - [TableName("SEbrowser.WidgetView"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class WidgetView : Widget - { - [ParentKey(typeof (WidgetCategory))] - public int CategoryID { get; set; } - } - -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/SEBrowser/WidgetCategory.cs b/Libraries/openXDA.Model/SEBrowser/WidgetCategory.cs deleted file mode 100644 index 62faf93e..00000000 --- a/Libraries/openXDA.Model/SEBrowser/WidgetCategory.cs +++ /dev/null @@ -1,52 +0,0 @@ -//****************************************************************************************************** -// WidgetCategory.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/10/2020 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace SEBrowser.Model -{ - /// - /// Defines the categories of widgets used in SEBrowser - /// - /// - /// Will need to use in SEbrowser ans OpenSEE too. - /// - [TableName("SEBrowser.WidgetCategory"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class WidgetCategory - { - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - public string Name { get; set; } - - [DefaultSortOrder(true)] - public int OrderBy { get; set; } - - #endregion - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/SearchRestrictionHelper.cs b/Libraries/openXDA.Model/SearchRestrictionHelper.cs deleted file mode 100644 index ca740df9..00000000 --- a/Libraries/openXDA.Model/SearchRestrictionHelper.cs +++ /dev/null @@ -1,55 +0,0 @@ -//****************************************************************************************************** -// SearchRestrictionHelper.cs - Gbtc -// -// Copyright © 2026, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/07/2026 - P. Crawford -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - internal static class SearchRestrictionHelper - { - // IN / NOT IN filters carry an array SearchParameter that must expand to one placeholder per element; - // a single placeholder cannot bind an array. - internal static RecordRestriction GetSearchRestriction(string fieldExpression, IRecordFilter filter, int parameterOffset = 0) - { - if (!string.Equals(filter.Operator, "IN", StringComparison.OrdinalIgnoreCase) && - !string.Equals(filter.Operator, "NOT IN", StringComparison.OrdinalIgnoreCase)) - return new RecordRestriction($"{fieldExpression} {filter.Operator} {{{parameterOffset}}}", filter.SearchParameter); - - object[] parameters = GetSearchParameters(filter.SearchParameter).ToArray(); - string placeholders = string.Join(", ", parameters.Select((_, index) => $"{{{index + parameterOffset}}}")); - - return new RecordRestriction($"{fieldExpression} {filter.Operator} ({placeholders})", parameters); - } - - private static IEnumerable GetSearchParameters(object searchParameter) - { - if (searchParameter is string searchText) - return searchText.Trim('(', ')').Split(',').Select(value => (object)value.Trim()); - - if (searchParameter is System.Collections.IEnumerable parameters) - return parameters.Cast(); - - return [searchParameter]; - } - } -} diff --git a/Libraries/openXDA.Model/Settings/BreakerReportSettings.cs b/Libraries/openXDA.Model/Settings/BreakerReportSettings.cs deleted file mode 100644 index 2d87837b..00000000 --- a/Libraries/openXDA.Model/Settings/BreakerReportSettings.cs +++ /dev/null @@ -1,64 +0,0 @@ -//****************************************************************************************************** -// BreakerReportsSettings.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/09/2019 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Model -{ - public class BreakerReportsSettings - { - #region [ Members ] - - // Constants - public const string CategoryName = "BreakerReports"; - - #endregion - - #region [ Properties ] - - /// - /// Indicates whether operation is enabled. - /// - [Setting] - [DefaultValue(false)] - public bool Enabled { get; set; } - - /// - /// Indicates whether operation is enabled. - /// - [Setting] - [DefaultValue("0 0 2 * *")] // Runs on second day of month to ensure all data is in - public string Schedule { get; set; } - - /// - /// Comma separated list of emails to send breaker reports to. - /// - [Setting] - [DefaultValue("")] - public string EmailList { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Settings/OpenSEESetting.cs b/Libraries/openXDA.Model/Settings/OpenSEESetting.cs deleted file mode 100644 index a1e5adc9..00000000 --- a/Libraries/openXDA.Model/Settings/OpenSEESetting.cs +++ /dev/null @@ -1,33 +0,0 @@ -//****************************************************************************************************** -// OpenSEESetting.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 02/05/2026 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [TableName("OpenSEE.Setting"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class OpenSEESetting : Setting { } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Settings/PQDigestSetting.cs b/Libraries/openXDA.Model/Settings/PQDigestSetting.cs deleted file mode 100644 index 877bff81..00000000 --- a/Libraries/openXDA.Model/Settings/PQDigestSetting.cs +++ /dev/null @@ -1,33 +0,0 @@ -//****************************************************************************************************** -// PQDigestSetting.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/20/2025 - Gabriel Santos -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [TableName("PQDigest.Setting"), UseEscapedName] - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class PQDigestSetting : Setting { } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/Settings/PQReportsSettings.cs b/Libraries/openXDA.Model/Settings/PQReportsSettings.cs deleted file mode 100644 index 45f77e93..00000000 --- a/Libraries/openXDA.Model/Settings/PQReportsSettings.cs +++ /dev/null @@ -1,116 +0,0 @@ -//****************************************************************************************************** -// ReportsSettings.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/14/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.Configuration; - -namespace openXDA.Model -{ - public class PQReportsSettings - { - #region [ Members ] - - // Constants - public const string CategoryName = "PQReports"; - - #endregion - - #region [ Properties ] - - /// - /// Indicates whether operation is enabled. - /// - [Setting] - [DefaultValue(false)] - public bool Enabled { get; set; } - - /// - /// Indicates whether operation is enabled. - /// - [Setting] - [DefaultValue("0 0 2 * *")] // Runs on second day of month to ensure all data is in - public string Schedule { get; set; } - - [Setting] - [DefaultValue(99.0D)] - public double FirstFrequencyPercentile { get; set; } - - [Setting] - [DefaultValue(0.3D)] - public double FirstFrequencyDeviationLimit { get; set; } - - [Setting] - [DefaultValue(99.95D)] - public double SecondFrequencyPercentile { get; set; } - - [Setting] - [DefaultValue(0.5D)] - public double SecondFrequencyDeviationLimit { get; set; } - - [Setting] - [DefaultValue(99.0D)] - public double FirstVoltagePercentile { get; set; } - - [Setting] - [DefaultValue(3.0D)] - public double FirstVoltageDeviationLimit { get; set; } - - [Setting] - [DefaultValue(99.95D)] - public double SecondVoltagePercentile { get; set; } - - [Setting] - [DefaultValue(5.0D)] - public double SecondVoltageDeviationLimit { get; set; } - - [Setting] - [DefaultValue(98.5D)] - public double FlickerPercentile { get; set; } - - [Setting] - [DefaultValue(1.0D)] - public double FlickerHighLimit { get; set; } - - [Setting] - [DefaultValue(99.95D)] - public double VoltageUnbalancePercentile { get; set; } - - [Setting] - [DefaultValue(2.0D)] - public double VoltageUnbalanceHighLimit { get; set; } - - [Setting] - [DefaultValue(0.0D)] - public double VoltageUnbalanceLowLimit { get; set; } - - [Setting] - [DefaultValue(99.95D)] - public double VoltageTHDPercentile { get; set; } - - [Setting] - [DefaultValue(8.0D)] - public double VoltageTHDHighLimit { get; set; } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/Settings/Setting.cs b/Libraries/openXDA.Model/Settings/Setting.cs deleted file mode 100644 index b9f2a866..00000000 --- a/Libraries/openXDA.Model/Settings/Setting.cs +++ /dev/null @@ -1,84 +0,0 @@ -//****************************************************************************************************** -// Setting.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel.DataAnnotations; -using Gemstone.ComponentModel.DataAnnotations; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - [PostRoles("Administrator")] - [TableName("Setting")] - [UseEscapedName] - public class Setting - { - [PrimaryKey(true)] - public int ID { get; set; } - - public string Name { get; set; } - - public string Value { get; set; } - - public string DefaultValue { get; set; } - } - - [TableName("DashSettings")] - public class DashSettings - { - [PrimaryKey(true)] - public int ID { get; set; } - - [Required] - [StringLength(500)] - public string Name { get; set; } - - [Required] - [StringLength(500)] - public string Value { get; set; } - - [Required] - public bool Enabled { get; set; } - } - - [PrimaryLabel("Name")] - [TableName("UserDashSettings")] - public class UserDashSettings - { - [PrimaryKey(true)] - public int ID { get; set; } - - [Required] - [Label("User Account")] - public Guid UserAccountID { get; set; } - - [Required] - public string Name { get; set; } - - [Required] - public string Value { get; set; } - - public bool Enabled { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/SystemCenter/AdditionalField.cs b/Libraries/openXDA.Model/SystemCenter/AdditionalField.cs deleted file mode 100644 index adf860e8..00000000 --- a/Libraries/openXDA.Model/SystemCenter/AdditionalField.cs +++ /dev/null @@ -1,44 +0,0 @@ -//****************************************************************************************************** -// AdditionalField.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/20/2019 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace SystemCenter.Model; - -[UseEscapedName] -[PatchRoles("Administrator, Transmission SME")] -[PostRoles("Administrator, Transmission SME")] -[DeleteRoles("Administrator, Transmission SME")] -public class AdditionalField -{ - [PrimaryKey(true)] - public int ID { get; set; } - public string ParentTable { get; set; } - public string FieldName { get; set; } - public string Type { get; set; } - public int? ExternalDBTableID { get; set; } - public bool IsSecure { get; set; } - public bool IsInfo { get; set; } - public bool IsKey { get; set; } - public bool Searchable { get; set; } -} diff --git a/Libraries/openXDA.Model/SystemCenter/DetailedAsset.cs b/Libraries/openXDA.Model/SystemCenter/DetailedAsset.cs deleted file mode 100644 index 1bf65f93..00000000 --- a/Libraries/openXDA.Model/SystemCenter/DetailedAsset.cs +++ /dev/null @@ -1,93 +0,0 @@ -//****************************************************************************************************** -// DetailedAsset.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/22/2021 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using Gemstone.Data; -using Gemstone.Data.Model; -using openXDA.Model; - -namespace SystemCenter.Model -{ - public class DetailedAsset - { - [PrimaryKey(true)] - public int ID { get; set; } - - [DefaultSortOrder] - public string AssetKey { get; set; } - public string AssetName { get; set; } - public double VoltageKV { get; set; } - public string AssetType { get; set; } - public int Meters { get; set; } - public int Locations { get; set; } - - // The frontend prefixes any user-defined Additional Field filter with "AdditionalField.", so this matches that prefix, strips - // it back to the real field name, and resolves the value through the AdditionalFieldSearch view. - [SearchExtension(@"^AdditionalField\.")] - public static RecordRestriction GetAdditionalFieldRestriction(IRecordFilter filter) - { - string fieldName = filter.FieldName["AdditionalField.".Length..]; - - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction valueRestriction = SearchRestrictionHelper.GetSearchRestriction("Value", filter, 1); - - return new RecordRestriction( - $"ID IN (SELECT ParentTableID FROM AdditionalFieldSearch WHERE ParentTable IN ('Line', 'Transformer', 'Breaker', 'CapBank', 'Bus', 'Generation', 'StationAux', 'StationBattery') AND FieldName = {{0}} AND {valueRestriction.FilterExpression})", - new object[] { fieldName }.Concat(valueRestriction.Parameters).ToArray()); - } - - [SearchExtension("^Meter$")] - public static RecordRestriction GetMeterRestriction(IRecordFilter filter) - { - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction restriction = SearchRestrictionHelper.GetSearchRestriction("Meter.AssetKey", filter); - - return new RecordRestriction( - $"ID IN (SELECT MeterAsset.AssetID FROM Meter JOIN MeterAsset ON Meter.ID = MeterAsset.MeterID WHERE {restriction.FilterExpression})", - restriction.Parameters); - } - - [SearchExtension("^Location$")] - public static RecordRestriction GetLocationRestriction(IRecordFilter filter) - { - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction restriction = SearchRestrictionHelper.GetSearchRestriction("Location.LocationKey", filter); - - return new RecordRestriction( - $"ID IN (SELECT AssetLocation.AssetID FROM Location JOIN AssetLocation ON AssetLocation.LocationID = Location.ID WHERE {restriction.FilterExpression})", - restriction.Parameters); - } - } -} diff --git a/Libraries/openXDA.Model/SystemCenter/DetailedLocation.cs b/Libraries/openXDA.Model/SystemCenter/DetailedLocation.cs deleted file mode 100644 index 0a13fbc6..00000000 --- a/Libraries/openXDA.Model/SystemCenter/DetailedLocation.cs +++ /dev/null @@ -1,104 +0,0 @@ -//****************************************************************************************************** -// DetailedLocation.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/22/2021 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using Gemstone.Data; -using Gemstone.Data.Model; -using openXDA.Model; - -namespace SystemCenter.Model; - -[PostRoles("Administrator, Transmission SME")] -public class DetailedLocation -{ - [PrimaryKey(true)] - public int ID { get; set; } - - [DefaultSortOrder] - public string LocationKey { get; set; } - - public string Name { get; set; } - - public string Alias { get; set; } - - public string ShortName { get; set; } - - public double Longitude { get; set; } - - public double Latitude { get; set; } - - public string Description { get; set; } - - public int Meters { get; set; } - - public int Assets { get; set; } - - // The frontend prefixes any user-defined Additional Field filter with "AdditionalField.", so this matches that prefix, strips - // it back to the real field name, and resolves the value through the AdditionalFieldSearch view. - [SearchExtension(@"^AdditionalField\.")] - public static RecordRestriction GetAdditionalFieldRestriction(IRecordFilter filter) - { - string fieldName = filter.FieldName["AdditionalField.".Length..]; - - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction valueRestriction = SearchRestrictionHelper.GetSearchRestriction("Value", filter, 1); - - return new RecordRestriction( - $"ID IN (SELECT ParentTableID FROM AdditionalFieldSearch WHERE ParentTable = 'Location' AND FieldName = {{0}} AND {valueRestriction.FilterExpression})", - new object[] { fieldName }.Concat(valueRestriction.Parameters).ToArray()); - } - - [SearchExtension("^Meter$")] - public static RecordRestriction GetMeterRestriction(IRecordFilter filter) - { - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction restriction = SearchRestrictionHelper.GetSearchRestriction("Meter.AssetKey", filter); - - return new RecordRestriction( - $"ID IN (SELECT Meter.LocationID FROM Meter WHERE {restriction.FilterExpression})", - restriction.Parameters); - } - - [SearchExtension("^Asset$")] - public static RecordRestriction GetAssetRestriction(IRecordFilter filter) - { - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction restriction = SearchRestrictionHelper.GetSearchRestriction("Asset.AssetKey", filter); - - return new RecordRestriction( - $"ID IN (SELECT AssetLocation.LocationID FROM Asset JOIN AssetLocation ON AssetLocation.AssetID = Asset.ID WHERE {restriction.FilterExpression})", - restriction.Parameters); - } -} diff --git a/Libraries/openXDA.Model/SystemCenter/DetailedMeter.cs b/Libraries/openXDA.Model/SystemCenter/DetailedMeter.cs deleted file mode 100644 index 667d1f43..00000000 --- a/Libraries/openXDA.Model/SystemCenter/DetailedMeter.cs +++ /dev/null @@ -1,68 +0,0 @@ -//****************************************************************************************************** -// DetailedMeter.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/01/2020 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using Gemstone.Data; -using Gemstone.Data.Model; -using openXDA.Model; - -namespace SystemCenter.Model -{ - public class DetailedMeter - { - [PrimaryKey(true)] - public int ID { get; set; } - - [DefaultSortOrder] - public string AssetKey { get; set; } - - public string Name { get; set; } - - public string Location { get; set; } - - public int MappedAssets { get; set; } - - public string Make { get; set; } - - public string Model { get; set; } - - // The frontend prefixes any user-defined Additional Field filter with "AdditionalField.", so this matches that prefix, strips - // it back to the real field name, and resolves the value through the AdditionalFieldSearch view. - [SearchExtension(@"^AdditionalField\.")] - public static RecordRestriction GetAdditionalFieldRestriction(IRecordFilter filter) - { - string fieldName = filter.FieldName["AdditionalField.".Length..]; - - using AdoDataConnection connection = new(Settings.Default); - TableOperations tableOps = new(connection); - if (RecordFilter.WildCardOperators.Contains(filter.Operator, StringComparer.OrdinalIgnoreCase) && filter.SearchParameter is string stringVal) - filter.SearchParameter = stringVal.Replace("*", tableOps.WildcardChar); - - RecordRestriction valueRestriction = SearchRestrictionHelper.GetSearchRestriction("Value", filter, 1); - - return new RecordRestriction( - $"ID IN (SELECT ParentTableID FROM AdditionalFieldSearch WHERE ParentTable = 'Meter' AND FieldName = {{0}} AND {valueRestriction.FilterExpression})", - new object[] { fieldName }.Concat(valueRestriction.Parameters).ToArray()); - } - } -} diff --git a/Libraries/openXDA.Model/SystemCenter/ValueList.cs b/Libraries/openXDA.Model/SystemCenter/ValueList.cs deleted file mode 100644 index fec40b4c..00000000 --- a/Libraries/openXDA.Model/SystemCenter/ValueList.cs +++ /dev/null @@ -1,211 +0,0 @@ -//****************************************************************************************************** -// ValueList.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/10/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.ComponentModel.DataAnnotations; -using Gemstone.Data; -using Gemstone.Data.Model; -using Gemstone.Web.APIController; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json.Linq; - -namespace SystemCenter.Model; - -[TableName("ValueList"), UseEscapedName, PrimaryLabel("Text")] -public class ValueList -{ - [PrimaryKey(true)] - public int ID { get; set; } - - [ParentKey(typeof(ValueListGroup))] - public int GroupID { get; set; } - public string Value { get; set; } - public string AltValue { get; set; } - public int SortOrder { get; set; } -} - -public class ValueListController : ModelController -{ - [HttpGet, Route("Group/{groupName}")] - public IActionResult GetValueListForGroup(string groupName) - { - using AdoDataConnection connection = CreateConnection(); - return Ok(GetGroup(groupName, connection)); - } - - [HttpGet, Route("Count/{groupName}")] - public IActionResult GetValueListCountDictionary(string groupName) - { - using AdoDataConnection connection = CreateConnection(); - - JObject dictionary = []; - foreach (ValueList item in GetGroup(groupName, connection)) - dictionary.Add(item.ID.ToString(), GetCount(groupName, item.Value, connection).ToString()); - - return Ok(dictionary); - } - - [HttpPatch] - public override Task Patch([FromBody] ValueList newRecord, CancellationToken cancellationToken) - { - // Check if Value changed - bool changeVal = false; - ValueList oldRecord; - - using (AdoDataConnection connection = CreateConnection()) - { - oldRecord = new TableOperations(connection).QueryRecordWhere("ID = {0}", newRecord.ID); - changeVal = !(newRecord.Value == oldRecord.Value); - } - - if (changeVal) - { - ValueListGroup? group; - using AdoDataConnection connection = CreateConnection(); - - group = new TableOperations(connection).QueryRecordWhere("ID = {0}", newRecord.GroupID); - - // Wrapping is needed here, since C# tries to use the wrong method signature otherwise - object[] parameters = { newRecord.Value, oldRecord.Value, group?.Name ?? "" }; - // Update Additional Fields - connection.ExecuteScalar(@"UPDATE - AdditionalFieldValue - SET [Value] = {0} - WHERE - [Value] = {1} AND - ( - SELECT TOP 1 Type - FROM AdditionalField - WHERE AdditionalField.ID = AdditionalFieldValue.AdditionalFieldID - ) = {2}", parameters); - - RestrictedValueList? restriction = RestrictedValueList.List.Find((g) => g.Name == group?.Name); - - if (!(restriction?.UpdateSQL is null)) - { - object[] updateSqlParams = { newRecord.Value, oldRecord.Value }; - connection.ExecuteScalar(restriction.UpdateSQL, updateSqlParams); - } - - } - - return base.Patch(newRecord, cancellationToken); - } - - public override Task Delete(ValueList record, CancellationToken cancellationToken) - { - ValueListGroup? group; - using AdoDataConnection connection = CreateConnection(); - - group = new TableOperations(connection).QueryRecordWhere("ID = {0}", record.GroupID); - RestrictedValueList? restriction = RestrictedValueList.List.Find((g) => g.Name == group.Name); - - if (!(restriction?.CountSQL is null)) - { - int count = connection.ExecuteScalar(restriction.CountSQL, record.Value); - - if (count > 0) - throw new Exception("Cannot delete value that is still in use."); - } - - connection.ExecuteScalar(@"DELETE FROM AdditionalFieldValue - WHERE - [Value] = {0} AND - (SELECT TOP 1 Type FROM AdditionalField AF WHERE AF.ID = AdditionalFieldValue.AdditionalFieldID) = {1}", (object)record.Value, group?.Name); - - return base.Delete(record, cancellationToken); - } - - [HttpGet, Route("Count/{groupName}/{value}")] - public IActionResult GetCount(string groupName, string value) - { - using AdoDataConnection connection = CreateConnection(); - - return Ok(GetCount(groupName, value, connection)); - } - - private IEnumerable GetGroup(string groupName, AdoDataConnection connection) - { - TableOperations groupTable = new(connection); - TableOperations valueTable = new(connection); - List groupIds = groupTable.QueryRecordsWhere("Name = {0}", groupName).Select(group => group?.ID ?? -1).ToList(); - - if (groupIds.Count() == 0) - { - RestrictedValueList restriction = RestrictedValueList.List.Find((g) => g.Name == groupName); - if (!(restriction is null)) - { - groupTable.AddNewRecord( - new ValueListGroup() - { - Description = "", - Name = restriction.Name - }); - groupIds.Add(connection.ExecuteScalar("SELECT @@IDENTITY")); - - int sortOrder = 1; - foreach (object item in restriction.DefaultItems) - { - string value; - string altValue; - if (item.GetType() == typeof(Tuple)) - { - value = ((Tuple)item).Item1; - altValue = ((Tuple)item).Item2; - } - else if (item.GetType() == typeof(string)) - { - value = (string)item; - altValue = (string)item; - } - else - throw new InvalidCastException($"Could not convert object in DefaultItems of value list {restriction.Name} to either tuple or string."); - valueTable.AddNewRecord( - new ValueList() - { - GroupID = groupIds[0], - Value = value, - AltValue = altValue, - SortOrder = sortOrder - }); - sortOrder++; - } - } - else - return new List(); - } - return valueTable.QueryRecordsWhere($"GroupID in ({string.Join(",", groupIds)})").OrderBy(v => v.SortOrder); - } - - private int GetCount(string groupName, string value, AdoDataConnection connection) - { - int nAddlFields = connection.ExecuteScalar(@"SELECT COUNT(AFV.ID) FROM AdditionalFieldValue AFV WHERE - [Value] = {0} AND (SELECT TOP 1 AF.ID FROM AdditionalField AF WHERE Type = {1}) = AFV.AdditionalFieldID - ", value, groupName); - RestrictedValueList restriction = RestrictedValueList.List.Find((g) => g.Name == groupName); - int count = 0; - if (!(restriction?.CountSQL is null)) - count = connection.ExecuteScalar(restriction.CountSQL, value); - - return nAddlFields + count; - } -} diff --git a/Libraries/openXDA.Model/SystemCenter/ValueListGroup.cs b/Libraries/openXDA.Model/SystemCenter/ValueListGroup.cs deleted file mode 100644 index 000908e3..00000000 --- a/Libraries/openXDA.Model/SystemCenter/ValueListGroup.cs +++ /dev/null @@ -1,205 +0,0 @@ -//****************************************************************************************************** -// ValueListGroup.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 09/10/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.ComponentModel.DataAnnotations; -using Gemstone.Data; -using Gemstone.Data.Model; -using Gemstone.Web.APIController; -using Microsoft.AspNetCore.Mvc; -using System.ComponentModel.DataAnnotations; - -namespace SystemCenter.Model -{ - [TableName("ValueListGroup"), UseEscapedName, PrimaryLabel("Name")] - public class ValueListGroup - { - [PrimaryKey(true)] - public int ID { get; set; } - - [StringLength(200)] - public string Name { get; set; } - public string Description { get; set; } - } - - public class RestrictedValueList - { - public string Name { get; set; } - public string CountSQL { get; set; } - public string UpdateSQL { get; set; } - - /// - /// Default items in a . - /// Objects may be either or of two , - /// where the represents <, > - /// - public object[] DefaultItems { get; set; } - - public static List List = new List(){ - new RestrictedValueList() { - Name = "TimeZones", - CountSQL = @"SELECT COUNT(ID) FROM - Meter - WHERE [TimeZone] = {0}", - UpdateSQL = @"UPDATE Meter - SET [TimeZone] = {0} - WHERE - [TimeZone] = {1}", - DefaultItems = new string[] {"UTC"} - }, - new RestrictedValueList() { - Name = "Make", - CountSQL = @"SELECT COUNT(ID) FROM - Meter - WHERE [Make] = {0}", - UpdateSQL = @"UPDATE - Meter - SET [Make] = {0} - WHERE - [Make] = {1}", - DefaultItems = new string[] {"GPA"} - }, - new RestrictedValueList() { - Name = "Model", - CountSQL = @"SELECT COUNT(ID) FROM - Meter - WHERE [Model] = {0}", - UpdateSQL = @"UPDATE - Meter - SET [Model] = {0} - WHERE - [Model] = {1}", - DefaultItems = new string[] {"PQMeter"} - }, - new RestrictedValueList() { - Name = "Unit", - CountSQL = @"SELECT COUNT(ID) FROM - ChannelGroupType - WHERE - [Unit] = {0}", - UpdateSQL = @"UPDATE - ChannelGroupType - SET [Unit] = {0} - WHERE - [Unit] = {1}", - DefaultItems = new string[] {"Unknown"} - }, - new RestrictedValueList() { - Name = "Category", - CountSQL = @"SELECT COUNT(ID) FROM - LocationDrawing - WHERE - [Category] = {0}", - UpdateSQL = @"UPDATE - LocationDrawing - SET [Category] = {0} - WHERE - [Category] = {1}", - DefaultItems = new string[] {"Oneline"} - }, - new RestrictedValueList() { - Name = "SpareChannel", - DefaultItems = new string[] {"Spare Channel"} - }, - new RestrictedValueList() { - Name = "TrendLabelDefaults", - DefaultItems = new Tuple[] { - new Tuple("Channel.MeterName", "Meter Name"), - new Tuple("Channel.AssetKey", "Asset Key"), - new Tuple("Channel.Name", "Channel Label"), - new Tuple("Channel.ChannelGroup", "Channel Group Name"), - new Tuple("Series.TypeName", "Channel Series") - } - }, - new RestrictedValueList() { - Name = "TrendLabelOptions", - DefaultItems = new Tuple[] { - new Tuple("Channel.MeterName", "Meter Name"), - new Tuple("Channel.MeterShortName", "Meter Short Name"), - new Tuple("Channel.MeterKey", "Meter Asset Key"), - new Tuple("Channel.AssetName", "Asset Name"), - new Tuple("Channel.AssetKey", "Asset Key"), - new Tuple("Channel.Phase", "Phase Name"), - new Tuple("Channel.Name", "Channel Label"), - new Tuple("Channel.Description", "Channel Description"), - new Tuple("Channel.ChannelGroup", "Channel Group Name"), - new Tuple("Channel.ChannelGroupType", "Channel Group Type"), - new Tuple("Series.TypeName", "Channel Series"), - new Tuple("Channel.Unit", "Unit") - } - } - }; - } - - [Route("api/ValueListGroup")] - public class ValueListGroupController : ModelController - { - public override Task Patch([FromBody] ValueListGroup newRecord, CancellationToken cancellationToken) - { - // Check if Value changed - bool changeVal = false; - ValueListGroup oldRecord; - - using (AdoDataConnection connection = CreateConnection()) - { - oldRecord = new TableOperations(connection).QueryRecordWhere("ID = {0}", newRecord.ID); - changeVal = !(newRecord.Name == oldRecord.Name); - } - - if (changeVal) - { - using AdoDataConnection connection = CreateConnection(); - - // Wrapping is needed here, since C# tries to use the wrong method signature otherwise - object[] parameters = { newRecord.Name, oldRecord.Name }; - - // Update Additional Fields - connection.ExecuteScalar(@"UPDATE - AdditionalField - SET [Type] = {0} - WHERE - [Type] = {1}", parameters); - - } - - return base.Patch(newRecord, cancellationToken); - } - - public override Task Delete(ValueListGroup record, CancellationToken cancellationToken) - { - using (AdoDataConnection connection = CreateConnection()) - { - // Wrapping is needed here, since C# tries to use the wrong method signature otherwise - object[] parameters = { record.Name }; - - // Update Additional Fields - connection.ExecuteScalar(@"UPDATE - AdditionalField - SET [Type] = 'string' - WHERE - [Type] = {0}", parameters); - } - - return base.Delete(record, cancellationToken); - } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/TransmissionElements/Asset.cs b/Libraries/openXDA.Model/TransmissionElements/Asset.cs deleted file mode 100644 index 1d484d37..00000000 --- a/Libraries/openXDA.Model/TransmissionElements/Asset.cs +++ /dev/null @@ -1,615 +0,0 @@ -//****************************************************************************************************** -// Asset.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 12/12/2019 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.Data; -using System.Text.RegularExpressions; -using Gemstone.Collections.CollectionExtensions; -using Gemstone.Data; -using Gemstone.Data.DataExtensions; -using Gemstone.Data.Model; -using Gemstone.StringExtensions; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - [PostRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - public class Asset - { - #region [ Members ] - - // Nested Types - private delegate List ConnectedChannelLookup(int parentID, int childID, string traversalSQL); - - private class TraversalContext - { - public AdoDataConnection Connection { get; } - public int LocationID { get; } - - public ConnectedChannelLookup ConnectedChannelLookup { get; } - public HashSet VisitedAssets { get; } - public HashSet ConnectedChannels { get; } - - public TraversalContext(AdoDataConnection connection, int locationID) - { - Connection = connection; - LocationID = locationID; - - ConnectedChannelLookup = GetConnectedChannelLookup(connection, locationID); - VisitedAssets = new HashSet(); - ConnectedChannels = new HashSet(); - } - } - - // Fields - private List m_assetLocations; - private List m_meterAssets; - private List m_directChannels; - private List m_connectedChannels; - private List m_connections; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - [Required] - public double VoltageKV { get; set; } - - [Required] - [StringLength(50)] - [DefaultSortOrder] - public string AssetKey { get; set; } - - public string Description { get; set; } - - [DefaultValue("")] - public string AssetName { get; set; } - - [Required] - public int AssetTypeID {get; set; } - - public bool Spare { get; set; } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - - [JsonIgnore] - [NonRecordField] - public List AssetLocations - { - get - { - return m_assetLocations ?? (m_assetLocations = QueryAssetLocations()); - } - set - { - m_assetLocations = value; - } - } - - [JsonIgnore] - [NonRecordField] - public List MeterAssets - { - get - { - return m_meterAssets ?? (m_meterAssets = QueryMeterAssets()); - } - set - { - m_meterAssets = value; - } - } - - [JsonIgnore] - [NonRecordField] - public List DirectChannels - { - get - { - return m_directChannels ?? (m_directChannels = QueryChannels()); - } - set - { - m_directChannels = value; - } - } - - [JsonIgnore] - [NonRecordField] - public List Connections - { - get - { - return m_connections ?? (m_connections = QueryConnections()); - } - set - { - m_connections = value; - } - } - - [JsonIgnore] - [NonRecordField] - public List ConnectedChannels - { - get - { - return m_connectedChannels ?? (m_connectedChannels = QueryConnectedChannels()); - } - set - { - m_connectedChannels = value; - } - } - - [JsonIgnore] - [NonRecordField] - public List ConnectedAssets => Connections? - .SelectMany(connection => new[] { connection.Parent, connection.Child }) - .Where(asset => asset.ID != ID) - .ToList(); - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get - { - return LazyContext.ConnectionFactory; - } - set - { - LazyContext.ConnectionFactory = value; - } - } - - #endregion - - #region [ Methods ] - - public IEnumerable GetAssetLocations(AdoDataConnection connection) - { - if (connection is null) - return null; - - TableOperations assetLocationTable = new TableOperations(connection); - return assetLocationTable.QueryRecordsWhere("AssetID = {0}", ID); - } - - private List QueryAssetLocations() - { - List assetLocations; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - assetLocations = GetAssetLocations(connection)? - .Select(LazyContext.GetAssetLocation) - .ToList(); - } - - if (!(assetLocations is null)) - { - foreach (AssetLocation assetLocation in assetLocations) - { - assetLocation.Asset = this; - assetLocation.LazyContext = LazyContext; - } - } - else - return new List(); - - return assetLocations; - } - - private List QueryMeterAssets() - { - List meterAssets; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - meterAssets = GetMeterAssets(connection)? - .Select(LazyContext.GetMeterAsset) - .ToList(); - } - - if (!(meterAssets is null)) - { - foreach (MeterAsset meterAsset in meterAssets) - { - meterAsset.Asset = this; - meterAsset.LazyContext = LazyContext; - } - } - - return meterAssets; - } - - private List QueryChannels() - { - List channels; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - channels = GetChannels(connection)? - .Select(LazyContext.GetChannel) - .ToList(); - } - - if (!(channels is null)) - { - foreach (Channel channel in channels) - { - channel.Asset = this; - channel.LazyContext = LazyContext; - } - } - - return channels; - } - - private List QueryConnectedChannels() - { - List channels; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - channels = GetConnectedChannels(connection)? - .Select(LazyContext.GetChannel) - .ToList(); - } - - if (!(channels is null)) - { - foreach (Channel channel in channels) - { - channel.LazyContext = LazyContext; - } - } - - return channels; - } - - private List QueryConnections() - { - List connections; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - connections = GetConnections(connection)? - .Select(LazyContext.GetAssetConnection) - .ToList(); - } - - if (!(connections is null)) - { - foreach (AssetConnection connection in connections) - { - connection.LazyContext = LazyContext; - } - } - - return connections; - } - - public IEnumerable GetMeterAssets(AdoDataConnection connection) - { - if (connection is null) - return null; - - TableOperations meterAssetTable = new TableOperations(connection); - return meterAssetTable.QueryRecordsWhere("AssetID = {0}", ID); - } - - public IEnumerable GetChannels(AdoDataConnection connection) - { - if (connection is null) - return null; - - TableOperations channelTable = new TableOperations(connection); - return channelTable.QueryRecordsWhere("AssetID = {0}", ID); - } - - public IEnumerable GetConnections(AdoDataConnection connection) - { - if (connection is null) - return null; - - TableOperations channelTable = new TableOperations(connection); - return channelTable.QueryRecordsWhere("ParentID = {0} OR ChildID = {1}", ID, ID); - } - - // Logic for Channels across Asset Connections - public IEnumerable GetConnectedChannels(AdoDataConnection connection) - { - if (connection is null) - return null; - - return AssetLocations - .SelectMany(assetLocation => TraverseConnectedChannels(connection, assetLocation.LocationID, ID)) - .Distinct(new ChannelComparer()); - } - - private IEnumerable TraverseConnectedChannels(AdoDataConnection connection, int locationID, int assetID) - { - TraversalContext context = new TraversalContext(connection, locationID); - ConnectedChannelLookup channelLookup = context.ConnectedChannelLookup; - context.VisitedAssets.Add(assetID); - - using (DataTable connectionTable = RetrieveConnectedAssets(connection, locationID, assetID)) - { - foreach (DataRow traversalRow in connectionTable.AsEnumerable()) - { - int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); - string jumpSQL = traversalRow.ConvertField("JumpSQL"); - - IEnumerable jumpChannels = channelLookup(connectedAssetID, assetID, jumpSQL) - .Where(channel => channel.AssetID == connectedAssetID); - - context.ConnectedChannels.UnionWith(jumpChannels); - } - - foreach (DataRow traversalRow in connectionTable.AsEnumerable()) - { - int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); - string passthroughSQL = traversalRow.ConvertField("PassthroughSQL"); - - List pathChannels = channelLookup(connectedAssetID, assetID, passthroughSQL) - .Where(channel => channel.AssetID != assetID) - .Except(context.ConnectedChannels) - .ToList(); - - if (pathChannels.Count == 0) - continue; - - TraverseConnectedChannels(context, pathChannels, connectedAssetID); - } - } - - return context.ConnectedChannels; - } - - private void TraverseConnectedChannels(TraversalContext context, List pathChannels, int visitedAssetID) - { - AdoDataConnection connection = context.Connection; - ConnectedChannelLookup channelLookup = context.ConnectedChannelLookup; - int locationID = context.LocationID; - - context.VisitedAssets.Add(visitedAssetID); - - using (DataTable connectionTable = RetrieveConnectedAssets(connection, locationID, visitedAssetID)) - { - foreach (DataRow traversalRow in connectionTable.AsEnumerable()) - { - int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); - - if (context.VisitedAssets.Contains(connectedAssetID)) - continue; - - string jumpSQL = traversalRow.ConvertField("JumpSQL"); - - IEnumerable jumpChannels = channelLookup(connectedAssetID, visitedAssetID, jumpSQL) - .Where(channel => channel.AssetID == connectedAssetID) - .Intersect(pathChannels); - - context.ConnectedChannels.UnionWith(jumpChannels); - } - - HashSet filteredPathChannels = new HashSet(pathChannels); - filteredPathChannels.ExceptWith(context.ConnectedChannels); - - foreach (DataRow traversalRow in connectionTable.AsEnumerable()) - { - if (filteredPathChannels.Count == 0) - break; - - int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); - - if (context.VisitedAssets.Contains(connectedAssetID)) - continue; - - string passthroughSQL = traversalRow.ConvertField("PassthroughSQL"); - - List passthroughChannels = channelLookup(connectedAssetID, visitedAssetID, passthroughSQL) - .Intersect(filteredPathChannels) - .ToList(); - - if (passthroughChannels.Count == 0) - continue; - - int connectedCount = context.ConnectedChannels.Count; - TraverseConnectedChannels(context, passthroughChannels, connectedAssetID); - - if (context.ConnectedChannels.Count != connectedCount) - filteredPathChannels.ExceptWith(context.ConnectedChannels); - } - } - - context.VisitedAssets.Remove(visitedAssetID); - } - - private DataTable RetrieveConnectedAssets(AdoDataConnection connection, int locationID, int visitedAssetID) - { - const string TraversalQueryFormat = - "SELECT DISTINCT " + - " ConnectedAsset.ID ConnectedAssetID, " + - " AssetRelationshipType.JumpConnection JumpSQL, " + - " AssetRelationshipType.PassThrough PassthroughSQL " + - "FROM " + - " Location JOIN " + - " Asset VisitedAsset ON " + - " Location.ID = {0} AND " + - " VisitedAsset.ID = {1} JOIN " + - " AssetConnection ON VisitedAsset.ID IN (AssetConnection.ParentID, AssetConnection.ChildID) JOIN " + - " Asset ConnectedAsset ON " + - " ConnectedAsset.ID IN (AssetConnection.ParentID, AssetConnection.ChildID) AND " + - " ConnectedAsset.ID <> VisitedAsset.ID JOIN " + - " AssetRelationshipType ON AssetConnection.AssetRelationshipTypeID = AssetRelationshipType.ID JOIN " + - " AssetLocation ON " + - " AssetLocation.AssetID = ConnectedAsset.ID AND " + - " AssetLocation.LocationID = Location.ID"; - - return connection.RetrieveData(TraversalQueryFormat, locationID, visitedAssetID); - } - - // Logic to find distance between two Assets - public int DistanceToAsset(int assetID) - { - int distance = 0; - HashSet visited = new HashSet(); - List next = new List() { this }; - - while (next.Count > 0) - { - if (next.Any(n => n.ID == assetID)) - return distance; - - foreach (Asset n in next) - visited.Add(n.ID); - - next = next - .SelectMany(n => n.ConnectedAssets) - .DistinctBy(n => n.ID) - .Where(n => !visited.Contains(n.ID)) - .ToList(); - - distance++; - } - - return -1; - } - - public T QueryAs(AdoDataConnection connection = null) where T : Asset, new() - { - if (this is T typedAsset) - return typedAsset; - - if (connection is null && ConnectionFactory is null) - throw new ArgumentNullException(nameof(connection)); - - Lazy lazyConnection = new Lazy(ConnectionFactory); - - try - { - TableOperations table = new TableOperations(connection ?? lazyConnection.Value); - return table.QueryRecordWhere("ID = {0}", ID); - } - finally - { - if (lazyConnection.IsValueCreated) - lazyConnection.Value.Dispose(); - } - } - - [Obsolete("Replaced by GetChannels")] - public IEnumerable GetChannel(AdoDataConnection connection) => GetChannels(connection); - - [Obsolete("Replaced by GetConnections")] - public IEnumerable GetConnection(AdoDataConnection connection) => GetConnections(connection); - - [Obsolete("Replaced by GetConnectedChannels")] - public IEnumerable GetConnectedChannel(AdoDataConnection connection) => GetConnectedChannels(connection); - - #endregion - - #region [ Static ] - - // Static Methods - private static ConnectedChannelLookup GetConnectedChannelLookup(AdoDataConnection connection, int locationID) - { - const string ChannelQueryFormat = - "SELECT SourceChannel.* " + - "FROM " + - " Channel SourceChannel JOIN " + - " Meter ON " + - " SourceChannel.MeterID = Meter.ID AND " + - " Meter.LocationID = {{0}} JOIN " + - " Asset ParentAsset ON ParentAsset.ID = {{1}} JOIN " + - " Asset ChildAsset ON ChildAsset.ID = {{2}} CROSS APPLY " + - " ({TraversalSQL}) Traversal(Traverse) " + - "WHERE Traversal.Traverse <> 0"; - - Dictionary channelLookup = new Dictionary(); - - var connectedChannelLookup = Enumerable - .Empty>() - .ToDictionary(_ => new { ParentID = 0, ChildID = 0, TraversalSQL = "" }); - - return (parentID, childID, traversalSQL) => - { - var key = new { ParentID = parentID, ChildID = childID, TraversalSQL = traversalSQL }; - return connectedChannelLookup.GetOrAdd(key, _ => RetrieveConnectedChannels(parentID, childID, traversalSQL)); - }; - - List RetrieveConnectedChannels(int parentID, int childID, string traversalSQL) - { - TableOperations channelTable = new TableOperations(connection); - - // lang=regex - const string Pattern = @"\{(?:parentid|childid|channelid)\}"; - string replacedSQL = Regex.Replace(traversalSQL, Pattern, ReplaceFormatParameter, RegexOptions.IgnoreCase); - - string channelQuery = ChannelQueryFormat - .Interpolate(new { TraversalSQL = replacedSQL }); - - return RetrieveRows(channelQuery, locationID, parentID, childID) - .Select(channelTable.LoadRecord) - .Select(LookUpChannel) - .ToList(); - } - - Channel LookUpChannel(Channel channel) => - channelLookup.GetOrAdd(channel.ID, _ => channel); - - string ReplaceFormatParameter(Match match) - { - switch (match.Value.ToLowerInvariant()) - { - case "{parentid}": return "ParentAsset.ID"; - case "{childid}": return "ChildAsset.ID"; - case "{channelid}": return "SourceChannel.ID"; - default: return match.Value; - } - } - - IEnumerable RetrieveRows(string query, params object[] args) - { - using (DataTable table = connection.RetrieveData(query, args)) - { - foreach (DataRow row in table.Rows) - yield return row; - } - } - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/TransmissionElements/BreakerOperation.cs b/Libraries/openXDA.Model/TransmissionElements/BreakerOperation.cs deleted file mode 100644 index 3be64ebe..00000000 --- a/Libraries/openXDA.Model/TransmissionElements/BreakerOperation.cs +++ /dev/null @@ -1,107 +0,0 @@ -//****************************************************************************************************** -// BreakerOperation.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/29/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.Data; -using Gemstone.Data; -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - public class BreakerOperation - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int EventID { get; set; } - - public int PhaseID { get; set; } - - public int BreakerOperationTypeID { get; set; } - - public string BreakerNumber { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime TripCoilEnergized { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime StatusBitSet { get; set; } - - public bool StatusBitChatter { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime APhaseCleared { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime BPhaseCleared { get; set; } - - [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] - public DateTime CPhaseCleared { get; set; } - - public double BreakerTiming { get; set; } - - public double StatusTiming { get; set; } - - public double APhaseBreakerTiming { get; set; } - - public double BPhaseBreakerTiming { get; set; } - - public double CPhaseBreakerTiming { get; set; } - - public bool DcOffsetDetected { get; set; } - - public double BreakerSpeed { get; set; } - - public string UpdatedBy { get; set; } - } - - [TableName("BreakerOperation")] - public class BreakersForDay : BreakerOperation { } - - public class BreakerView - { - [PrimaryKey(true)] - public int ID { get; set; } - - public int MeterID { get; set; } - - public int EventID { get; set; } - - public string EventType { get; set; } - - public string Energized { get; set; } - - public int BreakerNumber { get; set; } - - public string LineName { get; set; } - - public string PhaseName { get; set; } - - public double Timing { get; set; } - - public int Speed { get; set; } - - public string OperationType { get; set; } - - public string UpdatedBy { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/TransmissionElements/DER.cs b/Libraries/openXDA.Model/TransmissionElements/DER.cs deleted file mode 100644 index 9a0c78f0..00000000 --- a/Libraries/openXDA.Model/TransmissionElements/DER.cs +++ /dev/null @@ -1,66 +0,0 @@ -//****************************************************************************************************** -// DER.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 10/19/2021 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - - -using Gemstone.Data; -using Gemstone.Data.Model; -using System.ComponentModel.DataAnnotations; - -namespace openXDA.Model; - -[MetadataType(typeof(Asset))] -public class DER : Asset -{ - - #region [ Properties ] - - public double FullRatedOutputCurrent { get; set; } - - public string VoltageLevel { get; set; } - - #endregion - - #region [ Methods ] - - public static DER DetailedDER(Asset asset, AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations table = new TableOperations(connection); - DER record = table.QueryRecordWhere("ID = {0}", asset.ID); - if (record == null) - return null; - - record.LazyContext = asset.LazyContext; - record.ConnectionFactory = asset.ConnectionFactory; - - return record; - } - - public static DER DetailedDER(Asset asset) - { - return DetailedDER(asset, asset.ConnectionFactory.Invoke()); - } - #endregion -} diff --git a/Libraries/openXDA.Model/TransmissionElements/SourceImpedance.cs b/Libraries/openXDA.Model/TransmissionElements/SourceImpedance.cs deleted file mode 100644 index 998f1d16..00000000 --- a/Libraries/openXDA.Model/TransmissionElements/SourceImpedance.cs +++ /dev/null @@ -1,114 +0,0 @@ -//****************************************************************************************************** -// SourceImpedance.cs - Gbtc -// -// Copyright © 2017, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/19/2017 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; -using Newtonsoft.Json; - -namespace openXDA.Model -{ - [TableName("SourceImpedance")] - [PostRoles("Administrator, Transmission SME")] - [PatchRoles("Administrator, Transmission SME")] - [DeleteRoles("Administrator, Transmission SME")] - public class SourceImpedance - { - #region [ Members ] - - // Fields - private AssetLocation m_assetLocation; - - #endregion - - #region [ Properties ] - - [PrimaryKey(true)] - public int ID { get; set; } - - [ParentKey(typeof(AssetLocation))] - public int AssetLocationID { get; set; } - - public double RSrc { get; set; } - - public double XSrc { get; set; } - - [JsonIgnore] - [NonRecordField] - public AssetLocation AssetLocation - { - get - { - if (m_assetLocation is null) - m_assetLocation = LazyContext.GetAssetLocation(AssetLocationID); - - if (m_assetLocation is null) - m_assetLocation = QueryAssetLocation(); - - return m_assetLocation; - } - set => m_assetLocation = value; - } - - [JsonIgnore] - [NonRecordField] - public Func ConnectionFactory - { - get => LazyContext.ConnectionFactory; - set => LazyContext.ConnectionFactory = value; - } - - [JsonIgnore] - [NonRecordField] - internal LazyContext LazyContext { get; set; } = new LazyContext(); - - #endregion - - #region [ Methods ] - - public AssetLocation GetAssetLocation(AdoDataConnection connection) - { - if ((object)connection == null) - return null; - - TableOperations assetLocationTable = new TableOperations(connection); - return assetLocationTable.QueryRecordWhere("ID = {0}", AssetLocationID); - } - - private AssetLocation QueryAssetLocation() - { - AssetLocation assetLocation; - - using (AdoDataConnection connection = ConnectionFactory?.Invoke()) - { - assetLocation = GetAssetLocation(connection); - } - - if ((object)assetLocation != null) - assetLocation.LazyContext = LazyContext; - - return LazyContext.GetAssetLocation(assetLocation); - } - - #endregion - } -} diff --git a/Libraries/openXDA.Model/TransmissionElements/StandardMagDurCurve.cs b/Libraries/openXDA.Model/TransmissionElements/StandardMagDurCurve.cs deleted file mode 100644 index 2be02adf..00000000 --- a/Libraries/openXDA.Model/TransmissionElements/StandardMagDurCurve.cs +++ /dev/null @@ -1,41 +0,0 @@ -//****************************************************************************************************** -// OpenXDAController.cs - Gbtc -// -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 03/04/2020 - Billy Ernest -// Generated original version of source code. -// 04/11/2022 - G. Santos -// Copied portion of source code from SEBrowser. -// -//****************************************************************************************************** - -using Gemstone.Data.Model; - -namespace openXDA.Model -{ - [PostRoles("Administrator")] - [DeleteRoles("Administrator")] - [PatchRoles("Administrator")] - public class StandardMagDurCurve - { - [PrimaryKey] - public int ID { get; set; } - public string Name { get; set; } - public string Area { get; set; } - public string Color { get; set; } - } -} \ No newline at end of file diff --git a/Libraries/openXDA.Model/openXDA.Model.csproj b/Libraries/openXDA.Model/openXDA.Model.csproj deleted file mode 100644 index d7bb48d9..00000000 --- a/Libraries/openXDA.Model/openXDA.Model.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - net9.0 - Debug;Development;Release - enable - enable - - - - - - - - - - - - - - diff --git a/Libraries/openXDA.PQI/Address.cs b/Libraries/openXDA.PQI/Address.cs deleted file mode 100644 index 37d6e91d..00000000 --- a/Libraries/openXDA.PQI/Address.cs +++ /dev/null @@ -1,81 +0,0 @@ -//****************************************************************************************************** -// Address.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 05/19/2023 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - /// - /// Summary of the . - /// - public class Address - { - /// - /// Path to query this address - /// - public string Path { get; set; } - - /// - /// Path to query the company at this address - /// - public string Company { get; set; } - - /// - /// Path to query facilities at this address - /// - public string Facilities { get; set; } - - /// - /// First line of the address (street address) - /// - public string AddressLine1 { get; set; } - - /// - /// Second line of the address (building number, etc.) - /// - public string AddressLine2 { get; set; } - - /// - /// City in which the address is located - /// - public string City { get; set; } - - /// - /// State or province in which the address is located - /// - public string StateOrProvince { get; set; } - - /// - /// Zip code/postal code - /// - public string PostalCode { get; set; } - - /// - /// Country in which the address is located - /// - public string Country { get; set; } - - /// - /// True/false to indicate whether the address is primary - /// - public bool Primary { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/AuditCurve.cs b/Libraries/openXDA.PQI/AuditCurve.cs deleted file mode 100644 index 24ba81d2..00000000 --- a/Libraries/openXDA.PQI/AuditCurve.cs +++ /dev/null @@ -1,56 +0,0 @@ -//****************************************************************************************************** -// AuditCurve.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/09/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - - public class AuditCurve: PQIModel - { - /// - /// Path to query this audit curve - /// - public string Path { get; set; } - - /// - /// Path to query the equipment this audit curve applies to - /// - public string Equipment { get; set; } - - /// - /// Path to query the areas in which the equipment resides - /// - public string Curve { get; set; } - - /// - /// Path to query the curve itself - /// - public string AuditCurves { get; set; } - - /// - /// The type of the curve (TOLERANCE, PROTECTION, PQDATA) - /// - public string CurveType { get; set; } - - - } -} diff --git a/Libraries/openXDA.PQI/Company.cs b/Libraries/openXDA.PQI/Company.cs deleted file mode 100644 index 24d0701e..00000000 --- a/Libraries/openXDA.PQI/Company.cs +++ /dev/null @@ -1,56 +0,0 @@ -//****************************************************************************************************** -// Company.cs - Gbtc -// -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 05/19/2023 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - /// - /// Summary of the . - /// - public class Company - { - /// - /// Path to query this company - /// - public string Path { get; set; } - - /// - /// Path to query the addresses for this company - /// - public string Addresses { get; set; } - - /// - /// Type of the company (EPRI, UTILITY, CONTRACTOR) - /// - public string Type { get; set; } - - /// - /// Name of the company - /// - public string Name { get; set; } - - /// - /// Industry the company is in - /// - public string Industry { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/Equipment.cs b/Libraries/openXDA.PQI/Equipment.cs deleted file mode 100644 index 5c250b6d..00000000 --- a/Libraries/openXDA.PQI/Equipment.cs +++ /dev/null @@ -1,74 +0,0 @@ -//****************************************************************************************************** -// Equipment.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/22/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - /// - /// Impacted Equipment - /// - /// - /// This does not correspond to the PQI Equipment model. For the PQI model see - /// - public class Equipment - { - /// - /// Name of the facility - /// - public string Facility { get; set; } - - /// - /// Title of the area - /// - public string Area { get; set; } - - /// - /// Title of the equipment - /// - public string SectionTitle { get; set; } - - /// - /// Rank of the equipment - /// - public int SectionRank { get; set; } - - /// - /// Model of the component - /// - public string ComponentModel { get; set; } - - /// - /// Name of the manufacturer - /// - public string Manufacturer { get; set; } - - /// - /// Name of the series - /// - public string Series { get; set; } - - /// - /// Type of component - /// - public string ComponentType { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/Facility.cs b/Libraries/openXDA.PQI/Facility.cs deleted file mode 100644 index eca4ee2d..00000000 --- a/Libraries/openXDA.PQI/Facility.cs +++ /dev/null @@ -1,56 +0,0 @@ -//****************************************************************************************************** -// Facility.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/18/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - /// - /// Summary of the . For more detailed information use - /// - public class Facility - { - /// - /// Name of the facility - /// - public string Name { get; set; } - - /// - /// Voltage at the facility - /// - public string Voltage { get; set; } - - /// - /// Utility voltage supplied to the facility - /// - public string UtilitySupplyVoltage { get; set; } - - /// - /// Path to query this Facility - /// - public string Path { get; set; } - - /// - /// Path to query the address of the facility - /// - public string Address { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/FacilityAudit.cs b/Libraries/openXDA.PQI/FacilityAudit.cs deleted file mode 100644 index cf65c696..00000000 --- a/Libraries/openXDA.PQI/FacilityAudit.cs +++ /dev/null @@ -1,53 +0,0 @@ -//****************************************************************************************************** -// FacilityAudit.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/18/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - /// - /// Summary of the . - /// - public class FacilityAudit: PQIModel - { - /// - /// Name of the Audit - /// - public string AuditName { get; set; } - - /// - /// Path to query the equipment in the facility that was audited - /// - public string Equipment { get; set; } - - /// - /// Path to query the facility that was audited. - /// - public string Facility { get; set; } - - /// - /// Path to query this FacilityAudit - /// - public string Path { get; set; } - - - } -} diff --git a/Libraries/openXDA.PQI/FacilityInfo.cs b/Libraries/openXDA.PQI/FacilityInfo.cs deleted file mode 100644 index 5c66b549..00000000 --- a/Libraries/openXDA.PQI/FacilityInfo.cs +++ /dev/null @@ -1,83 +0,0 @@ -//****************************************************************************************************** -// FacilityInfo.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/22/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - public class FacilityInfo - { - /// - /// Name of the facility - /// - public string FacilityName { get; set; } - - /// - /// Voltage at the facility - /// - public string FacilityVoltage { get; set; } - - /// - /// Utility voltage supplied to the facility - /// - public string UtilitySupplyVoltage { get; set; } - - /// - /// First line of the address (street address) - /// - public string AddressLine1 { get; set; } - - /// - /// Second line of the address (building number, etc.) - /// - public string AddressLine2 { get; set; } - - /// - /// City in which the address is located - /// - public string City { get; set; } - - /// - /// State or province in which the address is located - /// - public string StateOrProvince { get; set; } - - /// - /// Zip code/postal code - /// - public string PostalCode { get; set; } - - /// - /// Country in which the address is located. - /// - public string Country { get; set; } - - /// - /// Name of the company - /// - public string CompanyName { get; set; } - - /// - /// Industry the company is in - /// - public string Industry { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/HttpClientExtensions.cs b/Libraries/openXDA.PQI/HttpClientExtensions.cs deleted file mode 100644 index b65b8d69..00000000 --- a/Libraries/openXDA.PQI/HttpClientExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -//****************************************************************************************************** -// HttpClientExtensions.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/27/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; - -namespace openXDA.PQI -{ - internal static class HttpClientExtensions - { - public static async Task SendRequestAsync(this HttpClient client, Action configure, CancellationToken cancellationToken) - { - using (HttpRequestMessage request = new HttpRequestMessage()) - { - configure(request); - return await client.SendAsync(request, cancellationToken).ConfigureAwait(false); - } - } - } -} diff --git a/Libraries/openXDA.PQI/HttpClientProvider.cs b/Libraries/openXDA.PQI/HttpClientProvider.cs deleted file mode 100644 index a246171b..00000000 --- a/Libraries/openXDA.PQI/HttpClientProvider.cs +++ /dev/null @@ -1,37 +0,0 @@ -//****************************************************************************************************** -// HttpClientProvider.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/26/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Net.Http; - -namespace openXDA.PQI -{ - public static class HttpClientProvider - { - public static HttpClient GetClient() => - LazyInstance.Value; - - private static Lazy LazyInstance { get; } - = new Lazy(() => new HttpClient()); - } -} diff --git a/Libraries/openXDA.PQI/PQIEquipment.cs b/Libraries/openXDA.PQI/PQIEquipment.cs deleted file mode 100644 index a4187930..00000000 --- a/Libraries/openXDA.PQI/PQIEquipment.cs +++ /dev/null @@ -1,65 +0,0 @@ -//****************************************************************************************************** -// PQIEquipment.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/09/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -namespace openXDA.PQI -{ - - public class PQIEquipment: PQIModel - { - /// - /// Path to query this equipment - /// - public string Path { get; set; } - - /// - /// Path to query the facility audit in which the equipment was audited - /// - public string FacilityAudit { get; set; } - - /// - /// Path to query the areas in which the equipment resides - /// - public string Areas { get; set; } - - /// - /// Path to query the audit curves assigned to the equipment - /// - public string AuditCurves { get; set; } - - /// - /// Title of the equipment - /// - public string Title { get; set; } - - /// - /// Rank of the equipment - /// - public int Rank { get; set; } - - /// - /// Content of the equipment - /// - public string Content { get; set; } - - } -} diff --git a/Libraries/openXDA.PQI/PQIModel.cs b/Libraries/openXDA.PQI/PQIModel.cs deleted file mode 100644 index 8ca730d5..00000000 --- a/Libraries/openXDA.PQI/PQIModel.cs +++ /dev/null @@ -1,36 +0,0 @@ -//****************************************************************************************************** -// PQIModel.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/09/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; - -namespace openXDA.PQI -{ - - public interface PQIModel - { - /// - /// Path to query this Model - /// - string Path { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/PQIWSClient.cs b/Libraries/openXDA.PQI/PQIWSClient.cs deleted file mode 100644 index 9ea65937..00000000 --- a/Libraries/openXDA.PQI/PQIWSClient.cs +++ /dev/null @@ -1,325 +0,0 @@ -//****************************************************************************************************** -// PQIWSClient.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/22/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; - -namespace openXDA.PQI -{ - public class PQIWSClient - { - private const string BasePath = "PQDashboard"; - - public PQIWSClient(string baseURL, Func tokenProvider) - { - BaseURL = baseURL; - TokenProvider = tokenProvider; - } - - private string BaseURL { get; } - private Func TokenProvider { get; } - - public async Task> GetAllFacilities(CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, "Facility"); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetAllAddresses(CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, "Address"); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetAllCompanies(CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, "Company"); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task GetFacilityInfoAsync(int facilityID, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, BasePath, "GetFacilityInfo"); - string queryString = $"facilityID={facilityID}"; - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}?{queryString}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync().ConfigureAwait(false); - } - - public async Task IsImpactedAsync(int facilityID, double magnitude, double duration, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, BasePath, "IsImpacted"); - - string queryString = - $"facilityID={facilityID}&" + - $"magnitude={magnitude}&" + - $"duration={duration}"; - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}?{queryString}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync().ConfigureAwait(false); - } - - public async Task> GetImpactedEquipmentAsync(int facilityID, double magnitude, double duration, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, BasePath, "GetEquipmentImpacted"); - - string queryString = - $"facilityID={facilityID}&" + - $"magnitude={magnitude}&" + - $"duration={duration}"; - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}?{queryString}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetFacilityAudits(int facilityID, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, "FacilityAudit"); - string queryString = $"facilityID={facilityID}"; - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}?{queryString}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetAuditedEquipment(int facilityAuditID, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, "Equipment"); - string queryString = $"facilityAuditID={facilityAuditID}"; - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}?{queryString}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetAuditedEquipment(FacilityAudit facilityAudit, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, facilityAudit.Equipment); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetAuditCurve(PQIEquipment equipment, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, equipment.AuditCurves); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task> GetAuditCurve(int equipmentID, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, "AuditCurve"); - string queryString = $"equipmentID={equipmentID}"; - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}?{queryString}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - public async Task GetTestCurve(AuditCurve auditCurve, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, auditCurve.Curve); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync().ConfigureAwait(false); - } - - public async Task> GetTestCurvePoints(TestCurve testCurve, CancellationToken cancellationToken = default) - { - string url = BuildURL(BaseURL, testCurve.Points); - - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri($"{url}"); - request.Method = HttpMethod.Get; - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", TokenProvider()); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - return await response.Content.ReadAsAsync>().ConfigureAwait(false); - } - - private static string BuildURL(params string[] parts) - { - const string Separator = "/"; - string combinedPath = ""; - - foreach (string path in parts) - { - if (path == null) - throw new ArgumentNullException(nameof(parts), "One of the strings in the array is null."); - - if (path.Length == 0) - continue; - - if (combinedPath.Length == 0) - combinedPath = path; - else if (path.StartsWith(Separator) && combinedPath.EndsWith(Separator)) - combinedPath += path.Substring(Separator.Length); - else if (path.StartsWith(Separator)) - combinedPath += path; - else if (combinedPath.EndsWith(Separator)) - combinedPath += path; - else - combinedPath += Separator + path; - } - - return combinedPath; - } - - private static HttpClient HttpClient => - HttpClientProvider.GetClient(); - } -} diff --git a/Libraries/openXDA.PQI/PQIWSQueryHelper.cs b/Libraries/openXDA.PQI/PQIWSQueryHelper.cs deleted file mode 100644 index 04b2a11c..00000000 --- a/Libraries/openXDA.PQI/PQIWSQueryHelper.cs +++ /dev/null @@ -1,282 +0,0 @@ -//****************************************************************************************************** -// PQIWSQueryHelper.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/29/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Gemstone.Data; -using Gemstone.Data.DataExtensions; - -namespace openXDA.PQI -{ - public class PQIWSQueryHelper - { - private class EquipmentComparer : IEqualityComparer - { - public bool Equals(Equipment x, Equipment y) - { - if (x is null && y is null) - return true; - - if (x is null || y is null) - return false; - - object xKey = GetKey(x); - object yKey = GetKey(y); - return Equals(xKey, yKey); - } - - public int GetHashCode(Equipment equipment) - { - object key = GetKey(equipment); - return key.GetHashCode(); - } - - private object GetKey(Equipment equipment) - { - return new - { - equipment.Facility, - equipment.Area, - equipment.SectionTitle, - equipment.SectionRank, - equipment.ComponentModel, - equipment.Manufacturer, - equipment.Series, - equipment.ComponentType - }; - } - - public static EquipmentComparer Instance { get; } - = new EquipmentComparer(); - } - - private class PQIModelComparer: IEqualityComparer where T: class, PQIModel - { - public bool Equals(T x, T y) - { - if (x is null && y is null) - return true; - - if (x is null || y is null) - return false; - - object xKey = GetKey(x); - object yKey = GetKey(y); - return Equals(xKey, yKey); - } - - public int GetHashCode(T facilityAudit) - { - object key = GetKey(facilityAudit); - return key.GetHashCode(); - } - - private object GetKey(T facilityAudit) - { - return new - { - facilityAudit.Path - }; - } - - public static PQIModelComparer Instance { get; } - = new PQIModelComparer(); - } - - private const string FacilityDisturbanceQueryFormat = - @"SELECT - Customer.PQIFacilityID, - Disturbance.PerUnitMagnitude, - Disturbance.DurationSeconds - FROM Disturbance LEFT JOIN - Event ON Event.ID = Disturbance.EventID LEFT JOIN - CustomerMeter ON CustomerMeter.MeterID = Event.MeterID LEFT JOIN - Customer ON Customer.ID = CustomerMeter.CustomerID - WHERE PQIFacilityID IS NOT NULL AND EventID = {0} - UNION - SELECT - Customer.PQIFacilityID, - Disturbance.PerUnitMagnitude, - Disturbance.DurationSeconds - FROM Disturbance LEFT JOIN - Event ON Event.ID = Disturbance.EventID LEFT JOIN - CustomerAsset ON CustomerAsset.AssetID = Event.AssetID LEFT JOIN - Customer ON Customer.ID = CustomerAsset.CustomerID - WHERE PQIFacilityID IS NOT NULL AND EventID = {0}"; - - public PQIWSQueryHelper(Func connectionFactory, PQIWSClient pqiwsClient) - { - ConnectionFactory = connectionFactory; - PQIWSClient = pqiwsClient; - } - - private Func ConnectionFactory { get; } - private PQIWSClient PQIWSClient { get; } - - public async Task HasImpactedComponentsAsync(int eventID, CancellationToken cancellationToken = default) - { - async Task IsImpactedAsync(DataRow facilityDisturbance) - { - int facilityID = facilityDisturbance.ConvertField("PQIFacilityID"); - double magnitude = facilityDisturbance.ConvertField("PerUnitMagnitude"); - double duration = facilityDisturbance.ConvertField("DurationSeconds"); - return await PQIWSClient.IsImpactedAsync(facilityID, magnitude, duration, cancellationToken).ConfigureAwait(false); - } - - async Task AnyImpactedAsync(IEnumerable> isImpactedTasks) - { - foreach (Task task in isImpactedTasks) - { - if (await task.ConfigureAwait(false)) - return true; - } - - return false; - } - - using (AdoDataConnection connection = ConnectionFactory()) - using (DataTable table = connection.RetrieveData(FacilityDisturbanceQueryFormat, eventID)) - { - var tasks = table - .AsEnumerable() - .Select(IsImpactedAsync); - - return await AnyImpactedAsync(tasks).ConfigureAwait(false); - } - } - - public async Task> GetAllImpactedEquipmentAsync(int eventID, CancellationToken cancellationToken = default) - { - using (AdoDataConnection connection = ConnectionFactory()) - return await GetAllImpactedEquipmentAsync(connection, eventID, cancellationToken).ConfigureAwait(false); - } - - public async Task> GetAllImpactedEquipmentAsync(IEnumerable eventIDs, CancellationToken cancellationToken = default) - { - using (AdoDataConnection connection = ConnectionFactory()) - { - Task> _GetAllImpactedEquipmentAsync(int eventID) => - GetAllImpactedEquipmentAsync(connection, eventID, cancellationToken); - - var tasks = eventIDs.Select(_GetAllImpactedEquipmentAsync); - List[] equipmentLists = await Task.WhenAll(tasks).ConfigureAwait(false); - return Flatten(equipmentLists); - } - } - - public async Task>>> GetAllTestCurvesAsync (IEnumerable eventIDs, CancellationToken cancellationToken = default) - { - using (AdoDataConnection connection = ConnectionFactory()) - { - Task>>> _GetAllTestCurvesAsync(int eventID) => - GetAllCurvesAsync(connection, eventID, cancellationToken); - - var tasks = eventIDs.Select(_GetAllTestCurvesAsync); - List>>[] curveList = await Task.WhenAll(tasks).ConfigureAwait(false); - return curveList.SelectMany(list => list).ToList(); - } - } - - private async Task>>> GetAllCurvesAsync(AdoDataConnection connection, int eventID, CancellationToken cancellationToken = default) - { - int GetFacilityID(DataRow facilityDisturbance) - { - return facilityDisturbance.ConvertField("PQIFacilityID"); - } - - async Task> GetFacilityAudits(int facilityID) - { - return await PQIWSClient.GetFacilityAudits(facilityID, cancellationToken).ConfigureAwait(false); - } - - async Task> GetAuditedEquipment(FacilityAudit facilityAudit) - { - return await PQIWSClient.GetAuditedEquipment(facilityAudit, cancellationToken).ConfigureAwait(false); - } - - async Task> GetAuditCurves(PQIEquipment equipment) - { - return await PQIWSClient.GetAuditCurve(equipment, cancellationToken).ConfigureAwait(false); - } - - async Task GetTestCurve(AuditCurve auditCurve) - { - return await PQIWSClient.GetTestCurve(auditCurve, cancellationToken).ConfigureAwait(false); - } - - async Task>> GetTestCurvePoints(TestCurve testCurve) - { - return new Tuple>(testCurve, (await PQIWSClient.GetTestCurvePoints(testCurve, cancellationToken).ConfigureAwait(false))); - } - - using (DataTable table = connection.RetrieveData(FacilityDisturbanceQueryFormat, eventID)) - { - int[] facilityIDs = table - .AsEnumerable() - .Select(GetFacilityID) - .ToArray(); - - List[] facilityAudits = await Task.WhenAll(facilityIDs.Distinct().Select(GetFacilityAudits)).ConfigureAwait(false); - List[] auditedEquipment = await Task.WhenAll(Flatten(facilityAudits).Select(GetAuditedEquipment)).ConfigureAwait(false); - List[] auditCurves = await Task.WhenAll(Flatten(auditedEquipment).Select(GetAuditCurves)).ConfigureAwait(false); - TestCurve[] testCurves = await Task.WhenAll(Flatten(auditCurves).Select(GetTestCurve)).ConfigureAwait(false); - - return (await Task.WhenAll(testCurves.Distinct().Select(GetTestCurvePoints)).ConfigureAwait(false)).ToList(); - } - } - private async Task> GetAllImpactedEquipmentAsync(AdoDataConnection connection, int eventID, CancellationToken cancellationToken) - { - async Task> GetImpactedEquipmentAsync(DataRow facilityDisturbance) - { - int facilityID = facilityDisturbance.ConvertField("PQIFacilityID"); - double magnitude = facilityDisturbance.ConvertField("PerUnitMagnitude"); - double duration = facilityDisturbance.ConvertField("DurationSeconds"); - return await PQIWSClient.GetImpactedEquipmentAsync(facilityID, magnitude, duration, cancellationToken).ConfigureAwait(false); - } - - using (DataTable table = connection.RetrieveData(FacilityDisturbanceQueryFormat, eventID)) - { - var tasks = table - .AsEnumerable() - .Select(GetImpactedEquipmentAsync); - - List[] equipmentLists = await Task.WhenAll(tasks).ConfigureAwait(false); - return Flatten(equipmentLists); - } - } - - private List Flatten(IEnumerable> equipmentLists) => equipmentLists - .SelectMany(list => list) - .Distinct(EquipmentComparer.Instance) - .ToList(); - - private List Flatten(IEnumerable> facilityAuditLists) where T: class,PQIModel => facilityAuditLists - .SelectMany(list => list) - .Distinct(PQIModelComparer.Instance) - .ToList(); - } -} diff --git a/Libraries/openXDA.PQI/PingClient.cs b/Libraries/openXDA.PQI/PingClient.cs deleted file mode 100644 index 51875a0c..00000000 --- a/Libraries/openXDA.PQI/PingClient.cs +++ /dev/null @@ -1,97 +0,0 @@ -//****************************************************************************************************** -// PingClient.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/26/2021 - Stephen C. Wills -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; - -namespace openXDA.PQI -{ - public class PingClient - { - public PingClient(string tokenURL) - { - TokenURL = tokenURL; - IsExpiredFunc = () => true; - } - - private string TokenURL { get; } - private Func IsExpiredFunc { get; set; } - - public string AccessToken { get; private set; } - public bool IsExpired => IsExpiredFunc(); - - /// - /// Exchange credentials for a new access token. - /// - /// The client application's credentials. - /// The user's credentials. - /// Token for cancelling the exchange. - /// The task that represents the exchange of credentials for an access token. - public async Task ExchangeAsync(NetworkCredential clientCredential, NetworkCredential userCredential, CancellationToken cancellationToken = default) - { - void ConfigureRequest(HttpRequestMessage request) - { - request.RequestUri = new Uri(TokenURL); - request.Method = HttpMethod.Post; - - string clientID = clientCredential.UserName; - string clientSecret = clientCredential.Password; - string credentials = $"{clientID}:{clientSecret}"; - byte[] encodedCredentials = Encoding.UTF8.GetBytes(credentials); - string credentials64 = Convert.ToBase64String(encodedCredentials); - request.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials64); - - List> body = new List>(); - body.Add(new KeyValuePair("username", userCredential.UserName)); - body.Add(new KeyValuePair("password", userCredential.Password)); - body.Add(new KeyValuePair("grant_type", "password")); - request.Content = new FormUrlEncodedContent(body); - - MediaTypeWithQualityHeaderValue acceptHeader = new MediaTypeWithQualityHeaderValue("application/json"); - request.Headers.Accept.Add(acceptHeader); - } - - using (HttpResponseMessage response = await HttpClient.SendRequestAsync(ConfigureRequest, cancellationToken).ConfigureAwait(false)) - { - response.EnsureSuccessStatusCode(); - - Stopwatch stopwatch = Stopwatch.StartNew(); - JObject content = await response.Content.ReadAsAsync(cancellationToken).ConfigureAwait(false); - int expiration = content["expires_in"].Value(); - AccessToken = content["access_token"].Value(); - IsExpiredFunc = () => stopwatch.Elapsed.TotalSeconds > expiration; - } - } - - private static HttpClient HttpClient => - HttpClientProvider.GetClient(); - } -} diff --git a/Libraries/openXDA.PQI/Properties/AssemblyInfo.cs b/Libraries/openXDA.PQI/Properties/AssemblyInfo.cs deleted file mode 100644 index 1d163786..00000000 --- a/Libraries/openXDA.PQI/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("openXDA.PQI")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("openXDA.PQI")] -[assembly: AssemblyCopyright("Copyright © 2021")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("3dec81f1-9a02-4bbf-8325-f332ac63393e")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyFileVersion("3.0.5.93")] diff --git a/Libraries/openXDA.PQI/TestCurve.cs b/Libraries/openXDA.PQI/TestCurve.cs deleted file mode 100644 index 20b900d7..00000000 --- a/Libraries/openXDA.PQI/TestCurve.cs +++ /dev/null @@ -1,96 +0,0 @@ -//****************************************************************************************************** -// TestCurve.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/09/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; - -namespace openXDA.PQI -{ - - public class TestCurve - { - /// - /// Path to query this test curve (aka ride-through curve) - /// - public string Path { get; set; } - - /// - /// Path to query the component this curve was assigned to - /// - public string Component { get; set; } - - /// - /// Path to query the audit curves associated with this test curve - /// - public string AuditCurves { get; set; } - - /// - /// Path to query the points in the curve - /// - public string Points { get; set; } - - /// - /// Name of the curve - /// - public string Name { get; set; } - - /// - /// Description of the curve - /// - public string Description { get; set; } - - /// - /// Entity - /// - public string Entity { get; set; } - - /// - /// Location - /// - public string Location { get; set; } - - /// - /// Investigator - /// - public string Investigator { get; set; } - - /// - /// Date - /// - public DateTime? Date { get; set; } - - /// - /// Additional notes about the curve - /// - public string Notes { get; set; } - - /// - /// Frequency (Hz) of the voltage - /// - public double? Frequency { get; set; } - - /// - /// Voltage level (in volts) during normal conditions - /// - public double? NominalVoltage { get; set; } - } -} diff --git a/Libraries/openXDA.PQI/TestCurvePoint.cs b/Libraries/openXDA.PQI/TestCurvePoint.cs deleted file mode 100644 index bad0c129..00000000 --- a/Libraries/openXDA.PQI/TestCurvePoint.cs +++ /dev/null @@ -1,53 +0,0 @@ -//****************************************************************************************************** -// TestCurvePoint.cs - Gbtc -// -// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 08/09/2022 - C. Lackner -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; - -namespace openXDA.PQI -{ - - public class TestCurvePoint - { - /// - /// Path to query this test curve point - /// - public string Path { get; set; } - - /// - /// Path to query the test curve this point belongs to - /// - public string TestCurve { get; set; } - - /// - /// X-value (duration) on a mag/dur chart - /// - public double X { get; set; } - - /// - /// Y-value(magnitude) on a mag/dur chart - /// - public double Y { get; set; } - - - } -} diff --git a/Libraries/openXDA.PQI/openXDA.PQI.csproj b/Libraries/openXDA.PQI/openXDA.PQI.csproj deleted file mode 100644 index f24661b6..00000000 --- a/Libraries/openXDA.PQI/openXDA.PQI.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - net9.0 - Debug;Development;Release - openXDA.PQI - openXDA.PQI - false - - - - - - - - - true - full - false - ..\..\..\Build\Output\Debug\Libraries\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\..\Build\Output\Release\Libraries\ - TRACE - prompt - 4 - - \ No newline at end of file diff --git a/Libraries/openXDA.Reports/AllBreakersReport.cs b/Libraries/openXDA.Reports/AllBreakersReport.cs deleted file mode 100644 index c248f090..00000000 --- a/Libraries/openXDA.Reports/AllBreakersReport.cs +++ /dev/null @@ -1,411 +0,0 @@ -//****************************************************************************************************** -// AllBreakersReport.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/05/2019 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; -using Gemstone.Configuration; -using Gemstone.Data; -using log4net; -using Root.Reports; - -namespace openXDA.Reports -{ - public class AllBreakersReport : Report - { - #region [ Members ] - - // Nested Types - public class Point - { - public DateTime Time; - public double Value; - } - - // Constants - private const double PageMarginMillimeters = 12.7D; // 1-inch margin - private const double PageHeightMillimeters = 8.5D * 25.4D; // 8.5 inch height (landscape) - private const double PageWidthMillimeters = 11.0D * 25.4D; // 11 inch width (landscape) - private const double FooterHeightMillimeters = (10.0D / 72.0D) * 25.4D; - private const double SpacingMillimeters = 6.0D; - - private const string TitleText = "All Breakers Report"; - - private const string Query = @" - SELECT - MAX(BreakerOperation.TripCoilEnergized) as LastOperationDate, - BreakerOperation.BreakerNumber, - COUNT(BreakerOperation.ID) as Total, - MaximoBreaker.AssetNum, - Asset.AssetName, - -- last timing info - (SELECT Name from Phase WHERE ID = (SELECT TOP 1 PhaseID FROM BreakerOperation as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized)) as LastPhase, - (SELECT TOP 1 BreakerTiming FROM BreakerOperation as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized) as LastWaveformTiming, - (SELECT TOP 1 StatusTiming FROM BreakerOperation as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized) as LastStatusTiming, - MaximoBreaker.BreakerSpeed as MfrSpeed, - (SELECT Name from BreakerOperationType WHERE ID = (SELECT TOP 1 BreakerOperationTypeID FROM BreakerOperation as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized)) as OperationTiming, - (SELECT TOP 1 CASE WHEN StatusTiming < BreakerTiming THEN 'Status' ELSE 'Waveform' END FROM BreakerOperation as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized) as LastMethod, - -- last slow - COUNT(LateBreakerOperation.ID) as TotalLateOperation, - MAX(LateBreakerOperation.TripCoilEnergized) as LastLateOperation, - -- mfr info - MaximoBreaker.Manufacturer, - MaximoBreaker.SerialNum, - MaximoBreaker.MfrYear, - MaximoBreaker.ModelNum, - MaximoBreaker.InterruptCurrentRating, - MaximoBreaker.ContinuousAmpRating - FROM - BreakerOperation JOIN - BreakerOperationType ON BreakerOperation.BreakerOperationTypeID = BreakerOperationType.ID LEFT OUTER JOIN - BreakerOperation LateBreakerOperation ON - BreakerOperation.ID = LateBreakerOperation.ID AND - BreakerOperationType.Name = 'Late' OUTER APPLY - ( - SELECT TOP 1 Asset.* - FROM - Asset JOIN - Channel ON Channel.AssetID = Asset.ID JOIN - BreakerChannel ON BreakerChannel.ChannelID = Channel.ID - WHERE BreakerChannel.BreakerNumber = BreakerOperation.BreakerNumber - ORDER BY Asset.ID - ) Asset LEFT OUTER JOIN - MaximoBreaker ON BreakerOperation.BreakerNumber = SUBSTRING(MaximoBreaker.BreakerNum, PATINDEX('%[^0]%', MaximoBreaker.BreakerNum + '.'), LEN(MaximoBreaker.BreakerNum)) - WHERE CAST(BreakerOperation.TripCoilEnergized AS DATE) BETWEEN {0} AND {1} - GROUP BY - BreakerOperation.BreakerNumber, - MaximoBreaker.AssetNum, - Asset.AssetName, - MaximoBreaker.Manufacturer, - MaximoBreaker.SerialNum, - MaximoBreaker.MfrYear, - MaximoBreaker.ModelNum, - MaximoBreaker.InterruptCurrentRating, - MaximoBreaker.ContinuousAmpRating, - MaximoBreaker.BreakerSpeed - ORDER BY - LastOperationDate - "; - - private const string TestQuery = @" - SELECT - MAX(BreakerOperation.TripCoilEnergized) as LastOperationDate, - BreakerOperation.BreakerNumber, - COUNT(BreakerOperation.ID) as Total, - MaximoBreaker.[Breaker Number] as AssetNum, - MaximoBreaker.[Line Name] as LineName, - -- last timing info - (SELECT Name from Phase WHERE ID = (SELECT TOP 1 PhaseID FROM GTCBreakerOperationsTable as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized)) as LastPhase, - (SELECT TOP 1 BreakerTiming FROM GTCBreakerOperationsTable as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized) as LastWaveformTiming, - (SELECT TOP 1 StatusTiming FROM GTCBreakerOperationsTable as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized) as LastStatusTiming, - MaximoBreaker.[Breaker Mfr Speed] as MfrSpeed, - (SELECT Name from BreakerOperationType WHERE ID = (SELECT TOP 1 BreakerOperationTypeID FROM GTCBreakerOperationsTable as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized)) as OperationTiming, - (SELECT TOP 1 CASE WHEN StatusTiming < BreakerTiming THEN 'Status' ELSE 'Waveform' END FROM GTCBreakerOperationsTable as bo WHERE bo.BreakerNumber = BreakerOperation.BreakerNumber ORDER BY TripCoilEnergized) as LastMethod, - -- last slow - COUNT(BOLate.ID) as TotalLateOperation, - MAX(BOLate.TripCoilEnergized) as LastLateOperation, - -- mfr info - MaximoBreaker.Manufacturer, - MaximoBreaker.[Serial Number] as SerialNum, - MaximoBreaker.[Mfr Year] as MfrYear, - MaximoBreaker.[Model Number] as ModelNum, - MaximoBreaker.[Interrupt current Rating (A)] as InterruptCurrentRating, - MaximoBreaker.[ Continuous Amp Rating (A)] as ContinuousAmpRating - FROM - GTCBreakerOperationsTable as BreakerOperation LEFT JOIN - GTCBreakerOperationsTable as BOLate ON BreakerOperation.ID = BOLate.ID AND BOLate.BreakerOperationTypeID = (SELECT ID FROM BreakerOperationType WHERE Name = 'Late') LEFT JOIN - MaximoBreakerInfo as MaximoBreaker ON BreakerOperation.BreakerNumber = SUBSTRING(MaximoBreaker.[Breaker Number], PATINDEX('%[^0]%', MaximoBreaker.[Breaker Number] + '.'), LEN(MaximoBreaker.[Breaker Number])) - WHERE - Cast(BreakerOperation.TripCoilEnergized as Date) BETWEEN {0} AND {1} - GROUP BY - BreakerOperation.BreakerNumber, - MaximoBreaker.[Breaker Number], - MaximoBreaker.[Line Name], - MaximoBreaker.Manufacturer, - MaximoBreaker.[Serial Number], - MaximoBreaker.[Mfr Year], - MaximoBreaker.[Breaker Mfr Speed], - MaximoBreaker.[Model Number], - MaximoBreaker.[Interrupt current Rating (A)], - MaximoBreaker.[ Continuous Amp Rating (A)] - ORDER BY - LastOperationDate - "; - - #endregion - - #region [ Constructors ] - - public AllBreakersReport(DateTime startTime, DateTime endTime) - { - StartTime = startTime; - EndTime = endTime; - FontDefinition = new FontDef(this, FontDef.StandardFont.Helvetica); - - using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) - { -#if DEBUG - DataTable = connection.RetrieveData(TestQuery, startTime, endTime); -#else - DataTable = connection.RetrieveData(Query, startTime, endTime); -#endif - } - } - - #endregion - - #region [ Properties ] - - public DateTime StartTime { get; set; } - public DateTime EndTime { get; set; } - public FontDef FontDefinition { get; set; } - public DataTable DataTable { get; set; } - - #endregion - - #region [ Methods ] - - public byte[] CreatePDF() - { - try - { - GenerateReport(); - - using (MemoryStream stream = new MemoryStream()) - { - formatter.Create(this, stream); - return stream.ToArray(); - } - } - catch (Exception ex) { - Log.Error(ex.ToString(), ex); - return null; - } - } - - private void GenerateReport() - { - CreatePage(); - - double verticalMillimeters = InsertHeader(); - CreateTable(verticalMillimeters); - - foreach (Page page in enum_Page) - InsertFooter(page); - } - - private double CreateTable(double verticalMillimeters) - { - if (DataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText(verticalMillimeters, $" No Breaker Operations during {StartTime:MM/dd/yyyy} - {EndTime:MM/dd/yyyy}"); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 7.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - - tlm.eNewContainer += (oSender, ea) => - { - verticalMillimeters += tlm.rCurY_MM; - verticalMillimeters = NextTablePage(verticalMillimeters, ea); - }; - - List columns = new List() - { - new { Name = "Last Op", Column = "LastOperationDate", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters)*.05 }, - new { Name = "Breaker", Column = "BreakerNumber", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .04 }, - new { Name = "# of Ops", Column = "Total", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .04 }, - new { Name = "Asset", Column = "AssetNum", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .05 }, - new { Name = "Line", Column = "LineName", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .10 }, - new { Name = "Phase", Column = "LastPhase", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .04 }, - new { Name = "Timing (wf)", Column = "LastWaveformTiming", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .05 }, - new { Name = "Timing (sb)", Column = "LastStatusTiming", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .05 }, - new { Name = "MFR Speed", Column = "MfrSpeed", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .04 }, - new { Name = "Operation Timing", Column = "OperationTiming", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .06 }, - new { Name = "Method", Column = "LastMethod", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .05 }, - new { Name = "# Late", Column = "TotalLateOperation", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .03 }, - new { Name = "Last Late", Column = "LastLateOperation", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .05 }, - new { Name = "MFR", Column = "Manufacturer", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .07 }, - new { Name = "Serial #", Column = "SerialNum", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .08 }, - new { Name = "MFR Year", Column = "MfrYear", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .04 }, - new { Name = "Model #", Column = "ModelNum", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .07}, - new { Name = "ICR (A)", Column = "InterruptCurrentRating", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .05}, - new { Name = "CAR (A)", Column = "ContinuousAmpRating", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .05 } - }; - - foreach (var column in columns) - new TlmColumnMM(tlm, column.Name, column.Width); - - List centeredCols = new List() { "Total", "BreakerNumber", "AssetNum", "LastPhase" }; - - foreach (DataRow row in DataTable.Rows) - { - tlm.NewRow(); - int index = 0; - - foreach (var column in columns) - { - if (column.Column == "LastOperationDate" || (column.Column == "LastLateOperation" && row[column.Column].ToString() != string.Empty)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 6.0D; - string date = DateTime.Parse(row[column.Column].ToString()).ToString("MM/dd/yyyy"); - string time = DateTime.Parse(row[column.Column].ToString()).ToString("HH:mm:ss"); - tlm.Add(index, new RepString(textProp, date)); - tlm.NewLine(index); - tlm.Add(index++, new RepString(textProp, time)); - } - else - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 6.0D; - string value = ""; - - value = row[column.Column].ToString(); - RepString repObj = new RepString(textProp, value); - if (centeredCols.Contains(column.Column)) - repObj.rAlignH = RepObj.rAlignCenter; - - AddDataColumn(tlm, index, value, textProp, column.Width); - index++; - - } - } - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - } - - private void AddDataColumn(TlmBase tlm, int index, string value, FontProp fontProp, double width) - { - double initialWidth = fontProp.rGetTextWidthMM(value); - string remainingString = value.Trim(); - - while (initialWidth > width) - { - string[] tokens = remainingString.Split(' '); - string splitValue = tokens.First(); - - foreach (string token in tokens.Skip(1)) - { - if (fontProp.rGetTextWidthMM(splitValue + token) < width) - splitValue = splitValue + ' ' + token; - else - break; - } - - remainingString = remainingString.Replace(splitValue, ""); - tlm.Add(index, new RepString(fontProp, splitValue)); - tlm.NewLine(index); - initialWidth = fontProp.rGetTextWidthMM(remainingString); - } - - tlm.Add(index, new RepString(fontProp, remainingString)); - } - - // Creates a page and sets width and height to standard 8.5x11 inches. - private Page CreatePage() - { - Page page = new Page(this); - page.rWidthMM = PageWidthMillimeters; - page.rHeightMM = PageHeightMillimeters; - return page; - } - - // Inserts the page footer onto the given page, which includes the time of report generation as well as the page number. - private double InsertFooter(Page page) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 12.0D; - page.AddMM(PageWidthMillimeters - PageMarginMillimeters - font.rGetTextWidthMM(page.iPageNo.ToString()), PageHeightMillimeters - 5, new RepString(font, page.iPageNo.ToString())); - return font.rSizeMM; - } - - // Inserts the page footer onto the given page, which includes the time of report generation as well as the page number. - private double InsertHeader() - { - string ReportIdentifier = "All Breakers Report - " + StartTime.ToString("MM/dd/yyyy") + " - " + EndTime.ToString("MM/dd/yyyy") + ""; - - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 12.0D; - - FontProp meterNameFont = new FontProp(FontDefinition, 0.0D); - meterNameFont.rSizePoint = 12.0D; - - int height = 6; - double reportIdentifierHorizontalPosition = PageWidthMillimeters / 2 - font.rGetTextWidthMM(ReportIdentifier) / 2; - page_Cur.AddMM(reportIdentifierHorizontalPosition, height, new RepString(font, ReportIdentifier)); - page_Cur.AddMM(0, 10, new RepRectMM(new BrushProp(this, Color.Black), PageWidthMillimeters, 0.1D)); - - return 20; - } - - // Inserts the given text as a section header (16-pt, bold). - private double InsertItalicText(double verticalMillimeters, string text) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 14.0D; - font.bBold = false; - font.bItalic = true; - page_Cur.AddMM(PageMarginMillimeters, verticalMillimeters, new RepString(font, text)); - return font.rSizeMM + 5; - } - - private double NextTablePage( double verticalMillimeters, TlmBase.NewContainerEventArgs ea) - { - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - CreatePage(); - verticalMillimeters = InsertHeader(); - } - - ea.container.rHeightMM = PageHeightMillimeters - verticalMillimeters - PageMarginMillimeters; - page_Cur.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - return verticalMillimeters; - } - - #endregion - - #region [ Static ] - - private static readonly ILog Log = LogManager.GetLogger(typeof(AllBreakersReport)); - - #endregion - } -} diff --git a/Libraries/openXDA.Reports/EmailWriter.cs b/Libraries/openXDA.Reports/EmailWriter.cs deleted file mode 100644 index 943f9d7e..00000000 --- a/Libraries/openXDA.Reports/EmailWriter.cs +++ /dev/null @@ -1,205 +0,0 @@ -//****************************************************************************************************** -// EmailWriter.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/13/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Configuration; -using Gemstone.Data; -using Gemstone.Data.DataExtensions; -using Gemstone.StringExtensions; -using log4net; -using openXDA.Configuration; -using openXDA.Model; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Net; -using System.Net.Mail; -using System.Xml.Linq; - -namespace openXDA.Reports -{ - public class EmailWriter - { - #region [ Constructors ] - - public EmailWriter(PQReportsSettings reportsSettings, EmailSection emailSettings) - { - ReportSettings = reportsSettings; - EmailSettings = emailSettings; - } - - #endregion - - #region [ Properties ] - - public EmailSection EmailSettings { get; } - public PQReportsSettings ReportSettings { get; } - - #endregion - - #region [ Methods ] - - public void Execute(int month, int year) - { - GenerateEmail(month, year); - } - - private void GenerateEmail(int month, int year) - { - using(AdoDataConnection connection = new AdoDataConnection(Settings.Default)) - { - string sql = $"SELECT Email FROM UserAccount WHERE Email IS NOT NULL AND Email <> '' AND ID IN (SELECT UserAccountID FROM EmailGroupUserAccount WHERE EmailGroupID IN (SELECT EmailGroupID FROM EmailGroupType WHERE EmailTypeID IN (SELECT ID FROM EmailType WHERE EmailCategoryID = (SELECT ID FROM EmailCategory WHERE Name = 'PQReport'))))"; - DataTable emailTable = connection.RetrieveData(sql); - List recipients = emailTable.Select().Select(row => row.ConvertField("Email")).ToList(); - string template = connection.ExecuteScalar("SELECT Template FROM XSLTemplate WHERE Name = 'PQReport'"); - string data = connection.ExecuteScalar(@" - SELECT - {0} as [Month], - {1} as [Year], - (select value from DashSettings where Name = 'System.XDAInstance') as [XDALink], - (SELECT - Meter.AssetKey as [Meter], - Report.Results as [Result], - Report.ID as [ReportID] - FROM - Report JOIN - Meter ON Report.MeterID = Meter.ID - WHERE - Month = {0} AND - Year = {1} - FOR XML RAW('Report') ,TYPE, ELEMENTS) as [Reports] - FOR XML RAW ('PQReport'),TYPE, ELEMENTS - ", month, year); - - XDocument htmlDocument = XDocument.Parse(data.ApplyXSLTransform(template), LoadOptions.PreserveWhitespace); - - try - { - string subject = (string)htmlDocument.Descendants("title").FirstOrDefault() ?? "Fault detected by openXDA"; - string html = htmlDocument.ToString(SaveOptions.DisableFormatting).Replace("&", "&").Replace("<", "<").Replace(">", ">"); - - - SendEmail(recipients, subject, html); - LoadSentEmail(connection, recipients, subject, html); - - } - catch (Exception ex) - { - Log.Error(ex.ToString()); - } - - } - } - - - private int LoadSentEmail(AdoDataConnection connection, List recipients, string subject, string body) - { - TimeZoneInfo xDATimeZone = TimeZoneInfo.FindSystemTimeZoneById(connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'XDATimeZone'")); - DateTime now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, xDATimeZone); - string toLine = string.Join("; ", recipients.Select(recipient => recipient.Trim())); - connection.ExecuteNonQuery("INSERT INTO SentEmail VALUES({0}, {1}, {2}, {3})", now, toLine, subject, body); - return connection.ExecuteScalar("SELECT @@IDENTITY"); - } - - private void SendEmail(List recipients, string subject, string body) - { - const int DefaultSMTPPort = 25; - - if (string.IsNullOrEmpty(EmailSettings.SMTPServer)) - return; - - string[] smtpServerParts = EmailSettings.SMTPServer.Split(':'); - string host = smtpServerParts[0]; - int port; - - if (smtpServerParts.Length <= 1 || !int.TryParse(smtpServerParts[1], out port)) - port = DefaultSMTPPort; - - using (SmtpClient smtpClient = new SmtpClient(host, port)) - using (MailMessage emailMessage = new MailMessage()) - { - if (!string.IsNullOrEmpty(EmailSettings.Username) && (object)EmailSettings.SecurePassword != null) - smtpClient.Credentials = new NetworkCredential(EmailSettings.Username, EmailSettings.SecurePassword); - - smtpClient.EnableSsl = EmailSettings.EnableSSL; - - emailMessage.From = new MailAddress(EmailSettings.FromAddress); - emailMessage.Subject = subject; - emailMessage.Body = body; - emailMessage.IsBodyHtml = true; - - // Add the specified To recipients for the email message - foreach (string toRecipient in recipients) - emailMessage.To.Add(toRecipient.Trim()); - - // Send the email - smtpClient.Send(emailMessage); - } - } - - - public void SendEmailWithAttachment(List recipients, string subject, string body, List attachments) - { - const int DefaultSMTPPort = 25; - - if (string.IsNullOrEmpty(EmailSettings.SMTPServer)) - return; - - string[] smtpServerParts = EmailSettings.SMTPServer.Split(':'); - string host = smtpServerParts[0]; - int port; - - if (smtpServerParts.Length <= 1 || !int.TryParse(smtpServerParts[1], out port)) - port = DefaultSMTPPort; - - using (SmtpClient smtpClient = new SmtpClient(host, port)) - using (MailMessage emailMessage = new MailMessage()) - { - if (!string.IsNullOrEmpty(EmailSettings.Username) && (object)EmailSettings.SecurePassword != null) - smtpClient.Credentials = new NetworkCredential(EmailSettings.Username, EmailSettings.SecurePassword); - - smtpClient.EnableSsl = EmailSettings.EnableSSL; - - emailMessage.From = new MailAddress(EmailSettings.FromAddress); - emailMessage.Subject = subject; - emailMessage.Body = body; - emailMessage.IsBodyHtml = true; - attachments.ForEach(x => emailMessage.Attachments.Add(x)); - - // Add the specified To recipients for the email message - foreach (string toRecipient in recipients) - emailMessage.To.Add(toRecipient.Trim()); - - // Send the email - smtpClient.Send(emailMessage); - } - } - - #endregion - - #region [ Static ] - // Static Fields - private static readonly ILog Log = LogManager.GetLogger(typeof(EmailWriter)); - #endregion - } -} diff --git a/Libraries/openXDA.Reports/IndividualBreakerReport.cs b/Libraries/openXDA.Reports/IndividualBreakerReport.cs deleted file mode 100644 index 4359c7e8..00000000 --- a/Libraries/openXDA.Reports/IndividualBreakerReport.cs +++ /dev/null @@ -1,701 +0,0 @@ -//****************************************************************************************************** -// IndividualBreakerReport.cs - Gbtc -// -// Copyright © 2019, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/02/2019 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Windows.Forms.DataVisualization.Charting; -using Gemstone.Data; -using log4net; -using Root.Reports; -using ChartSeries = System.Windows.Forms.DataVisualization.Charting.Series; -using Gemstone.Configuration; - -namespace openXDA.Reports -{ - public class IndividualBreakerReport : Root.Reports.Report - { - #region [ Members ] - public class Point { - public DateTime Time { get; set; } - public double? Value { get; set; } - } - // Constants - private const double PageMarginMillimeters = 25.4D; // 1-inch margin - private const double PageWidthMillimeters = 8.5D * 25.4D; // 8.5 inch width - private const double PageHeightMillimeters = 11.0D * 25.4D; // 11 inch height - - private const double FooterHeightMillimeters = (10.0D / 72.0D) * 25.4D; - private const double SpacingMillimeters = 6.0D; - - private const string TitleText = "Individual Breaker Report"; - - public const string timingQuery = - @" - SELECT - BreakerOperation.TripCoilEnergized as Time, - BreakerOperation.BreakerNumber, - MeterLine.LineName, - Phase.Name as Phase, - BreakerOperation.BreakerTiming, - CASE - WHEN Phase.Name = 'AN' THEN CAST(BreakerOperation.APhaseBreakerTiming as varchar(max)) - WHEN Phase.Name = 'BN' THEN CAST(BreakerOperation.BPhaseBreakerTiming as varchar(max)) - WHEN Phase.Name = 'CN' THEN CAST(BreakerOperation.CPhaseBreakerTiming as varchar(max)) - ELSE 'N/A' - END as WaveformTiming, - BreakerOperation.StatusTiming as StatusTiming, - MaximoBreaker.BreakerSpeed, - MaximoBreaker.BreakerSpeed * 1.12 as SpeedBandwidth, - MaximoBreaker.BreakerSpeed * 0.12 as Bandwidth, - BreakerOperationType.Name as OperationTiming, - MaximoBreaker.Manufacturer, - MaximoBreaker.SerialNum, - MaximoBreaker.MfrYear, - MaximoBreaker.ModelNum, - MaximoBreaker.InterruptCurrentRating, - MaximoBreaker.ContinuousAmpRating, - MIN(ROUND(FaultSummary.PrefaultCurrent, 0)) as PrefaultCurrent, - CASE - WHEN EventStat.IAMax >= EventStat.IBMax AND EventStat.IAMax >= EventStat.ICMax THEN Round(EventStat.IAMax, 0) - WHEN EventStat.IBMax > EventStat.IAMax AND EventStat.IAMax > EventStat.ICMax THEN Round(EventStat.IAMax, 0) - WHEN EventStat.ICMax > EventStat.IAMax AND EventStat.IAMax > EventStat.IBMax THEN Round(EventStat.IAMax, 0) - ELSE NULL - END as MaxCurrent - FROM - BreakerOperation JOIN - BreakerOperationType ON BreakerOperation.BreakerOperationTypeID = BreakerOperationType.ID JOIN - Phase ON Phase.ID = BreakerOperation.PhaseID JOIN - Event ON BreakerOperation.EventID = Event.ID JOIN - MeterLINE ON Event.MeterID = MeterLine.MeterID AND Event.LineID = MeterLine.LineID LEFT JOIN - MaximoBreaker ON BreakerOperation.BreakerNumber = SUBSTRING(MaximoBreaker.BreakerNum, PATINDEX('%[^0]%', MaximoBreaker.BreakerNum + '.'), LEN(MaximoBreaker.BreakerNum)) LEFT JOIN - FaultSummary ON Event.ID = FaultSummary.EventID AND FaultSummary.IsSelectedAlgorithm = 1 LEFT JOIN - EventStat ON Event.ID = EventStat.EventID - WHERE - BreakerOperation.BreakerNumber = {0} AND - CAST(BreakerOperation.TripCoilEnergized as Date) BETWEEN {1} AND {2} - GROUP BY - BreakerOperation.TripCoilEnergized, - BreakerOperation.BreakerNumber, - MeterLine.LineName, - Phase.Name, - BreakerOperation.BreakerTiming, - BreakerOperation.StatusTiming, - MaximoBreaker.BreakerSpeed, - MaximoBreaker.BreakerSpeed * 1.12, - MaximoBreaker.BreakerSpeed * 0.12, - BreakerOperationType.Name, - MaximoBreaker.Manufacturer, - MaximoBreaker.SerialNum, - MaximoBreaker.MfrYear, - MaximoBreaker.ModelNum, - MaximoBreaker.InterruptCurrentRating, - MaximoBreaker.ContinuousAmpRating, - BreakerOperation.APhaseBreakerTiming, - BreakerOperation.BPhaseBreakerTiming, - BreakerOperation.CPhaseBreakerTiming, - EventStat.IAMax, - EventStat.IBMax, - EventStat.ICMax - ORDER BY - Time - "; - - private const string testTimingQuery = @" - SELECT - * - FROM - IndividualBreakerQuery - WHERE - BreakerNumber = {0} AND - Cast(Time as Date) BETWEEN {1} AND {2} - ORDER BY Time - "; - - private const string infoQuery = - @" - SELECT DISTINCT - MaximoBreaker.BreakerNum as [Breaker Number], - MaximoBreaker.BreakerSpeed as [Breaker Mfr Speed], - MaximoBreaker.BreakerSpeed * 1.12 as [Speed Bandwidth], - MaximoBreaker.BreakerSpeed * 0.12 as [12% Speed Bandwidth], - MaximoBreaker.Manufacturer, - MaximoBreaker.SerialNum as [Serial Number], - MaximoBreaker.MfrYear as [Mfr Year], - MaximoBreaker.ModelNum as [Model Number], - MaximoBreaker.InterruptCurrentRating as [Interrupt Current Rating (A)], - MaximoBreaker.ContinuousAmpRating as [Continuous Amp Rating (A)] - FROM - MaximoBreaker - WHERE - BreakerNum = {0} - - "; - - private const string testInfoQuery = @" - SELECT - [Breaker Number], - [Breaker Mfr Speed], - [Speed Bandwidth], - [12% Speed Bandwidth], - Manufacturer, - [Serial Number], - [Mfr Year], - [Model Number], - [Interrupt Current Rating (A)], - [ Continuous Amp Rating (A)] - FROM - MaximoBreakerInfo - WHERE - [Breaker Number] = {0} - "; - - #endregion - - #region [ Properties ] - - public string BreakerID { get; set; } - public DateTime StartTime { get; set; } - public DateTime EndTime { get; set; } - public FontDef FontDefinition { get; set; } - public DataTable TimingDataTable { get; set; } - public DataTable InfoDataTable { get; set; } - public List TimingPoints { get; set; } - public List MaxCurrentPoints { get; set; } - - public double? SpeedBandwidth { get; set; } - public double? Speed { get; set; } - public double? InterruptCurrentRating { get; set; } - - #endregion - - #region [ Constructors ] - - public IndividualBreakerReport( string breakerId, DateTime startTime, DateTime endTime) - { - StartTime = startTime; - EndTime = endTime; - BreakerID = breakerId; - FontDefinition = new FontDef(this, "Helvetica"); - - using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { -#if DEBUG - TimingDataTable = connection.RetrieveData(testTimingQuery, breakerId, startTime, endTime); -#else - TimingDataTable = connection.RetrieveData(timingQuery, breakerId, startTime, endTime); -#endif - - TimingPoints = TimingDataTable.Select().Select(x => { - double r; - bool s = double.TryParse(x["WaveformTiming"].ToString(), out r); - return new Point { Time = DateTime.Parse(x["Time"].ToString()), Value = (s ? (double?)r : null) }; - }).OrderBy(x => x.Time).ToList(); - - MaxCurrentPoints = TimingDataTable.Select().Select(x => { - double r; - bool s = double.TryParse(x["MaxCurrent"].ToString(), out r); - return new Point { Time = DateTime.Parse(x["Time"].ToString()), Value = (s ? (double?)r : null) }; - }).OrderBy(x => x.Time).ToList(); - - -#if DEBUG - InfoDataTable = connection.RetrieveData(testInfoQuery, breakerId, startTime, endTime); -#else - InfoDataTable = connection.RetrieveData(infoQuery, breakerId, startTime, endTime); -#endif - - double result; - bool success = double.TryParse(InfoDataTable.Select().FirstOrDefault()?["Breaker Mfr Speed"].ToString(), out result); - Speed = (success ? (double?)result : null); - - success = double.TryParse(InfoDataTable.Select().FirstOrDefault()?["Speed Bandwidth"].ToString(), out result); - SpeedBandwidth = (success ? (double?)result : null); - - success = double.TryParse(InfoDataTable.Select().FirstOrDefault()?["Interrupt Current Rating (A)"].ToString(), out result); - InterruptCurrentRating = (success ? (double?)result : null); - - - } - } - - #endregion - - #region [ Methods ] - - public byte[] createPDF() - { - try - { - GenerateReport(); - - using (MemoryStream stream = new MemoryStream()) - { - this.formatter.Create(this, stream); - return stream.ToArray(); - } - } - catch (Exception ex) { - Log.Error(ex.ToString(), ex); - return null; - } - } - - private void GenerateReport() - { - CreatePage(); - double verticalMillimeters = InsertHeader(); - - verticalMillimeters = CreateInfoTable(verticalMillimeters); - verticalMillimeters = CreateTimingTable(verticalMillimeters); - - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - CreatePage(); - verticalMillimeters = InsertHeader(); - } - - Chart chart = GenerateTimingLineChart(); - verticalMillimeters += 75; - - if(chart != null) - page_Cur.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - CreatePage(); - verticalMillimeters = InsertHeader(); - } - - chart = GenerateMaxCurrentLineChart(); - verticalMillimeters += 75; - - if (chart != null) - page_Cur.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - foreach (Page page in enum_Page) - { - InsertFooter(page); - } - } - - private double CreateInfoTable(double verticalMillimeters) - { - - if (InfoDataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText(verticalMillimeters, $" No Breaker Information available."); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => - { - verticalMillimeters += tlm.rCurY_MM; - verticalMillimeters = NextTablePage(verticalMillimeters, ea); - }; - - new TlmColumnMM(tlm, "Breaker Info", (PageWidthMillimeters - 2 * PageMarginMillimeters) * .5); - new TlmColumnMM(tlm, "Value", (PageWidthMillimeters - 2 * PageMarginMillimeters) * .5); - - DataRow dataRow = InfoDataTable.Select().First(); - foreach (DataColumn column in InfoDataTable.Columns) - { - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, column.ColumnName)); - tlm.Add(1, new RepString(textProp, dataRow[column.ColumnName].ToString())); - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - } - - private double CreateTimingTable(double verticalMillimeters) - { - - - List columns = new List() - { - new { Name = "Time", Column = "Time", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters)*.1 }, - new { Name = "Line", Column = "LineName", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters)*.2 }, - new { Name = "Phase", Column = "Phase", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .1 }, - new { Name = "Timing (br)", Column = "BreakerTiming", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .1 }, - new { Name = "Timing (wf)", Column = "WaveformTiming", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .1}, - new { Name = "Timing (sp)", Column = "StatusTiming", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .1 }, - new { Name = "Classification", Column = "OperationTiming", Width = (PageWidthMillimeters - 2 * PageMarginMillimeters) * .1 }, - new { Name = "Prefault Current", Column = "PrefaultCurrent", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .1 }, - new { Name = "Max Current", Column = "MaxCurrent", Width =(PageWidthMillimeters - 2 * PageMarginMillimeters) * .1 }, - }; - - if (TimingDataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText(verticalMillimeters, $" No Breaker Operations during {StartTime.ToString("MM/dd/yyyy")} - {EndTime.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => - { - verticalMillimeters += tlm.rCurY_MM; - verticalMillimeters = NextTablePage(verticalMillimeters, ea); - }; - - - // define columns - foreach (var column in columns) { - new TlmColumnMM(tlm, column.Name, column.Width); - } - - - foreach(DataRow row in TimingDataTable.Rows) - { - tlm.NewRow(); - int index = 0; - foreach (var column in columns) { - if (column.Column == "Time") - { - string date = DateTime.Parse(row[column.Column].ToString()).ToString("MM/dd/yyyy"); - string time = DateTime.Parse(row[column.Column].ToString()).ToString("HH:mm:ss"); - tlm.Add(index, new RepString(textProp, date)); - tlm.NewLine(index); - tlm.Add(index++, new RepString(textProp, time)); - - } - else if (column.Column == "LineName") - AddDataColumn(tlm, index++, row[column.Column].ToString(), textProp, column.Width); - else - tlm.Add(index++, new RepString(textProp, row[column.Column].ToString())); - } - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - } - - private void AddDataColumn(TlmBase tlm, int index, string value, FontProp fontProp, double width) - { - double initialWidth = fontProp.rGetTextWidthMM(value); - string remainingString = value.Trim(); - while (initialWidth > width) - { - string[] tokens = remainingString.Split(' '); - string splitValue = tokens.First(); - - foreach (string token in tokens.Skip(1)) - { - if (fontProp.rGetTextWidthMM(splitValue + token) < width) - splitValue = splitValue + ' ' + token; - else - break; - } - - remainingString = remainingString.Replace(splitValue, ""); - tlm.Add(index, new RepString(fontProp, splitValue)); - tlm.NewLine(index); - initialWidth = fontProp.rGetTextWidthMM(remainingString); - } - tlm.Add(index, new RepString(fontProp, remainingString)); - } - - - // Creates a page and sets width and height to standard 8.5x11 inches. - private Page CreatePage() - { - Page page = new Page(this); - page.rWidthMM = PageWidthMillimeters; - page.rHeightMM = PageHeightMillimeters; - return page; - } - - // Inserts the page footer onto the given page, which includes the time of report generation as well as the page number. - private double InsertFooter(Page page) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 12.0D; - page.AddMM(PageWidthMillimeters - PageMarginMillimeters - font.rGetTextWidthMM(page.iPageNo.ToString()), PageHeightMillimeters - 15, new RepString(font, page.iPageNo.ToString())); - return font.rSizeMM; - } - - // Inserts the page footer onto the given page, which includes the time of report generation as well as the page number. - private double InsertHeader() - { - string ReportIdentifier = "Individual Breaker Report - " + StartTime.ToString("MM/dd/yyyy") + " - " + EndTime.ToString("MM/dd/yyyy") + ""; - - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 12.0D; - - FontProp meterNameFont = new FontProp(FontDefinition, 0.0D); - meterNameFont.rSizePoint = 12.0D; - - int height = 6; - - double reportIdentifierHorizontalPosition = PageWidthMillimeters / 2 - font.rGetTextWidthMM(ReportIdentifier) / 2; - - page_Cur.AddMM(reportIdentifierHorizontalPosition, height, new RepString(font, ReportIdentifier)); - page_Cur.AddMM(0, 10, new RepRectMM(new BrushProp(this, Color.Black), PageWidthMillimeters, 0.1D)); - - return 20; - } - - - // Inserts the given text as a section header (16-pt, bold). - private double InsertItalicText(double verticalMillimeters, string text) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 14.0D; - font.bBold = false; - font.bItalic = true; - page_Cur.AddMM(PageMarginMillimeters, verticalMillimeters, new RepString(font, text)); - return font.rSizeMM + 5; - } - - private double NextTablePage( double verticalMillimeters, TlmBase.NewContainerEventArgs ea) - { - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - CreatePage(); - verticalMillimeters = InsertHeader(); - } - - ea.container.rHeightMM = PageHeightMillimeters - verticalMillimeters - PageMarginMillimeters; - page_Cur.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - return verticalMillimeters; - } - - private Chart GenerateTimingLineChart() - { - if (TimingPoints.Count == 0) - { - return null; - } - - Chart chart; - double timingMax = Math.Ceiling(TimingPoints.Select(x => (x.Value == null ? 0 : (double)x.Value)).Max()); - double bandwidthMax = Math.Ceiling((SpeedBandwidth == null ? 0 : (double)SpeedBandwidth)); - - ChartArea area; - ChartSeries series; - area = new ChartArea(); - - // style x axis - area.AxisX.MajorGrid.Enabled = false; - area.AxisX.IsLabelAutoFit = false; - //area.AxisX.LabelAutoFitMinFontSize = 20; - //area.AxisX.LabelStyle.Format = "MM/dd/yyyy"; - area.AxisX.LabelStyle.Font = new Font(FontFamily.GenericSansSerif, 15); - area.AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount; - area.AxisX.Maximum = TimingPoints.Count + 1; - area.AxisX.Minimum = 0; - //area.AxisX.Interval = 1; - //area.AxisX.MajorTickMark.Interval = 1; - area.AxisX.TextOrientation = TextOrientation.Rotated90; - area.AxisX.LabelStyle.Angle = -45; - //area.AxisX.LabelStyle.IsEndLabelVisible = true; - //area.AxisX.LabelStyle.IsStaggered = true; - - // style y axis - //area.AxisY.MajorGrid.LineColor = Color.LightGray; - area.AxisY.Maximum = (bandwidthMax > timingMax ? bandwidthMax : timingMax); - area.AxisY.Minimum = 0; - area.AxisY.Interval = 1; - area.AxisY.LabelAutoFitMinFontSize = 15; - area.AxisY.LabelStyle.Format = "0"; - - - //create chart - chart = new Chart(); - chart.Width = 1200; - chart.Height = 500; - chart.Name = "Waveform Timing"; - - Legend legend = new Legend("Legend"); - legend.Font = new Font(FontFamily.GenericSansSerif, 15); - chart.Legends.Add(legend); - chart.ChartAreas.Add(area); - - - series = new ChartSeries("Waveform Timing"); - series.ChartType = SeriesChartType.Line; - series.BorderWidth = 2; - series.Color = Color.Black; - series.IsValueShownAsLabel = true; - - int index = 1; - foreach (var point in TimingPoints) - { - area.AxisX.CustomLabels.Add(index, index +.9, point.Time.ToString("MM/dd/yyyy")); - - if (point.Value == null) { - //series.Points.AddY(index++); - } - else { - DataPoint dataPoint = new DataPoint(index++, (double)point.Value); - - series.Points.Add(dataPoint); - } - } - - - chart.Series.Add(series); - - if(SpeedBandwidth != null) - chart.Series.Add(MakeLimitSeries((double)SpeedBandwidth, Color.Red, "12% Bandwidth", 0, TimingPoints.Count+1)); - if (Speed != null) - chart.Series.Add(MakeLimitSeries((double)Speed, Color.Orange, "MFR Speed", 0, TimingPoints.Count+1)); - - return chart; - - } - - private Chart GenerateMaxCurrentLineChart() - { - var nonNullPoints = MaxCurrentPoints.Where(x => x.Value != null); - - if (!nonNullPoints.Any()) - { - return null; - } - - Chart chart; - double max = Math.Ceiling(nonNullPoints.Select(x => (x.Value == null ? 0 : (double)x.Value)).Max()); - double icrMax = Math.Ceiling((InterruptCurrentRating == null ? 0 : (double)InterruptCurrentRating)); - - - ChartArea area; - ChartSeries series; - area = new ChartArea(); - // style x axis - area.AxisX.MajorGrid.Enabled = false; - area.AxisX.IsLabelAutoFit = false; - //area.AxisX.LabelAutoFitMinFontSize = 20; - //area.AxisX.LabelStyle.Format = "MM/dd/yyyy"; - area.AxisX.LabelStyle.Font = new Font(FontFamily.GenericSansSerif, 15); - area.AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount; - area.AxisX.Maximum = nonNullPoints.Count() + 1; - area.AxisX.Minimum = 0; - area.AxisX.Interval = 1; - area.AxisX.MajorTickMark.Interval = 1; - area.AxisX.TextOrientation = TextOrientation.Rotated90; - area.AxisX.LabelStyle.Angle = -45; - area.AxisX.LabelStyle.IsEndLabelVisible = true; - - // style y axis - //area.AxisY.MajorGrid.LineColor = Color.LightGray; - area.AxisY.Maximum = (icrMax > max ? icrMax : max); - area.AxisY.LabelAutoFitMinFontSize = 15; - area.AxisY.LabelStyle.Format = "0"; - - //create chart - chart = new Chart(); - chart.Width = 1200; - chart.Height = 500; - chart.Name = "Max Current"; - - Legend legend = new Legend("Legend"); - legend.Font = new Font(FontFamily.GenericSansSerif, 15); - chart.Legends.Add(legend); - chart.ChartAreas.Add(area); - - - series = new ChartSeries("Max Current"); - series.ChartType = SeriesChartType.Line; - series.BorderWidth = 2; - series.Color = Color.Black; - series.IsValueShownAsLabel = true; - - int index = 1; - foreach (var point in nonNullPoints) - { - area.AxisX.CustomLabels.Add(index, index + .9, point.Time.ToString("MM/dd/yyyy")); - - DataPoint dataPoint = new DataPoint(index++, (double)point.Value); - - series.Points.Add(dataPoint); - } - - chart.Series.Add(series); - - if(InterruptCurrentRating != null) - chart.Series.Add(MakeLimitSeries((double)InterruptCurrentRating, Color.Red, "ICR", 0, nonNullPoints.Count() + 1)); - - return chart; - - } - - - private ChartSeries MakeLimitSeries(double value, Color color, string name, int start, int end) - { - ChartSeries cs = new ChartSeries(name); - cs.ChartType = SeriesChartType.FastLine; - cs.BorderWidth = 1; - - cs.Color = color; - cs.Points.AddXY(start, value); - cs.Points.AddXY(end, value); - return cs; - } - - private Stream ChartToImage(Chart chart) - { - MemoryStream stream = new MemoryStream(); - chart.SaveImage(stream, ChartImageFormat.Jpeg); - stream.Position = 0; - return stream; - } - - #endregion - - #region [ Static ] - - private static readonly ILog Log = LogManager.GetLogger(typeof(PQReport)); - - #endregion - } -} diff --git a/Libraries/openXDA.Reports/PQReport.cs b/Libraries/openXDA.Reports/PQReport.cs deleted file mode 100644 index d7f202e7..00000000 --- a/Libraries/openXDA.Reports/PQReport.cs +++ /dev/null @@ -1,2034 +0,0 @@ -//****************************************************************************************************** -// PQReport.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 07/12/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using Gemstone.Data; -using Gemstone.Data.Model; -using log4net; -using openHistorian.XDALink; -using openXDA.Model; -using Root.Reports; -using System; -using System.Collections.Generic; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Windows.Forms.DataVisualization.Charting; -using ChartSeries = System.Windows.Forms.DataVisualization.Charting.Series; - -namespace openXDA.Reports -{ - public class PQReport : Root.Reports.Report - { - #region [ Members ] - - // Constants - private const double PageMarginMillimeters = 25.4D; // 1-inch margin - private const double PageWidthMillimeters = 8.5D * 25.4D; // 8.5 inch width - private const double PageHeightMillimeters = 11.0D * 25.4D; // 11 inch height - - private const double FooterHeightMillimeters = (10.0D / 72.0D) * 25.4D; - private const double SpacingMillimeters = 6.0D; - - private const int NumBuckets = 45; - - private const string TitleText = "Monthly PQ Compliance Report"; - - private class PointGroup - { - public string Name { get; set; } - public List Data { get; set; } - public Color Color { get; set; } - } - - private class SummaryResults - { - public SummaryResults() - { - Frequency = new FrequencyData(); - VoltageLN = new VoltageData(); - VoltageLL = new VoltageData(); - Flicker = new FlickerData(); - Imbalance = new ImbalanceData(); - THD = new THDData(); - Harmonics = new HarmonicsData(); - Sags = new SagsData(); - Swells = new SwellsData(); - Interruptions = new InterruptionsData(); - Faults = new FaultsData(); - } - - public FrequencyData Frequency { get; set; } - public VoltageData VoltageLN { get; set; } - public VoltageData VoltageLL { get; set; } - public FlickerData Flicker { get; set; } - public ImbalanceData Imbalance { get; set; } - public THDData THD { get; set; } - public HarmonicsData Harmonics { get; set; } - public SagsData Sags { get; set; } - public SwellsData Swells { get; set; } - public InterruptionsData Interruptions { get; set; } - public FaultsData Faults { get; set; } - - public class FrequencyData - { - public double Min { get; set; } - public double Avg { get; set; } - public double Max { get; set; } - public string Compliance { get; set; } - public double Nominal { get; set; } - } - public class VoltageData - { - public double Min { get; set; } - public double Avg { get; set; } - public double Max { get; set; } - public string Compliance { get; set; } - public double Nominal { get; set; } - } - public class FlickerData - { - public double Max { get; set; } - public string Compliance { get; set; } - } - public class ImbalanceData - { - public double Avg { get; set; } - public string Compliance { get; set; } - } - public class THDData - { - public double Min { get; set; } - public double Avg { get; set; } - public double Max { get; set; } - public string Compliance { get; set; } - } - - public class HarmonicsData - { - public string Compliance { get; set; } - } - - public class SagsData - { - public int Count { get; set; } - } - - public class SwellsData - { - public int Count { get; set; } - } - - public class InterruptionsData - { - public int Count { get; set; } - } - - public class FaultsData - { - public int Count { get; set; } - } - } - - private class Curves - { - public static List> IticUpperCurve { get; set; } - public static List> IticLowerCurve { get; set; } - - static Curves() - { - IticUpperCurve = new List>() - { - Tuple.Create(0.0001666667D, 5.0D), - Tuple.Create(0.001D, 2.0D), - Tuple.Create(0.003D, 1.4D), - Tuple.Create(0.003D, 1.2D), - Tuple.Create(0.5D, 1.2D), - Tuple.Create(0.5D, 1.1D), - Tuple.Create(10.0D, 1.1D) - }; - IticLowerCurve = new List>() - { - Tuple.Create(0.02D, 0.0D), - Tuple.Create(0.02D, 0.7D), - Tuple.Create(0.5D, 0.7D), - Tuple.Create(0.5D, 0.8D), - Tuple.Create(10.0D, 0.8D), - Tuple.Create(10.0D, 0.9D) - }; - } - } - - #endregion - - #region [ Properties ] - - public PQReportsSettings ReportsSettings { get; set; } - public Meter Meter { get; set; } - public DateTime FirstOfMonth { get; set; } - public DateTime EndOfMonth { get; set; } - public string Result { get; set; } - public FontDef FontDefinition { get; set; } - private SummaryResults Summary { get; set; } - private AdoDataConnection Connection { get; set; } - #endregion - - #region [ Constructors ] - - public PQReport(PQReportsSettings reportsSettings, Meter meter, DateTime firstOfMonth, DateTime endOfMonth, AdoDataConnection connection) - { - ReportsSettings = reportsSettings; - Meter = meter; - FirstOfMonth = firstOfMonth; - EndOfMonth = endOfMonth; - FontDefinition = new FontDef(this, "Helvetica"); - Summary = new SummaryResults(); - Connection = connection; - } - - #endregion - - #region [ Methods ] - - public byte[] createPDF() - { - try - { - GenerateReport(); - - using (MemoryStream stream = new MemoryStream()) - { - this.formatter.Create(this, stream); - return stream.ToArray(); - } - } - catch (Exception ex) { - Log.Error(ex.ToString(), ex); - return null; - } - } - - private void GenerateReport() - { - DateTime now = DateTime.Now; - - // Build Report - Page coverPage = CreatePage(); - Page pageTwo = CreatePage(); - CreateFrequencyPage(); - CreateVoltageLNPage(); - CreateVoltageLLPage(); - CreateFlickerPage(); - CreateImbalancePage(); - CreateTHDPage(); - //CreateHarmonicsPage(); - CreateMagDurPage(); - double verticalMillimeters = CreateInteruptionsPage(); - verticalMillimeters = CreateSagsPage(verticalMillimeters); - verticalMillimeters = CreateSwellsPage(verticalMillimeters); - verticalMillimeters = CreateFaultsPage(verticalMillimeters); - CreateSummaryPage(pageTwo); - - Result = ( - Summary.Frequency.Compliance == "Pass" && - Summary.VoltageLN.Compliance == "Pass" && - Summary.VoltageLL.Compliance == "Pass" && - Summary.Flicker.Compliance == "Pass" && - Summary.Imbalance.Compliance == "Pass" && - Summary.THD.Compliance == "Pass" && - Summary.Harmonics.Compliance == "Pass" - ? "Pass" : "Fail"); - - CreateCoverPage(coverPage); - - foreach (Page page in enum_Page) - { - if (page.iPageNo != 1) - InsertFooter(page); - } - } - - private void CreateCoverPage(Page page) - { - double verticalMillimeters = PageMarginMillimeters; - verticalMillimeters += InsertTitle(page, verticalMillimeters) + SpacingMillimeters; - - } - - private void CreateFrequencyPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 1: Power Frequency"); - verticalMillimeters += InsertNominal(page, verticalMillimeters, "Frequency", "60.00", "Hz"); - verticalMillimeters += InsertFrequencyPage(page, verticalMillimeters); - } - - private void CreateVoltageLNPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 2a: Supply Voltage (L-N)"); - verticalMillimeters += InsertVoltageLNPage(page, verticalMillimeters); - } - - private void CreateVoltageLLPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 2b: Supply Voltage (L-L)"); - verticalMillimeters += InsertVoltageLLPage(page, verticalMillimeters); - - } - - private void CreateFlickerPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 3: Flicker Severity"); - verticalMillimeters += InsertFlickerPage(page, verticalMillimeters); - } - - private void CreateImbalancePage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 4: Voltage Unbalance"); - verticalMillimeters += InsertImbalancePage(page, verticalMillimeters); - } - - private void CreateTHDPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 5: Voltage THD"); - verticalMillimeters += InsertTHDPage(page, verticalMillimeters); - } - - private void CreateHarmonicsPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 6: Harmonics"); - } - - private double CreateInteruptionsPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 8: Interruptions"); - - DataTable dataTable = Connection.RetrieveData(@" - Select - cast(Disturbance.StartTime as Date) as Date, - cast(Disturbance.StartTime as Time) as Time, - Disturbance.PerUnitMagnitude as Depth, - Disturbance.DurationSeconds as Duration - from - Event Join - Disturbance ON Event.ID = Disturbance.EventID - WHERE - Disturbance.PhaseID = (SELECT ID FROM Phase WHERE Name = 'Worst') AND - Event.EventTypeID = (SELECT ID FROM EventType WHERE Name ='Interruption') AND - Disturbance.StartTime BETWEEN {0} AND {1} AND - Event.MeterID = {2} - ", FirstOfMonth, EndOfMonth, Meter.ID); - - Summary.Interruptions.Count = dataTable.Rows.Count; - - if (dataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText( page, verticalMillimeters, $" No Interruptions during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => verticalMillimeters = NextTablePage(page, verticalMillimeters, ea); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Date", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Time", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Depth", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Duration", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - - foreach (DataRow row in dataTable.Rows) - { - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, row["Date"].ToString())); - tlm.Add(1, new RepString(textProp, row["Time"].ToString())); - tlm.Add(2, new RepString(textProp, row["Depth"].ToString())); - tlm.Add(3, new RepString(textProp, row["Duration"].ToString())); - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - } - - private double CreateSagsPage(double verticalMillimeters) - { - Page page = page_Cur; - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - page = CreatePage(); - verticalMillimeters = InsertHeader(page); - } - - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 9: Sags"); - - DataTable dataTable = Connection.RetrieveData(@" - Select - cast(Disturbance.StartTime as Date) as Date, - cast(Disturbance.StartTime as Time) as Time, - Disturbance.PerUnitMagnitude as Depth, - Disturbance.DurationSeconds as Duration - from - Event Join - Disturbance ON Event.ID = Disturbance.EventID - WHERE - Disturbance.PhaseID = (SELECT ID FROM Phase WHERE Name = 'Worst') AND - Event.EventTypeID = (SELECT ID FROM EventType WHERE Name ='Sag') AND - Disturbance.StartTime BETWEEN {0} AND {1} AND - Event.MeterID = {2} - ", FirstOfMonth, EndOfMonth, Meter.ID); - - Summary.Sags.Count = dataTable.Rows.Count; - - if (dataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Faults during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => verticalMillimeters = NextTablePage(page, verticalMillimeters, ea); - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Date", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Time", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Depth", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Duration (seconds)", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - - foreach (DataRow row in dataTable.Rows) - { - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, ((DateTime)row["Date"]).ToString("MM/dd/yyyy"))); - tlm.Add(1, new RepString(textProp, row["Time"].ToString())); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", double.Parse(row["Depth"].ToString()) * 100))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N3}", double.Parse(row["Duration"].ToString())))); - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - - } - - private double CreateSwellsPage(double verticalMillimeters) - { - Page page = page_Cur; - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - page = CreatePage(); - verticalMillimeters = InsertHeader(page); - } - - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 10: Swells"); - DataTable dataTable = Connection.RetrieveData(@" - Select - cast(Disturbance.StartTime as Date) as Date, - cast(Disturbance.StartTime as Time) as Time, - Disturbance.PerUnitMagnitude as Depth, - Disturbance.DurationSeconds as Duration - from - Event Join - Disturbance ON Event.ID = Disturbance.EventID - WHERE - Disturbance.PhaseID = (SELECT ID FROM Phase WHERE Name = 'Worst') AND - Event.EventTypeID = (SELECT ID FROM EventType WHERE Name ='Swell') AND - Disturbance.StartTime BETWEEN {0} AND {1} AND - Event.MeterID = {2} - ", FirstOfMonth, EndOfMonth, Meter.ID); - - Summary.Swells.Count = dataTable.Rows.Count; - - - if (dataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Swells during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => verticalMillimeters = NextTablePage(page, verticalMillimeters, ea); - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Date", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Time", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Depth", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Duration", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - - foreach (DataRow row in dataTable.Rows) - { - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, row["Date"].ToString())); - tlm.Add(1, new RepString(textProp, row["Time"].ToString())); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", double.Parse(row["Depth"].ToString()) * 100))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N3}", double.Parse(row["Duration"].ToString())))); - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - } - - private void CreateMagDurPage() - { - Page page = CreatePage(); - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader( page, verticalMillimeters, "Section 7: Mag-Dur Chart"); - - DataTable dataTable = Connection.RetrieveData(@" - Select - Disturbance.PerUnitMagnitude as Depth, - Disturbance.DurationSeconds as Duration - from - Event Join - Disturbance ON Event.ID = Disturbance.EventID - WHERE - Disturbance.PhaseID = (SELECT ID FROM Phase WHERE Name = 'Worst') AND - ( - Event.EventTypeID = (SELECT ID FROM EventType WHERE Name ='Sag') OR - Event.EventTypeID = (SELECT ID FROM EventType WHERE Name ='Swell') OR - Event.EventTypeID = (SELECT ID FROM EventType WHERE Name ='Interruption') - ) AND - Disturbance.StartTime BETWEEN {0} AND {1} AND - Event.MeterID = {2} - ", FirstOfMonth, EndOfMonth, Meter.ID); - - Chart chart = GenerateMagDurChart(dataTable.Select().Select(row => new Tuple(double.Parse(row["Duration"].ToString()), double.Parse(row["Depth"].ToString()))).ToList(), "0.0000 s", "0.0 %"); - verticalMillimeters += 150; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 150)); - - } - - private double CreateFaultsPage(double verticalMillimeters) - { - Page page = page_Cur; - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - page = CreatePage(); - verticalMillimeters = InsertHeader(page); - } - - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 11: Faults"); - DataTable dataTable = Connection.RetrieveData(@" - SELECT - Cast(FaultSummary.Inception as Date) as Date, - Cast(FaultSummary.Inception as Time) as Time, - FaultSummary.Distance, - FaultSummary.DurationSeconds as Duration - FROM - Event JOIN - FaultSummary ON Event.ID = FaultSummary.EventID - WHERE - FaultSummary.IsSelectedAlgorithm = 1 AND - FaultSummary.IsSuppressed = 0 AND - FaultSummary.IsValid = 1 AND - FaultSummary.Inception BETWEEN {0} AND {1} AND - Event.MeterID = {2} - ", FirstOfMonth, EndOfMonth, Meter.ID); - - Summary.Faults.Count = dataTable.Rows.Count; - - if (dataTable.Rows.Count == 0) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Faults during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => verticalMillimeters = NextTablePage(page, verticalMillimeters, ea); - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Date", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Time", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Distance", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - col = new TlmColumnMM(tlm, "Duration", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.25); - - foreach (DataRow row in dataTable.Rows) - { - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, row["Date"].ToString())); - tlm.Add(1, new RepString(textProp, row["Time"].ToString())); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", double.Parse(row["Distance"].ToString()) * 100))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N3}", double.Parse(row["Duration"].ToString())))); - } - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - return verticalMillimeters; - } - - private void CreateSummaryPage(Page page) - { - double verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Summary of Results"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => verticalMillimeters = NextTablePage(page, verticalMillimeters, ea); - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Measurement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.35); - col = new TlmColumnMM(tlm, "Min", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.15); - col = new TlmColumnMM(tlm, "Avg", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.15); - col = new TlmColumnMM(tlm, "Max", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.15); - col = new TlmColumnMM(tlm, "Compliance", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"1. Frequency ({Summary.Frequency.Nominal} Hz)")); - tlm.Add(1, new RepString(textProp, string.Format("{0:N2}", Summary.Frequency.Min))); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", Summary.Frequency.Avg))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N2}", Summary.Frequency.Max))); - tlm.Add(4, new RepString(textProp, Summary.Frequency.Compliance)); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"2a. Voltage L-N ({string.Format("{0:N0}", Summary.VoltageLN.Nominal)} V)")); - tlm.Add(1, new RepString(textProp, string.Format("{0:N2}", Summary.VoltageLN.Min))); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", Summary.VoltageLN.Avg))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N2}", Summary.VoltageLN.Max))); - tlm.Add(4, new RepString(textProp, Summary.VoltageLN.Compliance)); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"2b. Voltage L-L ({string.Format("{0:N0}", Summary.VoltageLL.Nominal)} V)")); - tlm.Add(1, new RepString(textProp, string.Format("{0:N2}", Summary.VoltageLL.Min))); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", Summary.VoltageLL.Avg))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N2}", Summary.VoltageLL.Max))); - tlm.Add(4, new RepString(textProp, Summary.VoltageLL.Compliance)); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"3. Flicker")); - tlm.Add(1, new RepString(textProp, "")); - tlm.Add(2, new RepString(textProp, "")); - tlm.Add(3, new RepString(textProp, string.Format("{0:N2}", Summary.Flicker.Max))); - tlm.Add(4, new RepString(textProp, Summary.Flicker.Compliance)); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"4. Imbalance")); - tlm.Add(1, new RepString(textProp, "")); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", Summary.Imbalance.Avg))); - tlm.Add(3, new RepString(textProp, "")); - tlm.Add(4, new RepString(textProp, Summary.Imbalance.Compliance)); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"5. THD")); - tlm.Add(1, new RepString(textProp, string.Format("{0:N2}", Summary.THD.Min))); - tlm.Add(2, new RepString(textProp, string.Format("{0:N2}", Summary.THD.Avg))); - tlm.Add(3, new RepString(textProp, string.Format("{0:N2}", Summary.THD.Max))); - tlm.Add(4, new RepString(textProp, Summary.THD.Compliance)); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"6. Harmonics")); - tlm.Add(1, new RepString(textProp, "")); - tlm.Add(2, new RepString(textProp, "")); - tlm.Add(3, new RepString(textProp, "")); - tlm.Add(4, new RepString(textProp, Summary.Harmonics.Compliance)); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => verticalMillimeters = NextTablePage(page, verticalMillimeters, ea); - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Event Type", (PageWidthMillimeters / 2 - PageMarginMillimeters) * 0.65); - col = new TlmColumnMM(tlm, "Count", (PageWidthMillimeters / 2 - PageMarginMillimeters) * 0.35); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"8. Interruptions")); - tlm.Add(1, new RepString(textProp, string.Format("{0}", Summary.Interruptions.Count))); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"9. Sags")); - tlm.Add(1, new RepString(textProp, string.Format("{0}", Summary.Sags.Count))); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"10. Swells")); - tlm.Add(1, new RepString(textProp, string.Format("{0}", Summary.Swells.Count))); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"11. Faults")); - tlm.Add(1, new RepString(textProp, string.Format("{0}", Summary.Faults.Count))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - } - - // Creates a page and sets width and height to standard 8.5x11 inches. - private Page CreatePage() - { - Page page = new Page(this); - page.rWidthMM = PageWidthMillimeters; - page.rHeightMM = PageHeightMillimeters; - return page; - } - - // Inserts the title and company text on the given page. - private double InsertTitle(Page page, double verticalMillimeters) - { - FontProp titleFont = new FontProp(FontDefinition, 0.0D); - FontProp companyFont = new FontProp(FontDefinition, 0.0D); - - titleFont.rSizePoint = 20.0D; - companyFont.rSizePoint = 14.0D; - titleFont.bBold = true; - companyFont.bBold = true; - - // Title - page.AddCB_MM(verticalMillimeters + titleFont.rSizeMM, new RepString(titleFont, TitleText)); - verticalMillimeters += 1.5D * titleFont.rSizeMM; - verticalMillimeters += 5; - - // Company - page.AddCB_MM(verticalMillimeters + companyFont.rSizeMM, new RepString(companyFont, $"{Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'CompanyName'")}")); - - verticalMillimeters += 1.5D * titleFont.rSizeMM; - - // openXDA - page.AddCB_MM(verticalMillimeters + companyFont.rSizeMM, new RepString(companyFont, $"openXDA")); - - verticalMillimeters += 1.5D * titleFont.rSizeMM; - - // Date - page.AddCB_MM(verticalMillimeters + companyFont.rSizeMM, new RepString(companyFont, $"{FirstOfMonth.ToString("MMMM yyyy")}")); - - verticalMillimeters += 1.5D * titleFont.rSizeMM; - - // Meter Name - page.AddCB_MM(verticalMillimeters + companyFont.rSizeMM, new RepString(companyFont, $"{Meter.Name} - {Result}")); - - verticalMillimeters += 1.5D * companyFont.rSizeMM; - - - return verticalMillimeters; - } - - // Inserts the page footer onto the given page, which includes the time of report generation as well as the page number. - private double InsertFooter(Page page) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 12.0D; - page.AddMM(PageWidthMillimeters - PageMarginMillimeters - font.rGetTextWidthMM(page.iPageNo.ToString()), PageHeightMillimeters - 15, new RepString(font, page.iPageNo.ToString())); - return font.rSizeMM; - } - - // Inserts the page footer onto the given page, which includes the time of report generation as well as the page number. - private double InsertHeader(Page page) - { - const string ReportIdentifier = "PQ Report - openXDA"; - - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 12.0D; - - FontProp meterNameFont = new FontProp(FontDefinition, 0.0D); - meterNameFont.rSizePoint = 12.0D; - - int height = 6; - - double reportIdentifierHorizontalPosition = PageWidthMillimeters / 2 - font.rGetTextWidthMM(ReportIdentifier) / 2; - double meterNameMaxWidth = reportIdentifierHorizontalPosition - PageMarginMillimeters - 4; - string meterName = Meter.Name; - - while (meterNameFont.rGetTextWidthMM(meterName) > meterNameMaxWidth) - meterNameFont.rSizePoint -= 1.0D; - - page.AddMM(PageMarginMillimeters, height, new RepString(meterNameFont, Meter.Name)); - page.AddMM(reportIdentifierHorizontalPosition, height, new RepString(font, ReportIdentifier)); - page.AddMM(PageWidthMillimeters - PageMarginMillimeters - font.rGetTextWidthMM(FirstOfMonth.ToString("MMMM yyyy")), height, new RepString(font, FirstOfMonth.ToString("MMMM yyyy"))); - page.AddMM(0, 10, new RepRectMM(new BrushProp(this, Color.Black), PageWidthMillimeters, 0.1D)); - - return 20; - } - - - // Inserts the given text as a section header (16-pt, bold). - private double InsertSectionHeader(Page page, double verticalMillimeters, string text) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 14.0D; - font.bBold = true; - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepString(font, text)); - return font.rSizeMM + 5; - } - - // Inserts the given text as a section header (16-pt, bold). - private double InsertItalicText(Page page, double verticalMillimeters, string text) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 14.0D; - font.bBold = false; - font.bItalic = true; - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepString(font, text)); - return font.rSizeMM + 5; - } - - // Inserts the given text as a section header (16-pt, bold). - private double InsertNominal(Page page, double verticalMillimeters, string type, string value, string units) - { - FontProp font = new FontProp(FontDefinition, 0.0D); - font.rSizePoint = 10.0D; - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepString(font, $"Nominal {type}: {value} {units}")); - return font.rSizeMM + 5; - } - - private double NextTablePage(Page page, double verticalMillimeters, TlmBase.NewContainerEventArgs ea) - { - if (verticalMillimeters > (PageHeightMillimeters * 0.75)) - { - page = CreatePage(); - verticalMillimeters = InsertHeader(page); - verticalMillimeters += InsertSectionHeader(page, verticalMillimeters, "Section 8: Sags (cont.)"); - } - - ea.container.rHeightMM = PageHeightMillimeters - verticalMillimeters - PageMarginMillimeters; - page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - return verticalMillimeters; - } - - private double InsertFrequencyPage(Page page, double verticalMillimeters) - { - string historianServer = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1"; - string historianInstance = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA"; - IEnumerable channels = new TableOperations(Connection).QueryRecordsWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'Frequency') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage')", Meter.ID); - - if (!channels.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Frequency channels setup on this meter."); - Summary.Frequency.Compliance = "Pass"; - return verticalMillimeters; - } - - double nominal = Summary.Frequency.Nominal = 60.0D; - - using (Historian historian = new Historian(historianServer, historianInstance)) - { - List points = historian.Read(channels.Select(x => x.ID), FirstOfMonth, EndOfMonth).ToList(); - - if (!points.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Frequency data during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - List avg = points - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - int firstPercentileSkipCount = (int)(avg.Count * (100.0D - ReportsSettings.FirstFrequencyPercentile) / 100.0D / 2.0D); - double firstPercentileMinLimit = nominal * (100.0D - ReportsSettings.FirstFrequencyDeviationLimit) / 100.0D; - double firstPercentileMaxLimit = nominal * (100.0D + ReportsSettings.FirstFrequencyDeviationLimit) / 100.0D; - double firstPercentileMin = avg.Skip(firstPercentileSkipCount).FirstOrDefault(); - double firstPercentileMax = avg.AsEnumerable().Reverse().Skip(firstPercentileSkipCount).FirstOrDefault(); - - bool firstTest = - firstPercentileMin >= firstPercentileMinLimit && - firstPercentileMax <= firstPercentileMaxLimit; - - int secondPercentileSkipCount = (int)(avg.Count * (100.0D - ReportsSettings.SecondFrequencyPercentile) / 100.0D / 2.0D); - double secondPercentileMinLimit = nominal * (100.0D - ReportsSettings.SecondFrequencyDeviationLimit) / 100.0D; - double secondPercentileMaxLimit = nominal * (100.0D + ReportsSettings.SecondFrequencyDeviationLimit) / 100.0D; - double secondPercentileMin = avg.Skip(secondPercentileSkipCount).FirstOrDefault(); - double secondPercentileMax = avg.AsEnumerable().Reverse().Skip(secondPercentileSkipCount).FirstOrDefault(); - - bool secondTest = - secondPercentileMin >= secondPercentileMinLimit && - secondPercentileMax <= secondPercentileMaxLimit; - - Summary.Frequency.Compliance = (firstTest && secondTest ? "Pass" : "Fail"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Monthly PQ Report Requirement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.40); - col = new TlmColumnMM(tlm, "Measured Frequency", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.40); - col = new TlmColumnMM(tlm, "Result", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.FirstFrequencyPercentile:0.##}% of the time: {firstPercentileMinLimit:N2} Hz - {firstPercentileMaxLimit:N2} Hz")); - tlm.Add(1, new RepString(textProp, (avg.Any() ? $"{firstPercentileMin:N2} - {firstPercentileMax:N2}" : "No Data Provided"))); - tlm.Add(2, new RepString(textProp, (firstTest ? "Pass" : "Fail"))); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.SecondFrequencyPercentile:0.##}% of the time: {secondPercentileMinLimit:N2} Hz - {secondPercentileMaxLimit:N2} Hz")); - tlm.Add(1, new RepString(textProp, (avg.Any() ? $"{secondPercentileMin:N2} - {secondPercentileMax:N2}" : "No Data Provided"))); - tlm.Add(2, new RepString(textProp, (secondTest ? "Pass" : "Fail"))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - List pointGroups = new List(); - - pointGroups.Add(new PointGroup() - { - Name = "Frequency", - Color = Color.DarkBlue, - Data = points.Where(point => point.SeriesID == SeriesID.Average).ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "Frequency Max", - Color = Color.DarkGreen, - Data = points.Where(point => point.SeriesID == SeriesID.Maximum).ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "Frequency Min", - Color = Color.Purple, - Data = points.Where(point => point.SeriesID == SeriesID.Minimum).ToList() - }); - - Chart chart = GenerateLineChart("Hz", pointGroups, secondPercentileMaxLimit + (secondPercentileMaxLimit - secondPercentileMinLimit) * .10, secondPercentileMinLimit - (secondPercentileMaxLimit - secondPercentileMinLimit) * .10, "MM/dd", "0.00", "Frequency", secondPercentileMaxLimit, firstPercentileMaxLimit, secondPercentileMinLimit, firstPercentileMinLimit, FirstOfMonth, EndOfMonth); - verticalMillimeters += 75; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - verticalMillimeters += 75; - - double maxValue = Summary.Frequency.Max = avg.Max(); - double minValue = Summary.Frequency.Min = avg.Min(); - chart = GenerateBarChart("0.00 Hz", avg, maxValue, minValue); - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - return verticalMillimeters; - } - } - - private double InsertVoltageLNPage( Page page, double verticalMillimeters) - { - string historianServer = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1"; - string historianInstance = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA"; - - Channel line1 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'AN')", Meter.ID); - Channel line2 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'BN')", Meter.ID); - Channel line3 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'CN')", Meter.ID); - - int lineId; - - if (line1 == null && line2 == null && line3 == null) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No L-N Voltage channels setup on this meter."); - Summary.VoltageLN.Compliance = "Pass"; - return verticalMillimeters; - } - - if (line1 != null) - lineId = line1.AssetID; - else if (line2 != null) - lineId = line2.AssetID; - else - lineId = line3.AssetID; - - double nominal = Summary.VoltageLN.Nominal = Connection.ExecuteScalar("SELECT VoltageKV FROM Asset WHERE ID = {0}", lineId) * 1000 / Math.Sqrt(3); - verticalMillimeters += InsertNominal(page, verticalMillimeters, "Voltage", string.Format("{0:N0}", nominal), "V L-N"); - - using (Historian historian = new Historian(historianServer, historianInstance)) - { - List points = historian.Read(new List() { line1.ID, line2.ID, line3.ID }, FirstOfMonth, EndOfMonth).ToList(); - - List avgLine1 = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - List avgLine2 = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - List avgLine3 = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - if (!avgLine1.Any() && !avgLine2.Any() && !avgLine3.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No L-N Voltage data during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - Summary.VoltageLN.Compliance = "Pass"; - return verticalMillimeters; - } - - Summary.VoltageLN.Min = points.Where(point => point.SeriesID == SeriesID.Minimum).Select(point => point.Value).Min(); - Summary.VoltageLN.Avg = points.Where(point => point.SeriesID == SeriesID.Average).Select(point => point.Value).Average(); - Summary.VoltageLN.Max = points.Where(point => point.SeriesID == SeriesID.Maximum).Select(point => point.Value).Max(); - - double firstPercentileMinLimit = nominal * (100.0D - ReportsSettings.FirstVoltageDeviationLimit) / 100.0D; - double firstPercentileMaxLimit = nominal * (100.0D + ReportsSettings.FirstVoltageDeviationLimit) / 100.0D; - - int firstPercentileSkipCountLine1 = (int)(avgLine1.Count * (100.0D - ReportsSettings.FirstVoltagePercentile) / 100.0D / 2.0D); - int firstPercentileSkipCountLine2 = (int)(avgLine2.Count * (100.0D - ReportsSettings.FirstVoltagePercentile) / 100.0D / 2.0D); - int firstPercentileSkipCountLine3 = (int)(avgLine3.Count * (100.0D - ReportsSettings.FirstVoltagePercentile) / 100.0D / 2.0D); - double firstPercentileMinLine1 = avgLine1.Skip(firstPercentileSkipCountLine1).FirstOrDefault(); - double firstPercentileMinLine2 = avgLine2.Skip(firstPercentileSkipCountLine2).FirstOrDefault(); - double firstPercentileMinLine3 = avgLine3.Skip(firstPercentileSkipCountLine3).FirstOrDefault(); - double firstPercentileMaxLine1 = avgLine1.AsEnumerable().Reverse().Skip(firstPercentileSkipCountLine1).FirstOrDefault(); - double firstPercentileMaxLine2 = avgLine2.AsEnumerable().Reverse().Skip(firstPercentileSkipCountLine2).FirstOrDefault(); - double firstPercentileMaxLine3 = avgLine3.AsEnumerable().Reverse().Skip(firstPercentileSkipCountLine3).FirstOrDefault(); - - bool firstTest = - firstPercentileMinLine1 >= firstPercentileMinLimit && - firstPercentileMaxLine1 <= firstPercentileMaxLimit && - firstPercentileMinLine2 >= firstPercentileMinLimit && - firstPercentileMaxLine2 <= firstPercentileMaxLimit && - firstPercentileMinLine3 >= firstPercentileMinLimit && - firstPercentileMaxLine3 <= firstPercentileMaxLimit; - - double secondPercentileMinLimit = nominal * (100.0D - ReportsSettings.SecondVoltageDeviationLimit) / 100.0D; - double secondPercentileMaxLimit = nominal * (100.0D + ReportsSettings.SecondVoltageDeviationLimit) / 100.0D; - - int secondPercentileSkipCountLine1 = (int)(avgLine1.Count * (100.0D - ReportsSettings.SecondVoltagePercentile) / 100.0D / 2.0D); - int secondPercentileSkipCountLine2 = (int)(avgLine2.Count * (100.0D - ReportsSettings.SecondVoltagePercentile) / 100.0D / 2.0D); - int secondPercentileSkipCountLine3 = (int)(avgLine3.Count * (100.0D - ReportsSettings.SecondVoltagePercentile) / 100.0D / 2.0D); - double secondPercentileMinLine1 = avgLine1.Skip(secondPercentileSkipCountLine1).FirstOrDefault(); - double secondPercentileMinLine2 = avgLine2.Skip(secondPercentileSkipCountLine2).FirstOrDefault(); - double secondPercentileMinLine3 = avgLine3.Skip(secondPercentileSkipCountLine3).FirstOrDefault(); - double secondPercentileMaxLine1 = avgLine1.AsEnumerable().Reverse().Skip(secondPercentileSkipCountLine1).FirstOrDefault(); - double secondPercentileMaxLine2 = avgLine2.AsEnumerable().Reverse().Skip(secondPercentileSkipCountLine2).FirstOrDefault(); - double secondPercentileMaxLine3 = avgLine3.AsEnumerable().Reverse().Skip(secondPercentileSkipCountLine3).FirstOrDefault(); - - bool secondTest = - secondPercentileMinLine1 >= secondPercentileMinLimit && - secondPercentileMaxLine1 <= secondPercentileMaxLimit && - secondPercentileMinLine2 >= secondPercentileMinLimit && - secondPercentileMaxLine2 <= secondPercentileMaxLimit && - secondPercentileMinLine3 >= secondPercentileMinLimit && - secondPercentileMaxLine3 <= secondPercentileMaxLimit; - - Summary.VoltageLN.Compliance = (firstTest && secondTest ? "Pass" : "Fail"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Monthly PQ Report Requirement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.30); - col = new TlmColumnMM(tlm, "Measured L1 Voltage", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L2 Voltage", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L3 Voltage", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Result", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.10); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.FirstVoltagePercentile:0.###}% of the time: {firstPercentileMinLimit:N1} V - {firstPercentileMaxLimit:N1} V")); - tlm.Add(1, new RepString(textProp, (avgLine1.Any() ? $"{firstPercentileMinLine1:N1}V - {firstPercentileMaxLine1:N1}V" : "No data for time period"))); - tlm.Add(2, new RepString(textProp, (avgLine2.Any() ? $"{firstPercentileMinLine2:N1}V - {firstPercentileMaxLine2:N2}V" : "No data for time period"))); - tlm.Add(3, new RepString(textProp, (avgLine3.Any() ? $"{firstPercentileMinLine3:N1}V - {firstPercentileMaxLine3:N2}V" : "No data for time period"))); - tlm.Add(4, new RepString(textProp, (firstTest ? "Pass" : "Fail"))); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.SecondVoltagePercentile:0.###}% of the time: {secondPercentileMinLimit:N1} V - {secondPercentileMaxLine1:N1} V")); - tlm.Add(1, new RepString(textProp, (avgLine1.Any() ? $"{secondPercentileMinLine1:N1}V - {secondPercentileMaxLine1:N1}V" : "No data for time period"))); - tlm.Add(2, new RepString(textProp, (avgLine2.Any() ? $"{secondPercentileMinLine2:N1}V - {secondPercentileMaxLine2:N1}V" : "No data for time period"))); - tlm.Add(3, new RepString(textProp, (avgLine3.Any() ? $"{secondPercentileMinLine3:N1}V - {secondPercentileMaxLine3:N1}V" : "No data for time period"))); - tlm.Add(4, new RepString(textProp, (secondTest ? "Pass" : "Fail"))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - List pointGroups = new List(); - - pointGroups.Add(new PointGroup() - { - Name = "L1-N", - Color = Color.DarkBlue, - Data = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L2-N", - Color = Color.DarkGreen, - Data = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L3-N", - Color = Color.Purple, - Data = points - .Where(point => point.ChannelID == line3.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - List avg = points - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .ToList(); - - double maxValue = avg.Max(); - double minValue = avg.Min(); - double chartHigh = (maxValue > secondPercentileMaxLimit ? maxValue : secondPercentileMaxLimit); - double chartLow = (minValue < secondPercentileMinLimit ? minValue : secondPercentileMinLimit); - double chartMax = chartHigh + (chartHigh - chartLow) * .10; - double chartMin = chartLow - (chartHigh - chartLow) * .10; - - Chart chart = GenerateLineChart("V", pointGroups, chartMax, chartMin, "MM/dd", "0.00", "Voltage L-L", secondPercentileMaxLimit, firstPercentileMaxLimit, secondPercentileMinLimit, firstPercentileMinLimit, FirstOfMonth, EndOfMonth); - verticalMillimeters += 75; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - verticalMillimeters += 75; - - chart = GenerateBarChart("0", avg, maxValue, minValue); - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - return verticalMillimeters; - } - } - - private double InsertVoltageLLPage(Page page, double verticalMillimeters) - { - string historianServer = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1"; - string historianInstance = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA"; - IEnumerable channels = new TableOperations(Connection).QueryRecordsWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage')", Meter.ID); - - Channel line1 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'AB')", Meter.ID); - Channel line2 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'BC')", Meter.ID); - Channel line3 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'RMS') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'CA')", Meter.ID); - - int lineId; - - if (line1 == null && line2 == null && line3 == null) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No L-L Voltage channels setup on this meter."); - Summary.VoltageLL.Compliance = "Pass"; - return verticalMillimeters; - } - - if (line1 != null) - lineId = line1.AssetID; - else if (line2 != null) - lineId = line2.AssetID; - else - lineId = line3.AssetID; - - double nominal = Summary.VoltageLL.Nominal = Connection.ExecuteScalar("SELECT VoltageKV FROM Asset WHERE ID = {0}", lineId) * 1000; - verticalMillimeters += InsertNominal(page, verticalMillimeters, "Voltage", string.Format("{0:N0}", nominal), "V L-L"); - - using (Historian historian = new Historian(historianServer, historianInstance)) - { - List points = historian.Read(new List() { line1.ID, line2.ID, line3.ID }, FirstOfMonth, EndOfMonth).ToList(); - - List avgLine1 = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - List avgLine2 = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - List avgLine3 = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - if (!avgLine1.Any() && !avgLine2.Any() && !avgLine3.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No L-L Voltage data during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - Summary.VoltageLL.Compliance = "Pass"; - return verticalMillimeters; - } - - Summary.VoltageLL.Min = points.Where(point => point.SeriesID == SeriesID.Minimum).Select(point => point.Value).Min(); - Summary.VoltageLL.Avg = points.Where(point => point.SeriesID == SeriesID.Average).Select(point => point.Value).Average(); - Summary.VoltageLL.Max = points.Where(point => point.SeriesID == SeriesID.Maximum).Select(point => point.Value).Max(); - - double firstPercentileMinLimit = nominal * (100.0D - ReportsSettings.FirstVoltageDeviationLimit) / 100.0D; - double firstPercentileMaxLimit = nominal * (100.0D + ReportsSettings.FirstVoltageDeviationLimit) / 100.0D; - - int firstPercentileSkipCountLine1 = (int)(avgLine1.Count * (100.0D - ReportsSettings.FirstVoltagePercentile) / 100.0D / 2.0D); - int firstPercentileSkipCountLine2 = (int)(avgLine2.Count * (100.0D - ReportsSettings.FirstVoltagePercentile) / 100.0D / 2.0D); - int firstPercentileSkipCountLine3 = (int)(avgLine3.Count * (100.0D - ReportsSettings.FirstVoltagePercentile) / 100.0D / 2.0D); - double firstPercentileMinLine1 = avgLine1.Skip(firstPercentileSkipCountLine1).FirstOrDefault(); - double firstPercentileMinLine2 = avgLine2.Skip(firstPercentileSkipCountLine2).FirstOrDefault(); - double firstPercentileMinLine3 = avgLine3.Skip(firstPercentileSkipCountLine3).FirstOrDefault(); - double firstPercentileMaxLine1 = avgLine1.AsEnumerable().Reverse().Skip(firstPercentileSkipCountLine1).FirstOrDefault(); - double firstPercentileMaxLine2 = avgLine2.AsEnumerable().Reverse().Skip(firstPercentileSkipCountLine2).FirstOrDefault(); - double firstPercentileMaxLine3 = avgLine3.AsEnumerable().Reverse().Skip(firstPercentileSkipCountLine3).FirstOrDefault(); - - bool firstTest = - firstPercentileMinLine1 >= firstPercentileMinLimit && - firstPercentileMaxLine1 <= firstPercentileMaxLimit && - firstPercentileMinLine2 >= firstPercentileMinLimit && - firstPercentileMaxLine2 <= firstPercentileMaxLimit && - firstPercentileMinLine3 >= firstPercentileMinLimit && - firstPercentileMaxLine3 <= firstPercentileMaxLimit; - - double secondPercentileMinLimit = nominal * (100.0D - ReportsSettings.SecondVoltageDeviationLimit) / 100.0D; - double secondPercentileMaxLimit = nominal * (100.0D + ReportsSettings.SecondVoltageDeviationLimit) / 100.0D; - - int secondPercentileSkipCountLine1 = (int)(avgLine1.Count * (100.0D - ReportsSettings.SecondVoltagePercentile) / 100.0D / 2.0D); - int secondPercentileSkipCountLine2 = (int)(avgLine2.Count * (100.0D - ReportsSettings.SecondVoltagePercentile) / 100.0D / 2.0D); - int secondPercentileSkipCountLine3 = (int)(avgLine3.Count * (100.0D - ReportsSettings.SecondVoltagePercentile) / 100.0D / 2.0D); - double secondPercentileMinLine1 = avgLine1.Skip(secondPercentileSkipCountLine1).FirstOrDefault(); - double secondPercentileMinLine2 = avgLine2.Skip(secondPercentileSkipCountLine2).FirstOrDefault(); - double secondPercentileMinLine3 = avgLine3.Skip(secondPercentileSkipCountLine3).FirstOrDefault(); - double secondPercentileMaxLine1 = avgLine1.AsEnumerable().Reverse().Skip(secondPercentileSkipCountLine1).FirstOrDefault(); - double secondPercentileMaxLine2 = avgLine2.AsEnumerable().Reverse().Skip(secondPercentileSkipCountLine2).FirstOrDefault(); - double secondPercentileMaxLine3 = avgLine3.AsEnumerable().Reverse().Skip(secondPercentileSkipCountLine3).FirstOrDefault(); - - bool secondTest = - secondPercentileMinLine1 >= secondPercentileMinLimit && - secondPercentileMaxLine1 <= secondPercentileMaxLimit && - secondPercentileMinLine2 >= secondPercentileMinLimit && - secondPercentileMaxLine2 <= secondPercentileMaxLimit && - secondPercentileMinLine3 >= secondPercentileMinLimit && - secondPercentileMaxLine3 <= secondPercentileMaxLimit; - - Summary.VoltageLL.Compliance = (firstTest && secondTest ? "Pass" : "Fail"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Monthly PQ Report Requirement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.30); - col = new TlmColumnMM(tlm, "Measured L1 Voltage", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L2 Voltage", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L3 Voltage", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Result", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.10); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.FirstVoltagePercentile:0.###}% of the time: {firstPercentileMinLimit:N1} V - {firstPercentileMaxLimit:N1} V")); - tlm.Add(1, new RepString(textProp, (avgLine1.Any() ? $"{firstPercentileMinLine1:N1}V - {firstPercentileMaxLine1:N1}V" : "No data for time period"))); - tlm.Add(2, new RepString(textProp, (avgLine2.Any() ? $"{firstPercentileMinLine2:N1}V - {firstPercentileMaxLine2:N1}V" : "No data for time period"))); - tlm.Add(3, new RepString(textProp, (avgLine3.Any() ? $"{firstPercentileMinLine3:N1}V - {firstPercentileMaxLine3:N1}V" : "No data for time period"))); - tlm.Add(4, new RepString(textProp, (firstTest ? "Pass" : "Fail"))); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.SecondVoltagePercentile:0.###}% of the time: {secondPercentileMinLimit:N1} V - {secondPercentileMaxLimit:N1} V")); - tlm.Add(1, new RepString(textProp, (avgLine1.Any() ? $"{secondPercentileMinLine1:N1}V - {secondPercentileMaxLine1:N1}V" : "No data for time period"))); - tlm.Add(2, new RepString(textProp, (avgLine2.Any() ? $"{secondPercentileMinLine2:N1}V - {secondPercentileMaxLine2:N1}V" : "No data for time period"))); - tlm.Add(3, new RepString(textProp, (avgLine3.Any() ? $"{secondPercentileMinLine3:N1}V - {secondPercentileMaxLine3:N1}V" : "No data for time period"))); - tlm.Add(4, new RepString(textProp, (secondTest ? "Pass" : "Fail"))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - List pointGroups = new List(); - pointGroups.Add(new PointGroup() - { - Name = "L1-L2", - Color = Color.DarkBlue, - Data = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L2-L3", - Color = Color.DarkGreen, - Data = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L3-L1", - Color = Color.Purple, - Data = points - .Where(point => point.ChannelID == line3.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - List avg = points - .Where(point => point.SeriesID == SeriesID.Average) - .Select(point => point.Value) - .ToList(); - - double maxValue = avg.Max(); - double minValue = avg.Min(); - double chartHigh = (maxValue > secondPercentileMaxLimit ? maxValue : secondPercentileMaxLimit); - double chartLow = (minValue < secondPercentileMinLimit ? minValue : secondPercentileMinLimit); - double chartMax = chartHigh + (chartHigh - chartLow) * .10; - double chartMin = chartLow - (chartHigh - chartLow) * .10; - - Chart chart = GenerateLineChart("V", pointGroups, chartMax, chartMin, "MM/dd", "0.00", "Voltage L-L", secondPercentileMaxLimit, firstPercentileMaxLimit, secondPercentileMinLimit, firstPercentileMinLimit, FirstOfMonth, EndOfMonth); - verticalMillimeters += 75; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - verticalMillimeters += 75; - - chart = GenerateBarChart("0", avg, maxValue, minValue); - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - return verticalMillimeters; - } - } - - private double InsertFlickerPage(Page page, double verticalMillimeters) - { - string historianServer = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1"; - string historianInstance = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA"; - Channel line1 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'FlkrPST') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'AN')", Meter.ID); - Channel line2 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'FlkrPST') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'BN')", Meter.ID); - Channel line3 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'FlkrPST') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'CN')", Meter.ID); - - if (line1 == null && line2 == null && line3 == null) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Flicker channels setup on this meter."); - Summary.Flicker.Compliance = "Pass"; - return verticalMillimeters; - } - - using (Historian historian = new Historian(historianServer, historianInstance)) - { - List points = historian.Read(new List() { line1.ID, line2.ID, line3.ID }, FirstOfMonth, EndOfMonth).Where(x => x.SeriesID == SeriesID.Maximum).ToList(); - - if (!points.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Flicker data during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - Summary.Flicker.Max = points.Max(point => point.Value); - - List maxLine1 = points - .Where(point => point.ChannelID == line1.ID) - .Select(point => point.Value) - .OrderByDescending(value => value) - .ToList(); - - List maxLine2 = points - .Where(point => point.ChannelID == line2.ID) - .Select(point => point.Value) - .OrderByDescending(value => value) - .ToList(); - - List maxLine3 = points - .Where(point => point.ChannelID == line3.ID) - .Select(point => point.Value) - .OrderByDescending(value => value) - .ToList(); - - double percentileMaxLimit = ReportsSettings.FlickerHighLimit; - - int percentileSkipCountLine1 = (int)(maxLine1.Count * (100.0D - ReportsSettings.FlickerPercentile) / 100.0D); - int percentileSkipCountLine2 = (int)(maxLine2.Count * (100.0D - ReportsSettings.FlickerPercentile) / 100.0D); - int percentileSkipCountLine3 = (int)(maxLine3.Count * (100.0D - ReportsSettings.FlickerPercentile) / 100.0D); - double percentileMaxLine1 = maxLine1.Skip(percentileSkipCountLine1).FirstOrDefault(); - double percentileMaxLine2 = maxLine2.Skip(percentileSkipCountLine2).FirstOrDefault(); - double percentileMaxLine3 = maxLine3.Skip(percentileSkipCountLine3).FirstOrDefault(); - - bool test = - percentileMaxLine1 <= percentileMaxLimit && - percentileMaxLine2 <= percentileMaxLimit && - percentileMaxLine3 <= percentileMaxLimit; - - Summary.Flicker.Compliance = (test ? "Pass" : "Fail"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Monthly PQ Report Requirement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.30); - col = new TlmColumnMM(tlm, "Measured L1 Plt", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L2 Plt", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L3 Plt", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Result", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.10); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.FlickerPercentile:0.###}% of the time: Plt <= {ReportsSettings.FlickerHighLimit:0.###}")); - tlm.Add(1, new RepString(textProp, $"{percentileMaxLine1:N2}")); - tlm.Add(2, new RepString(textProp, $"{percentileMaxLine2:N2}")); - tlm.Add(3, new RepString(textProp, $"{percentileMaxLine3:N2}")); - tlm.Add(4, new RepString(textProp, (test ? "Pass" : "Fail"))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - List pointGroups = new List(); - - pointGroups.Add(new PointGroup() - { - Name = "L1Max", - Color = Color.DarkBlue, - Data = points - .Where(point => point.ChannelID == line1.ID) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L2Max", - Color = Color.DarkGreen, - Data = points - .Where(point => point.ChannelID == line2.ID) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L3Max", - Color = Color.Purple, - Data = points - .Where(point => point.ChannelID == line3.ID) - .ToList() - }); - - double maxValue = points.Select(point => point.Value).Max(); - Chart chart = GenerateLineChart("", pointGroups, maxValue * 1.1, 0, "MM/dd", "0.00", "Flicker", ReportsSettings.FlickerHighLimit, null, null, null, FirstOfMonth, EndOfMonth); - verticalMillimeters += 75; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - verticalMillimeters += 75; - - chart = GenerateBarChart("0.00", points.Select(x => x.Value), maxValue, 0); - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - return verticalMillimeters; - } - } - - private double InsertImbalancePage(Page page, double verticalMillimeters) - { - string historianServer = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1"; - string historianInstance = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA"; - Channel channel = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'AvgImbal') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage')", Meter.ID); - - if (channel == null) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Imbalance channel setup on this meter."); - Summary.Imbalance.Compliance = "Pass"; - return verticalMillimeters; - } - - using (Historian historian = new Historian(historianServer, historianInstance)) - { - List points = historian.Read(new List() { channel.ID }, FirstOfMonth, EndOfMonth).Where(x => x.SeriesID == SeriesID.Average).ToList(); - - if (!points.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No Imbalance data during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - List avg = points - .Select(point => point.Value) - .OrderBy(value => value) - .ToList(); - - Summary.Imbalance.Avg = points.Select(point => point.Value).Average(); - - int percentileSkipCount = (int)(avg.Count * (100.0D - ReportsSettings.VoltageUnbalancePercentile) / 100.0D / 2.0D); - double percentileMinLimit = ReportsSettings.VoltageUnbalanceLowLimit; - double percentileMaxLimit = ReportsSettings.VoltageUnbalanceHighLimit; - double percentileMin = avg.Skip(percentileSkipCount).FirstOrDefault(); - double percentileMax = avg.AsEnumerable().Reverse().Skip(percentileSkipCount).FirstOrDefault(); - - bool test = - percentileMin >= percentileMinLimit && - percentileMax <= percentileMaxLimit; - - Summary.Imbalance.Compliance = (test ? "Pass" : "Fail"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Monthly PQ Report Requirement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.40); - col = new TlmColumnMM(tlm, "Measured Unbalance u2", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.40); - col = new TlmColumnMM(tlm, "Result", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.VoltageUnbalancePercentile:0.###}% of the time: {percentileMinLimit:0.###}% ~ {percentileMaxLimit:0.###}% u2")); - tlm.Add(1, new RepString(textProp, $"{percentileMax:N2}")); - tlm.Add(2, new RepString(textProp, (test ? "Pass" : "Fail"))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - List pointGroups = new List(); - - pointGroups.Add(new PointGroup() - { - Name = "Unbalance", - Color = Color.DarkBlue, - Data = points - }); - - Chart chart = GenerateLineChart("", pointGroups, Math.Max(percentileMax, percentileMaxLimit) * 1.1, Math.Min(percentileMin, percentileMinLimit), "MM/dd", "0.00", "Flicker", percentileMaxLimit, null, percentileMinLimit, null, FirstOfMonth, EndOfMonth); - verticalMillimeters += 75; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - verticalMillimeters += 75; - - chart = GenerateBarChart("0.00", avg, percentileMax, percentileMin); - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - return verticalMillimeters; - } - } - - private double InsertTHDPage(Page page, double verticalMillimeters) - { - string historianServer = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Server'") ?? "127.0.0.1"; - string historianInstance = Connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'Historian.Instance'") ?? "XDA"; - - Channel line1 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'TotalTHD') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'AN')", Meter.ID); - Channel line2 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'TotalTHD') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'BN')", Meter.ID); - Channel line3 = new TableOperations(Connection).QueryRecordWhere("MeterID = {0} AND MeasurementCharacteristicID = (SELECT ID FROM MeasurementCharacteristic WHERE Name = 'TotalTHD') AND MeasurementTypeID = (SELECT ID FROM MeasurementType WHERE Name = 'Voltage') AND PhaseID = (SELECT ID FROM Phase WHERE Name = 'CN')", Meter.ID); - - if (line1 == null && line2 == null && line3 == null) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No THD channels setup on this meter."); - Summary.THD.Compliance = "Pass"; - return verticalMillimeters; - } - - using (Historian historian = new Historian(historianServer, historianInstance)) - { - List points = historian.Read(new List() { line1.ID, line2.ID, line3.ID }, FirstOfMonth, EndOfMonth).ToList(); - - if (!points.Any()) - { - verticalMillimeters += InsertItalicText(page, verticalMillimeters, $" No THD data during {FirstOfMonth.ToString("MM/dd/yyyy")} - {EndOfMonth.ToString("MM/dd/yyyy")}"); - return verticalMillimeters; - } - - Summary.THD.Min = points.Where(point => point.SeriesID == SeriesID.Minimum).Select(point => point.Value).Min(); - Summary.THD.Avg = points.Where(point => point.SeriesID == SeriesID.Average).Select(point => point.Value).Average(); - Summary.THD.Max = points.Where(point => point.SeriesID == SeriesID.Maximum).Select(point => point.Value).Max(); - - List maxLine1 = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Maximum) - .Select(point => point.Value) - .OrderByDescending(value => value) - .ToList(); - - List maxLine2 = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Maximum) - .Select(point => point.Value) - .OrderByDescending(value => value) - .ToList(); - - List maxLine3 = points - .Where(point => point.ChannelID == line3.ID) - .Where(point => point.SeriesID == SeriesID.Maximum) - .Select(point => point.Value) - .OrderByDescending(value => value) - .ToList(); - - double percentileMaxLimit = ReportsSettings.VoltageTHDHighLimit; - - int percentileSkipCountLine1 = (int)(maxLine1.Count * (100.0D - ReportsSettings.VoltageTHDPercentile) / 100.0D); - int percentileSkipCountLine2 = (int)(maxLine2.Count * (100.0D - ReportsSettings.VoltageTHDPercentile) / 100.0D); - int percentileSkipCountLine3 = (int)(maxLine3.Count * (100.0D - ReportsSettings.VoltageTHDPercentile) / 100.0D); - double percentileMinLine1 = maxLine1.Last(); - double percentileMaxLine1 = maxLine1.Skip(percentileSkipCountLine1).FirstOrDefault(); - double percentileMinLine2 = maxLine2.Last(); - double percentileMaxLine2 = maxLine2.Skip(percentileSkipCountLine2).FirstOrDefault(); - double percentileMinLine3 = maxLine3.Last(); - double percentileMaxLine3 = maxLine3.Skip(percentileSkipCountLine3).FirstOrDefault(); - - bool test = - percentileMaxLine1 <= percentileMaxLimit && - percentileMaxLine2 <= percentileMaxLimit && - percentileMaxLine3 <= percentileMaxLimit; - - Summary.THD.Compliance = (test ? "Pass" : "Fail"); - - FontProp headerProp = new FontProp(FontDefinition, 0); - headerProp.rSizePoint = 10.0D; - using (TableLayoutManager tlm = new TableLayoutManager(headerProp)) - { - FontProp textProp = new FontProp(FontDefinition, 0); - textProp.rSizePoint = 8.0D; - tlm.tlmCellDef_Header.rAlignV = RepObj.rAlignCenter; // set vertical alignment of all header cells - tlm.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.LightGray); // set bottom line for all cells - tlm.tlmHeightMode = TlmHeightMode.AdjustLast; - tlm.eNewContainer += (oSender, ea) => page.AddMM(PageMarginMillimeters, verticalMillimeters, ea.container); - - // define columns - TlmColumn col; - col = new TlmColumnMM(tlm, "Monthly PQ Report Requirement", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.30); - col = new TlmColumnMM(tlm, "Measured L1 THD", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L2 THD", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Measured L3 THD", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.20); - col = new TlmColumnMM(tlm, "Result", (PageWidthMillimeters - 2 * PageMarginMillimeters) * 0.10); - - tlm.NewRow(); - tlm.Add(0, new RepString(textProp, $"{ReportsSettings.VoltageTHDPercentile:0.###}% of the time: THD <= {percentileMaxLimit:0.###}%")); - tlm.Add(1, new RepString(textProp, (maxLine1.Any() ? $"{percentileMinLine1:N2}% - {percentileMaxLine1:N2}%" : "No data for time period"))); - tlm.Add(2, new RepString(textProp, (maxLine2.Any() ? $"{percentileMinLine2:N2}% - {percentileMaxLine2:N2}%" : "No data for time period"))); - tlm.Add(3, new RepString(textProp, (maxLine3.Any() ? $"{percentileMinLine3:N2}% - {percentileMaxLine3:N2}%" : "No data for time period"))); - tlm.Add(4, new RepString(textProp, (test ? "Pass" : "Fail"))); - - tlm.Commit(); - - verticalMillimeters += tlm.rCurY_MM + 10; - } - - List pointGroups = new List(); - - pointGroups.Add(new PointGroup() - { - Name = "L1", - Color = Color.DarkBlue, - Data = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L2", - Color = Color.DarkGreen, - Data = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L3", - Color = Color.DarkMagenta, - Data = points - .Where(point => point.ChannelID == line3.ID) - .Where(point => point.SeriesID == SeriesID.Average) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L1-Max", - Color = Color.Blue, - Data = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Maximum) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L2-Max", - Color = Color.Green, - Data = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Maximum) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L3-Max", - Color = Color.Magenta, - Data = points - .Where(point => point.ChannelID == line3.ID) - .Where(point => point.SeriesID == SeriesID.Maximum) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L1-Min", - Color = Color.LightBlue, - Data = points - .Where(point => point.ChannelID == line1.ID) - .Where(point => point.SeriesID == SeriesID.Minimum) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L2-Min", - Color = Color.LightGreen, - Data = points - .Where(point => point.ChannelID == line2.ID) - .Where(point => point.SeriesID == SeriesID.Minimum) - .ToList() - }); - - pointGroups.Add(new PointGroup() - { - Name = "L3-Min", - Color = Color.LightPink, - Data = points - .Where(point => point.ChannelID == line3.ID) - .Where(point => point.SeriesID == SeriesID.Minimum) - .ToList() - }); - - double maxValue = points.Select(point => point.Value).Max(); - double minValue = points.Select(point => point.Value).Min(); - double chartHigh = (maxValue > 8 ? maxValue : 8); - double chartLow = (minValue < 0 ? minValue : 0); - double chartMax = chartHigh + (chartHigh - chartLow) * .10; - double chartMin = chartLow - (chartHigh - chartLow) * .10; - - Chart chart = GenerateLineChart("V", pointGroups, chartMax, chartMin, "MM/dd", "0.00", "Voltage L-L", percentileMaxLimit, null, null, null, FirstOfMonth, EndOfMonth); - verticalMillimeters += 75; - - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - verticalMillimeters += 75; - - chart = GenerateBarChart("0.00", points.Select(x => x.Value), maxValue, minValue); - page.AddMM(PageMarginMillimeters, verticalMillimeters, new RepImageMM(ChartToImage(chart), PageWidthMillimeters - 2 * PageMarginMillimeters, 75)); - - return verticalMillimeters; - } - } - - private Chart GenerateLineChart(string units, List pointsGroup, double max, double min, string xFormat, string yFormat, string title, double? highThreshold, double? highWarning, double? lowThreshold, double? lowWarning, DateTime start, DateTime end) - { - - Chart chart; - ChartArea area; - ChartSeries series; - area = new ChartArea(); - area.AxisX.MajorGrid.Enabled = false; - area.AxisX.LabelStyle.Format = xFormat; - area.AxisY.Title = units; - area.AxisY.LabelStyle.Format = yFormat; - area.AxisY.MajorGrid.LineColor = Color.LightGray; - area.AxisY.Maximum = max; - area.AxisY.Minimum = min; - - chart = new Chart(); - chart.Width = 1200; - chart.Height = 500; - chart.Name = title; - - chart.Legends.Add(new Legend()); - chart.ChartAreas.Add(area); - - foreach (var group in pointsGroup) - { - - series = new ChartSeries(group.Name); - series.ChartType = SeriesChartType.FastLine; - series.BorderWidth = 2; - series.Color = group.Color; - - foreach (var point in group.Data) - { - series.Points.AddXY(point.Timestamp, point.Value); - } - - chart.Series.Add(series); - } - - if (highThreshold.HasValue) - chart.Series.Add(MakeLimitSeries((double)highThreshold, Color.Red, "High Threshold", start, end)); - if (lowThreshold.HasValue) - chart.Series.Add(MakeLimitSeries((double)lowThreshold, Color.Red, "Low Threshold", start, end)); - if (highWarning.HasValue) - chart.Series.Add(MakeLimitSeries((double)highWarning, Color.Orange, "High Warning", start, end)); - if (lowWarning.HasValue) - chart.Series.Add(MakeLimitSeries((double)lowWarning, Color.Orange, "Low Warning", start, end)); - - return chart; - - } - - private Chart GenerateBarChart(string units, IEnumerable points, double max, double min) - { - ChartArea area = new ChartArea(); - area.AxisX.MajorGrid.Enabled = false; - area.AxisY.Enabled = AxisEnabled.False; - area.AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount; - area.AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont; - - Chart chart = new Chart(); - chart.Width = 1200; - chart.Height = 500; - chart.ChartAreas.Add(area); - - ChartSeries series = new ChartSeries("bars"); - series.ChartType = SeriesChartType.Column; - series.BorderWidth = 20; - series.Color = Color.DarkBlue; - - double step = (max - min) / NumBuckets; - - Dictionary buckets = Enumerable.Range(0, NumBuckets) - .GroupJoin(points, key => key, point => (int)((point - min) / step), (Key, grouping) => new { Key, Val = grouping.Count() }) - .ToDictionary(obj => (obj.Key * step + min).ToString(units), obj => obj.Val); - - foreach (var kvp in buckets) - series.Points.AddXY(kvp.Key, kvp.Value); - - chart.Series.Add(series); - - return chart; - } - - private Chart GenerateMagDurChart(List> events, string xFormat, string yFormat) - { - - Chart chart; - ChartArea area; - ChartSeries series; - area = new ChartArea(); - area.AxisX.MajorGrid.Enabled = false; - area.AxisX.LabelStyle.Format = xFormat; - area.AxisX.Maximum = 10; - area.AxisX.Minimum = 0.00001; - area.AxisX.IsLogarithmic = true; - area.AxisY.LabelStyle.Format = yFormat; - area.AxisY.MajorGrid.LineColor = Color.LightGray; - area.AxisY.Maximum = 6; - area.AxisY.Minimum = 0; - - chart = new Chart(); - chart.Width = 1000; - chart.Height = 1000; - chart.Name = "ITIC Curve (Interruptions, Sags, Swells)"; - chart.ChartAreas.Add(area); - - series = new ChartSeries("Points"); - series.ChartType = SeriesChartType.Point; - series.BorderWidth = 2; - series.Color = Color.DarkBlue; - - foreach (Tuple evt in events) - { - series.Points.AddXY(evt.Item1, evt.Item2); - } - - chart.Series.Add(series); - - series = new ChartSeries("ITIC Upper"); - series.ChartType = SeriesChartType.Line; - series.BorderWidth = 2; - series.Color = Color.Red; - - foreach (Tuple point in Curves.IticUpperCurve) - { - series.Points.AddXY(point.Item1, point.Item2); - } - - chart.Series.Add(series); - - series = new ChartSeries("ITIC Lower"); - series.ChartType = SeriesChartType.Line; - series.BorderWidth = 2; - series.Color = Color.Red; - - foreach (Tuple point in Curves.IticLowerCurve) - { - series.Points.AddXY(point.Item1, point.Item2); - } - - chart.Series.Add(series); - - return chart; - - } - - private ChartSeries MakeLimitSeries(double value, Color color, string name, DateTime start, DateTime end) - { - ChartSeries cs = new ChartSeries(name); - cs.ChartType = SeriesChartType.FastLine; - cs.BorderWidth = 1; - - cs.Color = color; - cs.Points.AddXY(start, value); - cs.Points.AddXY(end, value); - return cs; - } - - private Stream ChartToImage(Chart chart) - { - MemoryStream stream = new MemoryStream(); - chart.SaveImage(stream, ChartImageFormat.Jpeg); - stream.Position = 0; - return stream; - } - - #endregion - - #region [ Static ] - - private static readonly ILog Log = LogManager.GetLogger(typeof(PQReport)); - - #endregion - } -} diff --git a/Libraries/openXDA.Reports/Properties/AssemblyInfo.cs b/Libraries/openXDA.Reports/Properties/AssemblyInfo.cs deleted file mode 100644 index 46f31e06..00000000 --- a/Libraries/openXDA.Reports/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("openXDA.Reports")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("openXDA.Reports")] -[assembly: AssemblyCopyright("Copyright © 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("656f97d9-4fb6-4f65-a9a6-1a1dde3af634")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyVersion("3.0.5.93")] -[assembly: AssemblyFileVersion("3.0.5.93")] diff --git a/Libraries/openXDA.Reports/README.md b/Libraries/openXDA.Reports/README.md deleted file mode 100644 index 02165864..00000000 --- a/Libraries/openXDA.Reports/README.md +++ /dev/null @@ -1,7 +0,0 @@ -![Icon](http://www.gridprotectionalliance.org/images/products/icons%2064/openXDA.png)![openXDA](http://www.gridprotectionalliance.org/images/products/productTitles32/PQSiteReport.png) - -**eXtensible Disturbance Analytics PQ Site Report** - -# Overview -The OpenXDA PQ Site Report was developed to provide the OpenXDA service with a monthly reporting feature that will build and distribute a per meter pdf trending data report -each month that shows if there have been any compliance issues with regards to Voltage and THD. diff --git a/Libraries/openXDA.Reports/ReportsEngine.cs b/Libraries/openXDA.Reports/ReportsEngine.cs deleted file mode 100644 index b0d7f831..00000000 --- a/Libraries/openXDA.Reports/ReportsEngine.cs +++ /dev/null @@ -1,382 +0,0 @@ -//****************************************************************************************************** -// ReportsEngine.cs - Gbtc -// -// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. -// -// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See -// the NOTICE file distributed with this work for additional information regarding copyright ownership. -// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this -// file except in compliance with the License. You may obtain a copy of the License at: -// -// http://opensource.org/licenses/MIT -// -// Unless agreed to in writing, the subject software distributed under the License is distributed on an -// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the -// License for the specific language governing permissions and limitations. -// -// Code Modification History: -// ---------------------------------------------------------------------------------------------------- -// 06/14/2018 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Configuration; -using System.Data; -using System.IO; -using System.Linq; -using System.Net.Mail; -using System.Text; -using Gemstone; -using Gemstone.Configuration; -using Gemstone.Data; -using Gemstone.Data.Model; -using Gemstone.Scheduling; -using log4net; -using openXDA.Configuration; -using openXDA.Model; - -namespace openXDA.Reports -{ - public class ReportsEngine : IDisposable - { - #region [ Members ] - private bool m_disposed; - - #endregion - - #region [ Constructors ] - - public ReportsEngine() - { - PQReportsSettings = new PQReportsSettings(); - EmailSettings = new EmailSection(); - BreakerReportsSettings = new BreakerReportsSettings(); - - Scheduler = new ScheduleManager(); - Scheduler.Starting += Scheduler_Starting; - Scheduler.Started += Scheduler_Started; - Scheduler.ScheduleDue += Scheduler_ScheduleDue; - } - - #endregion - - #region [ Properties ] - - private ScheduleManager Scheduler { get; } - - public bool Running { get; private set; } - - [Category] - [SettingName(PQReportsSettings.CategoryName)] - public PQReportsSettings PQReportsSettings { get; } - - [Category] - [SettingName(BreakerReportsSettings.CategoryName)] - public BreakerReportsSettings BreakerReportsSettings { get; } - - [Category] - [SettingName(EmailSection.CategoryName)] - public EmailSection EmailSettings { get; } - - #endregion - - #region [ Methods ] - - public void ProcessMonthlyReport(Meter meter, DateTime month) - { - DateTime firstOfMonth = month.AddDays(1 - month.Day); - DateTime endOfMonth = firstOfMonth.AddMonths(1).AddDays(-1); - - using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) - { - ProcessMonthlyReport(meter, firstOfMonth, endOfMonth, connection); - } - } - - public bool Start() - { - try - { - if (!Running) - { - bool scheduled = false; - - if (PQReportsSettings.Enabled) { - Scheduler.AddSchedule("PQReports", PQReportsSettings.Schedule); - scheduled = true; - } - if (BreakerReportsSettings.Enabled) - { - Scheduler.AddSchedule("BreakerReports", PQReportsSettings.Schedule); - scheduled = true; - } - - if (scheduled) - { - Scheduler.Start(); - Running = true; - } - } - - return true; - } - catch (Exception ex) - { - Log.Error(ex.ToString(), ex); - return false; - } - } - - public void Stop() - { - if (Scheduler.IsRunning) - { - bool scheduled1 = false; - bool scheduled2 = false; - - if (!PQReportsSettings.Enabled) - scheduled1 = Scheduler.RemoveSchedule("PQReports"); - if (!BreakerReportsSettings.Enabled) - scheduled2 = Scheduler.RemoveSchedule("BreakerReports"); - - if (scheduled1 && scheduled2 ) - { - Scheduler.Stop(); - Running = false; - } - } - } - - public void Dispose() - { - if (m_disposed) - return; - - Scheduler.Starting -= Scheduler_Starting; - Scheduler.Started -= Scheduler_Started; - Scheduler.ScheduleDue -= Scheduler_ScheduleDue; - Scheduler.Dispose(); - - m_disposed = true; - } - - public void ReloadSystemSettings(string connectionString) - { - ConnectionStringParser.ParseConnectionString(connectionString, this); - - Scheduler.AddSchedule("PQReports", PQReportsSettings.Schedule, true); - Scheduler.AddSchedule("BreakerReports", BreakerReportsSettings.Schedule, true); - - if (PQReportsSettings.Enabled || BreakerReportsSettings.Enabled) - Start(); - else if (!PQReportsSettings.Enabled || !BreakerReportsSettings.Enabled) - Stop(); - - } - - private void Scheduler_Starting(object sender, EventArgs e) - { - } - - private void Scheduler_Started(object sender, EventArgs e) - { - Log.Info("Reports Engine has started successfully..."); - } - - private void Scheduler_Disposed(object sender, EventArgs e) - { - Log.Info("Reports Engine is disposed..."); - } - - private void Scheduler_ScheduleDue(object sender, EventArgs e) - { - Log.Info(string.Format($"Processing {e.Argument.Name}...")); - if (e.Argument.Name == "PQReports") - ProcessPQReports(); - else if (e.Argument.Name == "BreakerReports") - ProcessBreakerReports(); - } - - private void ProcessBreakerReports() { - DateTime today = DateTime.Now; - DateTime firstOfMonth = today.AddDays(1 - today.Day).AddMonths(-1); - DateTime endOfMonth = firstOfMonth.AddMonths(1).AddDays(-1); - - AllBreakersReport report = new AllBreakersReport(firstOfMonth, endOfMonth); - byte[] pdf = report.CreatePDF(); - if (pdf == null) return; - byte[] csv = ExportAllToCSV(report.DataTable, firstOfMonth, endOfMonth); - if (csv == null) return; - - using (MemoryStream pdfStream = new MemoryStream(pdf)) - using (MemoryStream csvStream = new MemoryStream(csv)) - { - string fileName = "AllBreakersReport_" + firstOfMonth.ToString("MM_dd_yyyy") + "_" + endOfMonth.ToString("MM_dd_yyyy"); - string pdfContentType = "application/pdf"; - string csvContentType = "text/csv"; - string pdfName = fileName + ".pdf"; - string csvName = fileName + ".csv"; - - List attachments = new List() { - new Attachment(pdfStream, pdfName, pdfContentType), - new Attachment(csvStream, csvName, csvContentType) - }; - - EmailWriter emailWriter = new EmailWriter(PQReportsSettings, EmailSettings); - emailWriter.SendEmailWithAttachment(BreakerReportsSettings.EmailList.Split(',').ToList(), $"Breaker Report for {fileName}", "", attachments); - - } - - } - - private void ProcessPQReports() - { - DateTime today = DateTime.Now; - DateTime firstOfMonth = today.AddDays(1 - today.Day).AddMonths(-1); - DateTime endOfMonth = firstOfMonth.AddMonths(1).AddDays(-1); - - using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) - { - // TODO: There is no EmailGroupAssetGroup - IEnumerable meters = new TableOperations(connection).QueryRecordsWhere("ID IN (SELECT MeterID FROM MeterAssetGroup WHERE AssetGroupID IN (SELECT AssetGroupID FROM EmailGroupAssetGroup WHERE EmailGroupID = (SELECT ID FROM EmailGroup WHERE Name = 'PQ Report')))"); - - foreach (Meter meter in meters) - ProcessMonthlyReport(meter, firstOfMonth, endOfMonth, connection); - - EmailWriter emailWriter = new EmailWriter(PQReportsSettings, EmailSettings); - emailWriter.Execute(firstOfMonth.Month, firstOfMonth.Year); - } - } - - private void ProcessMonthlyReport(Meter meter, DateTime firstOfMonth, DateTime endOfMonth, AdoDataConnection connection) - { - Log.Info($"Starting monthly Report for {meter.Name}..."); - PQReport pQReport = new PQReport(PQReportsSettings, meter, firstOfMonth, endOfMonth, connection); - byte[] pdf = pQReport.createPDF(); - Log.Info($"Completed monthly Report for {meter.Name}"); - - try - { - TableOperations to = new TableOperations(connection); - Report report = to.QueryRecordWhere("MeterID = {0} AND Month = {1} AND Year = {2}", meter.ID, firstOfMonth.Month, firstOfMonth.Year); - - if (report != null) - { - report.MeterID = meter.ID; - report.Month = firstOfMonth.Month; - report.Year = firstOfMonth.Year; - report.Results = pQReport.Result; - report.PDF = pdf; - - to.UpdateRecord(report); - } - else - { - to.AddNewRecord(new Report() - { - MeterID = meter.ID, - Month = firstOfMonth.Month, - Year = firstOfMonth.Year, - Results = pQReport.Result, - PDF = pdf - }); - } - - Log.Info($"Loaded monthly Report for {meter.Name}"); - } - catch (Exception ex) - { - Log.Error(ex.ToString(), ex); - } - } - - public string GetHelpMessage(string command) - { - StringBuilder helpMessage = new StringBuilder(); - - helpMessage.Append("Processes the month PQ Reports"); - helpMessage.AppendLine(); - helpMessage.AppendLine(); - helpMessage.Append(" Usage:"); - helpMessage.AppendLine(); - helpMessage.Append(" " + command); - helpMessage.AppendLine(); - helpMessage.Append(" " + command + " -?"); - helpMessage.AppendLine(); - helpMessage.AppendLine(); - helpMessage.Append(" Options:"); - helpMessage.AppendLine(); - helpMessage.Append(" -?".PadRight(25)); - helpMessage.Append("Displays this help message"); - - return helpMessage.ToString(); - } - - private DateTime GetPreviousMatch(Schedule schedule, DateTime now) - { - bool match = false; - - while (!match) - { - now = now.AddMinutes(-1); - - match = schedule.MinutePart.Matches(now); - match &= schedule.HourPart.Matches(now); - match &= schedule.DayPart.Matches(now); - match &= schedule.MonthPart.Matches(now); - match &= schedule.DaysOfWeekPart.Matches(now); - } - - return now; - } - - public void ProcessBreakerReportCommand() { - ProcessBreakerReports(); - } - - public byte[] ExportAllToCSV(DataTable table, DateTime fromDate, DateTime toDate) - { - if (table.Rows.Count == 0) return null; - - using (MemoryStream ms = new MemoryStream()) - using (StreamWriter writer = new StreamWriter(ms)) - { - // Write the CSV header to the file - writer.WriteLine(GetCSVHeader(table)); - - // Write data to the file - foreach (DataRow row in table.Rows) - writer.WriteLine(ToCSV(table, row)); - - return ms.ToArray(); - } - } - - // Converts the data group row of CSV data. - private string ToCSV(DataTable table, DataRow row) - { - IEnumerable columns = table.Columns.Cast().Select(x => "\"" + row[x.ColumnName] + "\""); - return string.Join(",", columns); - } - - // Converts the data group row of CSV data. - private string GetCSVHeader(DataTable table) - { - IEnumerable headers = table.Columns.Cast().Select(x => "\"" + x.ColumnName + "\""); - return string.Join(",", headers); - } - - #endregion - - #region [ Static ] - - private static readonly ILog Log = LogManager.GetLogger(typeof(ReportsEngine)); - private static readonly ConnectionStringParser ConnectionStringParser = new ConnectionStringParser(); - - #endregion - } -} diff --git a/Libraries/openXDA.Reports/openXDA.Reports.csproj b/Libraries/openXDA.Reports/openXDA.Reports.csproj deleted file mode 100644 index 239e67eb..00000000 --- a/Libraries/openXDA.Reports/openXDA.Reports.csproj +++ /dev/null @@ -1,52 +0,0 @@ - - - - Debug - AnyCPU - net9.0-windows - Library - true - openXDA.Reports - openXDA.Reports - false - Debug;Development;Release - - - true - full - false - ..\..\..\Build\Output\Debug\Libraries\ - DEBUG;TRACE - prompt - 4 - - - true - full - false - ..\..\..\Build\Output\Debug\Libraries\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\..\Build\Output\Release\Libraries\ - TRACE - prompt - 4 - - - - - - - - - - - - - - diff --git a/SEBrowser-dev.slnx b/SEBrowser-dev.slnx index ab2cbf62..53018827 100644 --- a/SEBrowser-dev.slnx +++ b/SEBrowser-dev.slnx @@ -5,16 +5,6 @@ - - - - - - - - - - diff --git a/SEBrowser/EventWidgets b/SEBrowser/EventWidgets index 8203aa8e..b414a37c 160000 --- a/SEBrowser/EventWidgets +++ b/SEBrowser/EventWidgets @@ -1 +1 @@ -Subproject commit 8203aa8eb88900156f81ec4df027f8bee1d0b460 +Subproject commit b414a37c073460c6a0f7471ade180fc7bd768794 diff --git a/SEBrowser/SEBrowser.csproj b/SEBrowser/SEBrowser.csproj index b1484c53..43a6dc5d 100644 --- a/SEBrowser/SEBrowser.csproj +++ b/SEBrowser/SEBrowser.csproj @@ -37,10 +37,15 @@ True True - - - - + + + + True + True + + + + @@ -50,11 +55,21 @@ - - - - - + + ..\Dependencies\OpenXDA\openXDA.APIAuthentication.dll + + + ..\Dependencies\OpenXDA\FaultAlgorithms.dll + + + ..\Dependencies\OpenXDA\FaultData.dll + + + ..\Dependencies\OpenXDA\openXDA.Model.dll + + + ..\Dependencies\OpenXDA\openXDA.PQI.dll +