Серверные скрипты Lua
Назначение
Сервер сбора данных поддерживает для узлов ENLOGIC любого типа исполнение пользовательских скриптов обработки данных на стороне сервера, разрабатываемых на языке программирования Lua.
Целевое назначение серверных скриптов:
· Обработка поступающих от удаленного контроллера параметров по сложным алгоритмам пользователя, формирование на основе поступающих данных дополнительных наборов тегов, которые можно стандартным способом использовать при создании интерфейса в проекте визуализации SCADA.
· Создание в сервере SCADA отображений (представлений) реальных технологических объектов (коммутационный аппарат, задвижка, технологический агрегат), консолидирующих в себе данные, поступающие от контроллера, результаты алгоритмической обработки скриптом и команды управления в сторону объекта.
· Разработка генераторов сигналов, имитаторов объектов различной сложности, для реализации учебных, тренировочных и демонстрационных функций.
В дальнейшем планируется развитие функциональности серверных скриптов Lua в других возможных направлениях – генерация алармов и сообщений, отправка сообщений MQTT и пр.
Настройка
Серверный скрипт представляется как новый вид протокола обмена (псевдо-протокол), и может быть добавлен в конфигурацию узла ENLOGIC любого типа – как контроллера с исполнительной системой ENLOGIC, так и любого произвольного источника данных типа КП МЭК 60870-5-104.
Добавляем протокол Lua в сервере из группы Сервер сбора данных:
В протокол добавляем модуль Скрипт Lua:
Настройки модуля Скрипт Lua:
Название файла скрипта – имя файла скрипта, который будет загружен для данного экземпляра модуля Скрипт Lua. Файл должен быть расположен в каталоге проекта, с которым работает SCADA, в папке lua (маленькими буквами, если в Linux). Один и тот же файл может использоваться многократно для разных экземпляров модулей Скрипт Lua, в произвольном числе контроллеров и станций данного проекта SCADA.
Название рабочей процедуры – название процедуры в файле, которая будет вызываться периодически сервером сбора данных. Одна и та же процедура может использоваться произвольное кол-во раз для разных экземпляров модулей Скрипт Lua (обеспечивается независимое состояние исполнителя Lua для каждого экземпляра скрипта).
Группа настроек Ссылки на внешние параметры скрипта представляет собой описание параметров данного узла ENLOGIC, к которым можно будет получить доступ из процедуры на скрипте Lua для чтения и записи значений параметров по заданному названию параметра. Предполагается, что эти значения поступают от реального контроллера по протоколу МЭК-104. Данные ссылки формируются парами Название ссылки (для использование внутри скрипта) и Адрес ссылки (МЭК-адрес реального параметра в конфигурации узла ENLOGIC).
Кроме обращения к параметру по названию скрипт Lua может прочитать и записать значение любого параметра в своем узле ENLOGIC, используя для этого абсолютный МЭК-адрес параметра из конфигурации узла. Но привязка в коде скрипта к глобальным адресам не позволит сделать скрипт, многократно применяемый для разных групп параметров. Поэтому, для создания более универсальных скриптов, не имеющих в коде скрипта жесткой привязки к абсолютным адресам параметров, используется механизм ссылок на внешние параметры скрипта. Ссылка имеет название, которое будет использоваться в коде скрипта для доступа к данному параметру, и адрес. Также имеется дополнительно настройка Смещение адресов для ссылок. При доступе из скрипта к параметру по названию ссылки сервер сбора данных определит реальный конечный адрес параметра в карте адресов данного узла ENLOGIC путем сложения адреса ссылки и значения смещения.
Если значение настройки Смещение адресов для ссылок равно 0 – то это фактически означает, что значения в полях Адрес ссылки являются абсолютными адресами. Если сформировать конфигурацию узла ENLOGIC таким образом, чтобы для фрагментов технологического процесса были однотипно сформированы наборы сигналов, то можно для этих наборов использовать единый серверный скрипт, с разными значениями в настройке Смещения адресов для ссылок.
Предусмотрена возможность настройки до 10 ссылок на внешние параметры, при необходимости это число может быть увеличено.
Несмотря на то, что серверный скрипт может изменить значение любого параметра в узле ENLOGIC, если в задачу скрипта входит генерация новых значений (тегов), то правильно будет новые значения формировать непосредственно в виде тегов внутри данного модуля Скрипт Lua. Это связано с тем, что если из скрипта Lua происходит вызов процедуры записи значения в какую то внешнюю относительно самого скрипта переменную, то данная команда записи будет инициировать передачу (запись) значения в реальный контроллер, который опрашивает сервер сбора данных (и это может происходить периодически раз в секунду). А если из скрипта Lua происходит запись значения во внутренний тег скрипта, то команда записи в удаленный контроллер не выполняется – значение остается только в сервере SCADA.
Теги скрипта Lua создаются в дереве по стандартной идеологии работы в среде разработки ENLOGIC – добавление групп и добавление тегов в группы.
Добавление группы:
Добавление тега в группу:
Из скрипта Lua получить доступ к тегам данного экземпляра модуля скрипт для чтения и записи значений можно по названию созданных тегов (как и для ссылок на внешние параметры, поэтому необходимо избегать совпадения имен параметров в тегах скрипта и в ссылках).
Техническая реализация
Сервер сбора данных в процессе старта производит разбор конфигурации и предварительную подготовку к исполнению. Для каждого модуля Скрипт Lua в конфигурации создается собственное состояние машины Lua. Благодаря этому все скрипты полностью независимы друг от друга (даже если созданы из одного файла скрипта и используют одну рабочую процедуру), и можно в общей кодовой секции скрипта объявлять и инициализировать глобальные переменные Lua, которые будут сохранять свое состояние между циклическими вызовами рабочей процедуры скрипта, и эти переменные будут доступны только для данного экземпляра модуля Скрипт Lua.
При старте сервера для каждого экземпляра модуля Скрипт Lua будет выполнен код общей кодовой секции Lua, размещенный в безымянном блоке скрипта (вне какой-либо процедуры), если такой код предусмотрен в данном файле скрипте. Рекомендуется в таком стартовом коде произвести инициализацию переменных, необходимых далее в процессе циклического вызова рабочей процедуры скрипта.
В каталоге проекта, в папке DAServer, в подпапке, соответствующей ID станции, формируется файл лога Lua.log работы исполнителя Lua. В файле лога отображаются результаты разбора конфигурации модулей скриптов Lua, списки переменных, возможные ошибки трансляции скриптов.
Пример файла лога:
После завершения старта сервера начинается циклический вызов рабочих процедур всех скриптов с периодом 1 сек. В текущей реализации пока предусмотрен только один алгоритм вызова рабочих процедур скриптов – поочередно для каждого модуля Скрипт Lua в конфигурации всех узлов ENLOGIC в данной станции, для которой запущен данный экземпляр сервера сбора данных. Работа происходит в одном отдельном потоке сервера сбора данных, предназначенном только для задачи циклического исполнения серверных скриптов. После поочередного вызова всех скриптов поток исполнения засыпает на время, оставшееся от периода выполнения в 1 секунду, и далее начинается новый цикл.
Комментарии от разработчика. Рассматривались различные реализации алгоритмов исполнения скриптов – возможность для каждого скрипта задать свой период, возможность вызова по событию, отдельные потоки-исполнители для каждого узла ENLOGIC, и пр. Вариантов может быть много, и, очевидно, что в дальнейшем будем их развивать, но в первой реализации пока было решено оставить только самый простой и понятный алгоритм, чтобы к другим реализациям подойти уже на основе накопленного в процессе опыта.
Необходимо понимать, что если один из скриптов в общей очередности будет производить длительные операции, то это затормозит общий цикл исполнения всех скриптов, и периодичность выполнения станет более 1 сек.
Для потока исполнения скриптов установлено значение внутреннего сторожевого таймера в 60 сек – это означает, что если суммарная длительность выполнения всех последовательных скриптов приведет к превышению времени 60 сек, то сервер сбора данных прервет свою работу, и далее подсистема управления службами (демонами) операционной системы запустит его снова.
В настоящее время целевое назначение скриптов – обработка оперативных значений! Предполагается, что любой скрипт в своей рабочей процедуре будет решать только такие алгоритмические задачи, поэтому время выполнения каждого скрипта будет небольшим. По мере появления новых типов задач для серверных скриптов, требующих параллельной работы, выполнения длительный операций, ожиданий – будут дополняться и новые варианты запуска скриптов.
Системные процедуры Lua для доступа к параметрам сервера сбора данных
Ядро сервера сбора данных предоставляет для скриптов Lua системные процедуры для чтения и записи значений параметров (переменных) внутри сервера сбора данных.
Сводная таблица системных процедур:
Название процедуры
|
Краткое описание
|
SSDGetAddrByName
|
Получение абсолютного МЭК-адреса параметра по названию переменной
|
SSDReadByAddr
|
Чтение значения параметра по его абсолютному адресу
|
SSDWriteByAddr
|
Запись значения параметра по его абсолютному адресу
|
SSDDebugLog
|
Вывод строки в файл лога работы скриптов Lua сервера сбора данных
|
SSDGetAddrByName
Получение абсолютного адреса параметра по названию переменной данного модуля Луа.
Формат вызова в Lua:
var_1_addr = SSDGetAddrByName("var_1")
Название переменной передается в виде строки в первом параметре процедуры. Сервер сбора данных по названию производит поиск в списке переменных данного скрипта. Список переменных скрипта содержит последовательно сначала список ссылок на внешние параметры данного скрипта, и далее список тегов (в дереве) внутри данного модуля скрипта. Названия переменных-ссылок и переменных-тегов могут иметь совпадения – сервер сбора данных не контролирует и не блокирует эту ситуацию, но процедура поиска адреса по имени вернет в ответ адрес первой переменной, имеющей запрошенное название.
Если запрошенный параметр является ссылкой, то абсолютный адрес получается путем сложения адреса найденной ссылки и значения смещения адресов для ссылок из настроек данного модуля Луа.
Если запрошенный параметр является тегом, то абсолютный адрес будет являться непосредственно адресом данного тега в конфигурации данного узла ENLOGIC.
Если переменная с переданным названием не найдена – возвращается значение 0.
Внимание! Использовать данную функцию можно только в начальной секции скрипта (безымянной части файла скрипта), чтобы произвести поиск адресов переменных скрипта, и использовать далее уже готовые адреса в самой периодической процедуре скрипта. В периодической процедуре скрипта данная функция всегда возвращает значение 0.
SSDReadByAddr
Чтение значения параметра по его абсолютному адресу.
Формат вызова в Lua:
v = SSDReadByAddr([integer] Addr)
Адрес передается первым параметром в виде целого числа.
Значение параметра возвращается из процедуры.
Тип возвращенного значения может быть следующим:
· nil – если возникает ошибка при запросе значения (например – неправильный адрес параметра), или если запрошенное значение имеет признак недостоверности
· boolean – значения false и true, соответствующие достоверным значениям дискретного типа; если тип значения в сервере DP, то также передаются значения OFF (DP=01) и ON (DP=10)
· number, подтип integer – используется для передачи достоверного промежуточного значения DP параметра: UNDEFINE (DP=00, значение 0), INVALID (DP=11, значение 3)
· number, подтип float – используется для передачи достоверного значения аналогового параметра
Рекомендуется в скрипте делать проверку возвращенного результата перед его последующим использованием с помощью функции type в языке Lua.
SSDWriteByAddr
Запись значения параметра по его абсолютному адресу.
Формат вызова в Lua:
b = SSDWriteByAddr([integer] Addr, value)
Адрес передается первым параметром в виде целого числа.
Значение передается вторым параметром. В качестве валидного входного значения рассматриваются только типы значений number (в том числе подтип integer) и boolean.
Функция возвращает true при успешной записи, или false при ошибке.
SSDDebugLog
Вывод строки в файл лога работы скриптов Lua сервера сбора данных.
Формат вызова в Lua:
SSDWriteByAddr([string] s)
Строка для вывода в лог передается первым параметром.
Основное назначение функции – тестирование и отладка скриптов.
Пример использования:
SSDDebugLog("Привет из скрипта Lua!") – вывод текстового сообщения
SSDDebugLog(string.format("Value = %s", tostring(v))) – вывод в лог строки со значением внутренней переменной v
Пример серверного скрипта:
Дополнительные материалы:
2) Программирование на языке Lua https://eligovision.ru/media/upload/lua.pdf
3) Справочное руководство по языку Lua 5.1 http://linuxshare.ru/docs/devel/languages/lua/reference/index.html