Отображение событий на каждую метку времени
В списке полей редактора отчетов данные из архива ошибок хранятся в узле Архив ошибок точки учета, а данные из архива событий устройства хранятся в узле Устройство->Архив событий устройства. Архив ошибок и архив событий это наборы записей с полями:
Архив ошибок связан с опрашиваемой точкой учета. Записи архива ошибок содержат дату/время начала метки времени DateTime, к которой относится ошибка. Архив событий связан с опрашиваемым устройством, тепловые вводы которого могут быть подключены к разным точкам учета. Записи архива событий содержат дату/время начала StartDateTime и окончания EndDateTime события, а также номер теплового ввода HeatLeadIn, к которому подключена точка учета. В редакторе отчетов информация по ошибкам и событиям на каждую метку времени хранится в полях DeviceErrorCodes, DeviceErrorDurations, DeviceEventCodes, DeviceEventDurations.
Примечание
Чтобы при формировании отчета была доступна информация о событиях устройства, необходимо в параметрах автоопроса или в параметрах ручного опроса выбрать загрузку архива событий. Архив ошибок, если он есть, заполняется автоматически при опросе точки учета.
За период одной метки времени могут происходить события относящиеся к разным типам, поэтому для каждого события указываются тип архива, номер теплового ввода, номер канала и код события. В полях DeviceErrorCodes и DeviceEventCodes информация хранится в виде строки с разделителями: архив1|ввод1|канал1|код1; ... архивN|вводN|каналN|кодN. В полях DeviceErrorDurations и DeviceEventDurations информация хранится в виде строки с разделителями: архив1|ввод1|канал1|код1|длительность1; ... архивN|вводN|каналN|кодN|длительностьN Длительность указывается в секундах. Коды событий зависят от модели устройства и описываются в руководстве по эксплуатации прибора. Если при формировании отчета для каждой метки времени требуется выводить информацию о типе архива, коде и длительности события, то это выполняется в скриптах обработчика Перед печатью для ячеек связанных с полем DeviceEventCodes или DeviceEventDurations.
Рассмотрим использование полей DeviceEventCodes и DeviceEventDurations для архива событий на примере отчетной формы для точки учета c прибором КМ-5. Использование полей DeviceErrorCodes и DeviceErrorDurations для архива ошибок выполняется аналогично.
ШАГ 1. Создайте отчетную форму для точки учета.
ШАГ 2. Добавьте колонку в секции PageHeader и Detail. Добавленную колонку секции Detail назовите EventArchive.
ШАГ 3. Свяжите добавленную колонку EventArchive с полем DeviceEventCodes из узла Архив потреблений и интеграторов.
ШАГ 4. Добавьте в секцию Detail ячейку с именем EventDuration. Свойству Видимость для этой ячейки задайте значение Нет. Эта ячейка нужна только для доступа к полю DeviceEventDurations.
ШАГ 5. Свяжите ячейку EventDuration с полем DeviceEventDurations.
ШАГ 6. Для вывода расшифровки кодов событий для каждого типа архива положите на форму в секцию ReportFooter поле DeviceEventDescription из узла Устройство.
Для отображения длительностей для групп событий добавьте в секцию ReportFooter таблицу. Задайте наименования ячеек как показано на рисунке для групп событий обозначенных символами U, E, D, g, G, *
Ячейку с длительностью отчетного периода свяжите с полем RequestedInterval из узла Рассчитанные значения->Суммарные потребления по системам снабжения за отчетный период, а ячейку с длительностью периода имеющихся данных с полем ExistingInterval.
ШАГ 7. В окне свойств колонки EventArchive в разделе Скрипты добавьте новый обработчик события Перед печатью.
ШАГ 8. Откроется редактор скриптов, в котором будет пустая заготовка обработчика Перед печатью c именем EventArchive_BeforePrint(). Перед обработчиком EventArchive_BeforePrint() добавьте массивы для хранения групп кодов событий и переменные для хранения длительностей соответствующих периодов:
`// Код периода отключения питания int[] codes_U = {122};
// Длительность отключения питания double period_U = 0;
// Код периода t1-t2 < min int[] codes_D = {96};
// Длительность периода t1-t2 < min double period_D = 0;
// Коды функционального отказа int[] codes_E = {61, 64, 65, 66, 67, 68, 69, 71, 73, 74, 76, 79, 81, 88, 90, 91, 93, 94, 106, 114, 119, 120, 121};
// Длительность функционального отказа double period_E = 0;
// Коды периода G > max int[] codes_G = {82, 85};
// Длительность периода G > max double period_G = 0;
// Коды периода G < min int[] codes_g = {84, 87};
// Длительность периода G < min double period_g = 0;
// Длительность периода для прочих кодов double period_other = 0; `
В метод EventArchive_BeforePrint() обработчика добавьте код, в котором формируется отображаемое значение ячейки EventArchive.
`// Формирует текст для колонки 'Архив событий' // Эта колонка связана с полем DeviceEventCodes, в котором события записаны в виде строки: // архив1|ввод1|канал1|код1; архив2|ввод2|канал2|код2; ... архивN|вводN|каналN|кодN private void EventArchive_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e) { // Строка с информацией о событиях. // Формат строки: архив1|ввод1|канал1|код1; архив2|ввод2|канал2|код2; ... архивN|вводN|каналN|кодN. string eventCodesString = ((XRLabel)sender).Text;
if (String.IsNullOrEmpty(eventCodesString))
return;
// Получаем массив типов архива и кодов событий:
// eventCodesString - строка с форматом: архив1|ввод1|канал1|код1; архив2|ввод2|канал2|код2; ... архивN|вводN|каналN|кодN
string[] eventCodes = eventCodesString.Split(new string[]{";"}, StringSplitOptions.RemoveEmptyEntries);
// Формируем обозначения для групп событий и типов архивов
string eventCodesSymbol = String.Empty;
foreach (string eventCodeInfo in eventCodes)
{
// Получаем информация по событию в виде строки: архив|ввод|канал|код
string[] eventInfo = (eventCodeInfo.Trim()).Split(new string[]{"|"}, StringSplitOptions.RemoveEmptyEntries);
// Код типа архива
int archiveType = -1;
if (!String.IsNullOrEmpty(eventInfo[0].Trim()))
archiveType = Convert.ToInt32(eventInfo[0]);
// Номер теплового ввода
int heatLeadIn = -1;
if (!String.IsNullOrEmpty(eventInfo[1].Trim()))
heatLeadIn = Convert.ToInt32(eventInfo[1]);
// Номер канала
int channelNumber = -1;
if (!String.IsNullOrEmpty(eventInfo[2].Trim()))
channelNumber = Convert.ToInt32(eventInfo[2]);
// Код события
int code = -1;
if (!String.IsNullOrEmpty(eventInfo[3].Trim()))
code = Convert.ToInt32(eventInfo[3]);
// Формируем символьное отображение набора событий в зависимости от кода события
// Период отключения питания
if (Array.Exists(codes_U, delegate(int c) { return (c == code); }) && eventCodesSymbol.IndexOf("U") == -1)
eventCodesSymbol += "U";
// Период t1-t2 < min
else if (Array.Exists(codes_D, delegate(int c) { return (c == code); }) && eventCodesSymbol.IndexOf("D") == -1)
eventCodesSymbol += "D";
// Период функционального отказа
else if (Array.Exists(codes_E, delegate(int c) { return (c == code); }) && eventCodesSymbol.IndexOf("E") == -1)
eventCodesSymbol += "E";
// Период G > max
else if (Array.Exists(codes_G, delegate(int c) { return (c == code); }) && eventCodesSymbol.IndexOf("G") == -1)
eventCodesSymbol += "G";
// Период G < min
if (Array.Exists(codes_g, delegate(int c) { return (c == code); }) && eventCodesSymbol.IndexOf("g") == -1)
eventCodesSymbol += "g";
// Период прочих кодов
else if (eventCodesSymbol.IndexOf("*") == -1)
eventCodesSymbol += "*";
}
// Задаем текст отображаемый в ячейке EventArchive
((XRLabel)sender).Text = eventCodesSymbol;
} `
ШАГ 9. В окне свойств ячейки EventDuration в разделе Скрипты добавьте новый обработчик Перед печатью с именем EventsDuration_BeforePrint. В метод EventsDuration_BeforePrint() обработчика добавьте код, в котором формируются суммарные длительности для групп событий:
` // Формируем суммарные длительности для групп событий
// Ячейка EventsDuration связана с полем DeviceEventDuration, в котором события записаны в виде строки:
// архив1|ввод1|канал1|код1|длительность1; архив2|ввод2|канал2|код2|длительность2; ... архивN|вводN|каналN|кодN|длительностьN
// Ячейка EventsDuration нужна только для расчета суммарных длительностей, поэтому ее можно сделать невидимой, установив свойство Видимость = Нет
private void EventDuration_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e) { // Получаем содержимое ячейки. string eventDurationString = ((XRLabel)sender).Text;
if (String.IsNullOrEmpty(eventDurationString))
return;
// Получаем массив кодов и длительностей событий
// Каждый элемент мвссива - это строка формата: архив|ввод|канал|код|длительность
string[] eventDurations = eventDurationString.Split(new string[]{";"}, StringSplitOptions.RemoveEmptyEntries);
// Перебираем события и формируем суммарные длительности
foreach (string eventDuration in eventDurations)
{
// eventDuration - строка c форматом: архив|ввод|канал|код|длительность
string[] codeDuration = (eventDuration.Trim()).Split(new string[]{"|"}, StringSplitOptions.RemoveEmptyEntries);
// Код типа архива
int archiveType = -1;
if (!String.IsNullOrEmpty(codeDuration[0].Trim()))
archiveType = Convert.ToInt32(codeDuration[0]);
// Номер теплового ввода
int heatLeadIn = -1;
if (!String.IsNullOrEmpty(codeDuration[1].Trim()))
heatLeadIn = Convert.ToInt32(codeDuration[1]);
// Номер канала
int channelNumber = -1;
if (!String.IsNullOrEmpty(codeDuration[2].Trim()))
channelNumber = Convert.ToInt32(codeDuration[2]);
// Код события
int code = -1;
if (!String.IsNullOrEmpty(codeDuration[3].Trim()))
code = Convert.ToInt32(codeDuration[3]);
// Длительность события в секундах
double duration = 0;
if (!String.IsNullOrEmpty(codeDuration[4].Trim()))
duration = Convert.ToDouble(codeDuration[4]);
// Переводим длительность события из секунд в доли часа
duration = duration / 3600D;
// Период отключения питания
if (Array.Exists(codes_U, delegate(int c) { return (c == code); }))
period_U += duration;
// Период t1-t2 < min
else if (Array.Exists(codes_D, delegate(int c) { return (c == code); }))
period_D += duration;
// Период функционального отказа
else if (Array.Exists(codes_E, delegate(int c) { return (c == code); }))
period_E += duration;
// Период G > max
else if (Array.Exists(codes_G, delegate(int c) { return (c == code); }))
period_G += duration;
// Период G < min
else if (Array.Exists(codes_g, delegate(int c) { return (c == code); }))
period_g += duration;
// Период прочих кодов
else
period_other += duration;
}
} `
ШАГ 10. Для всех ячеек с длительностями групп событий в добавленной таблице в секции ReportFooter в разделе Скрипты добавьте обработчик Перед печатью c именем Period_BeforePrint. В метод Period_BeforePrint() обработчика добавьте код, в котором заполняются ячейки с суммарными длительностями для групп событий:
// Отображаем суммарные длительности периодов групп событий
private void Period_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
XRTableCell cell= ((XRTableCell)sender);
double period = 0;
switch (cell.Name)
{
case "Period_U": // Период отключения питания
period = period_U;
break;
case "Period_D": // Период t1-t2 < min
period = period_D;
break;
case "Period_E": // Период функционального отказа
period = period_E;
break;
case "Period_Gmax": // Период G > max
period = period_G;
break;
case "Period_Gmin": // Период G < min
period = period_g;
break;
case "Period_Other": // Период прочие
period = period_other;
break;
}
cell.Text = String.Format("{0:F4}", period);
}
ШАГ 11. Сохраните отчетную форму. Если сформировать отчет по созданной отчетной форме, то он будет выглядеть так: