Источник: «Инфосистемы Джет»
Источник: «Инфосистемы Джет»

В этом посте мы хотим рассказать, как перешли от проприетарного решения в области мониторинга электросетевого оборудования на Open Source систему и с какими проблемами нам пришлось при этом столкнуться. Реальный кейс по мониторингу промышленного оборудования с помощью Zabbix.

Энергетики подкинули задачу

Ранее мы уже имели опыт в настройке мониторинга различного оборудования для энергообеспечения ЦОД, поэтому очередная задача от энергетиков казалась легко выполнимой. Однако что-то пошло не так…

Нам позвонил коллега-энергетик и спросил: «А вы сможете настроить мониторинг состояния электрощитов?»

«Ну, разумеется, мы можем всё, но нужно конкретное ТЗ», — ответили мы.

В ходе обсуждений выяснилось, что коллеги уже пользуются системой мониторинга, однако ее поддержка платная, гибкость в настройке отсутствует, и она полностью проприетарная. Система мониторинга представляла собой приложение, написанное на C#, которое отображает поверх изображения плана серверной состояние щитов, может отправлять уведомления об отклонениях с помощью SMS/Email и даже хранить историю за пару дней. Всё это выглядело в лучших традициях подобных АСУ ТП и напоминало панель управления космолетом.

Итак, что же изначально у нас было:

  • n-ое количество преобразователей RS-232/422/485 в Ethernet «MOXA NPort 5150»;

  • подключенные к ним по RS-485 измерительные приборы Satec;

  • несколько измерителей Satec, подключенных напрямую по Ethernet;

  • уже настроенная система SCADA;

  • огромное желание заполучить эти данные в Zabbix.

Приступаем к изучению

Энергетики предоставили планы размещения устройств по серверным, адреса преобразователей MOXA, доступ к существующему мониторингу, и мы приступили к изучению работы системы. Разумеется, наши «исследования» не должны были влиять на работу текущей инсталляции, поэтому мы были весьма ограничены в действиях.

Изучив планы, выделили две схемы подключения оборудования: с использованием преобразователей MOXA и прямое подключение к приборам учета Satec (рис. 1). В обоих случаях транспортом выступал TCP, необходимости напрямую работать с последовательными портами не было.

Рис. 1. Варианты схем подключения оборудования (Источник: «Инфосистемы Джет»)
Рис. 1. Варианты схем подключения оборудования (Источник: «Инфосистемы Джет»)

Поскольку информации о работе системы не было, а все данные были зашиты в один бинарный файл, для начала мы решили проанализировать трафик и посмотреть, как ПО «общается» с оборудованием. Изучая трафик, мы обнаружили, что для общения с приборами учета используется протокол Modbus — очень распространенный протокол, который применяется в сетях промышленной автоматизации. Привычных протоколов SNMP и IPMI у данных приборов нет.

Система мониторинга Zabbix, начиная с версии 5.2 умеет получать данные через агента по этому протоколу. Для этого используется ключ modbus.get, который может применяться для подключения протоколов TCP/RTU/ASCII. Подробнее с параметрами и синтаксисом можно ознакомиться тут.

Ну вот вроде бы и все, ставь агента, собирай данные — дело на пять минут. Мы испробовали этот метод на счетчиках, подключенных напрямую через Ethernet, и получили очень странные показатели частоты и напряжения, но с этим мы разберемся чуть позже. А вот в случае использования MOXA в качестве преобразователя, на выходе в Zabbix мы благополучно получали ошибку:

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

Далее, мы подробнее ознакомились с документацией MOXA и проанализировали трафик, сгенерированный уже настроенной SCADA-системой в сторону MOXA и обратно, с трафиком, генерируемым Zabbix. И обнаружили, что есть разница в структуре TCP пакета.

Для получения метрик Zabbix использует протокол обмена Modbus TCP, у которого структура пакетов отличается от Modbus RTU наличием дополнительного заголовка и отсутствием CRC-суммы (рис. 2).

