コード例 #1
0
        public static void ProgrammaticAnalysisRecalculation(PISystem system, AFDatabase database, AFCategory category)
        {
            // we start by generating timestamps we want to recalculate
            // we could get them from existing recorded values, etc...
            //
            // here we simply generate yesterdays hourly values ...
            var recalculationTimeStamps = new List <AFTime>();

            for (int i = 0; i < 24; i++)
            {
                recalculationTimeStamps.Add(new AFTime(DateTime.Today.Subtract(TimeSpan.FromDays(1)) + TimeSpan.FromDays(i) + TimeSpan.FromSeconds(2)));
            }


            AFNamedCollectionList <AFAnalysis> analysislist;

            analysislist = AFAnalysis.FindAnalyses(database, null, null, null, category, null, null, AFStatus.None, AFSortField.ID, AFSortOrder.Ascending, 0, 1000);
            Console.WriteLine(category.Name);
            Console.WriteLine(analysislist.Count);

            foreach (var afAnalysis in analysislist)
            {
                // we recalculate results
                var results = Calculate(afAnalysis, recalculationTimeStamps);

                // we could delete values here, but I simply replce them instead

                // we insert our new values
                AFListData.UpdateValues(results, AFUpdateOption.Replace);
            }
        }
コード例 #2
0
        private void WriteData()
        {
            List <AFValue> values;
            var            allValues = new List <AFValue>();


            // gets all currently available values from the queue
            while (SharedData.DataWriterQueue.TryDequeue(out values))
            {
                if (values != null)
                {
                    allValues.AddRange(values);
                }
            }

            // writes data only if there is data
            if (allValues.Count != 0)
            {
                _logger.InfoFormat("Sorting and writing {0} values.", allValues.Count);
                // writing into PI : we sort all the values per timestamp, that will make life easier for the PI Server
                allValues.Sort();
                AFListData.UpdateValues(allValues, AFUpdateOption.NoReplace, AFBufferOption.BufferIfPossible);

                // clear the values
                allValues.Clear();

                _logger.InfoFormat("Write completed. Waiting for new data.");
            }
        }
コード例 #3
0
        public void UpdateValues(AFValues cityValues)
        {
            AFErrors <AFValue> errors = AFListData.UpdateValues(cityValues, AFUpdateOption.NoReplace);

            if ((errors != null) && (errors.HasErrors))
            {
                log.Error(errors.Errors.First().Value.Message);
            }
        }
