Движок правил wb-rules 1.7/en: различия между версиями

Материал из Wiren Board
(Новая страница: «<syntaxhighlight lang="js"> defineVirtualDevice("vdev", { ... cells: { ... mycell: { type: "value", value: "10",…»)
(Новая страница: «Before: <pre> 2019-01-05 17:29:50myFuncTwo called 2019-01-05 17:29:50test1: 84, test2: Hello 2019-01-05 17:29:50myFuncOne called 2019-01-05 17:29:50test1: 84 2019…»)
(не показано 28 промежуточных версий этого же участника)
Строка 56: Строка 56:




Now:
Стало:
<pre>
<pre>
2019-01-05 17:28:42myFuncTwo called
2019-01-05 17:28:42myFuncTwo called
Строка 70: Строка 70:




=== Note ===
=== Примечание ===


In previous versions of wb-rules, it was recommended to use loopback to isolate rules, i.e. to isolate rules.  
В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е.  
wrapping the script code into a construct:
оборачивание кода сценария в конструкцию:
<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
(function() {
(function() {
     // script code goes here
     // код сценария идёт здесь
})();
})();
</syntaxhighlight>
</syntaxhighlight>


Starting from version 1.7, such a construction is usually not necessary. However, the old scripts,
Начиная с версии 1.7, в подобной конструкции обычно нет необходимости. Тем не менее, старые сценарии,
using this construction, will continue to work without changes in behavior.
использующие эту конструкцию, продолжат работу без изменений в поведении.




=== workarounds ===
=== Обходные пути ===


If your system used a shared global space to store shared data and functions,
Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций,
there are several ways to implement this behavior:
есть несколько способов реализации такого поведения:




==== Permanent repository ====
==== Постоянное хранилище ====


You can also use global persistent storages to exchange data.
Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage).


'''Warning:''' when using global persistent stores, a name match may occur,  
'''Внимание:''' при использовании глобальных постоянных хранилищ может произойти совпадение имён, в
in this case, a hard-to-detect behavior violation is possible.
этом случае возможно труднообнаруживаемое нарушение поведения.


<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
Строка 102: Строка 102:
/// ...
/// ...


ps.myvar = "value"; // this value is available for users of "my-global-storage"
ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage"
</syntaxhighlight>
</syntaxhighlight>




==== A prototype of the global object ====
==== Прототип глобального объекта ====


'''WARNING:''' method is considered "dirty" because all variables and functions published in this way,
'''ВНИМАНИЕ:''' метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом,
become available to all scenarios in the system. Try to avoid this method. The programmer is solely responsible for the undefined behavior of the device when using this method
становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое
поведение при использовании этого метода несёт ответственность сам программист.


Global objects of all scenarios have a common object-"prototype", in which standard functions are defined
Глобальные объекты всех сценариев имеют общий объект-''прототип'', в котором определены стандартные функции
wb-rules (such as defineRule, setTimeout, etc.). It can be used to pass variables or functions
wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции
General field of view.
в общую область видимости.


<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
global.__proto__.myVar = 42; // now myVar - is a common variable for all scripts
global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев


// the variable can be accessed from other scripts as follows
// из других сценариев к переменной можно обращаться так
log("shared myVar: {}", myVar);
log("shared myVar: {}", myVar);


// or like this, which is a bit more accurate, because it clearly shows where the variable is defined
// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
log("shared myVar: {}", global.__proto__.myVar);
log("shared myVar: {}", global.__proto__.myVar);
</syntaxhighlight>
</syntaxhighlight>


The variable search rule in the first case will look like this:
Правило поиска переменной в первом случае будет выглядеть так:


# Check if there is myVar among local variables (defined as var myVar = ...).
# Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...).
# If not, check if there is myVar in the global object (defined as myVar = ...).
# Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...).
# If not, check if myVar is in the "prototype" of the global object (defined as global.__proto__.myVar).
# Если нет, проверяем, есть ли myVar в ''прототипе'' глобального объекта (определённой как global.__proto__.myVar).


The search stops as soon as the variable is found.
Поиск останавливается, как только переменная найдена.


Thus, the first way of addressing will only work if myVar is not defined in the upper scopes.
Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости.






== Persistent Data Storage ==
== Постоянное хранилище данных ==


WB-rules 1.7 adds support for persistent storage. In fact, these are the objects in which the values will be stored
В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться
even if the controller loses power. These stores are useful for storing States or configurations.
даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации.


<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
Строка 149: Строка 150:
</syntaxhighlight>
</syntaxhighlight>


Only global repositories, that is, visible by the same name from all script files, are supported.
Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев.




== Virtual devices ==
== Виртуальные устройства ==


In previous versions of wb-rules, the values of virtual device controls were stored only in MQTT retained, which is not very reliable (in the case of
В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае
power loss data could easily be lost). Starting with version 2.0, these values are also stored in a special permanent storage
потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной
memory and restored when the script is loaded.
памяти и восстанавливаются при загрузке сценария.


If it is necessary to restore a strictly defined value (i.e. not to restore the previous saved value) every time the script is restarted,
Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое),
you can add the forceDefault field to the control description:
можно добавить в описание контрола поле forceDefault:


<syntaxhighlight lang="js">
<syntaxhighlight lang="js">
Строка 169: Строка 170:
             type: "value",
             type: "value",
             value: "10",
             value: "10",
             forceDefault: true // every time the script box mycell will receive a value of 10
             forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10
         }
         }
     }
     }
});
});
</syntaxhighlight>
</syntaxhighlight>

