Документация разработчика

Общая информация

Внутренние переменные скрипта

_script_name - переменная, содержащая название текущего скрипта
_script_uuid - переменная, содержащая uuid (уникальный идентификатор) текущего скрипта
store - таблица для хранения временных данных, уникальная для каждого скрипта. Ее можно использовать просто как переменную:

store.value = 5
print(store.value) -- 5

main_store - таблица, в которой находятся хранилища всех запущенных с момента запуска системы скриптов.
Первый уровень таблицы — UUID скриптов. Второй уровень — store каждого скрипта. UUID скрипта можно узнать, нажав на значок "i" в интерфейсе. С помощью этой таблицы можно получать доступ к хранилищам других скриптов:

store.table = {1,2,3,4,5}
print(main_store["8d72fe2f-801e-48d1-ac1a-526f3e2622c0"].table) -- { 1, 2, 3, 4, 5 }

Например, это позволяет передавать между скриптами функции или таблицы, которые нельзя напрямую передать через BUS.

Функции для работы с логами

Функции log_info(), log_warning(), log_error(), log_user()

Добавляют в системный лог запись уровня "INFO", "WARNING", "ERROR" и "USER" соответственно.
Использование: log_info("Found correlation!"), log_warning("Found correlation!") , log_error("Found correlation!") , log_user("Found correlation!")
Ничего не возвращает.

Функции log() и print()

log() - алиас для функции log_user()
print() - алиас для функции log_user()

Функции для работы с центральной шиной

Функция update()

Функция update() предназаначена для создания и обновления топиков на шине.

Функция принимает на вход таблицу ключ-значение, ключами в которой являются имена параметров, а значениями — значения параметров.

Названия доступных параметров:

  • topic: имя топика, строка
  • value: значение топика, строка или число(преобразуется в строку)
  • type: тип топика, строка
  • tags: теги топика(таблица lua)
  • shadow: признак "тихого" обновления, true или false
  • check: признак проверки перед обновлением, true или false
  • time: время обновления, если оно отличается от текущего, число, микросекунды

Обязателен только параметр topic. При передаче таблицы только с параметром topic будет обновлено время обновления соответствующего топика.

Функция возвращает true или false, и в случае false, вторым аргументом - описание ошибки.

Данные, поступающие из драйверов или скриптов, могут обновлять значение топика в стандартном (standard) или теневом (shadow) режиме В первом случае, отработают все скрипты, которые подписаны на изменения значения топика, во втором случае, значение будет изменено без запуска скриптов. При обновлении самим скриптом топика, на который он подписан, коллбек в скрипте вызываться не будет.
Если shadow = true, скрипты, подписанные на изменение, запущены не будут.

Если check = true, время в bus обновится только если новое значение топика не будет совпадать со старым(все приводится к строке). Скрипты тоже не будут запущены, если значение не изменилось.

Пример использования функции update():
local result, err = update{topic = "/test/", value = 40, type = "test_type", tags = {"test", "test2"}}

Функция bus_serialize()

Получает содержимое центральной шины (bus) в виде вложенной таблицы.
Использование: local table = bus_serialize(pattern)
Возвращает таблицу. Если передана переменная "pattern", то будет выбрана только часть таблицы, соответствующая заданному шаблону. Шаблоны соответствуют правилам lua patterns

Вспомогательные функции

Функция round()

Функция для "правильного" математического округления с произвольной точностью.
Получает число и количество знаков после запятой, возвращает округленное число. Если количество знаков не указано, используется 2.
Использование: local round_value = round(value, rounds)

Примеры использования:

local value = 3.1415926535
print(round(value)) --> 3.14
print(round(value, 2)) --> 3.14
print(round(value, 3)) --> 3.142

Функция deepcopy()

Функция для копирования таблиц lua(если попытаться скопировать таблицу table_a = table_b, мы получим две ссылки на одну и ту же таблицу).
Получает таблицу, возвращает копию таблицу. Таблица не должна быть рекурсивной, иначе функция переполнит стек.
Использование: local copy_table = deepcopy(table)

Пример использования:

local old_table = {1, 2, 4}
local copy_table = deepcopy(old_table)

Функция get_settings_value()

Функция, позволяющая использовать в скриптах значения настроек Glial (настраиваются во вкладке Settings панели).
Функция get_settings_value(name, [default_value]) вызывается обязательным значением name (имя настройки) и опциональным default_value (значение по умолчанию).
Возвращает 4 значения, если параметр есть в хранилище settings: true, значение настройки, имя настройки, описание настройки.
Возвращает 2 значения, если параметра нет в хранилище, но get_settings_value был вызван с default_value: true, значение настройки.
Возвращает одно значение, если параметра в хранилище нет, и get_settings_value без вызван без значения по умолчанию - false.

