РЕЖИМ РАБОТЫ:  9.00 - 18.00 ПН - ПТ +7(495) 989-22-49 info@insat.ru

ФБ «Скрипт C#» и его использование в MasterSCADA. Генерация архива

ФБ «Скрипт C#» и его использование в MasterSCADA. Генерация архива

В предыдущем примере мы рассмотрели задачу чтения архива и его анализа. Теперь рассмотрим решение обратной задачи – генерации архива с собственными метками времени.
Генерация архива средствами скрипта может потребоваться в различных ситуациях, но чаще всего это требуется если необходимо обрабатывать внешние архивные источники данных – файлы или базы данных. В качестве примера рассмотрим чтение архива из CSV файла.

Допустим у нас существует CSV файл, из которого нужно периодически (по сигналу) выполнять считывание данных с последующей записью в архив. CSV файл состоит из 6 столбцов – метки времени в формате Дата-Время, и 5 вещественных значений, поля разделены символом «точка с запятой».
Добавим скрипт, и добавим в него 2 входа – «Считать» и «Имя файла», а также 5 выходов «Параметр1» .. «Параметр5».
Что данные сохранялись нужно настроить архивацию у выходов. При этом для такого способа формирования архива лучше использовать периодическую архивацию с шагом в 00:00:00 – при таком способе будут записываться все значения, которые будут поступать из кода, а при остановке скады не будет формироваться значение с признаком Норма-Останов. Включим данный способ архивации у каждого выхода.
Приступим к написанию кода. Для чтения файла мы будем использовать класс StreamReader – данный класс позволяет считывать символы из потока байтов в заданной кодировки. Для того чтобы данный класс был доступен в коде нужно в секции using объявить класс:
using System.IO;


Приступим написанию кода. В секции класса объявим переменную M, в которую будем сохранять значение входа «Считать» - для выполнения кода по переднему фронту на входе. Также перед тем как выполнять код нужно убедится, что задан путь файла. Для этого проверим его на значение Null, а также убедимся, что имя не пустое – для этого нужно сравнить ее со свойством string.Empty или просто с пустой строкой - "".
public partial class ФБ : ScriptBase
{
bool? M=false;
    public override void Execute()
    {
    if (Считать==true && M==false && Файл!=string.Empty && Файл!=null)
        {    
   
}
    M=Считать;
    }
}


Для того чтобы открыть файл на чтение, создадим класс StreamReader. При создании класса вызывается его конструктор (метод который позволяет инициализировать параметры класса). Конструкторов у данного класса несколько (так называемый перегруженный конструктор). Мы вызовем конструктор с одним параметром – именем файла. Описание данного конструктора можно прочитать здесь:
https://msdn.microsoft.com/ru-ru/library/f2ke0fzy(v=vs.110).aspx
Поскольку у нас файл содержит только цифры и несколько символов, такого вызова будет достаточно. Однако если читать файл, содержащий символы (особенно кириллические), то следует вызывать метод с тремя аргументами – именем, кодировкой и флагом обнаружения порядка байта:
https://msdn.microsoft.com/ru-ru/library/ms143457(v=vs.110).aspx

При этом класс StreamReader мы вызовем через оператор using(не путайте с директивой using). Данный оператор предназначен для работы с неуправляемыми ресурсами – файлами, SQL соединениями и т.д. Вызов через данный оператор гарантирует очищение памяти после выполнения кода.
using(var file = new StreamReader(Файл)) //открытие файла для чтения
 {
     //здесь мы разместим код чтения файла
 }


Итак, у нас создана переменная file, которую мы будем использовать для работы с нашим файлом. Файл состоит из строк, нам необходимо построчно считывать его, разбирать строку на компоненты (метка времени и значения) и записывать на выходы.
Для считывания строки используется метод ReadLine, метод возвращает строку.
var line=file.ReadLine();//считывание строк из файла