Версия 18:11, 6 июня 2019

Другие языки:

The updated wb-rules engine contains a number of important innovations regarding the logic of scripting.

Scripts

Isolation of scripts

Starting with wb-rules v.1.7, local variables and functions declared in the script file are not visible in other scripts. Thus, each script can define its own functions and variables without the risk of changing the behavior of other scripts.


Example

As an example, here are two scenarios that run simultaneously in the rules engine. Each scenario defines variables and functions.

In previous versions of wb-rules, refering to a global variable, that is modified in several script files, may cause undefined behavior. Starting from v.1.7, the behavior is strictly defined and is the same as if the script is the only one in the system.

The comments indicate the output of the log commands for earlier versions and for the current version. Note the 'var' before the variables.

rules1.js

var test1 = 42;

setInterval(function myFuncOne() {
    log("myFuncOne called");
    log("test1: {}", test1);
    log("test2: {}", test2);
}, 5000);

rules2.js

test1 = 84;
test2 = "Hello";

setInterval(function myFuncTwo() {
    log("myFuncTwo called");
    log("test1: {}, test2: {}", test1, test2);
}, 5000);


Before:

2019-01-05 17:29:50myFuncTwo called
2019-01-05 17:29:50test1: 84, test2: Hello
2019-01-05 17:29:50myFuncOne called
2019-01-05 17:29:50test1: 84
2019-01-05 17:29:50test2: Hello


Стало:

2019-01-05 17:28:42myFuncTwo called
2019-01-05 17:28:42test1: 84, test2: Hello
2019-01-05 17:28:42myFuncOne called
2019-01-05 17:28:42test1: 42
2019-01-05 17:28:42ECMAScript error: ReferenceError: identifier 'test2' undefined
duk_js_var.c:1232
myFuncOne /etc/wb-rules/rules1.js:6 preventsyield



Примечание

В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. оборачивание кода сценария в конструкцию:

(function() {
    // код сценария идёт здесь
})();

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


Обходные пути

Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, есть несколько способов реализации такого поведения:


Постоянное хранилище

Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage).

Внимание: при использовании глобальных постоянных хранилищ может произойти совпадение имён, в этом случае возможно труднообнаруживаемое нарушение поведения.

var ps = new PersistentStorage("my-global-storage", {global: true});

/// ...

ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage"


Прототип глобального объекта

ВНИМАНИЕ: метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом, становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое поведение при использовании этого метода несёт ответственность сам программист.

Глобальные объекты всех сценариев имеют общий объект-прототип, в котором определены стандартные функции wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции в общую область видимости.

global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев

// из других сценариев к переменной можно обращаться так
log("shared myVar: {}", myVar);

// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
log("shared myVar: {}", global.__proto__.myVar);

Правило поиска переменной в первом случае будет выглядеть так:

  1. Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...).
  2. Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...).
  3. Если нет, проверяем, есть ли myVar в прототипе глобального объекта (определённой как global.__proto__.myVar).

Поиск останавливается, как только переменная найдена.

Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости.


Постоянное хранилище данных

В 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
        }
    }
});