Пример использования:

local boolean, setting_value, setting_name, setting_description = get_settings_value('setting_name')

Встроенные библиотеки

Для использования этих библиотек не нужно делать require, они уже есть в области видимости каждого скрипта.

Библиотека HTTP Client

Библиотека, реализующая примитивы для http-запросов.
Уже созданный экземпляр доступен через объект http_client, т.е. для метода request() нужно вызвать http_client.request()
Пример использования:

local r = http_client:get('http://google.com')
print(r.body)

Документация

Библиотека MQTT

Библиотека, реализующая клиента протокола MQTT. Доступна через объект mqtt
Пример использования:

local mqtt_object = mqtt.new("client_id", true)
mqtt_object:connect({ host='127.0.0.1', port=1883 })
ok, err = mqtt_object:subscribe('my/topic/#', 1)
ok, err = mqtt_object:publish('my/topic/#', 'Some payload as string', mqtt.QOS_0, mqtt.RETAIN)

Документация

Библиотека JSON

Библиотека, конвертирующая таблицы lua в json и обратно. Доступна через объект json
Пример использования:

json.encode({abc = 234, cde = 345}) --> '{"cde":345,"abc":234}'
json.decode('[123, "hello"]') --> [123, 'hello']

Документация

Библиотека Socket

Библиотека для доступа к системным сокетам. Доступна через объект socket
Пример использования:

local sock_1 = socket('AF_INET', 'SOCK_DGRAM', 'udp')
local sock_2 = socket('AF_INET', 'SOCK_DGRAM', 'udp')
sock_1:bind('127.0.0.1')
sock_2:sendto('127.0.0.1', sock_1:name().port,'X')
message = sock_1:recvfrom()
print(message) --> X

Документация

Библиотека Clock

Библиотека для получения текущего времени. Доступна через объект clock

local current_time_s = clock.time()  -- = clock.time64()/1000/1000/1000
local current_time_ms = clock.time() * 1000 -- = clock.time64()/1000/1000
local current_time_ns = clock.time64() 

Документация

Библиотека Fiber

Библиотека для работы с потоками. Доступна через объект fiber
Не стоит подключать библиотеку fiber вручную, т.е. делать "local fiber = require 'fiber'".
В этом случае, ошибки внутри тредов fiber не попадут в лог конкретного скрипта и не сгенерируют ошибку, что усложняет отладку.
В библиотеке доступны методы fiber.sleep(), fiber.create(), fiber.kill(), fiber.yield(), fiber.self(), fiber.status(). Для остальных нужно делать require и оборачивать функции, которые запускаются через fiber.create() в pcall()/xpcall().
Пример использования:

local function loop()
   while true do
      print("tick")
      fiber.sleep(1.2) --seconds
   end
end
fiber.create(loop)

Документация

Скрипты и драйвера

Drivers

Драйвера — это скрипты на Lua, которые реализуют тот или иной протокол(часто с привлечением сторонних библиотек) для связи с устройством, конвертируя данные приходящие с каждого устройства в единый формат. Они работают в качестве транслятора между "языком" устройства и общей шиной.

Рассмотрим драйверы подробнее на примере шаблона драйвера, который подставляется при его создании:

masks = {"/test/1", "/test/2"}

local function main()
   while true do
      print("Test driver loop")
      fiber.sleep(600)
   end
end

function init()
   store.fiber_object = fiber.create(main)
end

function destroy()
   if (store.fiber_object:status() ~= "dead") then
      store.fiber_object:cancel()
   end
end

function topic_update_callback(value, topic, timestamp)
   print("Test driver callback:", value, topic)
end

Функция init() выполняется при запуске драйвера. В данном примере, она создает объект fiber_object из функции main.

function init()
   store.fiber_object = fiber.create(main)
end

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

local function main()
   while true do
      print("Test driver loop")
      fiber.sleep(600)
   end
end

Для управления файбером (потоком) используются функции модуля fiber. В данном случае - fiber.sleep(600) - скрипт будет ждать 600 секунд по окончанию каждой итерации цикла.

Функция destroy() выполняется при остановке скрипта.
В ней целесообразно размещать логику, которая выгружает из памяти используемые данные, сохраняет состояние для будущих запусков или предотвращает завершение скрипта до перезагрузки Glial.

function destroy()
   if (store.fiber_object:status() ~= "dead") then
      store.fiber_object:cancel()
   end
end

В коде примера, функция destroy() завершает файбер, в случае если он уже не завершен или остановлен из-за ошибки.