コード例 #4
0
        public static void SwapValues(AFDatabase database, string meter1, string meter2, string startTime, string endTime)
        {
            Console.WriteLine(string.Format("Swap values for meters: {0}, {1} between {2} and {3}", meter1, meter2, startTime, endTime));

            // NOTE: This method does not ensure that there is no data loss if there is failure.
            // Persist the data first in case you need to rollback.
            AFAttribute attr1 = AFAttribute.FindAttribute(@"\Meters\" + meter1 + @"|Energy Usage", database);
            AFAttribute attr2 = AFAttribute.FindAttribute(@"\Meters\" + meter2 + @"|Energy Usage", database);

            AFTime      start     = new AFTime(startTime);
            AFTime      end       = new AFTime(endTime);
            AFTimeRange timeRange = new AFTimeRange(start, end);

            // Get values to delete for meter1
            AFValues valsToRemove1 = attr1.Data.RecordedValues(
                timeRange: timeRange,
                boundaryType: AFBoundaryType.Inside,
                desiredUOM: null,
                filterExpression: null,
                includeFilteredValues: false);

            // Get values to delete for meter2
            AFValues valsToRemove2 = attr2.Data.RecordedValues(
                timeRange: timeRange,
                boundaryType: AFBoundaryType.Inside,
                desiredUOM: null,
                filterExpression: null,
                includeFilteredValues: false);

            if (valsToRemove1.Count == 0 && valsToRemove2.Count == 0)
            {
                throw new Exception("There are no values to swap.");
            }

            List <AFValue> valsToRemove = valsToRemove1.ToList();

            valsToRemove.AddRange(valsToRemove2.ToList());

            // Remove the values
            AFListData.UpdateValues(valsToRemove, AFUpdateOption.Remove);

            // Create new AFValues from the other meter and assign them to this meter
            List <AFValue> valsToAdd1 = valsToRemove2.Select(v => new AFValue(attr1, v.Value, v.Timestamp)).ToList();
            List <AFValue> valsToAdd2 = valsToRemove1.Select(v => new AFValue(attr2, v.Value, v.Timestamp)).ToList();

            List <AFValue> valsCombined = valsToAdd1;

            valsCombined.AddRange(valsToAdd2);

            AFListData.UpdateValues(valsCombined, AFUpdateOption.Insert);
            Console.WriteLine();
        }
コード例 #5
0
        private void WriteData(CancellationToken cancelToken, int writingDelay, string resultsToFile)
        {
            List <AFValue> values;
            var            allValues = new List <AFValue>();

            while (true)
            {
                if (cancelToken.IsCancellationRequested)
                {
                    return;
                }

                // gets currently available values from the queue
                while (DataQueue.TryDequeue(out values))
                {
                    allValues.AddRange(values);
                }

                // we go into writing data only if there is data
                if (allValues.Count != 0)
                {
                    _logger.InfoFormat("Data Writer is sorting {0} values to be written", allValues.Count);


                    _logger.InfoFormat("Data Writer values sorting completed. Now Writing...");

                    if (string.IsNullOrEmpty(resultsToFile))
                    {
                        // writing into PI : we sort all the values per timestamp, that will make life easier for the PI Server
                        allValues.Sort();
                        AFListData.UpdateValues(allValues, AFUpdateOption.Replace, AFBufferOption.BufferIfPossible);
                    }
                    else
                    {
                        // writing into a text file: we sort by tagname, then by timestamp.  For readability.
                        // This is a way to check calculation results
                        var sortedvalues = allValues.OrderBy(a => a.PIPoint.Name).ThenBy(a => a.Timestamp).ToList();
                        File.WriteAllLines(resultsToFile + "_" + DateTime.Now.ToIsoReadable() + ".csv", sortedvalues.Select((v) => v.Timestamp.LocalTime.ToIsoReadable() + "," + v.Value + "," + v.Attribute.PIPoint.Name + "," + v.Attribute.Name));
                    }


                    // after values are written, we dont need them anymore
                    allValues.Clear();

                    _logger.InfoFormat("Writing completed, sleeping for now...");
                }

                Thread.Sleep(TimeSpan.FromSeconds(writingDelay));
            }
        }
コード例 #6
0
        public void Flush()
        {
            var sw = Stopwatch.StartNew();

            int numValuesWritten           = 0;
            AFErrors <AFValue> writeErrors = null;

            try
            {
                // Write results with "Replace" mode. Ideally you would first want to delete existing data and then publish new results, in order to make sure we don't end up with mixed old & new events.
                writeErrors       = AFListData.UpdateValues(_values, AFUpdateOption.Replace);
                numValuesWritten += _values.Count;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to publish outputs using bulk call. {0}", ex.Message);
                return;
            }
            finally
            {
                _values.Clear();
            }

            if (!ReferenceEquals(writeErrors, null) && writeErrors.HasErrors)
            {
                foreach (var afError in writeErrors.PISystemErrors)
                {
                    Console.WriteLine("Error while writing outputs to AF Server {0}. {1}", afError.Key, afError.Value.Message);
                }

                foreach (var piError in writeErrors.PIServerErrors)
                {
                    Console.WriteLine("Error while writing outputs to Data archive {0}. {1}", piError.Key, piError.Value.Message);
                }

                if (writeErrors.Errors.Count > 0)
                {
                    numValuesWritten -= writeErrors.Errors.Count;
                    Console.WriteLine("{0} Errors when publishing output results.", writeErrors.Errors.Count);
                    foreach (var error in writeErrors.Errors)
                    {
                        Console.WriteLine("/t{0}: {1}", error.Key.Attribute.Name, error.Value.Message);
                    }
                }
            }

            Console.WriteLine("Published {0} values. ({1} ms)", numValuesWritten, sw.ElapsedMilliseconds);
        }
コード例 #7
0
        public void Run()
        {
            PISystems piSystems = new PISystems();
            PISystem  piSystem  = piSystems["<AFSERVER>"];

            AFDatabase afDatabase = piSystem.Databases["Basic-AFSDK-Sample"];

            AFElement boilerA = afDatabase.Elements["Region_0"].Elements["BoilerA"];

            AFElementTemplate   elementTemplate         = afDatabase.ElementTemplates["BasicBoilerTemplate"];
            AFAttributeTemplate temperatureAttrTemplate = elementTemplate.AttributeTemplates["Temperature"];
            AFAttributeTemplate modeAttrTemplate        = elementTemplate.AttributeTemplates["Mode"];

            AFElement.LoadAttributes(new[] { boilerA }, new[] { temperatureAttrTemplate, modeAttrTemplate });

            AFEnumerationSet digSet = afDatabase.EnumerationSets["Modes"];

            IList <AFValue> valuesToWrite = new List <AFValue>();

            for (int i = 0; i < 10; i++)
            {
                AFTime time = new AFTime(new DateTime(2015, 1, 1, i, 0, 0, DateTimeKind.Local));

                AFValue afValueFloat = new AFValue(i, time);
                // Associate the AFValue to an attribute so we know where to write to.
                afValueFloat.Attribute = boilerA.Attributes["Temperature"];

                AFEnumerationValue digSetValue    = i % 2 == 0 ? digSet["Auto"] : digSet["Manual"];
                AFValue            afValueDigital = new AFValue(digSetValue, time);
                afValueDigital.Attribute = boilerA.Attributes["Mode"];

                valuesToWrite.Add(afValueFloat);
                valuesToWrite.Add(afValueDigital);
            }

            // Perform a bulk write. Use a single local call to PI Buffer Subsystem if possible.
            // Otherwise, make a single call to the PI Data Archive.
            // We use no compression just so we can check all the values are written.
            // AFListData is the class that provides the bulk write method.
            AFListData.UpdateValues(valuesToWrite, AFUpdateOption.InsertNoCompression, AFBufferOption.BufferIfPossible);
        }