Чтобы считать все строки мы будем использовать цикл while – данный цикл выполняется пока условие равно true. Условием выхода из цикла в данном случае будет окончание файла – в этом случае переменная line будет равна null.
var line=file.ReadLine();//считывание строк из файла
while (line!=null) 
    {               
        //здесь мы обработаем строку
        line = file.ReadLine();         
    }

Теперь нужно обработать строку line – разбить ее на составляющие. Напомним, что каждая строка у нас представляет собой метку времени и 5 значений, разделенных символом «точка с запятой». Для разбора строки на составляющие нужно использовать метод строки Split. Данный метод разбирает строку на составляющие разделенные заданным символом. В качестве результата метод возвращает массив строк.
String[] substrings = line.Split(';'); //разбор строки на составляющие

Массив у нас содержит 6 строк. Нулевой элемент массива – метка времени, но она все еще представлена в виде строки. Для перевода ее во время у класса DateTime есть метод Parse – данный метод преобразует строку в эквивалентное ему значение времени.
var Time = DateTime.Parse(substrings[0]);

Получить значение числа можно аналогичным образом - вызвав этот же метод но уже у класса Double.

Теперь осталось записать значения и метку времени на выходы архива. Для того чтобы записать значение на выход с определенным значением и меткой времени используется метод SetValue. В качестве аргументов ему необходимо передать – имя выхода, и значение выхода (содержащее непосредственно значение, метку времени, и при необходимости – признак качества). Пример такого вызова метода:
SetValue("Выход", new PinValue(Value,Time));


Как можно видеть создается класс PinValue, в конструктор которого передается значение и метка времени.

Имена выходов у нас имеют имена Параметр1..Параметр5. Можно сделать 5 строк вызывающих метод SetValue, либо произвести запись в цикле. Остановимся на втором варианте – реализуем его с помощью цикла for.
for (int i=1;i<=5;i++)
    {
        SetValue("Параметр"+i.ToString(), new PinValue(Double.Parse(substrings[i]),Time));
    }

В итоге наш код будет выглядеть следующим образом.
public partial class ФБ : ScriptBase
{
bool? M=false;
    public override void Execute()
    {    
        if (Считать==true && M==false && Файл!=string.Empty && Файл!=null)
        {    
            using(var file = new StreamReader(Файл)) //открытие файла для чтения
            {
                var line=file.ReadLine();
                while (line!=null)
                {           
                    String[] substrings = line.Split(';'); //разбор строки на составляющие              
                    var Time = DateTime.Parse(substrings[0]);
                    for (int i=1;i<=5;i++)
                    {
                        SetValue("Параметр"+i.ToString(), new PinValue(Double.Parse(substrings[i]),Time));
                    }
                    line=file.ReadLine();//считывание строк из файла
                }          
            }
        }
        M=Считать;
    }
}

Запустим режим исполнения и выполним считывание файла – данные считались и записались на выходы.
Обратите внимание, что архив генерируется с признаком качества «Норма» (192 – Good). Если необходимо генерировать архив с различными метками времени, то нужно сначала сформировать нужный вам признак качества. Для этого предназначен класс
MasterSCADA.Hlp.Pins.PinQuality

Данный класс также имеет перегруженный конструктор, в один из которых можно передать значение признака качества. Например, инициализация класса с признаком качества Good (Норма):
var qual= new MasterSCADA.Hlp.Pins.PinQuality(192);

После этого можно вызвать другой конструктор класса PinValue содержащий признак качества
var qual= new MasterSCADA.Hlp.Pins.PinQuality(192);
SetValue("Параметр"+i.ToString(), new PinValue(Double.Parse(substrings[i]),qual,Time));


Скрипт можно считать завершенным, однако полезно обеспечить защиту кода от ошибок, например, если файла не окажется по указанному пути. Для этого используются операторы try – catch. Оператор try в случае появления исключения перехватывает исключение, и передает оператору catch. Это позволяет корректно обработать ошибки и должны образом проинформировать пользователя.

Пример описанного скрипта для чтения CSV файла, дополненного обработкой ошибок через try-catch с выводом сигнала ошибки на выход ФБ и в лог скады можно скачать по этой ссылке.

яндекс.ћетрика