Обработка архивов

<< Click to Display Table of Contents >>

Navigation:  Проект > Элементы дерева объектов > Палитра ФБ > Служебные > Скрипт > Руководство и примеры > Работа с архивом данных >

Обработка архивов

Теперь рассмотрим обратную ситуацию - архив необходимо прочитать и как-либо обработать. Можно использовать для решения данной задачи штатный функционал MasterSCADA - функции работы с архивом модуля Расчет, а также тренды или редактор отчетов. Однако если требуется сложный алгоритм обработки данных - например найти максимум за какой-то интервал времени, найти значение превышающее заданное, определенное значение на интервале и т.д., то в этом случае следует использовать скрипт.

В качестве примера напишем скрипт, который будет производить поиск максимального значения за заданный интервал времени, и выдавать на выход значение и его метку времени.

Сначала подготовим необходимые для отладки компоненты. Добавим в объект команду, включим у нее архивацию и наполним ее данными - введем  в нее значения вручную. Например, получится вот такой набор данных:

sluzhebnie_skript_rukovodstvo_i_primery_obrabotka_arhivov1

Теперь добавим в дерево скрипт и добавим в него Вход - на него будет поступать сигнал с нашей команды, входы времени Начало и Конец - за этот интервал мы будем искать максимум, логический вход Найти, и два выхода - Значение и МеткаВремени, в которые мы выведем результат.

sluzhebnie_skript_rukovodstvo_i_primery_obrabotka_arhivov2

Установим связь между Команда 1 и Вход.

Поиск мы будем выполнять по переднему фронту входа Найти. Также нужно убедится что Начало и Конец имеют значения, и Конец больше чем Начало.

bool? M = false;
public override void Execute()
{
    if (Найти == true && M == false && Начало.HasValue && Конец.HasValue && Начало < Конец)
    {
    }
    M = Найти;
}

Теперь можно приступить к чтению архива из входа. Можно получить переменную как мы делали при переборе переменных на прошлом шаге, но если нас интересует вход скрипта, то можно воспользоваться методом:

var elem = HostFB.InputGroup.GetPin("Вход").TreePinHlp;

Теперь мы можем обратится к архиву переменной, который находится в свойстве DataArchiveItem.

var arch=elem.DataArchiveItem;

Теперь у нас есть переменная arch, которая содержит все методы для выборки архива.

Теперь объявим локальные переменные для поиска - StartTime и EndTime.

DateTime EndTime=Конец.Value.ToUniversalTime();
DateTime StartTime=Начало.Value.ToUniversalTime();

Ранее мы уже упоминали, что архив в MasterSCADA хранится в формате UTC, поэтому и при обращении к нему нужно использовать время UTC. Поэтому мы приводим значения на входа Начало и Конец к UTC, с помощью метода ToUniversalTime().

Теперь выполним выборку из архива:

var mas=arch.Read(StartTime, EndTime, false);

У переменной arch (которая является классом архива входа), вызывается метод Read – чтение архива, в качестве аргумента ему передается время начала, конца и флаг необходимости чтения граничных данных (то есть нужно ли вернуть значения на границе заданного диапазона). Метод вернет PinValue[] – это массив класса PinValue, то есть набор состояний входа и всех его атрибутов (значение, метка времени, признак качества).

Теперь обработаем архив:

var mas = k.Read(StartTime, EndTime, false);
double? Val = null;
DateTime? TimeStamp = null;
foreach (var element in mas)
{
    if (Val.HasValue == false || Convert.ToDouble(element.Value) > Val.Value)
    {
        Val = Convert.ToDouble(element.Value);
        TimeStamp = element.Time.ToLocalTime();
    }
}
Значение = Val;
МеткаВремени = TimeStamp;

Вначале объявим переменную Val – типа Double(Nullable) и переменную TimeStamp типа DateTime(Nullable), эти переменные и получат значение и метку времени найденного максимума.

Затем перебираем переменные в цикле foreach, который каждое значение поочередно кладет в переменную element, которая имеет тип PinValue. После мы проверяем, если значение Val пустое и равно null, то мы сохраняем его значение и метку времени. Аналогично мы делаем если значение есть, но новое значение больше сохраненного. Затем выводим результат.

Итоговый код будет выглядеть следующим образом.

public partial class ФБ : ScriptBase
{
 bool? M = false;
 public override void Execute()
 {
  if (Найти == true && M == false && Начало.HasValue && Конец.HasValue && Начало < Конец)
  {
   var elem = HostFB.InputGroup.GetPin("Вход").TreePinHlp;
   var k = elem.DataArchiveItem;
   DateTime EndTime = Конец.Value.ToUniversalTime();
   DateTime StartTime = Начало.Value.ToUniversalTime();
   var mas = k.Read(StartTime, EndTime, false);
   double? Val = null;
   DateTime? TimeStamp = null;
   foreach (var element in mas)
   {
    if (Val.HasValue == false || Convert.ToDouble(element.Value) > Val.Value)
    {
     Val = Convert.ToDouble(element.Value);
     TimeStamp = element.Time.ToLocalTime();
    }
   }
   Значение = Val;
   МеткаВремени = TimeStamp;
  }
  M = Найти;
 }
}

Данный код легко адаптировать под любую другую задачу - исправить код в цикле foreach, согласно вашей задаче.

Проверим работу скрипта. Запустим режим исполнения, зададим Начало и Конец и запустим поиск.

sluzhebnie_skript_rukovodstvo_i_primery_obrabotka_arhivov

Будет выведено максимальное значение и метка его времени.

Готовый скрипт можно скачать по ссылке.

Однако у данного скрипта есть одна проблема - его можно использовать только в проектах с файловым архивом, и на небольших выборках. Если же используется БД (особенно удаленная), или нужно делать большие и частые выборки в автоматическом режиме, то необходимо сделать асинхронный запрос - подробнее в следующем шаге.