<< Click to Display Table of Contents >> Navigation: Проект > Элементы дерева объектов > Палитра ФБ > Служебные > Скрипт > Руководство и примеры > Работа с архивом сообщений > Квитирование сообщений |
В качестве примера мы будем из скрипта выполнять квитирование всех сообщений определенных категорий. В реальном проекте, если такая задача возникнет, можно опять же воспользоваться ФБ "Счетчик событий" - он умеет выполнять квитирование, но в качестве примера такой вариант использования скрипта достаточно наглядный.
Для примера сделаем дерево следующей структуры:
У нас 4 объекта, во всех - по 3 сообщения разных категорий. С помощью скрипта нужно иметь возможность выполнить квитирование всех сообщений данных категорий. Создадим скрипт, в который добавим два входа КвитироватьАварии и КвитироватьПредупреждения.
Сначала в методе Start найдем ID нужных нам категорий - аварии и предупреждения, и сохраним их ID в отдельных переменных - CatCrash и CatWarning.
bool? M = false;
bool? L = false;
uint CatCrash = 0;
uint CatWarning = 0;
public override void Start()
{
var project = HostFB.TreeItemHlp.Project;
//фильтр по определенным категориям
foreach (var cat in project.SystemTreeRootItem.EventCategories.Values)
{
if (cat.Name == "Авария")
{
CatCrash = (uint)cat.ID;
continue;
}
if (cat.Name == "Предупреждение")
{
CatWarning = (uint)cat.ID;
continue;
}
}
}
В методе Execute мы будем вызывать метод, в который будем передавать ID категории, и который будет выполнять квитирование. Сначала напишем этот метод.
private void Ack(uint Cat)
{
var filter_ack = new EventFilterData();
filter_ack.OnlyNotAcked = true; //только неквитированные
filter_ack.EventCategories = new uint[1] { Cat };//фильтр по категории
var events_ack = HostFB.TreeItemHlp.Project.AlarmManager.GetEvents(HostFB.TreeItemHlp.Parent, filter_ack, 50);
EventID[] Ids = events_ack.Select(x => x.EventID).ToArray();
HostFB.TreeItemHlp.Project.AlarmManager.AckEvents(Ids, "Comment");
}
Половина кода нам уже известна - создается фильтр, в его настройках указывается только неквитированные сообщения, а также фильтрация по переданной категории. При задании фильтра категории необходимо передать массив, поскольку у нас всего один элемент, то мы создаем массив с одним элементов и передаем ему в конструктор ID нашей категории.
Затем при помощи метода GetEvents запрашиваются сообщения текущего объекта, с настройками фильтра.
С помощью метода Select происходит выборка из массива events_ack, идентификаторов сообщений EventID. Чтобы объявление EventID стало бы доступным, нужно добавить пространство имен:
using MasterSCADA.Interfaces;
Главная строчка в данном коде - это квитирование в методе AckEvents.
HostFB.TreeItemHlp.Project.AlarmManager.AckEvents(Ids, "Comment");
В качестве аргументов данный метод принимает массив ID сообщений и комментарий, с которым будут квитированы сообщений.
Осталось только вызвать данный код в методе Execute.
public override void Execute()
{
if (КвитироватьАварии == true && M == false)
{
Ack(CatCrash);
}
M = КвитироватьАварии;
if (КвитироватьПредупреждения == true && L == false)
{
Ack(CatWarning);
}
L = КвитироватьПредупреждения;
}
Итоговый код будет выглядеть следующим образом.
public partial class ФБ : ScriptBase
{
bool? M = false;
bool? L = false;
uint CatCrash = 0;
uint CatWarning = 0;
public override void Start()
{
var project = HostFB.TreeItemHlp.Project;
//фильтр по определенным категориям
foreach (var cat in project.SystemTreeRootItem.EventCategories.Values)
{
if (cat.Name == "Авария")
{
CatCrash = (uint)cat.ID;
continue;
}
if (cat.Name == "Предупреждение")
{
CatWarning = (uint)cat.ID;
continue;
}
}
}
public override void Execute()
{
if (КвитироватьАварии == true && M == false)
{
Ack(CatCrash);
}
M = КвитироватьАварии;
if (КвитироватьПредупреждения == true && L == false)
{
Ack(CatWarning);
}
L = КвитироватьПредупреждения;
}
private void Ack(uint Cat)
{
var filter_ack = new EventFilterData();
filter_ack.OnlyNotAcked = true; //только неквитированные
filter_ack.EventCategories = new uint[1] { Cat };//фильтр по категории
var events_ack = HostFB.TreeItemHlp.Project.AlarmManager.GetEvents(HostFB.TreeItemHlp.Parent, filter_ack, 50);
EventID[] Ids = events_ack.Select(x => x.EventID).ToArray();
HostFB.TreeItemHlp.Project.AlarmManager.AckEvents(Ids, "Comment");
}
}
Попробуем проверить. Запустим режим исполнения и включим несколько сообщений разных категорий и откроем журнал.
Теперь включим вход КвитироватьАварии - сообщения квитируются.
Попробуйте сделать аналогично и с сообщениями предупреждений.
Теперь попробуем сделать несколько сообщений одного источника.
А теперь попробуем их квитировать.
Квитировалось только последнее, а остальные остались не квитированными.
Дело в том, что в MasterSCADA есть кэш сообщений и есть архив сообщений. Сначала сообщение поступают в кэш, а спустя время, или если появится новое сообщение, попадают в архив. Метод GetEvents берет сообщения именно их кэша. Когда мы просто отслеживаем сообщения и сразу же на них реагируем, то это нормально, но если нам требуется выборку из архива сообщений, т.е. несколько сообщений от источника или вовсе сообщения с прошлого запуска, то и нужно обращаться к архиву. Для этого есть отдельный метод.
Рассмотрим данный метод на том же примере. Сделаем копию имеющегося скрипта и будем редактировать его - назовем его "Скрипт квитирования из архива". Изменения затронут только метод Ack - остальной код останется таким же.
Для того чтобы получить архив сообщений нужно сделать получить класс сервера сообщений, с нужными параметрами (объект и фильтр):
var server = HostFB.TreeItemHlp.Project.GetService<EventServer>();
var enumerator = server.CreateEnumerator(HostFB.TreeItemHlp.Parent, filter_ack, true);
А затем загружать из него сообщения порционно с помощью метода:
var archEvents = enumerator.Next(500);
В качестве аргумента ему передается сколько максимально сообщений из архива нужно забрать. Данный метод нужно вызывать, обрабатывать его сообщения до тех пор он не вернет количество сообщений - 0, данное действие лучше всего сделать в цикле.
Для того чтобы получить доступ к серверу сообщений нужно сначала подключить библиотеку MasterSCADA.Archive.dll, на вкладке Настройки.
А затем добавить пространство имен:
using MasterSCADA.Archive.Events;
Код метода Ack будет выглядеть следующим образом:
private void Ack(uint Cat)
{
var filter_ack = new EventFilterData();
filter_ack.OnlyNotAcked = true;
filter_ack.EventCategories = new uint[1] { Cat };
var server = HostFB.TreeItemHlp.Project.GetService<EventServer>();
var enumerator = server.CreateEnumerator(HostFB.TreeItemHlp.Parent, filter_ack, true);
while (true)
{
var archEvents = enumerator.Next(500);
if (archEvents.Count == 0) break;
EventID[] Ids = archEvents.Select(x => x.EventID).ToArray();
HostFB.TreeItemHlp.Project.AlarmManager.AckEvents(Ids, "Comment");
}
}
Запустим режим исполнения и попробуем теперь квитировать наши сообщения:
Теперь все сообщения квитировались корректно.
Однако Enumerator.Next выполняет обращение к базе, а как мы уже писали ранее такие запросы нужно выполнять в асинхронных метода. Но адаптировать его на асинхронный запрос не сложно - исправленный пример по ссылке.