Lua Сценарії
Про
Система сценаріїв у контролері Butler використовується для автоматизації поведінки вашого будинку.
Lua сценарії створені для ще більшого розширення можливостей автоматизації, з можливістю реалізації більш складних сценаріїв автоматизації (ніж можливо за допомогою базових блокових сцен) у Lua Programming Language.
Сценарій складається з частини умови та частини дії, які редагуються у відповідних та окремих полях інтерфейсу користувача.
Життєвий цикл сцени
Коли сценарій створюється, менеджер сценаріїв збирає список можливих тригерів для нього і зберігає їх.
Потім, коли будь-який з тригерів активовано (наприклад, спрацьовує параметр пристрою), менеджер сценаріїв перевіряє умову сценарію, а потім викликає частину дії сценарію.
Виконання сценарію розділене на блоки, кожен block
виконується послідовно, і може повернути delay
перед наступним блоком, і (необов'язково) повідомлення для реєстрації в журналі.
Контекст сцени відкидається після кожного блоку , тому, якщо вам потрібно зберігати деякі дані між блоками, вам слід використовувати глобальні змінні. Спільний доступ до даних між блоками ще не реалізовано.
Виконання сцени зупиняється, коли будь-який блок повертає finished = true
, або коли всі блоки виконано.
Існує також жорстке обмеження лічильників блоків, якщо сценарій перевищує його, його буде зупинено.
Умова сцени
Умова сцени визначається як об'єкт JSON.
[
{
"type": "DeviceParameter",
"id": 22,
"parameter": "Level",
"operation": "==",
"valueType": "Integer",
"value": 20
},
{
"type": "LogicOr"
},
{
"type": "DeviceParameter",
"id": 23,
"parameter": "currentSetpoints.Heat",
"operation": "changed",
"valueType": "None"
}
]
Коренем умови сцени є масив, що містить описи умов. Умови оцінюються послідовно.
Типи умов
Для кожної умови, в масиві умов, поле type
є обов'язковим і вказує, який тип умови. Поля умов можуть відрізнятися для різних типів умов (за винятком поля type
), усі вони описані нижче.
Логічні умови
Логічні умови використовуються для об'єднання кількох умов разом або їх заперечення для створення більш складних сценаріїв. Доступні три типи логічних умов:
LogicAnd
Ця умова істинна, якщо умови до і після неї є істинними.
{
"type": "LogicAnd"
}
LogicOr
Ця умова істинна, якщо принаймні одна з її сусідніх умов є істинною.
{
"type": "LogicOr"
}
LogicNot
Ця умова заперечує наступну умову
{
"type": "LogicNot"
}
Умови пристрою
Існує кілька типів умов, які перевіряють параметри пристрою.
Зміна параметра пристрою
"type": "DeviceParameter"
Сценарій можна запустити при зміні "будь-якого" параметра будь-якого пристрою, якщо зазначена зміна робить умову правдивою (операція changed
є дещо винятком, див. Умова сцени > Операції > changed).
{
"type": "DeviceParameter",
"id": 22,
"parameter": "Value",
"operation": ">",
"valueType": "Integer",
"value": 20
}
type
- ідентифікатор типу умовиid
- ідентифікатор пристроюparameter
- назва параметра (див. Специфікацію Butler API для отримання додаткової інформації про доступні параметри)operation
- операція порівняння (див. Умова сцени > Операції)valueType
- тип значення порівняння (див. Умова сцени > Типи значень)value
- саме значення порівняння (повинно бути пропущено, якщоvalueType
дорівнює"None"
)
Порівняння пристроїв
"type": "DevicesComparison"
Цей тип умови використовується для запуску, коли результат порівняння значень параметрів двох пристроїв стає істинним. Користувач повинен вказати дві цілі для порівняння, якими може бути будь-який довільний параметр будь-якого пристрою, єдина вимога полягає в тому, що параметри повинні бути одного типу (тобто обидва числові).
{
"type": "DeviceComparison",
"targets": [
{
"id": 22,
"parameter": "Level",
"valueType": "Integer"
},
{
"id": 23,
"parameter": "Value",
"valueType": "Double",
}
],
"operation": "<"
}
target
- (масив з двох елементів) список цілейid
- ідентифікатор пристроюparameter
- назва параметра (див. Специфікацію Butler API для отримання додаткової інформації про доступні параметри)valueType
- тип значення порівняння (див. Умова сцени > Типи значень)
operation
- операція порівняння Умова сцени > Операції
Умови погоди
"type": "Weather"
Якщо все налаштовано правильно, контролер періодично завантажує дані про погоду для налаштованого місця розташування, зміни яких можуть запускати сценарії.
{
"type": "Weather",
"condition": "time_of_day",
"operation": "==",
"valueType": "String",
"value": "Day"
}
condition
- властивість погоди для перевірки Може бути одним із наступних варіантів:temperature
- температура зовнішнього повітря (у градусах Цельсія)humidity
- відносна вологістьpressure
- тискtime_of_day
-Night
абоDay
, Ніч починається в час заходу сонця, День починається на сході сонцяweather
- погодні умови, доступні варіанти:Rain
,Snow
,Mist
,Clear
,Clouds
. Для ньогоoperation
має бутиcontains
operation
- операція порівняння Умова сцени > ОпераціїvalueType
- тип значення порівняння (див. Умова сцени > Типи значень)value
- саме значення порівняння (повинно бути пропущено, якщоvalueType
дорівнює"None"
)
Операції
Операції використовуються для порівняння значень в умовах.
==
- значення дорівнює значенню порівняння!=
- значення не дорівнює значенню порівняння>
- значення більше значення порівняння>=
- значення більше або дорівнює значенню порівняння<
- значення менше значення порівняння<=
- значення менше або дорівнює значенню порівнянняchanged
- значення змінилося (значення порівняння ігнорується в цьому випадку)contains
- значення містить значення порівняння (лише для типу умовиWeather
)
Для блоку умови DevicesComparison
також доступна додаткова операція:
diff==
- різниця між значеннями дорівнює значенню порівнянняdiff!=
- різниця між значеннями не дорівнює значенню порівнянняdiff>
- різниця між значеннями більша за значення порівнянняdiff>=
- різниця між значеннями більша або дорівнює значенню порівнянняdiff<
- різниця між значеннями менша за значення порівнянняdiff<=
- різниця між значеннями менша або дорівнює значенню порівняння
Типи значень
Тип значення визначає, як слід обробляти значення порівняння.
None
- значення порівняння не потрібнеInteger
- значення порівняння є цілим числомInteger64
- значення порівняння є 64-бітним цілим числомDouble
- значення порівняння є числом з плаваючою комою подвійної точностіFloat
- значення порівняння є числом з плаваючою комою одинарної точностіString
- значення порівняння є рядкомBoolean
- значення порівняння є булевим
Дія сцени
Дія сцени - це код Lua, який буде виконано, коли буде запущено сцену.
local device = gateway.get_device(33)
device:call_action("setStatus", {status = true})
return {
status = true,
delay = 0,
message = "Device turned on",
finished = true
}
Сцена повинна повертати результат свого виконання у вигляді таблиці з наступними полями:
- status - результат виконання сцени (boolean)
- delay - затримка перед наступним кроком сцени (integer) див. Дія сцени > Затримка
- message - повідомлення для реєстрації в журналі системи (string)
- finished - чи завершено сцену, чи ні (boolean)
Також можна використовувати спрощене повернення, у цьому випадку це має бути масив з 4 елементів у такому порядку: status, delay, message, finished.
return {true, 0, "Device turned on", true}
Глобальні змінні
Середовище виконання Lua в Butler надає набір функцій і об'єктів для взаємодії з системою, а також деякі додаткові утиліти.
- block - індекс поточного блоку, див. Життєвий цикл сцени
- gateway - об'єкт шлюзу, див. Об'єкт шлюзу
- log - функції ведення журналів, див. Функції ведення журналів
- json - модуль JSON, див. Модуль JSON
- http - модуль HTTP, див. Модуль HTTP
- utils - допоміжні функції, див. Модуль Utils
Функції ведення журналів
Функції ведення журналів використовуються для реєстрації повідомлень у системному журналі. Існує чотири рівні ведення журналів: debug
, info
, warn
, error
.
Усі функції ведення журналів приймають кілька аргументів будь-якого типу, які будуть об'єднані в одне повідомлення.
log.debug(...)
записує повідомлення з рівнем налагодження
log.info(...)
записує повідомлення з рівнем інформації
log.warn(...)
записує повідомлення з рівнем попередження
log.error(...)
записує повідомлення з рівнем помилки
log.debug("Debug message")
log.info("Info message")
log.warn("Warning message")
log.error("Error message")
log.debug("Debug message", {a = 1, b = 2}, 3, true)
Шлюз
Об'єкт gateway
використовується для взаємодії з системою, отримання інформації про пристрої, кімнати тощо.
gateway.get_device(device_id)
Повертає об'єкт пристрою за його ідентифікатором.
local device = gateway.get_device(33)
Отриманий об'єкт представляє пристрій, повний список доступних методів див. Об'єкт пристрою
gateway.get_devices()
Повертає список усіх пристроїв у системі.
local devices = gateway.get_devices()
for _, device in ipairs(devices) do
log.info("Device name: ", device.name)
end
gateway.send_notification(clients, message)
Надсилає push-повідомлення вказаним клієнтам.
Параметри:
clients
- список ідентифікаторів клієнтів, яким потрібно надіслати сповіщення, або*
, щоб надіслати всім клієнтамmessage
- повідомлення push-повідомлення
local device = gateway.get_device(33)
gateway.send_notification({"*"}, "Device " .. device.name .. " turned " .. (device.parameters.Status == true and "on" or "off")
gateway.weather
Містить поточні дані про погоду
gateway.weather.humidity
- відносна вологістьgateway.weather.temperature
- температура зовнішнього повітря (у градусах Цельсія)gateway.weather.pressure
- атмосферний тискgateway.weather.visibility
- видимість у метрахgateway.weather.time_of_day
-night
абоday
, ніч починається в час заходу сонця, день починається на сході сонцяgateway.weather.wind.speed
- швидкість вітру в м/сgateway.weather.wind.direction
- напрямок вітру в градусахgateway.weather.wind.cardinal
- напрямок вітру за сторонами світу (N, NE, E, SE, S, SW, W, NW)gateway.weather.weather
- список поточних погодних умов, доступні варіанти:Rain
,Snow
,Mist
,Clear
,Clouds
local device = gateway.get_device(33)
if gateway.weather.temperature > 20 then
device:call_action("setStatus", {status = true})
else
device:call_action("setStatus", {status = false})
end
gateway.scenes
Містить методи для взаємодії з іншими сценами
gateway.scenes.activate(scene_id)
Активує сцену за її ідентифікатором.
gateway.scenes.activate(1)
gateway.scenes.deactivate(scene_id)
Деактивує сцену за її ідентифікатором.
Неактивні сцени не будуть запускатися умовами, але їх можна активувати вручну або іншими сценами.
gateway.scenes.deactivate(1)
gateway.scenes.run(scene_id)
Запускає сцену за її ідентифікатором.
Коли сцена запускається таким чином, її умови не перевіряються, і її дія виконується негайно.
gateway.scenes.run(1)
Об'єкт пристрою
Екземпляр об'єкта пристрою повертається функцією gateway.get_device
. Він використовується для взаємодії з пристроєм, отримання інформації про нього та виклику дій.
Поля:
id
- ідентифікатор пристроюname
- назва пристроюtype
- тип пристрою, див. Специфікацію Butler API для отримання додаткової інформаціїhidden
- чи приховано пристрій в інтерфейсі користувачаlast_online
- позначка часу останньої активності пристроюinterfaces
- список інтерфейсів пристрою (наприклад,ZWaveDevice
,SwitchBinary
тощо, див. Специфікацію Butler API для отримання додаткової інформації про інтерфейси та їх параметри)parameters
- таблиця, що містить параметри пристрою (наприклад,Level
,Value
тощо, див. Специфікацію Butler API для отримання додаткової інформації про параметри та їх значення
device:call_action(action_name, params)
Параметри:
action_name
- назва дії для викликуparams
- таблиця з параметрами для дії
Викликає дію пристрою із зазначеними параметрами.
Дія не буде викликана, якщо пристрій її не підтримує, або якщо параметри неправильні.
local device = gateway.get_device(33)
device:call_action("setStatus", {status = true})
Модуль JSON
Надає функції для кодування та декодування рядків JSON.
json.encode(value, options)
Повертає JSON рядкове представлення значення.
Параметри:
value
- значення для кодуванняoptions
- таблиця з параметрами для кодуванняpretty
- якщоtrue
, отриманий JSON буде відформатовано з новими рядками та відступамиindent
- ціле число, кількість пробілів для використання для відступу, ігнорується, якщоpretty
має значенняfalse
, за замовчуванням2
local json_str = json.encode(
{
a = 1,
b = 2
})
-- will return '{"a":1,"b":2}'
local json_str = json.encode(
{
a = 1,
b = 2
},
{
pretty = true,
indent = 8
})
--[[
will return:
{
"a": 1,
"b": 2
}
]]
json.decode(json_str)
Повертає декодоване значення з рядка JSON.
Параметри:
json_str
- рядок JSON для декодування
local value = json.decode('{"a":1,"b":2}')
-- value will be a table {a = 1, b = 2}
Модуль HTTP
Модуль HTTP є синхронним і блокуватиме виконання, доки запит не буде завершено, тому він може (і, ймовірно, буде) сповільнювати виконання сцени.
Надає функції для створення HTTP-запитів.
http.get(url, options)
Виконує GET-запит до вказаної URL-адреси.
Параметри:
url
- URL-адреса запитуoptions
- таблиця з параметрами для запитуheaders
- таблиця з заголовками для надсиланняparams
- таблиця з параметрами запиту
Повертає таблицю з даними відповіді:
status
- код стану HTTPbody
- тіло відповіді
local response = http.get("http://example.com")
log.info("Response status: ", response.status)
log.info("Response body: ", response.body)
http.post(url, options)
Виконує POST-запит до вказаної URL-адреси.
Параметри:
url
- URL-адреса запитуoptions
- таблиця з параметрами для запитуheaders
- таблиця з заголовками для надсиланняparams
- таблиця з параметрами запитуbody
- тіло запиту
Повертає таблицю з даними відповіді:
status
- код стану HTTPbody
- тіло відповіді
local response = http.post("http://example.com", {
body = json.encode({
a = 1,
b = 2
}),
headers = {
["Content-Type"] = "application/json"
}
})
log.info("Response status: ", response.status)
log.info("Response body: ", response.body)
http.put(url, options)
Виконує PUT-запит до вказаної URL-адреси.
Ті самі параметри та значення, що й у http.post(url, options)
http.delete(url, options)
Виконує DELETE-запит до вказаної URL-адреси.
Ті самі параметри та значення, що й у http.post(url, options)
Модуль Utils
Надає допоміжні функції.
utils.in_period(time, period)
Перевіряє, чи знаходиться вказаний час у вказаному періоді.
Параметри:
time
- час для перевірки у форматіHH:MM
period
- період для перевірки у форматіHH:MM-HH:MM
Повертає true
, якщо час знаходиться в періоді, false
інакше.
local result = utils.in_period("12:00", "10:00-14:00")
log.info("Time is in period: ", result)
-- will return true