Скрипты — различия между версиями

Материал из WebHMI Wiki
Перейти к: навигация, поиск
(SendViberMessage(chatId, message))
(SendViberMessage(chatId, message))
Строка 126: Строка 126:
 
== SendViberMessage(chatId, message)  ==
 
== SendViberMessage(chatId, message)  ==
 
Функция SendViberMessage отправляет сообщение с текстом '''message''' в чат с Id = '''chatId'''. Возвращает 1 если произошла ошибка и 0 в случае успеха. <br/>
 
Функция SendViberMessage отправляет сообщение с текстом '''message''' в чат с Id = '''chatId'''. Возвращает 1 если произошла ошибка и 0 в случае успеха. <br/>
Успех не означает доставку сообщения, а только успех при создании запроса. Для работы этой функции необходимо наличие работающего интернет-подключения, учетной записи в системе <a href="http://wiki.webhmi.com.ua/index.php/%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_WebHMI_%D0%BA_Level2">Level2</a> и положительного баланса в этой системе. Отправка сообщений в Viber — платная услуга.<br/>
+
Успех не означает доставку сообщения, а только успех при создании запроса. Для работы этой функции необходимо наличие работающего интернет-подключения, учетной записи в системе [http://wiki.webhmi.com.ua/index.php/%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_WebHMI_%D0%BA_Level2 Level2] и положительного баланса в этой системе. Отправка сообщений в Viber — платная услуга.<br/>
  
 
Для получения ChatId перейдите по ссылке http://viber.com/webhmi на мобильном телефоне (предварительно установив Viber), нажмите кнопку Have a look.<br/>
 
Для получения ChatId перейдите по ссылке http://viber.com/webhmi на мобильном телефоне (предварительно установив Viber), нажмите кнопку Have a look.<br/>

Версия 16:16, 15 декабря 2016

О скриптах Lua

WebHMI начиная с версии 1.10.0.3393 позволяет создавать пользовательские скрипты на языке Lua 5.1 [1].

Управление скриптами происходит в пункте меню Setup --> Scripts:
Lua-scripts-1.png

Scripts edit.png

Каждый скрипт должен содержать в себе функцию с именем main. Именно она будет вызвана в необходимый момент (в зависимости от настроек скрипта - в каждом цикле, при действии на dashboard или при изменении значения регистра). Также, весь скрипт будет выполнен один раз при запуске демона. Это необходимо для компиляции сценария Lua и его валидации. Выполнен будет весь код, который находится в глобальной области видимости (т.е. вне функции main, функция main не будет вызвана). Это может быть полезно для инициализации некоторых переменный и т.п.

В функцию main будет передан один параметр — userId — ID пользователя, который выполнил этот скрипт. Если скрипт выполняется в каждом цикле или при изменении регистра то userId будет равен нулю.

WebHMI накладывает следующие ограничения на стандартные функции и библиотеки языка Lua:

  • не доступны такие функции и таблицы: require, print, loadfile, dofile, os.execute, os.getenv, os.remove, os.rename, os.tmpname, package, debug.debug, debug.getfenv, debug.getregistry, arg
  • не доступны библиотеки: io

Помимо стандартных функций Lua, в WebHMI определены еще такие функции:

  • GetReg
  • SetReg
  • WriteReg
  • AddInfoMessage
  • AddWarningMessage
  • AddAlertMessage
  • SendSMS
  • SendTelegramMessage
  • SendViberMessage
  • ERROR
  • INFO
  • DEBUG
  • TRACE
  • ApplyRecipe


Для удобства работы с регистрами из программ Lua, каждому регистру можно присвоить символическое имя и работать из Lua уже с этим именем. Это имя указывается в настройках регистра в поле Variable name:
Lua-scripts-3.png

Lua-scripts-4.png

Пример простейшего скрипта, который показывает вызовы всех WebHMI функций:

function main (userId)
    local randomVal = GetReg("random_val");
    SetReg("random_val_copy", randomVal);
    WriteReg("result", randomVal + 2);

    AddInfoMessage("This is a Lua script", userId);
    AddWarningMessage("Warning. This is a Lua script", userId);
    AddAlertMessage("Alert! This is a Lua script", userId);

    SendSMS("380501234567", "This is a test SMS");

    ERROR("This message will be added to communication log with ERROR level");
    INFO("This message will be added to communication log with INFO level");
    DEBUG("This message will be added to communication log with DEBUG level");
    TRACE("This message will be added to communication log with TRACE level");
end

Несмотря на то, что встроенный редактор проверяет синтаксис программы, он не в состоянии выявить все ошибки, которые могу возникнуть в процессе выполнения скрипта. В случаях, если во время его выполнения возникнут какие-либо ошибки, они будут выведены в Communication Log.

Например, при выполнении этого скрипта произойдет ошибка т.к. переменная random не объявлена.

function main (userId)
    
  local v1 = GetReg("Drying_Humidity1_Value");
  v1 = v1+random; -- ошибка здесь, если убрать random, всё становится ок
  
  SetReg("Drying_Humidity1_Value", v1);
  WriteReg("Drying_Humidity1_Value", v1); 
  
  AddInfoMessage(v1, userId);
end

В Communication Log можно будет увидеть такие записи:

Jan 23 12:09:27.047: ERROR: LUA scripts: Can't execute LUA script #1. Error #2: [string "Calculate humidity"]:4: attempt to perform arithmetic on a nil value (global 'random')
Jan 23 12:09:27.551: ERROR: LUA scripts: Can't execute LUA script #1. Error #2: [string "Calculate humidity"]:4: attempt to perform arithmetic on a nil value (global 'random')
Jan 23 12:09:28.051: ERROR: LUA scripts: Can't execute LUA script #1. Error #2: [string "Calculate humidity"]:4: attempt to perform arithmetic on a nil value (global 'random')

Здесь видно, что произошла ошибка при попытке выполнения арифметической операции с неопределенной переменной (nil). Ошибка произошла в скрипте номер 1, его название "Calculate humidity", ошибка произошла в строке номер 4. Переменная, которая вызвала ошибку называется 'random'.

Таким образом, с помощью этого лога можно найти все ошибки выполнения сценариев.

GetReg(variable_name[, connection_name])

Функция GetReg возвращает текущее значение регистра с именем переменной variable_name где variable_name — это значение Srcipt alias из настроек регистра. Вместо variable_name можно указывать число — ID регистра. Однако, ID регистра — это менее наглядный способ и он усложняет чтение программы.

Опциональный параметр connection_name можно указать если в нескольких разных соединениях есть регистры с одинаковым variable_name. В этом случае connection_name указывает из какого конкретно соединения необходимо читать регистр с именем variable_name. Также, вместо строки connection_name можно указывать ID соединения. Однако, опять же, константы усложняют чтение кода и предпочтительней использовать именованные строки.

Если регистр не найден или не был прочитан то возвращается значение nil.

Для удобства выбора регистров возле редактора скриптов есть три дополнительные кнопки.
Help-buttons.png

При нажатии на любую из них появляется всплывающее окно со списком регистров.
Regs-select.png

После щелчка по интересуещему регистру в редактор будет вставлен код с идентификатором выбранного регистра (variable_name если есть или ID) и комментарием с именем регистра, его адресом и именем соединения.
Reg-selected.png

SetReg(variable_name[,connection_name] , new_value)

Функция SetReg устанавливает текущее значение регистра с именем переменной variable_name в new_value для текущего цикла. Запись во внешние устройства не происходит и при опросе этого регистра в последующих циклах будет прочитано старое значение. Возвращает 1 если произошла ошибка и 0 в случае успеха.

Параметры variable_name и connection_name работают так же как и в функции GetReg.

WriteReg(variable_name, new_value)

Функция WriteReg устанавливает текущее значение регистра с именем переменной variable_name в new_value для текущего цикла цикле и записывает это значение во внешнее устройство в начале следующего цикла. При опросе этого регистра в последующих циклах будет прочитано новое значение (если оно не изменится самим устройством). Возвращает 1 если произошла ошибка и 0 в случае успеха.

Параметры variable_name и connection_name работают так же как и в функции GetReg.

SendSMS(phone_number, message)

Функция SendSMS отправляет запрос на отправку SMS на номер phone_number с текстом message. Возвращает false если произошла ошибка и true в случае успеха. Успех не означает доставку сообщения, а только успех при создании запроса. Для работы этой функции необходимо наличие интернет-подключения и предоплаты за услуги SMS.
Формат phone_number — только цифры с указанием кода страны, без пробелов, скобок, знака плюс. Например, 380123456789.

SendTelegramMessage(chatId, message)

Функция SendTelegramMessage отправляет сообщение с текстом message в чат с Id = chatId . Возвращает 1 если произошла ошибка и 0 в случае успеха. Успех не означает доставку сообщения, а только успех при создании запроса. Для работы этой функции необходимо наличие работающего интернет-подключения и доступа к серверу webhmicloud.com.

Для получения ChatId перейдите по ссылке http://telegram.me/webhmibot на мобильном телефоне (предварительно установив Telegram) и начните диалог с ботом webhmibot командой /start. В ответ вы получите сообщение с уникальным идентификатором чата ChatId.

Пример:

Chatid.png


SendViberMessage(chatId, message)

Функция SendViberMessage отправляет сообщение с текстом message в чат с Id = chatId. Возвращает 1 если произошла ошибка и 0 в случае успеха.
Успех не означает доставку сообщения, а только успех при создании запроса. Для работы этой функции необходимо наличие работающего интернет-подключения, учетной записи в системе Level2 и положительного баланса в этой системе. Отправка сообщений в Viber — платная услуга.

Для получения ChatId перейдите по ссылке http://viber.com/webhmi на мобильном телефоне (предварительно установив Viber), нажмите кнопку Have a look.
Viber-pa.png

Вы попадете в публичный аккаунт WebHMI. Перейдите в личные сообщения публичного аккаунта.
Viber-private-message.png

Напишите любой текст в чате. В ответ вы получите сообщение с уникальным идентификатором чата ChatId.
400px

AddInfoMessage(message, userId)

Функция AddInfoMessage добавляет сообщение message с уровнем Info в журнал Messages. userId — это ID пользователя, от имени которого должно быть добавлено сообщение. Возвращает 1 если произошла ошибка и 0 в случае успеха.

AddWarningMessage(message, userId)

Функция AddWarningMessage добавляет сообщение message с уровнем Warning в журнал Messages. userId — это ID пользователя, от имени которого должно быть добавлено сообщение. Возвращает 1 если произошла ошибка и 0 в случае успеха.

AddAlertMessage(message, userId)

Функция AddAlertMessage добавляет сообщение message с уровнем Alert в журнал Messages. userId — это ID пользователя, от имени которого должно быть добавлено сообщение. Возвращает 1 если произошла ошибка и 0 в случае успеха.

ERROR(message)

Функция ERROR добавляет сообщение message уровня ERROR в Communication Log (Maintenance --> Communication Log). Возвращает 1 если произошла ошибка и 0 в случае успеха.

INFO(message)

Функция INFO добавляет сообщение message уровня INFO в Communication Log (Maintenance --> Communication Log). Возвращает 1 если произошла ошибка и 0 в случае успеха.

DEBUG(message)

Функция DEBUG добавляет сообщение message уровня DEBUG в Communication Log (Maintenance --> Communication Log). Возвращает 1 если произошла ошибка и 0 в случае успеха.

TRACE(message)

Функция TRACE добавляет сообщение message уровня TRACE в Communication Log (Maintenance --> Communication Log). Возвращает 1 если произошла ошибка и 0 в случае успеха.

ApplyRecipe(recipeId, userId)

Функция ApplyRecipe применяет рецепт с номером recipeId от имени пользователя с id = userId. Если у данного пользователя нет прав доступа к этому рецепту то рецепт применен не будет. Применение рецепта заключается в записи в регистры, которые указаны в рецепте, соответствующих значений.


GetCurrentAlerts()

Функция GetCurrentAlerts возвращает список текущих аварий. Возвращаемое значение — таблица. Ключем является номер аварии, значением — таблица со свойствами аварии. Свойства аварии:

СвойствоОписаниеТип данных
startTimeВремя возникновения аварииNumber, UnixTime
regIdНомер регистра, в котором флаг аварии привел к этой аварииNumber
regAliasИмя переменной регистра для программString
bitНомер бита с флагом аварииNumber
titleНазвание аварииString
connectionTitleНазвание соединенияString
connectionIdID соединенияNumber
connectionAliasИмя переменной соединения для программString
acknowledgedByИмя пользователя, который подтвердил аварию. Если авария не подтверждена — пустая строка.String
acknowledgedTimeВремя, когда авария был подтверждена. Если авария не подтверждена — 0.Number, UnixTime
canBeAcknowledgedФлаг, обозначающий что данную аварию можно подтверждать.Boolean

Используя данную структру, можно реализовать, например, различные сценарии оповещения о неподтвержденных авариях.

Пример такой программы:

local notificationsSent = {};
function main (userId)
    local alerts = GetCurrentAlerts();
    if (#alerts > 0) then
        for num,alert in pairs(alerts) do 
            local now = os.time();
            local canBeAcknowledged = alert['canBeAcknowledged'];
            local acknowledgedTime = alert['acknowledgedTime'];
            local startTime = alert['startTime'];
            local waitSecondsBeforeEscalate = 300; -- оповещать об авариях, которые неподтвержены более 5 минут
            local regId = alert['regId'];
            local bit = alert['bit'];
            if (canBeAcknowledged and acknowledgedTime == 0) then
                if (now - startTime > waitSecondsBeforeEscalate) then
                    if (notificationsSent[regId] == nil or notificationsSent[regId][bit] ~= startTime) then
                        --ERROR("Alert" .. alert['title'] .. " was not acknowledged!");
                        SendSMS("380501234567", "Не подтведжена авария: " .. alert['title']);
                        if (notificationsSent[regId] == nil) then
                            notificationsSent[regId] = {};
                        end
                        notificationsSent[regId][bit] = startTime;
                    end
                end
            end
        end
    end
end