Рис. 2: Пример структуры Modbus RTU/TCP пакетов (Источник: http://www.simplymodbus.ca/TCP.htm)
Рис. 2: Пример структуры Modbus RTU/TCP пакетов (Источник: http://www.simplymodbus.ca/TCP.htm)

Получается, что Zabbix отправлял передатчику (MOXA) пакет Modbus TCP, тот его обрабатывал и передавал нашему щиту пакет без CRC и с дополнительным заголовком. Конкретно у этих измерительных приборов на борту был только порт RS-485, и они вполне справедливо «посылали нас» при попытке «накормить их каким-то мусором». Причем посылали с использованием протокола Modbus RTU, который, в свою очередь, не понимал уже Zabbix. Стало понятно, что стандартными средствами мониторинга нам не обойтись.

Разбираемся дальше

Раз Zabbix не может напрямую общаться с нашими щитами, необходимо разработать прослойку для получения и возможной предобработки данных. Ознакомившись с популярными библиотеками для работы с протоколом Modbus, мы решили написать прототип на Python с использованием модуля PyModbus.

Вот как это все выглядело на практике.

Для начала нужно сформировать пакет формата Modbus RTU:

SlaveID — 1 байт

Код функции — 1 байт

Адрес первого регистра — 2 байта

Количество регистров — 2 байта

CRC — 2 байта

где:

SlaveID — идентификатор устройства Satec, находящегося за MOXA;

код функции — идентификатор функции, выполняющей действия над регистрами (табл. 1);

адрес первого регистра — адрес первого регистра с данными устройства;

количество регистров — то количество регистров, идущих подряд от указанного ранее «первого» регистра, которое нам необходимо прочитать;

CRC — контрольная сумма сформированного пакета.

Таблица 1. Коды и описание функций, используемых в протоколе Modbus (Источник: http://www.simplymodbus.ca/TCP.htm)

Код функции

Что делает функция

Тип значения

Тип доступа 

01 (0x01)

Чтение DO

Read Coil Status

Дискретное

Чтение

02 (0x02)

Чтение DI

Read Input Status

Дискретное

Чтение

03 (0x03)

Чтение AO

Read Holding Registers

16-битное

Чтение

04 (0x04)

Чтение AI

Read Input Registers

16-битное

Чтение

05 (0x05)

Запись одного DO

Force Single Coil

Дискретное

Запись

06 (0x06)

Запись одного AO

Preset Single Register

16-битное

Запись   

15 (0x0F)

Запись нескольких DO

Force Multiple Coil   

Дискретное   

Запись

16 (0x10)

Запись нескольких AO

Preset Multiple Registers

16-битное

Запись

А теперь — ловкость рук и никакого мошенничества. Нас интересует функция чтения «Read Input Registers» с кодом 04. Для того, чтобы понять, какой адрес первого регистра нам необходим, обратимся к технической документации конкретного измерительного прибора Satec и увидим, что нужные нам данные по напряжению и частоте начинаются с 256 и заканчиваются 272 регистром (нужно прочитать 16 регистров подряд). Считаем для всего этого «великолепия» CRC и получаем итоговый пакет:

0c

04

01 00

00 16

71 25

Теперь можно отправлять эти данные с помощью TCP нашей MOXA и ждать ответа, который, в свою очередь, имеет следующий формат:

Адрес устройства

Код функции

Количество байтов

Значения регистров

CRC

Если все сделано верно, то мы получим в ответ массив с «сырыми» данными, которые еще нужно будет обработать.

Что делать с ответом

Вот мы и достали заветные циферки из наших щитов, но почему частота равна 2501 Гц, а входное напряжение 5000 В? Все дело в том, что Satec может отдавать данные в трех различных форматах, для которых требуется дополнительная обработка:

  • 16-bit integer,

  • 32-bit integer/ mod 10000,

  • 32-bit integer (два 16-bit регистра, которые хранят по половине числа).

При этом в 16-битном формате числа могут отдаваться или в «сыром» виде (так как они уже были получены от отслеживаемого прибора), или будут требовать еще дополнительной обработки. Это правило справедливо для чтения и записи данных в регистры.

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

Пример описания регистров из техдокументации.
Пример описания регистров из техдокументации.

«LIN3» — это функция, выполняющая преобразование необработанных данных в диапазоне от 0 до 9999 в определяемый пользователем диапазон Low/HIgh. Сама функция выглядит следующим образом:

result=\left ( \frac{X}{9999} \right )\times \left ( HIGH-LOW \right )+LOW

где:

  • X — «сырое» значение от 0 до 9999;

  • HIGH и LOW — верхняя и нижняя границы.

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

Итоговая схема реализации:

  • Передаем IP-адрес MOXA и набор unitID конечных устройств Satec в качестве аргументов скрипту.

  • Скрипт опрашивает счетчики и возвращает данные в виде массива значений.

  • Zabbix обрабатывает полученный массив и с помощью автоматического обнаружения создает набор метрик для хранения данных.

  • Каждая метрика содержит правило предобработки, которые вычисляет итоговое значение по формуле.

Что же касается самого скрипта, это — внешняя проверка Zabbix-сервера, поэтому располагаем скрипт в директории /usr/lib/zabbix/externalscripts. В зависимости от входных параметров выполняется либо автообнаружение устройств, либо получение данных с конкретного устройства. В качестве конфигуратора используется xls-файл, в котором описываем всю необходимую информацию: ip-moxa, unitID, название щита расположения прибора Satec, а также все переменные для расчета по формулам напряжения, силы тока, мощности и т. д. (рис. 4). Нет, современные технологии не обошли нас стороной, и YAML-файлами мы тоже «балуемся», просто в данном случае было проще сделать так.

Рис. 4. Пример конфигурационного файла (Источник: «Инфосистемы Джет»)
Рис. 4. Пример конфигурационного файла (Источник: «Инфосистемы Джет»)

В Zabbix, используя ключ moxa_app[discovery,{HOST.CONN}], передаем параметры для скрипта:

  • moxa_app — название самого скрипта;

  • discovery — параметр, запускающий автообнаружение;

  • {HOST.CONN} — адрес MOXA.

Скрипт на входе, видя параметр discovery, парсит содержимое xls-файла и получает по IP-адресу хоста данные по щиту, которые возвращает в виде json-объекта. Далее Zabbix из этого объекта создает набор метрик c правилами предобработки для расчета значений (рис. 5).

Рис. 5. Пример возвращаемого json-объекта (Источник: «Инфосистемы Джет»)
Рис. 5. Пример возвращаемого json-объекта (Источник: «Инфосистемы Джет»)

Для получения данных мы используем один элемент на каждый unitID, в котором собирается информация из всех регистров за один раз. Затем эта информация применяется в «зависимых» элементах данных. Для этого используется тот же скрипт, но в качестве аргументов передает ключ get, unitID из конфига (мы его получили на этапе выполнения правила дискаверинга) и {HOST.CONN}. На рисунке 6 показано, как выглядит подключение и запрос данных с помощью PyModbus.

Рис. 6. Пример реализации подключения к электрощиту (Источник: «Инфосистемы Джет»)
Рис. 6. Пример реализации подключения к электрощиту (Источник: «Инфосистемы Джет»)

Как можно увидеть из листинга скрипта, используется порт 502, в нашем случае — ModbusRtuFramer. Запрашиваем данные от MOXA 192.168.0.5 начиная с 256 регистра, 50 регистров, с UNIT id: 1

А вот так выглядит правило JS предобработки, о котором мы говорили ранее, для каждого элемента данных:

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

По собранным данным можно строить графики и создавать информативные дашборды в системах ИТ-мониторинга Zabbix и Grafana. Можно гибко настроить оповещения и эскалации с учетом времени возникновения проблемы или ее критичности, чего не было ранее. Также мы можем задействовать такой механизм Zabbix, как «карты сети» и, используя план здания, отображать агрегированное состояние щитов и выводить список проблем. На рисунке 7 дан пример такой небольшой карты.

Рис. 7. Пример реализации плана этажа с помощью карты сети (Источник: «Инфосистемы Джет»)
Рис. 7. Пример реализации плана этажа с помощью карты сети (Источник: «Инфосистемы Джет»)

Заключение

Zabbix «из коробки» умеет собирать данные с разных источников, поддерживает push/pull модели опроса и большое число протоколов связи и передачи данных, среди которых SNMP, WMI, JMX, HTTP/HTTPS, XML Soap, SSH, Telnet, ICMP, агенты, трапы и др. Открытый исходный код и возможность писать модули для расширения функционала позволяют модифицировать систему мониторинга и добавлять необходимый функционал. Однако если у вас в штате нет людей, хорошо знающих C, или вам необходимо проверить еще не подтвержденную концепцию, то в этом случае мы рекомендуем использовать внешние скрипты либо агенты/трапы для реализации задуманного. В нашем варианте мы остановились на реализации модуля на Python, поскольку его проще поддерживать, и этот подход позволил нам безболезненно обновлять Zabbix-сервер.

Jet Service Team

Комментарии (2)


  1. sbr2004
    03.11.2022 11:07

    Почему не собираете сразу в UINT32/INT32, без преобразования?


    1. mvolotov
      03.11.2022 12:14

      В данном случае satec отдаёт интересующие метрики только в UINT16. Есть набор UINT32 с 287 по 302 регистр. Было бы отлично обойтись без преобразований)