Движок правил wb-rules 1.7: различия между версиями
Fizikdaos (обсуждение | вклад) |
|||
(не показано 6 промежуточных версий 3 участников) | |||
Строка 1: | Строка 1: | ||
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев. | |||
== | = Сценарии = | ||
== Постоянное хранилище данных == | |||
В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться | |||
даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации. | |||
<syntaxhighlight lang="js"> | |||
var ps = new PersistentStorage("my-storage", { global: true }); | |||
= | ps.key = "Hello World"; | ||
log(ps.key); | |||
</syntaxhighlight> | |||
Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев. | |||
== Виртуальные устройства == | |||
В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае | |||
В предыдущих версиях wb-rules | потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной | ||
памяти и восстанавливаются при загрузке сценария. | |||
Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое), | |||
можно добавить в описание контрола поле forceDefault: | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
defineVirtualDevice("vdev", { | |||
... | |||
cells: { | |||
... | |||
mycell: { | |||
type: "value", | |||
value: "10", | |||
forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10 | |||
} | |||
} | |||
}); | |||
</syntaxhighlight> | |||
= Модули = | |||
Начиная с версии 1.7, в движке правил wb-rules появилась поддержка подключаемых JS-модулей (похожая по поведению на | |||
аналогичную в Node.js, но с некоторыми особенностями). | |||
== Расположение == | |||
Поиск модулей происходит по следующим путям (в заданном порядке): | |||
* /etc/wb-rules/modules | |||
* /usr/share/wb-rules/modules | |||
Таким образом, пользовательские модули удобно складывать в /etc/wb-rules. | |||
Добавить свои пути можно редактированием /etc/default/wb-rules добавлением путей | |||
к переменной WB_RULES_MODULES через разделитель (:): | |||
<syntaxhighlight lang="bash"> | |||
... | |||
WB_RULES_MODULES="/etc/wb-rules/modules:/usr/share/wb-rules/modules" | |||
... | |||
</syntaxhighlight> | </syntaxhighlight> | ||
== Подключение модуля к сценарию == | |||
Подключение модуля происходит с помощью функции require(). Она возвращает объект, экспортированный | |||
модулем (exports). | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
... | |||
var | var myModule = require("myModule"); | ||
... | |||
</syntaxhighlight> | </syntaxhighlight> | ||
При этом движок правил будет искать файл myModule.js по очереди в директориях поиска (см. Расположение). | |||
Также допустим поиск файла модуля по поддиректориям в директориях поиска, тогда вызов будет выглядеть так: | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
( | ... | ||
var myModule = require("path/to/myModule"); | |||
... | |||
</syntaxhighlight> | </syntaxhighlight> | ||
После того, как файл будет найден, его содержимое будет выполнено, и из файла будет передан объект exports. | |||
'''Примечание 1:''' если модуль был подключен в одном сценарии несколько раз (несколько вызовов require("myModule")), | |||
содержимое файла модуля будет выполнено только в первый раз, а при повторных вызовах будет возвращаться сохранённый | |||
объект exports. | |||
'''Примечание 2:''' если модуль подключается в разных сценариях, для каждого сценария будет создан свой объект модуля | |||
и заново выполнен весь код модуля. Если модулю требуется использовать данные, общие для всех файлов сценариев, | |||
для хранения данных следует использовать объект module.static. | |||
=== | == Создание модуля == | ||
Для создания модуля достаточно создать файл с именем, соответсвующим имени модуля (с расширением .js) в директории | |||
/etc/wb-rules/modules. | |||
В этом файле будут доступны все стандартные функции wb-rules, а также набор специальных объектов, с помощью | |||
которого можно реализовать необходимый функционал модуля. | |||
=== Объект exports === | |||
С помощью объекта exports можно передавать пользовательскому сценарию параметры и методы. | |||
==== Пример ==== | |||
Файл модуля /etc/wb-rules/modules/myModule.js | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
exports.hello = function(text) { | |||
log("Hello from module, {}", text); | |||
}; | |||
< | exports.answer = 42; | ||
</syntaxhighlight> | |||
< | Файл сценария scenario.js | ||
<syntaxhighlight lang="js"> | |||
var m = require("myModule"); | |||
m.hello("world"); // выведет в лог "Hello from module, world" | |||
log("The answer is {}", m.answer); // выведет в лог "The answer is 42" | |||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Будьте внимательны:''' объект exports можно '''только дополнять значениями''', но не переопределять. | |||
Иначе значения экспортированы не будут! | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
exports = function(text) { | |||
log("Hello from module, {}", text); | |||
}; | |||
// Ожидание: | |||
var m = require("my-module"); | |||
m("world"); // не работает | |||
// На практике m будет пустым объектом. | |||
// | // Та же проблема произойдёт при использовании такой конструкции: | ||
log(" | exports = { | ||
hello: function(text) { | |||
log("Hello from module, {}", world); | |||
}, | |||
answer: 42 | |||
}; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Объект module === | |||
Объект module содержит параметры, относящиеся непосредственно к файлу модуля. | |||
==== module.filename ==== | |||
Содержит полный путь до файла ''модуля''. Например, для модуля, сохранённого в /etc/wb-rules/modules/myModule.js: | |||
< | <syntaxhighlight lang="js"> | ||
log(module.filename); // выведет /etc/wb-rules/modules/myModule.js | |||
</syntaxhighlight> | |||
==== module.static ==== | |||
Объект, хранящий данные, общие для всех экземпляров данного модуля. Его следует использовать для тех данных, | |||
которые должны быть доступны сразу во всех сценариях, использующих данный модуль. | |||
== | Файл /etc/wb-rules/modules/myModule.js | ||
<syntaxhighlight lang="js"> | |||
exports.counter = function() { | |||
if (module.static.count === undefined) { | |||
module.static.count = 1; | |||
} | |||
log("Number of calls: {}", module.static.count); | |||
module.static.count++; | |||
}; | |||
</syntaxhighlight> | |||
< | Файл сценария scenario1.js | ||
<syntaxhighlight lang="js"> | |||
var m = require("myModule"); | |||
m.counter(); | |||
m.counter(); | |||
</syntaxhighlight> | |||
Файл сценария scenario2.js | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
var | var m = require("myModule"); | ||
m.counter(); | |||
m.counter(); | |||
m.counter(); | |||
</syntaxhighlight> | |||
В результате работы двух скриптов в логе окажется 5 сообщений: | |||
< | <syntaxhighlight> | ||
Number of calls: 1 | |||
Number of calls: 2 | |||
Number of calls: 3 | |||
Number of calls: 4 | |||
Number of calls: 5 | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=== __filename === | |||
Переменная __filename берётся из глобального объекта сценария, к которому подключается модуль, и содержит имя файла | |||
сценария. | |||
В случае, если модуль подключается в другом модуле, переменная __filename, тем не менее, будет содержать именно | |||
В | имя файла сценария - вершины дерева зависимостей. | ||
< | Файл /etc/wb-rules/modules/myModule.js | ||
<syntaxhighlight lang="js"> | |||
exports.hello = function() { | |||
log(__filename); | |||
}; | |||
</syntaxhighlight> | |||
Файл сценария /etc/wb-rules/scenario1.js | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
var m = require("myModule"); | |||
m.hello(); // выведет scenario1.js | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Версия 12:39, 26 декабря 2018
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев.
Сценарии
Постоянное хранилище данных
В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации.
var ps = new PersistentStorage("my-storage", { global: true });
ps.key = "Hello World";
log(ps.key);
Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев.
Виртуальные устройства
В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной памяти и восстанавливаются при загрузке сценария.
Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое), можно добавить в описание контрола поле forceDefault:
defineVirtualDevice("vdev", {
...
cells: {
...
mycell: {
type: "value",
value: "10",
forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10
}
}
});
Модули
Начиная с версии 1.7, в движке правил wb-rules появилась поддержка подключаемых JS-модулей (похожая по поведению на аналогичную в Node.js, но с некоторыми особенностями).
Расположение
Поиск модулей происходит по следующим путям (в заданном порядке):
- /etc/wb-rules/modules
- /usr/share/wb-rules/modules
Таким образом, пользовательские модули удобно складывать в /etc/wb-rules.
Добавить свои пути можно редактированием /etc/default/wb-rules добавлением путей к переменной WB_RULES_MODULES через разделитель (:):
...
WB_RULES_MODULES="/etc/wb-rules/modules:/usr/share/wb-rules/modules"
...
Подключение модуля к сценарию
Подключение модуля происходит с помощью функции require(). Она возвращает объект, экспортированный модулем (exports).
...
var myModule = require("myModule");
...
При этом движок правил будет искать файл myModule.js по очереди в директориях поиска (см. Расположение).
Также допустим поиск файла модуля по поддиректориям в директориях поиска, тогда вызов будет выглядеть так:
...
var myModule = require("path/to/myModule");
...
После того, как файл будет найден, его содержимое будет выполнено, и из файла будет передан объект exports.
Примечание 1: если модуль был подключен в одном сценарии несколько раз (несколько вызовов require("myModule")), содержимое файла модуля будет выполнено только в первый раз, а при повторных вызовах будет возвращаться сохранённый объект exports.
Примечание 2: если модуль подключается в разных сценариях, для каждого сценария будет создан свой объект модуля и заново выполнен весь код модуля. Если модулю требуется использовать данные, общие для всех файлов сценариев, для хранения данных следует использовать объект module.static.
Создание модуля
Для создания модуля достаточно создать файл с именем, соответсвующим имени модуля (с расширением .js) в директории /etc/wb-rules/modules.
В этом файле будут доступны все стандартные функции wb-rules, а также набор специальных объектов, с помощью которого можно реализовать необходимый функционал модуля.
Объект exports
С помощью объекта exports можно передавать пользовательскому сценарию параметры и методы.
Пример
Файл модуля /etc/wb-rules/modules/myModule.js
exports.hello = function(text) {
log("Hello from module, {}", text);
};
exports.answer = 42;
Файл сценария scenario.js
var m = require("myModule");
m.hello("world"); // выведет в лог "Hello from module, world"
log("The answer is {}", m.answer); // выведет в лог "The answer is 42"
Будьте внимательны: объект exports можно только дополнять значениями, но не переопределять. Иначе значения экспортированы не будут!
exports = function(text) {
log("Hello from module, {}", text);
};
// Ожидание:
var m = require("my-module");
m("world"); // не работает
// На практике m будет пустым объектом.
// Та же проблема произойдёт при использовании такой конструкции:
exports = {
hello: function(text) {
log("Hello from module, {}", world);
},
answer: 42
};
Объект module
Объект module содержит параметры, относящиеся непосредственно к файлу модуля.
module.filename
Содержит полный путь до файла модуля. Например, для модуля, сохранённого в /etc/wb-rules/modules/myModule.js:
log(module.filename); // выведет /etc/wb-rules/modules/myModule.js
module.static
Объект, хранящий данные, общие для всех экземпляров данного модуля. Его следует использовать для тех данных, которые должны быть доступны сразу во всех сценариях, использующих данный модуль.
Файл /etc/wb-rules/modules/myModule.js
exports.counter = function() {
if (module.static.count === undefined) {
module.static.count = 1;
}
log("Number of calls: {}", module.static.count);
module.static.count++;
};
Файл сценария scenario1.js
var m = require("myModule");
m.counter();
m.counter();
Файл сценария scenario2.js
var m = require("myModule");
m.counter();
m.counter();
m.counter();
В результате работы двух скриптов в логе окажется 5 сообщений:
Number of calls: 1
Number of calls: 2
Number of calls: 3
Number of calls: 4
Number of calls: 5
__filename
Переменная __filename берётся из глобального объекта сценария, к которому подключается модуль, и содержит имя файла сценария.
В случае, если модуль подключается в другом модуле, переменная __filename, тем не менее, будет содержать именно имя файла сценария - вершины дерева зависимостей.
Файл /etc/wb-rules/modules/myModule.js
exports.hello = function() {
log(__filename);
};
Файл сценария /etc/wb-rules/scenario1.js
var m = require("myModule");
m.hello(); // выведет scenario1.js