В случае, если остановку драйвера требуется отсрочить до перезагрузки Glial(или если нельзя завершить драйвер без перезагрузки системы), функция destroy должна вернуть false.

function destroy()
   return false
end

Функция topic_update_callback() используется для реакции на изменение значений топиков на шине.

function topic_update_callback(value, topic, timestamp)
   print("Test driver callback:", value, topic)
end

Топики, изменение которых отслеживается драйвером перечисляются в виде масок в переменной masks.

masks = {"/test/1", "/test/2"}

Т.е. в данном случае, при каждом изменении топиков /test/1 и /test/1 будет выполнена функция, делающая запись в логах с названием и значением топика.

Примеры драйверов

Bus-event scripts

Этот тип скриптов выполняется для каждого устройства из группы устройств, определяемых маской, при обновлении их данных на центральной шине.
Bus-event scripts

Маски должны описываться в виде lua patterns, но с условием — паттерн должен соотвествовать всей строке, а не только его части.

Т.е. маска "/test/" будет соотвествовать только топику "/test/", но не "/test/value". Для соотвествия множеству топиков надо указать измеряемую часть специально: "/test/.+". В таком виде маска будет соотвествовать топикам "/test/value", "/test/value/exp" и всем другим, начинающимся на "/test/".

В теле скрипта должна присутствовать функция event_handler(), в которую будет передано значение измененного топика, адрес и время изменения этого топика:

function event_handler(value, topic, timestamp)
   print(value, topic, timestamp) --> "5 /test/device 1542652525"
end

Также, в теле скрипта можно создать функции init() и destroy(), которые будут вызваны при инициализации скрипта и его выгрузке соответственно.
Это может быть полезно, например, если нужно сделать экспорт множества топиков по маске в MQTT.

У Bus-event скриптов существует возможность однократного запуска нажатием кнопки "Run Once" на странице редактиования скрипта или на странице со списком скриптов.
При однократном запуске, принудительно запускается event_handler() c аргументами value=0, topic="once". Не выполняются init() и destroy(). Однократный запуск полезен для отладки и совершения разовых действий.

Примеры bus-event скриптов

Web-event scripts

Скрипты, выполняемые при обращении к выбранному URL ("endpoint") с помощью HTTP запроса.

Web-event scripts

Функция, реализующая непосредственную логику при обработке запроса — http_callback().

При создании web-event скрипта, необходимо дать ему название и указать endpoint.
Полный адрес скрипта формируется как адрес_сервера:порт + /we/ + endpoint и отображается в нижней части модального окна как "Full script URL".

Создание web-event скрипта

В скриптах доступны переменные, содержащие данные запроса:

function http_callback(params, req)
   return {data=params}
end

Если в функции http_callback() вернуть одно значение-таблицу (напр. return table), то она будет сериализована в JSON и в таком виде отдана клиенту http-сервера.
Если необходимо управлять возвращаемыми данными напрямую, то надо вернуть 2 значения (напр. return nil, 'OK'), тогда первое значение будет отброшено, а второе - выдано клиенту в "сыром" виде без сериализации.
Для дополнительных сведений смотрите документацию HTTP сервера Tarantool

Примеры web-event скриптов

Timer-event scripts

Скрипты, выполняемые с определенным интервалом (указывается в секундах).

Timer-event script

Для создания скрипта, укажите его название и желаемый интервал его выполнения в секундах.

Код скрипта должен находиться внутри функции event_handler().

function event_handler()
   print("Timer event start")
end

Примеры timer-event скриптов

Schedule scripts

Скрипты, выполняемые по заданному расписанию.

Schedule script

Для создания скрипта, укажите его название и расписание в формате crontab.
Формат отличается от стандартного необходимостью указания секунд в интервале (первый символ). Если вам не нужны секунды, укажите в первом символе "0". Не указываете там "*", иначе скрипт будет запускаться каждую секунду в подходящих интервалах.

┌───────────── секунды (0 - 59)
│ ┌───────────── минуты (0 - 59)
│ │ ┌───────────── часы (0 - 23)
│ │ │ ┌───────────── дни месяца (1 - 31)
│ │ │ │ ┌───────────── месяца (JAN-DEC или 1 - 12)
│ │ │ │ │ ┌───────────── день недели (SUN-SAT или 0 - 6) (с воскресения до субботы)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *

К примеру, с такими настройками расписания, скрипт будет запускаться по четвергам в 13:45:15

 15 45 13 * * 4

Код скрипта должен находиться внутри функции event_handler().

function event_handler()
   print("Shedule event start")
end

Примеры shedule-event скриптов

Last Updated: 5/14/2019, 6:32:14 PM